|
@@ -1,13 +1,19 @@
|
|
|
<script setup lang="ts">
|
|
|
import type { PostSketch } from '@/models'
|
|
|
-import { onMounted, ref } from 'vue'
|
|
|
+import { computed, onMounted, ref, watch } from 'vue'
|
|
|
import { api } from '@/utils/axios'
|
|
|
import PostCard from '@/components/PostCard.vue'
|
|
|
+import { useTokenStore } from '@/stores/auth.ts'
|
|
|
+import { delay } from '@/utils'
|
|
|
+import { writeIcon } from '@/assets/icons.ts'
|
|
|
+import { router } from '@/router'
|
|
|
|
|
|
const data = ref<PostSketch[]>([])
|
|
|
const pageSize = 10
|
|
|
const isEnd = ref(false)
|
|
|
|
|
|
+const tokenStore = useTokenStore();
|
|
|
+
|
|
|
function nextDatum() {
|
|
|
if (isEnd.value) {
|
|
|
return
|
|
@@ -27,11 +33,58 @@ function nextDatum() {
|
|
|
|
|
|
onMounted(() => {
|
|
|
nextDatum()
|
|
|
-})
|
|
|
+});
|
|
|
+
|
|
|
+const tokenAvailable = ref(false);
|
|
|
+
|
|
|
+const floatBtnElementAnimationStyle = ref({
|
|
|
+ display: "none",
|
|
|
+ transform: "scale(0)",
|
|
|
+ transition: "all .3s"
|
|
|
+});
|
|
|
+
|
|
|
+watch(() => tokenStore.available, async (newValue) => {
|
|
|
+ if (!tokenAvailable.value && newValue) {
|
|
|
+ tokenAvailable.value = true;
|
|
|
+ floatBtnElementAnimationStyle.value.display = "block";
|
|
|
+ floatBtnElementAnimationStyle.value.transform = "scale(0)";
|
|
|
+ await delay(20);
|
|
|
+ floatBtnElementAnimationStyle.value.transform = "scale(100%)";
|
|
|
+ } else if (tokenAvailable.value && !newValue) {
|
|
|
+ tokenAvailable.value = false;
|
|
|
+ floatBtnElementAnimationStyle.value.transform = "scale(0)";
|
|
|
+ await delay(320);
|
|
|
+ floatBtnElementAnimationStyle.value.display = "none";
|
|
|
+ }
|
|
|
+}, {immediate: true});
|
|
|
+
|
|
|
+const tips = [
|
|
|
+ "写点东西?", "有新鲜事?", "有新技术?", "有新发现?", "有新想法?"
|
|
|
+];
|
|
|
+
|
|
|
+const tipIndex = ref(0);
|
|
|
+
|
|
|
+const currentTip = computed(() => tips[tipIndex.value]);
|
|
|
+
|
|
|
+const changeTip = () => {
|
|
|
+ tipIndex.value = (tipIndex.value + 1) % tips.length;
|
|
|
+}
|
|
|
+
|
|
|
+function handleWriteClick() {
|
|
|
+ router.push("/editor")
|
|
|
+}
|
|
|
+
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <div>
|
|
|
+ <div style="position: relative;">
|
|
|
+ <div class="float-btn" @click.stop="handleWriteClick" :style="floatBtnElementAnimationStyle" @mouseenter="changeTip">
|
|
|
+ <div class="float-btn-content">
|
|
|
+ <div class="float-btn-ico" v-html="writeIcon.template"/>
|
|
|
+ <div>{{ currentTip }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
<PostCard v-for="item of data" :key="item.id" :target="item" />
|
|
|
<div
|
|
|
class="post-item"
|
|
@@ -63,5 +116,52 @@ onMounted(() => {
|
|
|
color: var(--text-color);
|
|
|
}
|
|
|
|
|
|
+.float-btn {
|
|
|
+ position: fixed;
|
|
|
+ right: 48px;
|
|
|
+ bottom: 32px;
|
|
|
+ padding: 8px;
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ border-radius: 24px;
|
|
|
+ overflow: hidden;
|
|
|
+ fill: var(--text-color);
|
|
|
+ color: var(--text-color);
|
|
|
+ background-color: var(--secondary-background-color);
|
|
|
+ box-shadow: rgba(0, 0, 0, 0.4) 0 0 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ z-index: 10;
|
|
|
+}
|
|
|
+
|
|
|
+.float-btn:hover {
|
|
|
+ fill: var(--secondary-background-color);
|
|
|
+ background-color: var(--text-color);
|
|
|
+ color: var(--secondary-background-color);
|
|
|
+ right: 32px;
|
|
|
+ bottom: 24px;
|
|
|
+ width: 150px;
|
|
|
+ height: 48px;
|
|
|
+ border-radius: 32px;
|
|
|
+}
|
|
|
+
|
|
|
+.float-btn-content {
|
|
|
+ width: 256px;
|
|
|
+ display: flex;
|
|
|
+ gap: 8px;
|
|
|
+ font-size: large;
|
|
|
+ font-weight: bold;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.float-btn-ico {
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ transition: all .3s;
|
|
|
+}
|
|
|
+
|
|
|
+.float-btn:hover .float-btn-content .float-btn-ico {
|
|
|
+ width: 48px;
|
|
|
+ height: 48px;
|
|
|
+}
|
|
|
|
|
|
</style>
|