@open-slide/core 0.0.2 → 0.0.4
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/bin.js +2 -0
- package/dist/{build-DJGuOT6x.js → build-CuoESF2g.js} +1 -1
- package/dist/cli/bin.js +5 -5
- package/dist/config-DF58h0l4.js +641 -0
- package/dist/{dev-0SG0ArzD.js → dev-rlOZacWo.js} +1 -1
- package/dist/index.d.ts +7 -9
- package/dist/{preview-61Aawrlg.js → preview-DCrD9X36.js} +1 -1
- package/dist/vite/index.js +1 -1
- package/package.json +7 -4
- package/src/app/App.tsx +2 -2
- package/src/app/components/ClickNavZones.tsx +34 -0
- package/src/app/components/Player.tsx +26 -7
- package/src/app/components/ThumbnailRail.tsx +5 -5
- package/src/app/components/inspector/CommentPopover.tsx +3 -11
- package/src/app/components/inspector/InspectOverlay.tsx +15 -4
- package/src/app/components/inspector/InspectorProvider.tsx +12 -5
- package/src/app/components/sidebar/FolderItem.tsx +188 -0
- package/src/app/components/sidebar/IconPicker.tsx +59 -0
- package/src/app/components/sidebar/Sidebar.tsx +118 -0
- package/src/app/components/ui/dialog.tsx +141 -0
- package/src/app/components/ui/dropdown-menu.tsx +228 -0
- package/src/app/components/ui/popover.tsx +72 -0
- package/src/app/components/ui/tabs.tsx +79 -0
- package/src/app/lib/export-html.ts +313 -0
- package/src/app/lib/folders.ts +166 -0
- package/src/app/lib/inspector/fiber.ts +2 -2
- package/src/app/lib/inspector/useComments.ts +8 -8
- package/src/app/lib/sdk.ts +18 -5
- package/src/app/lib/slides.ts +8 -0
- package/src/app/routes/Home.tsx +540 -63
- package/src/app/routes/Slide.tsx +298 -0
- package/src/app/virtual.d.ts +4 -4
- package/dist/config-Opp2R1Jf.js +0 -335
- package/src/app/lib/decks.ts +0 -8
- package/src/app/routes/Deck.tsx +0 -185
package/src/app/routes/Deck.tsx
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { ChevronLeft, ChevronRight, Play } from 'lucide-react';
|
|
2
|
-
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
|
-
import { Link, useParams, useSearchParams } from 'react-router-dom';
|
|
4
|
-
import { CommentWidget } from '@/components/inspector/CommentWidget';
|
|
5
|
-
import { InspectOverlay } from '@/components/inspector/InspectOverlay';
|
|
6
|
-
import { InspectorProvider, InspectToggleButton } from '@/components/inspector/InspectorProvider';
|
|
7
|
-
import { Button } from '@/components/ui/button';
|
|
8
|
-
import { Separator } from '@/components/ui/separator';
|
|
9
|
-
import { Player } from '../components/Player';
|
|
10
|
-
import { SlideCanvas } from '../components/SlideCanvas';
|
|
11
|
-
import { ThumbnailRail } from '../components/ThumbnailRail';
|
|
12
|
-
import { loadDeck } from '../lib/decks';
|
|
13
|
-
import type { DeckModule } from '../lib/sdk';
|
|
14
|
-
|
|
15
|
-
export function Deck() {
|
|
16
|
-
const { deckId = '' } = useParams();
|
|
17
|
-
const [searchParams, setSearchParams] = useSearchParams();
|
|
18
|
-
const [deck, setDeck] = useState<DeckModule | null>(null);
|
|
19
|
-
const [error, setError] = useState<string | null>(null);
|
|
20
|
-
const [playing, setPlaying] = useState(false);
|
|
21
|
-
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
let cancelled = false;
|
|
24
|
-
setDeck(null);
|
|
25
|
-
setError(null);
|
|
26
|
-
loadDeck(deckId)
|
|
27
|
-
.then((mod) => {
|
|
28
|
-
if (!cancelled) setDeck(mod);
|
|
29
|
-
})
|
|
30
|
-
.catch((e) => {
|
|
31
|
-
if (!cancelled) setError(String(e?.message ?? e));
|
|
32
|
-
});
|
|
33
|
-
return () => {
|
|
34
|
-
cancelled = true;
|
|
35
|
-
};
|
|
36
|
-
}, [deckId]);
|
|
37
|
-
|
|
38
|
-
const pages = useMemo(() => deck?.default ?? [], [deck]);
|
|
39
|
-
const pageCount = pages.length;
|
|
40
|
-
const rawIndex = Number(searchParams.get('p') ?? '1') - 1;
|
|
41
|
-
const index = Number.isFinite(rawIndex) ? Math.max(0, Math.min(pageCount - 1, rawIndex)) : 0;
|
|
42
|
-
|
|
43
|
-
const goTo = useCallback(
|
|
44
|
-
(i: number) => {
|
|
45
|
-
const clamped = Math.max(0, Math.min(pageCount - 1, i));
|
|
46
|
-
setSearchParams(
|
|
47
|
-
(prev) => {
|
|
48
|
-
const next = new URLSearchParams(prev);
|
|
49
|
-
next.set('p', String(clamped + 1));
|
|
50
|
-
return next;
|
|
51
|
-
},
|
|
52
|
-
{ replace: true },
|
|
53
|
-
);
|
|
54
|
-
},
|
|
55
|
-
[pageCount, setSearchParams],
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (playing) return;
|
|
60
|
-
const onKey = (e: KeyboardEvent) => {
|
|
61
|
-
if (e.target instanceof HTMLElement && e.target.matches('input, textarea')) return;
|
|
62
|
-
if (e.key === 'ArrowRight' || e.key === 'PageDown') {
|
|
63
|
-
e.preventDefault();
|
|
64
|
-
goTo(index + 1);
|
|
65
|
-
} else if (e.key === 'ArrowLeft' || e.key === 'PageUp') {
|
|
66
|
-
e.preventDefault();
|
|
67
|
-
goTo(index - 1);
|
|
68
|
-
} else if (e.key === 'f' || e.key === 'F') {
|
|
69
|
-
setPlaying(true);
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
window.addEventListener('keydown', onKey);
|
|
73
|
-
return () => window.removeEventListener('keydown', onKey);
|
|
74
|
-
}, [index, goTo, playing]);
|
|
75
|
-
|
|
76
|
-
if (error) {
|
|
77
|
-
return (
|
|
78
|
-
<div className="mx-auto max-w-3xl px-8 py-16 text-muted-foreground">
|
|
79
|
-
<Link to="/" className="text-sm font-medium text-primary hover:underline">
|
|
80
|
-
← Home
|
|
81
|
-
</Link>
|
|
82
|
-
<h2 className="mt-4 text-xl font-semibold text-foreground">Failed to load deck</h2>
|
|
83
|
-
<pre className="mt-4 overflow-auto rounded-md border bg-card p-4 text-xs whitespace-pre-wrap shadow-sm">
|
|
84
|
-
{error}
|
|
85
|
-
</pre>
|
|
86
|
-
</div>
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (!deck) {
|
|
91
|
-
return (
|
|
92
|
-
<div className="mx-auto max-w-3xl px-8 py-16 text-sm text-muted-foreground">
|
|
93
|
-
Loading {deckId}…
|
|
94
|
-
</div>
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (pageCount === 0) {
|
|
99
|
-
return (
|
|
100
|
-
<div className="mx-auto max-w-3xl px-8 py-16 text-muted-foreground">
|
|
101
|
-
<Link to="/" className="text-sm font-medium text-primary hover:underline">
|
|
102
|
-
← Home
|
|
103
|
-
</Link>
|
|
104
|
-
<h2 className="mt-4 text-xl font-semibold text-foreground">Empty deck</h2>
|
|
105
|
-
<p className="mt-2 text-sm">
|
|
106
|
-
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-xs">
|
|
107
|
-
slides/{deckId}/index.tsx
|
|
108
|
-
</code>{' '}
|
|
109
|
-
must{' '}
|
|
110
|
-
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-xs">export default</code> a
|
|
111
|
-
non-empty array of components.
|
|
112
|
-
</p>
|
|
113
|
-
</div>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (playing) {
|
|
118
|
-
return (
|
|
119
|
-
<Player pages={pages} index={index} onIndexChange={goTo} onExit={() => setPlaying(false)} />
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const CurrentPage = pages[index];
|
|
124
|
-
const title = deck.meta?.title ?? deckId;
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<InspectorProvider deckId={deckId}>
|
|
128
|
-
<div className="flex h-screen flex-col overflow-hidden bg-background">
|
|
129
|
-
<header className="flex shrink-0 items-center gap-4 border-b bg-card px-5 py-3">
|
|
130
|
-
<Button asChild variant="ghost" size="sm">
|
|
131
|
-
<Link to="/">
|
|
132
|
-
<ChevronLeft className="size-4" />
|
|
133
|
-
Home
|
|
134
|
-
</Link>
|
|
135
|
-
</Button>
|
|
136
|
-
<Separator orientation="vertical" className="h-5" />
|
|
137
|
-
<h1 className="flex-1 text-center text-sm font-semibold tracking-tight">{title}</h1>
|
|
138
|
-
<InspectToggleButton />
|
|
139
|
-
<Button size="sm" onClick={() => setPlaying(true)}>
|
|
140
|
-
<Play className="size-4" />
|
|
141
|
-
Play <kbd className="ml-1 rounded bg-primary-foreground/20 px-1 text-[10px]">F</kbd>
|
|
142
|
-
</Button>
|
|
143
|
-
</header>
|
|
144
|
-
|
|
145
|
-
<div className="flex min-h-0 flex-1">
|
|
146
|
-
<div className="w-[17rem] shrink-0">
|
|
147
|
-
<ThumbnailRail pages={pages} current={index} onSelect={goTo} />
|
|
148
|
-
</div>
|
|
149
|
-
<main className="relative min-h-0 min-w-0 flex-1 bg-background p-8">
|
|
150
|
-
<SlideCanvas>
|
|
151
|
-
<CurrentPage />
|
|
152
|
-
</SlideCanvas>
|
|
153
|
-
<InspectOverlay />
|
|
154
|
-
</main>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
<footer className="flex shrink-0 items-center justify-center gap-4 border-t bg-card p-3">
|
|
158
|
-
<Button
|
|
159
|
-
variant="outline"
|
|
160
|
-
size="sm"
|
|
161
|
-
onClick={() => goTo(index - 1)}
|
|
162
|
-
disabled={index === 0}
|
|
163
|
-
>
|
|
164
|
-
<ChevronLeft className="size-4" />
|
|
165
|
-
Prev
|
|
166
|
-
</Button>
|
|
167
|
-
<span className="min-w-16 text-center text-sm text-muted-foreground tabular-nums">
|
|
168
|
-
{index + 1} / {pageCount}
|
|
169
|
-
</span>
|
|
170
|
-
<Button
|
|
171
|
-
variant="outline"
|
|
172
|
-
size="sm"
|
|
173
|
-
onClick={() => goTo(index + 1)}
|
|
174
|
-
disabled={index === pageCount - 1}
|
|
175
|
-
>
|
|
176
|
-
Next
|
|
177
|
-
<ChevronRight className="size-4" />
|
|
178
|
-
</Button>
|
|
179
|
-
</footer>
|
|
180
|
-
|
|
181
|
-
<CommentWidget />
|
|
182
|
-
</div>
|
|
183
|
-
</InspectorProvider>
|
|
184
|
-
);
|
|
185
|
-
}
|