Skip to content

Commit 44dde15

Browse files
committed
feat: add clicks slider in list overview
1 parent fc14491 commit 44dde15

File tree

2 files changed

+95
-31
lines changed

2 files changed

+95
-31
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<script setup lang="ts">
2+
import type { ClicksContext } from '@slidev/types'
3+
import type { Ref } from 'vue'
4+
import { computed, defineProps } from 'vue'
5+
6+
const props = defineProps<{
7+
clickContext: [Ref<number>, ClicksContext]
8+
}>()
9+
10+
const total = computed(() => props.clickContext[1].total)
11+
const current = computed({
12+
get() {
13+
return props.clickContext[0].value > total.value ? -1 : props.clickContext[0].value
14+
},
15+
set(value: number) {
16+
// eslint-disable-next-line vue/no-mutating-props
17+
props.clickContext[0].value = value
18+
},
19+
})
20+
21+
const range = computed(() => Array.from({ length: total.value + 1 }, (_, i) => i))
22+
</script>
23+
24+
<template>
25+
<div
26+
class="flex gap-0.5 items-center select-none"
27+
:title="`Clicks in this slide: ${total}`"
28+
>
29+
<div class="flex gap-1 items-center min-w-16">
30+
<carbon:cursor-1 text-sm op50 />
31+
<span v-if="current <= total && current >= 0" text-primary>{{ current }}/</span>
32+
<span op50>{{ total }}</span>
33+
</div>
34+
<div
35+
relative flex-auto h5 flex="~"
36+
@dblclick="current = 999999"
37+
>
38+
<div
39+
v-for="i of range" :key="i"
40+
border="y main" of-hidden relative
41+
:class="[
42+
i === 0 ? 'rounded-l border-l' : '',
43+
i === total ? 'rounded-r border-r' : '',
44+
]"
45+
:style="{ width: `${1 / total * 100}%` }"
46+
>
47+
<div absolute inset-0 z--1 :class=" i <= current ? 'bg-primary' : ''" />
48+
<div
49+
:class="[
50+
+i === +current ? 'text-white font-bold op100' : 'op30',
51+
i === 0 ? 'rounded-l' : '',
52+
i === total ? 'rounded-r' : 'border-r border-main',
53+
]"
54+
w-full h-full text-xs flex items-center justify-center
55+
>
56+
{{ i }}
57+
</div>
58+
</div>
59+
<input v-model="current" absolute inset-0 type="range" :min="0" :max="total" :step="1" z-10 op0>
60+
</div>
61+
</div>
62+
</template>

packages/client/pages/overview.vue

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
<script setup lang="ts">
2+
import type { Ref } from 'vue'
23
import { computed, nextTick, onMounted, reactive, ref } from 'vue'
34
import { useHead } from '@unhead/vue'
45
import type { RouteRecordRaw } from 'vue-router'
56
import type { ClicksContext } from 'packages/types'
67
import { themeVars } from '../env'
78
import { rawRoutes } from '../logic/nav'
8-
import { useClicksContextBase } from '../composables/useClicks'
9+
import { useFixedClicks } from '../composables/useClicks'
910
import { isColorSchemaConfigured, isDark, toggleDark } from '../logic/dark'
1011
import { getSlideClass } from '../utils'
1112
import SlideContainer from '../internals/SlideContainer.vue'
1213
import SlideWrapper from '../internals/SlideWrapper'
1314
import DrawingPreview from '../internals/DrawingPreview.vue'
1415
import IconButton from '../internals/IconButton.vue'
1516
import NoteEditor from '../internals/NoteEditor.vue'
17+
import OverviewClicksSlider from '../internals/OverviewClicksSlider.vue'
1618
1719
const cardWidth = 450
1820
@@ -27,16 +29,16 @@ const wordCounts = computed(() => rawRoutes.map(route => wordCount(route.meta?.s
2729
const totalWords = computed(() => wordCounts.value.reduce((a, b) => a + b, 0))
2830
const totalClicks = computed(() => rawRoutes.map(route => getSlideClicks(route)).reduce((a, b) => a + b, 0))
2931
30-
const clicksContextMap = new WeakMap<RouteRecordRaw, ClicksContext>()
32+
const clicksContextMap = new WeakMap<RouteRecordRaw, [Ref<number>, ClicksContext]>()
3133
function getClickContext(route: RouteRecordRaw) {
3234
// We create a local clicks context to calculate the total clicks of the slide
3335
if (!clicksContextMap.has(route))
34-
clicksContextMap.set(route, useClicksContextBase(() => 999999, route?.meta?.clicks))
36+
clicksContextMap.set(route, useFixedClicks(route, 9999))
3537
return clicksContextMap.get(route)!
3638
}
3739
3840
function getSlideClicks(route: RouteRecordRaw) {
39-
return route.meta?.clicks || getClickContext(route)?.total
41+
return route.meta?.clicks || getClickContext(route)?.[1]?.total
4042
}
4143
4244
function wordCount(str: string) {
@@ -133,36 +135,36 @@ onMounted(() => {
133135
<div class="text-3xl op20 mb2">
134136
{{ idx + 1 }}
135137
</div>
138+
</div>
139+
<div class="flex flex-col gap-2 my5">
136140
<div
137-
v-if="getSlideClicks(route)"
138-
class="flex gap-0.5 op50 items-center justify-end"
139-
:title="`Clicks in this slide: ${getSlideClicks(route)}`"
141+
class="border rounded border-main overflow-hidden bg-main select-none h-max"
142+
:style="themeVars"
143+
@dblclick="openSlideInNewTab(route.path)"
140144
>
141-
<carbon:cursor-1 text-sm />
142-
{{ getSlideClicks(route) }}
145+
<SlideContainer
146+
:key="route.path"
147+
:width="cardWidth"
148+
:clicks-disabled="true"
149+
class="pointer-events-none important:[&_*]:select-none"
150+
>
151+
<SlideWrapper
152+
:is="route.component"
153+
v-if="route?.component"
154+
:clicks-context="getClickContext(route)[1]"
155+
:class="getSlideClass(route)"
156+
:route="route"
157+
render-context="overview"
158+
/>
159+
<DrawingPreview :page="+route.path" />
160+
</SlideContainer>
143161
</div>
144-
</div>
145-
<div
146-
class="border rounded border-main overflow-hidden bg-main my5 select-none h-max"
147-
:style="themeVars"
148-
@dblclick="openSlideInNewTab(route.path)"
149-
>
150-
<SlideContainer
151-
:key="route.path"
152-
:width="cardWidth"
153-
:clicks-disabled="true"
154-
class="pointer-events-none important:[&_*]:select-none"
155-
>
156-
<SlideWrapper
157-
:is="route.component"
158-
v-if="route?.component"
159-
:clicks-context="getClickContext(route)"
160-
:class="getSlideClass(route)"
161-
:route="route"
162-
render-context="overview"
163-
/>
164-
<DrawingPreview :page="+route.path" />
165-
</SlideContainer>
162+
<OverviewClicksSlider
163+
v-if="getSlideClicks(route)"
164+
mt-2
165+
:click-context="getClickContext(route)"
166+
class="w-full"
167+
/>
166168
</div>
167169
<div class="py3 mt-0.5 mr--8 ml--4 op0 transition group-hover:op100">
168170
<IconButton

0 commit comments

Comments
 (0)