Merge branch 'master' into dev
This commit is contained in:
commit
60904b752f
6 changed files with 77 additions and 42 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Flame, MousePointerClick, Users } from 'lucide-vue-next'
|
import { Flame, MousePointerClick, Users } from 'lucide-vue-next'
|
||||||
|
import NumberFlow from '@number-flow/vue'
|
||||||
|
|
||||||
const defaultData = Object.freeze({
|
const defaultData = Object.freeze({
|
||||||
visits: 0,
|
visits: 0,
|
||||||
|
|
@ -46,15 +47,7 @@ onBeforeUnmount(() => {
|
||||||
<MousePointerClick class="w-4 h-4 text-muted-foreground" />
|
<MousePointerClick class="w-4 h-4 text-muted-foreground" />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div
|
<NumberFlow class="text-2xl font-bold" :class="{ 'blur-md opacity-60': !counters.visits }" :value="counters.visits" />
|
||||||
class="text-2xl font-bold"
|
|
||||||
:class="{ 'blur-lg': !counters.visits }"
|
|
||||||
>
|
|
||||||
{{ formatNumber(counters.visits) }}
|
|
||||||
</div>
|
|
||||||
<!-- <p class="text-xs text-muted-foreground">
|
|
||||||
+90
|
|
||||||
</p> -->
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<Card>
|
<Card>
|
||||||
|
|
@ -65,15 +58,7 @@ onBeforeUnmount(() => {
|
||||||
<Users class="w-4 h-4 text-muted-foreground" />
|
<Users class="w-4 h-4 text-muted-foreground" />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div
|
<NumberFlow class="text-2xl font-bold" :class="{ 'blur-md opacity-60': !counters.visitors }" :value="counters.visitors" />
|
||||||
class="text-2xl font-bold"
|
|
||||||
:class="{ 'blur-lg': !counters.visitors }"
|
|
||||||
>
|
|
||||||
{{ formatNumber(counters.visitors) }}
|
|
||||||
</div>
|
|
||||||
<!-- <p class="text-xs text-muted-foreground">
|
|
||||||
+90
|
|
||||||
</p> -->
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<Card>
|
<Card>
|
||||||
|
|
@ -84,15 +69,7 @@ onBeforeUnmount(() => {
|
||||||
<Flame class="w-4 h-4 text-muted-foreground" />
|
<Flame class="w-4 h-4 text-muted-foreground" />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div
|
<NumberFlow class="text-2xl font-bold" :class="{ 'blur-md opacity-60': !counters.referers }" :value="counters.referers" />
|
||||||
class="text-2xl font-bold"
|
|
||||||
:class="{ 'blur-lg': !counters.referers }"
|
|
||||||
>
|
|
||||||
{{ formatNumber(counters.referers) }}
|
|
||||||
</div>
|
|
||||||
<!-- <p class="text-xs text-muted-foreground">
|
|
||||||
-20
|
|
||||||
</p> -->
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -6,23 +6,37 @@ const links = ref([])
|
||||||
const limit = 24
|
const limit = 24
|
||||||
let cursor = ''
|
let cursor = ''
|
||||||
let listComplete = false
|
let listComplete = false
|
||||||
|
let listError = false
|
||||||
|
|
||||||
async function getLinks() {
|
async function getLinks() {
|
||||||
const data = await useAPI('/api/link/list', {
|
try {
|
||||||
query: {
|
const data = await useAPI('/api/link/list', {
|
||||||
limit,
|
query: {
|
||||||
cursor,
|
limit,
|
||||||
},
|
cursor,
|
||||||
})
|
},
|
||||||
links.value = links.value.concat(data.links).filter(Boolean) // Sometimes cloudflare will return null, filter out
|
})
|
||||||
cursor = data.cursor
|
links.value = links.value.concat(data.links).filter(Boolean) // Sometimes cloudflare will return null, filter out
|
||||||
listComplete = data.list_complete
|
cursor = data.cursor
|
||||||
|
listComplete = data.list_complete
|
||||||
|
listError = false
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
listError = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isLoading } = useInfiniteScroll(
|
const { isLoading } = useInfiniteScroll(
|
||||||
document,
|
document,
|
||||||
getLinks,
|
getLinks,
|
||||||
{ distance: 150, interval: 1000, canLoadMore: () => !listComplete },
|
{
|
||||||
|
distance: 150,
|
||||||
|
interval: 1000,
|
||||||
|
canLoadMore: () => {
|
||||||
|
return !listError && !listComplete
|
||||||
|
},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
function updateLinkList(link, type) {
|
function updateLinkList(link, type) {
|
||||||
|
|
@ -46,7 +60,7 @@ function updateLinkList(link, type) {
|
||||||
<DashboardNav class="flex-1">
|
<DashboardNav class="flex-1">
|
||||||
<DashboardLinksEditor @update:link="updateLinkList" />
|
<DashboardLinksEditor @update:link="updateLinkList" />
|
||||||
</DashboardNav>
|
</DashboardNav>
|
||||||
<DashboardLinksSearch />
|
<LazyDashboardLinksSearch />
|
||||||
</div>
|
</div>
|
||||||
<section class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
<section class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||||
<DashboardLinksLink
|
<DashboardLinksLink
|
||||||
|
|
@ -68,5 +82,14 @@ function updateLinkList(link, type) {
|
||||||
>
|
>
|
||||||
No more
|
No more
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="listError"
|
||||||
|
class="flex items-center justify-center text-sm"
|
||||||
|
>
|
||||||
|
Loading links failed,
|
||||||
|
<Button variant="link" @click="getLinks">
|
||||||
|
Try again
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const isOpen = ref(false)
|
||||||
const searchTerm = ref('')
|
const searchTerm = ref('')
|
||||||
const selectedLink = ref(null)
|
const selectedLink = ref(null)
|
||||||
|
|
||||||
const links = await useAPI('/api/link/search')
|
const links = ref([])
|
||||||
|
|
||||||
const { results: filteredLinks } = useFuse(searchTerm, links, {
|
const { results: filteredLinks } = useFuse(searchTerm, links, {
|
||||||
fuseOptions: {
|
fuseOptions: {
|
||||||
|
|
@ -37,6 +37,14 @@ function selectLink(link) {
|
||||||
query: { slug: link.slug },
|
query: { slug: link.slug },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getLinks() {
|
||||||
|
links.value = await useAPI('/api/link/search')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getLinks()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -73,7 +81,7 @@ function selectLink(link) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Badge v-if="link.item?.comment" variant="secondary">
|
<Badge v-if="link.item?.comment" variant="secondary">
|
||||||
<div class="w-24 truncate">
|
<div class="max-w-24 truncate">
|
||||||
{{ link.item?.comment }}
|
{{ link.item?.comment }}
|
||||||
</div>
|
</div>
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "sink",
|
"name": "sink",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "pnpm@9.7.1",
|
"packageManager": "pnpm@9.7.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
"lint-staged": "lint-staged"
|
"lint-staged": "lint-staged"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@number-flow/vue": "^0.3.3",
|
||||||
"@unovis/ts": "^1.4.4",
|
"@unovis/ts": "^1.4.4",
|
||||||
"@unovis/vue": "^1.4.4",
|
"@unovis/vue": "^1.4.4",
|
||||||
"@vee-validate/zod": "^4.13.2",
|
"@vee-validate/zod": "^4.13.2",
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@ importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@number-flow/vue':
|
||||||
|
specifier: ^0.3.3
|
||||||
|
version: 0.3.3(vue@3.4.38(typescript@5.4.5))
|
||||||
'@unovis/ts':
|
'@unovis/ts':
|
||||||
specifier: ^1.4.4
|
specifier: ^1.4.4
|
||||||
version: 1.4.4
|
version: 1.4.4
|
||||||
|
|
@ -1228,6 +1231,11 @@ packages:
|
||||||
resolution: {integrity: sha512-54voNDBobGdMl3BUXSu7UaDh1P85PGHWlJ5e0XhPugo1JulOyCtp2I+5ri4wplGDJ8QGwPEQW7/x3yTLU7yF1A==}
|
resolution: {integrity: sha512-54voNDBobGdMl3BUXSu7UaDh1P85PGHWlJ5e0XhPugo1JulOyCtp2I+5ri4wplGDJ8QGwPEQW7/x3yTLU7yF1A==}
|
||||||
engines: {node: '>=16.14.0'}
|
engines: {node: '>=16.14.0'}
|
||||||
|
|
||||||
|
'@number-flow/vue@0.3.3':
|
||||||
|
resolution: {integrity: sha512-yjuTRzwBUqh4rMZYSXG3/0Bv3YuLLUD3TIh7y7qXYCtorUyYP4/fPocVfrCh2TBlAu/jgci7BtvwC0IFnbNUtw==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3
|
||||||
|
|
||||||
'@nuxt/devalue@2.0.2':
|
'@nuxt/devalue@2.0.2':
|
||||||
resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==}
|
resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==}
|
||||||
|
|
||||||
|
|
@ -3245,6 +3253,9 @@ packages:
|
||||||
jiti:
|
jiti:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
esm-env@1.2.1:
|
||||||
|
resolution: {integrity: sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==}
|
||||||
|
|
||||||
espree@10.1.0:
|
espree@10.1.0:
|
||||||
resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==}
|
resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
@ -4265,6 +4276,9 @@ packages:
|
||||||
nth-check@2.1.1:
|
nth-check@2.1.1:
|
||||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||||
|
|
||||||
|
number-flow@0.4.2:
|
||||||
|
resolution: {integrity: sha512-YLN73/m8BUU4r/6mq9zqLdpFKt3LSPPRectOECheA9jtNWF4PP8EIz0+Z1giqu/x9nS86KnKwwouLXXiqnjhQQ==}
|
||||||
|
|
||||||
nuxi@3.12.0:
|
nuxi@3.12.0:
|
||||||
resolution: {integrity: sha512-6vRdiXTw9SajEQOUi6Ze/XaIXzy1q/sD5UqHQSv3yqTu7Pot5S7fEihNXV8LpcgLz+9HzjVt70r7jYe7R99c2w==}
|
resolution: {integrity: sha512-6vRdiXTw9SajEQOUi6Ze/XaIXzy1q/sD5UqHQSv3yqTu7Pot5S7fEihNXV8LpcgLz+9HzjVt70r7jYe7R99c2w==}
|
||||||
engines: {node: ^16.10.0 || >=18.0.0}
|
engines: {node: ^16.10.0 || >=18.0.0}
|
||||||
|
|
@ -6800,6 +6814,12 @@ snapshots:
|
||||||
'@nodelib/fs.scandir': 3.0.0
|
'@nodelib/fs.scandir': 3.0.0
|
||||||
fastq: 1.17.1
|
fastq: 1.17.1
|
||||||
|
|
||||||
|
'@number-flow/vue@0.3.3(vue@3.4.38(typescript@5.4.5))':
|
||||||
|
dependencies:
|
||||||
|
esm-env: 1.2.1
|
||||||
|
number-flow: 0.4.2
|
||||||
|
vue: 3.4.38(typescript@5.4.5)
|
||||||
|
|
||||||
'@nuxt/devalue@2.0.2': {}
|
'@nuxt/devalue@2.0.2': {}
|
||||||
|
|
||||||
'@nuxt/devtools-kit@1.3.9(magicast@0.3.4)(rollup@4.18.0)(vite@5.4.1(@types/node@20.12.11)(terser@5.31.0))':
|
'@nuxt/devtools-kit@1.3.9(magicast@0.3.4)(rollup@4.18.0)(vite@5.4.1(@types/node@20.12.11)(terser@5.31.0))':
|
||||||
|
|
@ -9364,6 +9384,8 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
esm-env@1.2.1: {}
|
||||||
|
|
||||||
espree@10.1.0:
|
espree@10.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.12.1
|
acorn: 8.12.1
|
||||||
|
|
@ -10498,6 +10520,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 1.0.0
|
||||||
|
|
||||||
|
number-flow@0.4.2:
|
||||||
|
dependencies:
|
||||||
|
esm-env: 1.2.1
|
||||||
|
|
||||||
nuxi@3.12.0:
|
nuxi@3.12.0:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ export default eventHandler(async (event) => {
|
||||||
while (true) {
|
while (true) {
|
||||||
const { keys, list_complete, cursor } = await KV.list({
|
const { keys, list_complete, cursor } = await KV.list({
|
||||||
prefix: `link:`,
|
prefix: `link:`,
|
||||||
limit: 1,
|
limit: 1000,
|
||||||
cursor: finalCursor,
|
cursor: finalCursor,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue