@open-slide/core 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/env.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Ambient module declarations for assets imported from `slides/<id>/assets/`.
|
|
2
|
+
// Mirrors Vite's default asset handling (default export = resolved URL).
|
|
3
|
+
//
|
|
4
|
+
// Consumers opt in via tsconfig:
|
|
5
|
+
//
|
|
6
|
+
// { "compilerOptions": { "types": ["@open-slide/core/env"] } }
|
|
7
|
+
|
|
8
|
+
declare module '*.svg' {
|
|
9
|
+
const src: string;
|
|
10
|
+
export default src;
|
|
11
|
+
}
|
|
12
|
+
declare module '*.png' {
|
|
13
|
+
const src: string;
|
|
14
|
+
export default src;
|
|
15
|
+
}
|
|
16
|
+
declare module '*.jpg' {
|
|
17
|
+
const src: string;
|
|
18
|
+
export default src;
|
|
19
|
+
}
|
|
20
|
+
declare module '*.jpeg' {
|
|
21
|
+
const src: string;
|
|
22
|
+
export default src;
|
|
23
|
+
}
|
|
24
|
+
declare module '*.webp' {
|
|
25
|
+
const src: string;
|
|
26
|
+
export default src;
|
|
27
|
+
}
|
|
28
|
+
declare module '*.gif' {
|
|
29
|
+
const src: string;
|
|
30
|
+
export default src;
|
|
31
|
+
}
|
|
32
|
+
declare module '*.avif' {
|
|
33
|
+
const src: string;
|
|
34
|
+
export default src;
|
|
35
|
+
}
|
|
36
|
+
declare module '*.mp4' {
|
|
37
|
+
const src: string;
|
|
38
|
+
export default src;
|
|
39
|
+
}
|
|
40
|
+
declare module '*.webm' {
|
|
41
|
+
const src: string;
|
|
42
|
+
export default src;
|
|
43
|
+
}
|
|
44
|
+
declare module '*.woff' {
|
|
45
|
+
const src: string;
|
|
46
|
+
export default src;
|
|
47
|
+
}
|
|
48
|
+
declare module '*.woff2' {
|
|
49
|
+
const src: string;
|
|
50
|
+
export default src;
|
|
51
|
+
}
|
|
52
|
+
declare module '*.ttf' {
|
|
53
|
+
const src: string;
|
|
54
|
+
export default src;
|
|
55
|
+
}
|
|
56
|
+
declare module '*.otf' {
|
|
57
|
+
const src: string;
|
|
58
|
+
export default src;
|
|
59
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-slide/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Runtime and CLI for open-slide — write slides in slides/, we handle the rest.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"./vite": {
|
|
12
12
|
"types": "./dist/vite/index.d.ts",
|
|
13
13
|
"import": "./dist/vite/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./env": {
|
|
16
|
+
"types": "./env.d.ts"
|
|
14
17
|
}
|
|
15
18
|
},
|
|
16
19
|
"bin": {
|
|
@@ -19,6 +22,7 @@
|
|
|
19
22
|
"files": [
|
|
20
23
|
"bin.js",
|
|
21
24
|
"dist",
|
|
25
|
+
"env.d.ts",
|
|
22
26
|
"src/app",
|
|
23
27
|
"skills",
|
|
24
28
|
"README.md"
|
|
@@ -72,64 +72,64 @@ export function PresentControlBar({
|
|
|
72
72
|
>
|
|
73
73
|
<TooltipProvider delayDuration={300}>
|
|
74
74
|
<TooltipContainerCtx.Provider value={tooltipContainer ?? null}>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
<div className="pointer-events-auto flex h-11 items-center gap-1 rounded-full border border-white/10 bg-black/55 px-2 text-white/85 shadow-[0_8px_30px_-8px_oklch(0_0_0/0.6)] backdrop-blur-md">
|
|
76
|
+
<BarButton label="Previous slide (←)" onClick={onPrev} disabled={index === 0}>
|
|
77
|
+
<ChevronLeft className="size-4" />
|
|
78
|
+
</BarButton>
|
|
79
|
+
<BarButton label="Next slide (→)" onClick={onNext} disabled={index >= total - 1}>
|
|
80
|
+
<ChevronRight className="size-4" />
|
|
81
|
+
</BarButton>
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
<Divider />
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
<span className="px-2 font-mono text-[11.5px] tracking-[0.08em] tabular-nums uppercase select-none text-white/85">
|
|
86
|
+
<span className="text-white">{(index + 1).toString().padStart(2, '0')}</span>
|
|
87
|
+
<span className="text-white/35"> / </span>
|
|
88
|
+
<span>{total.toString().padStart(2, '0')}</span>
|
|
89
|
+
</span>
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
<Divider />
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
<ElapsedClock startedAt={startedAt} />
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
<Divider />
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
97
|
+
<BarButton label="Slide overview (O)" onClick={onOverview}>
|
|
98
|
+
<Grid2x2 className="size-4" />
|
|
99
|
+
</BarButton>
|
|
100
|
+
<BarButton
|
|
101
|
+
label="Black screen (B)"
|
|
102
|
+
onClick={() => onBlackout('black')}
|
|
103
|
+
active={blackout === 'black'}
|
|
104
|
+
>
|
|
105
|
+
<Square className="size-4 fill-current" />
|
|
106
|
+
</BarButton>
|
|
107
|
+
<BarButton
|
|
108
|
+
label="White screen (W)"
|
|
109
|
+
onClick={() => onBlackout('white')}
|
|
110
|
+
active={blackout === 'white'}
|
|
111
|
+
>
|
|
112
|
+
<Sun className="size-4" />
|
|
113
|
+
</BarButton>
|
|
114
|
+
<BarButton label="Laser pointer (L)" onClick={onLaser} active={laser}>
|
|
115
|
+
<Crosshair className="size-4" />
|
|
116
|
+
</BarButton>
|
|
117
|
+
<BarButton label="Presenter view (P)" onClick={onPresenter}>
|
|
118
|
+
<MonitorSpeaker className="size-4" />
|
|
119
|
+
</BarButton>
|
|
120
|
+
<BarButton label="Keyboard shortcuts (?)" onClick={onHelp}>
|
|
121
|
+
<Keyboard className="size-4" />
|
|
122
|
+
</BarButton>
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
124
|
+
{allowExit && (
|
|
125
|
+
<>
|
|
126
|
+
<Divider />
|
|
127
|
+
<BarButton label="Exit (Esc)" onClick={onExit}>
|
|
128
|
+
<LogOut className="size-4" />
|
|
129
|
+
</BarButton>
|
|
130
|
+
</>
|
|
131
|
+
)}
|
|
132
|
+
</div>
|
|
133
133
|
</TooltipContainerCtx.Provider>
|
|
134
134
|
</TooltipProvider>
|
|
135
135
|
</div>
|
|
@@ -22,14 +22,7 @@ type Props = {
|
|
|
22
22
|
* so each preview is rendered with the slide's design tokens but with
|
|
23
23
|
* motion frozen. Arrow keys move focus; Enter/click jumps and closes.
|
|
24
24
|
*/
|
|
25
|
-
export function PresentOverviewGrid({
|
|
26
|
-
pages,
|
|
27
|
-
design,
|
|
28
|
-
open,
|
|
29
|
-
current,
|
|
30
|
-
onClose,
|
|
31
|
-
onSelect,
|
|
32
|
-
}: Props) {
|
|
25
|
+
export function PresentOverviewGrid({ pages, design, open, current, onClose, onSelect }: Props) {
|
|
33
26
|
const [focused, setFocused] = useState(current);
|
|
34
27
|
const gridRef = useRef<HTMLDivElement>(null);
|
|
35
28
|
const focusedRef = useRef<HTMLButtonElement | null>(null);
|
package/src/app/routes/home.tsx
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FolderInput,
|
|
3
|
-
FolderPlus,
|
|
4
|
-
MoreHorizontal,
|
|
5
|
-
Pencil,
|
|
6
|
-
Search,
|
|
7
|
-
Trash2,
|
|
8
|
-
X,
|
|
9
|
-
} from 'lucide-react';
|
|
1
|
+
import { FolderInput, FolderPlus, MoreHorizontal, Pencil, Search, Trash2, X } from 'lucide-react';
|
|
10
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
11
3
|
import { Link, useSearchParams } from 'react-router-dom';
|
|
12
4
|
import { Button } from '@/components/ui/button';
|
|
@@ -79,7 +71,9 @@ export function Home() {
|
|
|
79
71
|
const [query, setQuery] = useState('');
|
|
80
72
|
const [titleMap, setTitleMap] = useState<Record<string, string>>({});
|
|
81
73
|
const reportTitle = useCallback((slideId: string, slideTitle: string) => {
|
|
82
|
-
setTitleMap((prev) =>
|
|
74
|
+
setTitleMap((prev) =>
|
|
75
|
+
prev[slideId] === slideTitle ? prev : { ...prev, [slideId]: slideTitle },
|
|
76
|
+
);
|
|
83
77
|
}, []);
|
|
84
78
|
|
|
85
79
|
const trimmedQuery = query.trim().toLowerCase();
|
|
@@ -152,7 +146,9 @@ export function Home() {
|
|
|
152
146
|
.toString()
|
|
153
147
|
.padStart(2, '0')}
|
|
154
148
|
{isSearching && (
|
|
155
|
-
<span className="opacity-40"
|
|
149
|
+
<span className="opacity-40">
|
|
150
|
+
/{visibleSlides.length.toString().padStart(2, '0')}
|
|
151
|
+
</span>
|
|
156
152
|
)}
|
|
157
153
|
</span>
|
|
158
154
|
<div className="ml-auto w-full md:w-auto">
|
|
@@ -219,13 +215,7 @@ function MobileFolderPill({
|
|
|
219
215
|
);
|
|
220
216
|
}
|
|
221
217
|
|
|
222
|
-
function SearchInput({
|
|
223
|
-
value,
|
|
224
|
-
onChange,
|
|
225
|
-
}: {
|
|
226
|
-
value: string;
|
|
227
|
-
onChange: (value: string) => void;
|
|
228
|
-
}) {
|
|
218
|
+
function SearchInput({ value, onChange }: { value: string; onChange: (value: string) => void }) {
|
|
229
219
|
return (
|
|
230
220
|
<div className="relative w-full md:w-[240px]">
|
|
231
221
|
<Search
|
|
@@ -262,8 +252,8 @@ function NoResultsState({ query, onClear }: { query: string; onClear: () => void
|
|
|
262
252
|
</div>
|
|
263
253
|
<p className="mt-4 font-heading text-[15px] font-semibold tracking-tight">No matches</p>
|
|
264
254
|
<p className="mt-1.5 text-[13px] leading-relaxed text-muted-foreground">
|
|
265
|
-
Nothing matches{' '}
|
|
266
|
-
|
|
255
|
+
Nothing matches <span className="font-medium text-foreground">“{query}”</span>{' '}
|
|
256
|
+
in this folder.
|
|
267
257
|
</p>
|
|
268
258
|
<Button variant="ghost" size="sm" className="mt-4" onClick={onClear}>
|
|
269
259
|
Clear search
|
|
@@ -413,10 +403,7 @@ function SlideCard({
|
|
|
413
403
|
setDragging(true);
|
|
414
404
|
}}
|
|
415
405
|
onDragEnd={() => setDragging(false)}
|
|
416
|
-
className={cn(
|
|
417
|
-
'group relative motion-safe:transition-opacity',
|
|
418
|
-
dragging && 'opacity-40',
|
|
419
|
-
)}
|
|
406
|
+
className={cn('group relative motion-safe:transition-opacity', dragging && 'opacity-40')}
|
|
420
407
|
>
|
|
421
408
|
<Link to={`/s/${id}`} className="block focus-visible:outline-none">
|
|
422
409
|
{/* Slide thumb — tight border, grey baseboard, no shadcn rounded-xl */}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ChevronLeft,
|
|
3
|
-
ChevronRight,
|
|
4
|
-
Loader2,
|
|
5
|
-
RotateCcw,
|
|
6
|
-
Square,
|
|
7
|
-
Sun,
|
|
8
|
-
} from 'lucide-react';
|
|
1
|
+
import { ChevronLeft, ChevronRight, Loader2, RotateCcw, Square, Sun } from 'lucide-react';
|
|
9
2
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
10
3
|
import { useParams } from 'react-router-dom';
|
|
11
4
|
import { Button } from '@/components/ui/button';
|
|
@@ -71,14 +64,8 @@ export function Presenter() {
|
|
|
71
64
|
const goPrev = useCallback(() => send({ type: 'prev' }), [send]);
|
|
72
65
|
const goNext = useCallback(() => send({ type: 'next' }), [send]);
|
|
73
66
|
const goTo = useCallback((i: number) => send({ type: 'goto', index: i }), [send]);
|
|
74
|
-
const toggleBlack = useCallback(
|
|
75
|
-
|
|
76
|
-
[send],
|
|
77
|
-
);
|
|
78
|
-
const toggleWhite = useCallback(
|
|
79
|
-
() => send({ type: 'toggle-blackout', mode: 'white' }),
|
|
80
|
-
[send],
|
|
81
|
-
);
|
|
67
|
+
const toggleBlack = useCallback(() => send({ type: 'toggle-blackout', mode: 'black' }), [send]);
|
|
68
|
+
const toggleWhite = useCallback(() => send({ type: 'toggle-blackout', mode: 'white' }), [send]);
|
|
82
69
|
|
|
83
70
|
// Local-window key bindings mirror the projection's main shortcuts so the
|
|
84
71
|
// presenter can drive without the mouse.
|
|
@@ -368,10 +355,7 @@ function Clock() {
|
|
|
368
355
|
return () => clearInterval(id);
|
|
369
356
|
}, []);
|
|
370
357
|
return (
|
|
371
|
-
<time
|
|
372
|
-
title="Current time"
|
|
373
|
-
className="font-mono text-[12px] tabular-nums text-white/55"
|
|
374
|
-
>
|
|
358
|
+
<time title="Current time" className="font-mono text-[12px] tabular-nums text-white/55">
|
|
375
359
|
{now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
|
376
360
|
</time>
|
|
377
361
|
);
|
|
@@ -397,4 +381,3 @@ function ElapsedClock({ startedAt }: { startedAt: number }) {
|
|
|
397
381
|
</time>
|
|
398
382
|
);
|
|
399
383
|
}
|
|
400
|
-
|