@kywk/open-slide-core 2.3.1 → 2.3.2
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/dist/{build-CZ6Qtrng.js → build-46dO14h1.js} +1 -1
- package/dist/cli/bin.js +4 -4
- package/dist/{config-CpmGqpQi.d.ts → config-CDrYgaEj.d.ts} +6 -2
- package/dist/{config-B5LArqpp.js → config-KyYvWqq-.js} +2061 -355
- package/dist/{dev-CCgdakbZ.js → dev-C0n-o0-c.js} +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +73 -32
- package/dist/locale/index.d.ts +1 -1
- package/dist/locale/index.js +1 -1
- package/dist/{preview-AwAqvG17.js → preview-CDWAGSfB.js} +1 -1
- package/dist/{types-CvAqFqsY.d.ts → types-DFK02XVv.d.ts} +110 -0
- package/dist/{update-C_RlnKu4.js → update-CqZqQRQk.js} +128 -7
- package/dist/vite/index.d.ts +1 -1
- package/dist/vite/index.js +1 -1
- package/dist/{zh-tw-B7_Oqv2q.js → zh-tw-B1pkKQsc.js} +535 -0
- package/package.json +9 -2
- package/src/agent/prompt.ts +141 -0
- package/src/agent/provider.ts +123 -0
- package/src/agent/types.ts +151 -0
- package/src/app/components/agent/agent-dock.tsx +35 -0
- package/src/app/components/agent/agent-markdown.tsx +45 -0
- package/src/app/components/agent/agent-panel.tsx +692 -0
- package/src/app/components/agent/agent-presence.tsx +74 -0
- package/src/app/components/agent/composer.tsx +120 -0
- package/src/app/components/agent/connect-view.tsx +184 -0
- package/src/app/components/agent/history-view.tsx +135 -0
- package/src/app/components/agent/provider-logo.tsx +34 -0
- package/src/app/components/agent/transcript.tsx +609 -0
- package/src/app/components/command/slide-command-menu.tsx +10 -0
- package/src/app/components/inline-svg.tsx +52 -21
- package/src/app/components/inspector/comment-layer.tsx +20 -1
- package/src/app/components/inspector/image-crop-dialog.tsx +1 -5
- package/src/app/components/inspector/inspector-panel.tsx +1 -1
- package/src/app/components/mermaid.tsx +42 -11
- package/src/app/components/panel/editor-sidebar.tsx +85 -16
- package/src/app/components/panel/panel-shell.tsx +2 -2
- package/src/app/components/panel/resize-handle.tsx +129 -0
- package/src/app/lib/agent/use-agent.ts +543 -0
- package/src/app/lib/use-auto-grow.ts +15 -0
- package/src/app/lib/utils.ts +4 -0
- package/src/app/routes/home.tsx +43 -7
- package/src/app/routes/slide.tsx +103 -104
- package/src/app/styles.css +170 -0
- package/src/editing/placeholder-id.ts +1 -0
- package/src/locale/en.ts +106 -0
- package/src/locale/es.ts +108 -0
- package/src/locale/ja.ts +99 -0
- package/src/locale/types.ts +109 -0
- package/src/locale/zh-cn.ts +96 -0
- package/src/locale/zh-tw.ts +96 -0
package/src/app/routes/slide.tsx
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
MoreHorizontal,
|
|
15
15
|
Play,
|
|
16
16
|
Presentation,
|
|
17
|
+
Sparkles,
|
|
17
18
|
Terminal,
|
|
18
19
|
} from 'lucide-react';
|
|
19
20
|
import {
|
|
@@ -21,12 +22,16 @@ import {
|
|
|
21
22
|
type RefObject,
|
|
22
23
|
useCallback,
|
|
23
24
|
useEffect,
|
|
25
|
+
useLayoutEffect,
|
|
24
26
|
useMemo,
|
|
25
27
|
useRef,
|
|
26
28
|
useState,
|
|
27
29
|
} from 'react';
|
|
28
30
|
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
|
29
31
|
import { toast } from 'sonner';
|
|
32
|
+
import { AgentToggleButton } from '@/components/agent/agent-dock';
|
|
33
|
+
import { AgentPanel } from '@/components/agent/agent-panel';
|
|
34
|
+
import { AgentPresence } from '@/components/agent/agent-presence';
|
|
30
35
|
import { AssetView } from '@/components/asset-view';
|
|
31
36
|
import { HistoryProvider } from '@/components/history-provider';
|
|
32
37
|
import { CommentLayer } from '@/components/inspector/comment-layer';
|
|
@@ -40,6 +45,7 @@ import {
|
|
|
40
45
|
} from '@/components/inspector/inspector-provider';
|
|
41
46
|
import { SaveBar } from '@/components/inspector/save-bar';
|
|
42
47
|
import { EditorSidebar } from '@/components/panel/editor-sidebar';
|
|
48
|
+
import { ResizeHandle, useStoredWidth } from '@/components/panel/resize-handle';
|
|
43
49
|
import { DesignProvider } from '@/components/style-panel/design-provider';
|
|
44
50
|
import { DesignToggleButton } from '@/components/style-panel/style-panel';
|
|
45
51
|
import { Button, buttonVariants } from '@/components/ui/button';
|
|
@@ -57,6 +63,7 @@ import {
|
|
|
57
63
|
} from '@/components/ui/dropdown-menu';
|
|
58
64
|
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
59
65
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
|
66
|
+
import { setDockOpen, useAgentActivity, useAgentDock } from '@/lib/agent/use-agent';
|
|
60
67
|
import { useFolders } from '@/lib/folders';
|
|
61
68
|
import {
|
|
62
69
|
hasModifier,
|
|
@@ -74,6 +81,7 @@ import { format, useLocale } from '@/lib/use-locale';
|
|
|
74
81
|
import { useMediaQuery } from '@/lib/use-media-query';
|
|
75
82
|
import { useWheelPageNavigation } from '@/lib/use-wheel-page-navigation';
|
|
76
83
|
import { cn } from '@/lib/utils';
|
|
84
|
+
import type { AgentTurnContext } from '../../agent/types';
|
|
77
85
|
import { SlideCommandMenu } from '../components/command/slide-command-menu';
|
|
78
86
|
import { PdfProgressToast, PptxProgressToast } from '../components/export-progress-toast';
|
|
79
87
|
import { NotesDrawer } from '../components/notes-drawer';
|
|
@@ -132,6 +140,13 @@ export function Slide() {
|
|
|
132
140
|
const [designOpen, setDesignOpen] = useState(false);
|
|
133
141
|
const [overviewOpen, setOverviewOpen] = useState(false);
|
|
134
142
|
const [commandOpen, setCommandOpen] = useState(false);
|
|
143
|
+
const { open: agentOpen, toggle: toggleAgent } = useAgentDock();
|
|
144
|
+
useLayoutEffect(() => {
|
|
145
|
+
if (agentOpen) setDesignOpen(false);
|
|
146
|
+
}, [agentOpen]);
|
|
147
|
+
useLayoutEffect(() => {
|
|
148
|
+
if (designOpen) setDockOpen(false);
|
|
149
|
+
}, [designOpen]);
|
|
135
150
|
const [, setWarmedTick] = useState(0);
|
|
136
151
|
const handleAssetsWarmed = useCallback(() => {
|
|
137
152
|
markDeckWarmed(slideId);
|
|
@@ -195,6 +210,16 @@ export function Slide() {
|
|
|
195
210
|
[pageCount, setSearchParams],
|
|
196
211
|
);
|
|
197
212
|
|
|
213
|
+
// While an agent writes this deck page by page, jump to each page as it
|
|
214
|
+
// lands so the user can follow along.
|
|
215
|
+
const agentActivity = useAgentActivity(slideId);
|
|
216
|
+
const agentWriting = agentActivity !== null;
|
|
217
|
+
const seenPageCount = useRef(pageCount);
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
if (agentWriting && pageCount > seenPageCount.current) goTo(pageCount - 1);
|
|
220
|
+
seenPageCount.current = pageCount;
|
|
221
|
+
}, [agentWriting, pageCount, goTo]);
|
|
222
|
+
|
|
198
223
|
const reorderPage = useCallback(
|
|
199
224
|
async (from: number, to: number) => {
|
|
200
225
|
if (from === to) return;
|
|
@@ -351,11 +376,13 @@ export function Slide() {
|
|
|
351
376
|
setPlayMode('window');
|
|
352
377
|
} else if (import.meta.env.DEV && (e.key === 'd' || e.key === 'D')) {
|
|
353
378
|
setDesignOpen((v) => !v);
|
|
379
|
+
} else if (import.meta.env.DEV && (e.key === 'a' || e.key === 'A')) {
|
|
380
|
+
toggleAgent();
|
|
354
381
|
}
|
|
355
382
|
};
|
|
356
383
|
window.addEventListener('keydown', onKey);
|
|
357
384
|
return () => window.removeEventListener('keydown', onKey);
|
|
358
|
-
}, [index, goTo, playMode, slideId, overviewOpen]);
|
|
385
|
+
}, [index, goTo, playMode, slideId, overviewOpen, toggleAgent]);
|
|
359
386
|
|
|
360
387
|
if (error) {
|
|
361
388
|
return (
|
|
@@ -619,8 +646,11 @@ export function Slide() {
|
|
|
619
646
|
<InspectorProvider
|
|
620
647
|
slideId={slideId}
|
|
621
648
|
pageIndex={index}
|
|
622
|
-
panelHidden={designOpen}
|
|
623
|
-
onPanelOpen={() =>
|
|
649
|
+
panelHidden={designOpen || agentOpen}
|
|
650
|
+
onPanelOpen={() => {
|
|
651
|
+
setDesignOpen(false);
|
|
652
|
+
setDockOpen(false);
|
|
653
|
+
}}
|
|
624
654
|
>
|
|
625
655
|
<SelectionReporter />
|
|
626
656
|
<div className="flex h-dvh flex-col overflow-hidden bg-sidebar text-foreground">
|
|
@@ -739,6 +769,12 @@ export function Slide() {
|
|
|
739
769
|
/>
|
|
740
770
|
)}
|
|
741
771
|
<DropdownMenuGroup>
|
|
772
|
+
{narrowToolbar && import.meta.env.DEV && (
|
|
773
|
+
<DropdownMenuItem onClick={toggleAgent}>
|
|
774
|
+
<Sparkles />
|
|
775
|
+
{t.agent.openTitle}
|
|
776
|
+
</DropdownMenuItem>
|
|
777
|
+
)}
|
|
742
778
|
<DropdownMenuItem onClick={() => setCommandOpen(true)}>
|
|
743
779
|
<Terminal />
|
|
744
780
|
{t.commandMenu.trigger}
|
|
@@ -753,6 +789,7 @@ export function Slide() {
|
|
|
753
789
|
</DropdownMenuContent>
|
|
754
790
|
</DropdownMenu>
|
|
755
791
|
)}
|
|
792
|
+
{import.meta.env.DEV && view === 'slides' && !narrowToolbar && <AgentToggleButton />}
|
|
756
793
|
{view === 'slides' && !narrowToolbar && (
|
|
757
794
|
<DesignToggleButton active={designOpen} onToggle={() => setDesignOpen((v) => !v)} />
|
|
758
795
|
)}
|
|
@@ -834,6 +871,7 @@ export function Slide() {
|
|
|
834
871
|
ref={slideViewportRef}
|
|
835
872
|
data-inspector-root
|
|
836
873
|
data-slide-id={slideId}
|
|
874
|
+
data-agent-provider={agentActivity?.provider}
|
|
837
875
|
className="relative min-h-0 min-w-0 flex-1 bg-background p-2 md:mx-2 md:mb-2 md:rounded-[10px] md:p-10 md:shadow-edge md:ring-1 md:ring-foreground/[0.06]"
|
|
838
876
|
>
|
|
839
877
|
<SlideViewportNavigation
|
|
@@ -856,6 +894,7 @@ export function Slide() {
|
|
|
856
894
|
<InlineEditLayer />
|
|
857
895
|
<SaveBar />
|
|
858
896
|
{import.meta.env.DEV && <CommentLayer />}
|
|
897
|
+
{agentActivity && <AgentPresence activity={agentActivity} revision={pages} />}
|
|
859
898
|
</main>
|
|
860
899
|
{/* Mobile-only horizontal rail. Sits below the canvas and
|
|
861
900
|
pads its bottom for the iOS home indicator / Safari URL bar. */}
|
|
@@ -875,6 +914,17 @@ export function Slide() {
|
|
|
875
914
|
<EditorSidebar
|
|
876
915
|
designOpen={designOpen}
|
|
877
916
|
onCloseDesign={() => setDesignOpen(false)}
|
|
917
|
+
agentOpen={agentOpen}
|
|
918
|
+
agent={
|
|
919
|
+
import.meta.env.DEV && (
|
|
920
|
+
<SlideAgentDock
|
|
921
|
+
slideId={slideId}
|
|
922
|
+
slideTitle={title}
|
|
923
|
+
pageNumber={index + 1}
|
|
924
|
+
totalPages={pageCount}
|
|
925
|
+
/>
|
|
926
|
+
)
|
|
927
|
+
}
|
|
878
928
|
/>
|
|
879
929
|
</div>
|
|
880
930
|
{import.meta.env.DEV && (
|
|
@@ -916,6 +966,7 @@ export function Slide() {
|
|
|
916
966
|
onCopyLink: copyLink,
|
|
917
967
|
onOverview: () => setOverviewOpen(true),
|
|
918
968
|
onToggleDesignPanel: () => setDesignOpen((v) => !v),
|
|
969
|
+
onToggleAgentPanel: toggleAgent,
|
|
919
970
|
onExportHtml: exportHtml,
|
|
920
971
|
onExportPdf: exportPdf,
|
|
921
972
|
onExportPptx: exportPptx,
|
|
@@ -935,14 +986,6 @@ const DEFAULT_RAIL_WIDTH = 264;
|
|
|
935
986
|
const MIN_RAIL_WIDTH = 200;
|
|
936
987
|
const MAX_RAIL_WIDTH = 480;
|
|
937
988
|
|
|
938
|
-
function readStoredRailWidth(): number {
|
|
939
|
-
if (typeof window === 'undefined') return DEFAULT_RAIL_WIDTH;
|
|
940
|
-
const raw = window.localStorage.getItem(RAIL_WIDTH_STORAGE_KEY);
|
|
941
|
-
const parsed = raw == null ? Number.NaN : Number(raw);
|
|
942
|
-
if (!Number.isFinite(parsed)) return DEFAULT_RAIL_WIDTH;
|
|
943
|
-
return Math.min(MAX_RAIL_WIDTH, Math.max(MIN_RAIL_WIDTH, parsed));
|
|
944
|
-
}
|
|
945
|
-
|
|
946
989
|
function ResizableRail(props: {
|
|
947
990
|
pages: SlideModule['default'];
|
|
948
991
|
design?: SlideModule['design'];
|
|
@@ -954,103 +997,26 @@ function ResizableRail(props: {
|
|
|
954
997
|
onOverview?: () => void;
|
|
955
998
|
}) {
|
|
956
999
|
const t = useLocale();
|
|
957
|
-
const [width, setWidth] =
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
window.localStorage.setItem(RAIL_WIDTH_STORAGE_KEY, String(width));
|
|
964
|
-
}, [width]);
|
|
965
|
-
|
|
966
|
-
useEffect(() => {
|
|
967
|
-
if (!resizing) return;
|
|
968
|
-
const prev = {
|
|
969
|
-
cursor: document.body.style.cursor,
|
|
970
|
-
userSelect: document.body.style.userSelect,
|
|
971
|
-
};
|
|
972
|
-
document.body.style.cursor = 'col-resize';
|
|
973
|
-
document.body.style.userSelect = 'none';
|
|
974
|
-
return () => {
|
|
975
|
-
document.body.style.cursor = prev.cursor;
|
|
976
|
-
document.body.style.userSelect = prev.userSelect;
|
|
977
|
-
};
|
|
978
|
-
}, [resizing]);
|
|
979
|
-
|
|
980
|
-
const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
|
|
981
|
-
e.preventDefault();
|
|
982
|
-
e.currentTarget.setPointerCapture(e.pointerId);
|
|
983
|
-
dragRef.current = { startX: e.clientX, startWidth: width };
|
|
984
|
-
setResizing(true);
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
const onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {
|
|
988
|
-
if (!dragRef.current) return;
|
|
989
|
-
const delta = e.clientX - dragRef.current.startX;
|
|
990
|
-
const next = Math.min(
|
|
991
|
-
MAX_RAIL_WIDTH,
|
|
992
|
-
Math.max(MIN_RAIL_WIDTH, dragRef.current.startWidth + delta),
|
|
993
|
-
);
|
|
994
|
-
setWidth(next);
|
|
995
|
-
};
|
|
996
|
-
|
|
997
|
-
const onPointerUp = (e: React.PointerEvent<HTMLDivElement>) => {
|
|
998
|
-
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
999
|
-
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
1000
|
-
}
|
|
1001
|
-
dragRef.current = null;
|
|
1002
|
-
setResizing(false);
|
|
1003
|
-
};
|
|
1004
|
-
|
|
1005
|
-
const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
1006
|
-
const step = e.shiftKey ? 32 : 8;
|
|
1007
|
-
if (e.key === 'ArrowLeft') {
|
|
1008
|
-
e.preventDefault();
|
|
1009
|
-
e.stopPropagation();
|
|
1010
|
-
setWidth((w) => Math.max(MIN_RAIL_WIDTH, w - step));
|
|
1011
|
-
} else if (e.key === 'ArrowRight') {
|
|
1012
|
-
e.preventDefault();
|
|
1013
|
-
e.stopPropagation();
|
|
1014
|
-
setWidth((w) => Math.min(MAX_RAIL_WIDTH, w + step));
|
|
1015
|
-
} else if (e.key === 'Home') {
|
|
1016
|
-
e.preventDefault();
|
|
1017
|
-
e.stopPropagation();
|
|
1018
|
-
setWidth(DEFAULT_RAIL_WIDTH);
|
|
1019
|
-
}
|
|
1020
|
-
};
|
|
1000
|
+
const [width, setWidth] = useStoredWidth(
|
|
1001
|
+
RAIL_WIDTH_STORAGE_KEY,
|
|
1002
|
+
DEFAULT_RAIL_WIDTH,
|
|
1003
|
+
MIN_RAIL_WIDTH,
|
|
1004
|
+
MAX_RAIL_WIDTH,
|
|
1005
|
+
);
|
|
1021
1006
|
|
|
1022
1007
|
return (
|
|
1023
1008
|
<div className="relative hidden shrink-0 md:block" style={{ width }}>
|
|
1024
1009
|
<ThumbnailRail width={width} {...props} />
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
onPointerMove={onPointerMove}
|
|
1036
|
-
onPointerUp={onPointerUp}
|
|
1037
|
-
onPointerCancel={onPointerUp}
|
|
1038
|
-
onKeyDown={onKeyDown}
|
|
1039
|
-
onDoubleClick={() => setWidth(DEFAULT_RAIL_WIDTH)}
|
|
1040
|
-
className={cn(
|
|
1041
|
-
'group/resize absolute inset-y-0 right-0 z-20 w-1.5 translate-x-1/2 cursor-col-resize touch-none outline-none',
|
|
1042
|
-
'focus-visible:bg-brand/20',
|
|
1043
|
-
)}
|
|
1044
|
-
>
|
|
1045
|
-
<span
|
|
1046
|
-
aria-hidden
|
|
1047
|
-
className={cn(
|
|
1048
|
-
'pointer-events-none absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-brand opacity-0 transition-opacity duration-150',
|
|
1049
|
-
'group-hover/resize:opacity-100 group-focus-visible/resize:opacity-100',
|
|
1050
|
-
resizing && 'opacity-100',
|
|
1051
|
-
)}
|
|
1052
|
-
/>
|
|
1053
|
-
</div>
|
|
1010
|
+
<ResizeHandle
|
|
1011
|
+
width={width}
|
|
1012
|
+
min={MIN_RAIL_WIDTH}
|
|
1013
|
+
max={MAX_RAIL_WIDTH}
|
|
1014
|
+
defaultWidth={DEFAULT_RAIL_WIDTH}
|
|
1015
|
+
edge="right"
|
|
1016
|
+
label={t.thumbnailRail.resizeRail}
|
|
1017
|
+
onResize={setWidth}
|
|
1018
|
+
className="right-0 translate-x-1/2"
|
|
1019
|
+
/>
|
|
1054
1020
|
</div>
|
|
1055
1021
|
);
|
|
1056
1022
|
}
|
|
@@ -1096,6 +1062,39 @@ function EditorMenuItems({
|
|
|
1096
1062
|
);
|
|
1097
1063
|
}
|
|
1098
1064
|
|
|
1065
|
+
function SlideAgentDock({
|
|
1066
|
+
slideId,
|
|
1067
|
+
slideTitle,
|
|
1068
|
+
pageNumber,
|
|
1069
|
+
totalPages,
|
|
1070
|
+
}: {
|
|
1071
|
+
slideId: string;
|
|
1072
|
+
slideTitle: string;
|
|
1073
|
+
pageNumber: number;
|
|
1074
|
+
totalPages: number;
|
|
1075
|
+
}) {
|
|
1076
|
+
const { selected, comments } = useInspector();
|
|
1077
|
+
const context = useMemo<AgentTurnContext>(
|
|
1078
|
+
() => ({
|
|
1079
|
+
slideId,
|
|
1080
|
+
slideTitle,
|
|
1081
|
+
pageNumber,
|
|
1082
|
+
totalPages,
|
|
1083
|
+
pendingComments: comments.length,
|
|
1084
|
+
selection: selected
|
|
1085
|
+
? {
|
|
1086
|
+
line: selected.line,
|
|
1087
|
+
column: selected.column,
|
|
1088
|
+
tagName: selected.anchor.tagName.toLowerCase(),
|
|
1089
|
+
text: (selected.anchor.textContent ?? '').replace(/\s+/g, ' ').trim().slice(0, 120),
|
|
1090
|
+
}
|
|
1091
|
+
: null,
|
|
1092
|
+
}),
|
|
1093
|
+
[slideId, slideTitle, pageNumber, totalPages, comments.length, selected],
|
|
1094
|
+
);
|
|
1095
|
+
return <AgentPanel context={context} onClose={() => setDockOpen(false)} />;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1099
1098
|
function AgentConnectedBadge() {
|
|
1100
1099
|
const t = useLocale();
|
|
1101
1100
|
const connected = useAgentSocketConnected();
|
package/src/app/styles.css
CHANGED
|
@@ -383,3 +383,173 @@
|
|
|
383
383
|
background-clip: content-box;
|
|
384
384
|
}
|
|
385
385
|
}
|
|
386
|
+
|
|
387
|
+
/* Agent presence: ring, write sweep and shimmer shown while an agent edits a deck. */
|
|
388
|
+
@property --agent-angle {
|
|
389
|
+
syntax: "<angle>";
|
|
390
|
+
inherits: false;
|
|
391
|
+
initial-value: 0deg;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
[data-agent-provider] {
|
|
395
|
+
--agent-a: oklch(0.68 0.14 42);
|
|
396
|
+
--agent-b: oklch(0.82 0.12 75);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
[data-agent-provider="codex"] {
|
|
400
|
+
--agent-a: oklch(0.64 0.13 170);
|
|
401
|
+
--agent-b: oklch(0.7 0.14 240);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
@keyframes agent-spin {
|
|
405
|
+
to {
|
|
406
|
+
--agent-angle: 360deg;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
@keyframes agent-fade-in {
|
|
411
|
+
from {
|
|
412
|
+
opacity: 0;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.agent-ring {
|
|
417
|
+
pointer-events: none;
|
|
418
|
+
position: absolute;
|
|
419
|
+
inset: 0;
|
|
420
|
+
border-radius: inherit;
|
|
421
|
+
padding: 1.5px;
|
|
422
|
+
background: conic-gradient(
|
|
423
|
+
from var(--agent-angle),
|
|
424
|
+
transparent 0deg,
|
|
425
|
+
var(--agent-a) 70deg,
|
|
426
|
+
var(--agent-b) 140deg,
|
|
427
|
+
transparent 210deg,
|
|
428
|
+
transparent 360deg
|
|
429
|
+
);
|
|
430
|
+
mask:
|
|
431
|
+
linear-gradient(#000 0 0) content-box exclude,
|
|
432
|
+
linear-gradient(#000 0 0);
|
|
433
|
+
animation:
|
|
434
|
+
agent-spin 3.6s linear infinite,
|
|
435
|
+
agent-fade-in 400ms var(--ease-swift) both;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.agent-glow {
|
|
439
|
+
pointer-events: none;
|
|
440
|
+
position: absolute;
|
|
441
|
+
inset: 0;
|
|
442
|
+
border-radius: inherit;
|
|
443
|
+
box-shadow:
|
|
444
|
+
inset 0 0 0 1px color-mix(in oklch, var(--agent-a) 35%, transparent),
|
|
445
|
+
inset 0 0 48px -12px color-mix(in oklch, var(--agent-a) 45%, transparent);
|
|
446
|
+
animation: agent-fade-in 400ms var(--ease-swift) both;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
@keyframes agent-sweep {
|
|
450
|
+
from {
|
|
451
|
+
background-position: 120% 0;
|
|
452
|
+
opacity: 1;
|
|
453
|
+
}
|
|
454
|
+
to {
|
|
455
|
+
background-position: -20% 0;
|
|
456
|
+
opacity: 0;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.agent-sweep {
|
|
461
|
+
pointer-events: none;
|
|
462
|
+
position: absolute;
|
|
463
|
+
inset: 0;
|
|
464
|
+
border-radius: inherit;
|
|
465
|
+
background: linear-gradient(
|
|
466
|
+
105deg,
|
|
467
|
+
transparent 35%,
|
|
468
|
+
color-mix(in oklch, var(--agent-b) 22%, transparent) 50%,
|
|
469
|
+
transparent 65%
|
|
470
|
+
);
|
|
471
|
+
background-size: 250% 100%;
|
|
472
|
+
animation: agent-sweep 900ms var(--ease-swift) both;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
@keyframes agent-shimmer {
|
|
476
|
+
from {
|
|
477
|
+
background-position: 100% 0;
|
|
478
|
+
}
|
|
479
|
+
to {
|
|
480
|
+
background-position: 0% 0;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.agent-shimmer {
|
|
485
|
+
background: linear-gradient(
|
|
486
|
+
90deg,
|
|
487
|
+
var(--muted-foreground) 35%,
|
|
488
|
+
var(--foreground) 50%,
|
|
489
|
+
var(--muted-foreground) 65%
|
|
490
|
+
);
|
|
491
|
+
background-size: 300% 100%;
|
|
492
|
+
background-clip: text;
|
|
493
|
+
color: transparent;
|
|
494
|
+
animation: agent-shimmer 1.8s linear infinite;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
@keyframes agent-progress {
|
|
498
|
+
from {
|
|
499
|
+
transform: translateX(-100%);
|
|
500
|
+
}
|
|
501
|
+
to {
|
|
502
|
+
transform: translateX(250%);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.agent-progress {
|
|
507
|
+
pointer-events: none;
|
|
508
|
+
position: absolute;
|
|
509
|
+
inset-inline: 0;
|
|
510
|
+
top: 0;
|
|
511
|
+
height: 1.5px;
|
|
512
|
+
overflow: hidden;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.agent-progress::after {
|
|
516
|
+
content: "";
|
|
517
|
+
position: absolute;
|
|
518
|
+
inset-block: 0;
|
|
519
|
+
width: 40%;
|
|
520
|
+
background: linear-gradient(90deg, transparent, var(--agent-a), var(--agent-b), transparent);
|
|
521
|
+
animation: agent-progress 1.6s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
@media (prefers-reduced-motion: reduce) {
|
|
525
|
+
.agent-ring {
|
|
526
|
+
animation: agent-fade-in 160ms ease-out both;
|
|
527
|
+
--agent-angle: 120deg;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.agent-sweep {
|
|
531
|
+
display: none;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.agent-shimmer {
|
|
535
|
+
animation: none;
|
|
536
|
+
color: var(--foreground);
|
|
537
|
+
background: none;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
.agent-progress::after {
|
|
541
|
+
animation: none;
|
|
542
|
+
width: 100%;
|
|
543
|
+
opacity: 0.6;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.sidebar-swap {
|
|
548
|
+
animation: agent-fade-in 160ms var(--ease-swift, ease-out);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
@media (prefers-reduced-motion: reduce) {
|
|
552
|
+
.sidebar-swap {
|
|
553
|
+
animation: none;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const UNTITLED_SLIDE_ID_RE = /^untitled(-\d+)?$/;
|
package/src/locale/en.ts
CHANGED
|
@@ -96,6 +96,7 @@ export const en: Locale = {
|
|
|
96
96
|
},
|
|
97
97
|
|
|
98
98
|
slide: {
|
|
99
|
+
resizeSidePanel: 'Resize side panel',
|
|
99
100
|
home: 'Home',
|
|
100
101
|
backToHome: 'Back to home',
|
|
101
102
|
agentConnected: 'Agent connected',
|
|
@@ -540,4 +541,109 @@ export const en: Locale = {
|
|
|
540
541
|
expandPromptAria: 'Expand prompt',
|
|
541
542
|
collapsePromptAria: 'Collapse prompt',
|
|
542
543
|
},
|
|
544
|
+
|
|
545
|
+
agent: {
|
|
546
|
+
title: 'Agent',
|
|
547
|
+
beta: 'Beta',
|
|
548
|
+
betaTitle: 'Early preview',
|
|
549
|
+
betaHint: 'Replies, edits and tool calls can occasionally fail or do something unexpected.',
|
|
550
|
+
open: 'Agent',
|
|
551
|
+
openTitle: 'Open the agent panel',
|
|
552
|
+
close: 'Close agent panel',
|
|
553
|
+
newSession: 'New chat',
|
|
554
|
+
sessions: 'History',
|
|
555
|
+
noSessions: 'No conversations yet.',
|
|
556
|
+
deleteSession: 'Delete conversation',
|
|
557
|
+
historyThisDeck: 'This deck',
|
|
558
|
+
historyOtherDecks: 'Other decks',
|
|
559
|
+
historyEmptyHint: 'Chats you start in this panel show up here.',
|
|
560
|
+
sessionRunning: 'Working',
|
|
561
|
+
composerPlaceholder: 'Ask {provider} to create or edit slides…',
|
|
562
|
+
send: 'Send',
|
|
563
|
+
stop: 'Stop',
|
|
564
|
+
working: 'Working',
|
|
565
|
+
contextPage: 'Page {n}',
|
|
566
|
+
contextSelection: 'Selection',
|
|
567
|
+
pendingComments: { one: '{count} comment', other: '{count} comments' },
|
|
568
|
+
applyComments: 'Apply comments',
|
|
569
|
+
applyCommentsWith: 'Apply with {provider}',
|
|
570
|
+
createDeck: 'New deck',
|
|
571
|
+
createDeckWith: 'Create a deck with {provider}',
|
|
572
|
+
quickCreate: 'Draft a new deck',
|
|
573
|
+
quickCreateHint: 'Opens a blank deck; describe it and the agent drafts it page by page.',
|
|
574
|
+
quickApply: 'Apply pending comments',
|
|
575
|
+
quickApplyHint: 'Resolves every @slide-comment marker in this slide.',
|
|
576
|
+
quickTheme: 'Create a theme',
|
|
577
|
+
quickThemeHint: 'Extracts or designs a reusable theme under themes/.',
|
|
578
|
+
quickEdit: 'Edit this page',
|
|
579
|
+
quickEditHint: 'Describe a change to the page you are viewing.',
|
|
580
|
+
emptyTitle: 'What should we build?',
|
|
581
|
+
emptyHint: 'Describe a deck, or pick a starting point.',
|
|
582
|
+
questionSubmit: 'Continue',
|
|
583
|
+
questionOther: 'Other',
|
|
584
|
+
questionOtherPlaceholder: 'Type your own answer',
|
|
585
|
+
questionCancelled: 'Dismissed',
|
|
586
|
+
permissionTitle: 'Needs approval',
|
|
587
|
+
allow: 'Allow',
|
|
588
|
+
deny: 'Deny',
|
|
589
|
+
allowed: 'Allowed',
|
|
590
|
+
denied: 'Denied',
|
|
591
|
+
autoApprove: 'Auto-approve',
|
|
592
|
+
autoApproveHint: 'Run commands without asking. Edits inside the workspace are always allowed.',
|
|
593
|
+
resultDone: 'Done',
|
|
594
|
+
resultStopped: 'Stopped',
|
|
595
|
+
resultSeconds: '{seconds}s',
|
|
596
|
+
errorEyebrow: 'Error',
|
|
597
|
+
statusLoading: 'Checking agents',
|
|
598
|
+
disabled: 'The agent panel is disabled in open-slide.config.ts.',
|
|
599
|
+
connectTitle: 'Connect an agent',
|
|
600
|
+
connectDescription:
|
|
601
|
+
'Drive your coding agent from here instead of a terminal. Agents installed on this machine connect automatically and reuse their sign-in.',
|
|
602
|
+
connect: 'Connect',
|
|
603
|
+
connecting: 'Connecting',
|
|
604
|
+
connected: 'Connected',
|
|
605
|
+
connectInstallHint: 'Adds {pkg} to this workspace with {pm}.',
|
|
606
|
+
cliFound: 'CLI found · v{version}',
|
|
607
|
+
cliFoundNoVersion: 'CLI found',
|
|
608
|
+
cliMissing: 'CLI not found on PATH',
|
|
609
|
+
cliHint: 'Install the {name} CLI and sign in once; the panel reuses its login.',
|
|
610
|
+
needCliTitle: 'Install Claude Code or Codex first',
|
|
611
|
+
needCliDescription:
|
|
612
|
+
'The panel drives the coding agent CLI on this machine, and none was found on your PATH. Install one, sign in once in a terminal, then check again.',
|
|
613
|
+
checkAgain: 'Check again',
|
|
614
|
+
retry: 'Retry',
|
|
615
|
+
toastConnected: '{name} connected',
|
|
616
|
+
toastConnectFailed: 'Could not install {pkg}',
|
|
617
|
+
manageConnections: 'Manage agents',
|
|
618
|
+
backToChat: 'Back',
|
|
619
|
+
toastSendFailed: 'Could not send message',
|
|
620
|
+
newDeckTitle: "What's this deck about?",
|
|
621
|
+
newDeckHint:
|
|
622
|
+
'Describe the topic, audience and tone. {provider} drafts it page by page while you watch.',
|
|
623
|
+
newDeckPlaceholder: 'A 10-minute talk on…',
|
|
624
|
+
toastCreateDeckFailed: 'Could not create a deck',
|
|
625
|
+
steps: { one: '{count} step', other: '{count} steps' },
|
|
626
|
+
questionSkip: 'Skip',
|
|
627
|
+
copyMessage: 'Copy',
|
|
628
|
+
copied: 'Copied',
|
|
629
|
+
editMessage: 'Edit',
|
|
630
|
+
cancelEdit: 'Cancel',
|
|
631
|
+
sendEdit: 'Send',
|
|
632
|
+
editHint:
|
|
633
|
+
'Sending replaces the conversation after this message. Edits already made to files stay.',
|
|
634
|
+
modelDefault: 'Default',
|
|
635
|
+
reasoning: 'Reasoning',
|
|
636
|
+
effortAuto: 'Auto',
|
|
637
|
+
efforts: {
|
|
638
|
+
minimal: 'Minimal',
|
|
639
|
+
low: 'Low',
|
|
640
|
+
medium: 'Medium',
|
|
641
|
+
high: 'High',
|
|
642
|
+
xhigh: 'Extra high',
|
|
643
|
+
max: 'Max',
|
|
644
|
+
},
|
|
645
|
+
presenceEditing: '{provider} is editing',
|
|
646
|
+
presenceThinking: 'Thinking',
|
|
647
|
+
presenceWaiting: 'Waiting for you',
|
|
648
|
+
},
|
|
543
649
|
};
|