@rimori/react-client 0.4.11-next.4 → 0.4.11-next.6
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.
|
@@ -24,7 +24,7 @@ import { PiCodeBlock } from 'react-icons/pi';
|
|
|
24
24
|
import { TbBlockquote, TbTable, TbColumnInsertRight, TbRowInsertBottom, TbColumnRemove, TbRowRemove, TbArrowMergeBoth, TbBrandYoutube, TbPhoto, } from 'react-icons/tb';
|
|
25
25
|
import { GoListOrdered } from 'react-icons/go';
|
|
26
26
|
import { AiOutlineUnorderedList } from 'react-icons/ai';
|
|
27
|
-
import { LuClipboardPaste, LuHeading1, LuHeading2, LuHeading3, LuLink, LuUnlink } from 'react-icons/lu';
|
|
27
|
+
import { LuClipboardPaste, LuHeading1, LuHeading2, LuHeading3, LuLink, LuUnlink, LuCopy, LuCheck, LuMaximize2, LuMinimize2, } from 'react-icons/lu';
|
|
28
28
|
import { FaBold, FaCode, FaItalic, FaParagraph, FaStrikethrough } from 'react-icons/fa';
|
|
29
29
|
import { ImageUploadExtension, triggerImageUpload } from './ImageUploadExtension';
|
|
30
30
|
// Extends TipTap's Paragraph to serialize empty paragraphs as <p></p>.
|
|
@@ -126,7 +126,7 @@ const InlinePanel = ({ panel, onClose, editor, onUpdate, labels }) => {
|
|
|
126
126
|
? labels.addYoutubeConfirm
|
|
127
127
|
: labels.appendMarkdownConfirm })] })] }));
|
|
128
128
|
};
|
|
129
|
-
const MenuBar = ({ editor, onUpdate, uploadImage, labels }) => {
|
|
129
|
+
const MenuBar = ({ editor, onUpdate, uploadImage, labels, onCopy, copied, isFullscreen, onToggleFullscreen, }) => {
|
|
130
130
|
const [activePanel, setActivePanel] = useState(null);
|
|
131
131
|
const toggle = (panel) => setActivePanel((prev) => (prev === panel ? null : panel));
|
|
132
132
|
const inTable = editor.isActive('table');
|
|
@@ -135,7 +135,7 @@ const MenuBar = ({ editor, onUpdate, uploadImage, labels }) => {
|
|
|
135
135
|
'text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:opacity-40 disabled:pointer-events-none';
|
|
136
136
|
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "bg-muted/50 border-b border-border text-base flex flex-row flex-wrap items-center gap-0.5 p-1.5", children: [_jsx(EditorButton, { editor: editor, action: "toggleBold", isActive: editor.isActive('bold'), label: _jsx(FaBold, {}), disabled: true, title: labels.bold }), _jsx(EditorButton, { editor: editor, action: "toggleItalic", isActive: editor.isActive('italic'), label: _jsx(FaItalic, {}), disabled: true, title: labels.italic }), _jsx(EditorButton, { editor: editor, action: "toggleStrike", isActive: editor.isActive('strike'), label: _jsx(FaStrikethrough, {}), disabled: true, title: labels.strike }), _jsx(EditorButton, { editor: editor, action: "toggleCode", isActive: editor.isActive('code'), label: _jsx(FaCode, {}), disabled: true, title: labels.code }), _jsx(EditorButton, { editor: editor, action: "setParagraph", isActive: editor.isActive('paragraph'), label: _jsx(FaParagraph, {}), title: labels.paragraph }), _jsx(EditorButton, { editor: editor, action: "setHeading1", isActive: editor.isActive('heading', { level: 1 }), label: _jsx(LuHeading1, { size: "24px" }), title: labels.heading1 }), _jsx(EditorButton, { editor: editor, action: "setHeading2", isActive: editor.isActive('heading', { level: 2 }), label: _jsx(LuHeading2, { size: "24px" }), title: labels.heading2 }), _jsx(EditorButton, { editor: editor, action: "setHeading3", isActive: editor.isActive('heading', { level: 3 }), label: _jsx(LuHeading3, { size: "24px" }), title: labels.heading3 }), _jsx(EditorButton, { editor: editor, action: "toggleBulletList", isActive: editor.isActive('bulletList'), label: _jsx(AiOutlineUnorderedList, { size: "24px" }), title: labels.bulletList }), _jsx(EditorButton, { editor: editor, action: "toggleOrderedList", isActive: editor.isActive('orderedList'), label: _jsx(GoListOrdered, { size: "24px" }), title: labels.orderedList }), _jsx(EditorButton, { editor: editor, action: "toggleCodeBlock", isActive: editor.isActive('codeBlock'), label: _jsx(PiCodeBlock, { size: "24px" }), title: labels.codeBlock }), _jsx(EditorButton, { editor: editor, action: "toggleBlockquote", isActive: editor.isActive('blockquote'), label: _jsx(TbBlockquote, { size: "24px" }), title: labels.blockquote }), _jsx("div", { className: "w-px h-5 bg-border mx-0.5" }), _jsxs("div", { className: "inline-flex rounded-md border border-border bg-transparent overflow-hidden", children: [_jsx("button", { type: "button", onClick: () => toggle('link'), title: labels.setLink, className: 'w-8 h-8 flex items-center justify-center rounded-none first:rounded-l-md last:rounded-r-md transition-colors duration-150 ' +
|
|
137
137
|
'text-muted-foreground hover:bg-accent hover:text-accent-foreground border-r border-border last:border-r-0' +
|
|
138
|
-
(isLink ? ' bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-foreground' : ''), children: _jsx(LuLink, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().unsetLink().run(), disabled: !isLink, title: labels.unsetLink, className: "w-8 h-8 flex items-center justify-center rounded-none first:rounded-l-md last:rounded-r-md transition-colors duration-150 text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:opacity-40 disabled:pointer-events-none border-r border-border last:border-r-0", children: _jsx(LuUnlink, { size: 18 }) })] }), _jsx("button", { type: "button", onClick: () => toggle('youtube'), className: tableBtnClass, title: labels.addYoutube, children: _jsx(TbBrandYoutube, { size: 18 }) }), uploadImage && (_jsx("button", { type: "button", onClick: () => triggerImageUpload(uploadImage, editor), className: tableBtnClass, title: labels.insertImage, children: _jsx(TbPhoto, { size: 18 }) })), _jsx("div", { className: "w-px h-5 bg-border mx-0.5" }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(), className: tableBtnClass, title: labels.insertTable, children: _jsx(TbTable, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().addColumnAfter().run(), className: tableBtnClass, disabled: !inTable, title: labels.addColumnAfter, children: _jsx(TbColumnInsertRight, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().addRowAfter().run(), className: tableBtnClass, disabled: !inTable, title: labels.addRowAfter, children: _jsx(TbRowInsertBottom, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().deleteColumn().run(), className: tableBtnClass, disabled: !inTable, title: labels.deleteColumn, children: _jsx(TbColumnRemove, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().deleteRow().run(), className: tableBtnClass, disabled: !inTable, title: labels.deleteRow, children: _jsx(TbRowRemove, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().mergeOrSplit().run(), className: tableBtnClass, disabled: !inTable, title: labels.mergeOrSplit, children: _jsx(TbArrowMergeBoth, { size: 18 }) }), _jsx("div", { className: "w-px h-5 bg-border mx-0.5" }), _jsx("button", { type: "button", onClick: () => toggle('markdown'), className: tableBtnClass, title: labels.appendMarkdown, children: _jsx(LuClipboardPaste, { size: 18 }) })] }), _jsx(InlinePanel, { panel: activePanel, onClose: () => setActivePanel(null), editor: editor, onUpdate: onUpdate, labels: labels })] }));
|
|
138
|
+
(isLink ? ' bg-primary/10 text-primary dark:bg-primary/20 dark:text-primary-foreground' : ''), children: _jsx(LuLink, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().unsetLink().run(), disabled: !isLink, title: labels.unsetLink, className: "w-8 h-8 flex items-center justify-center rounded-none first:rounded-l-md last:rounded-r-md transition-colors duration-150 text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:opacity-40 disabled:pointer-events-none border-r border-border last:border-r-0", children: _jsx(LuUnlink, { size: 18 }) })] }), _jsx("button", { type: "button", onClick: () => toggle('youtube'), className: tableBtnClass, title: labels.addYoutube, children: _jsx(TbBrandYoutube, { size: 18 }) }), uploadImage && (_jsx("button", { type: "button", onClick: () => triggerImageUpload(uploadImage, editor), className: tableBtnClass, title: labels.insertImage, children: _jsx(TbPhoto, { size: 18 }) })), _jsx("div", { className: "w-px h-5 bg-border mx-0.5" }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(), className: tableBtnClass, title: labels.insertTable, children: _jsx(TbTable, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().addColumnAfter().run(), className: tableBtnClass, disabled: !inTable, title: labels.addColumnAfter, children: _jsx(TbColumnInsertRight, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().addRowAfter().run(), className: tableBtnClass, disabled: !inTable, title: labels.addRowAfter, children: _jsx(TbRowInsertBottom, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().deleteColumn().run(), className: tableBtnClass, disabled: !inTable, title: labels.deleteColumn, children: _jsx(TbColumnRemove, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().deleteRow().run(), className: tableBtnClass, disabled: !inTable, title: labels.deleteRow, children: _jsx(TbRowRemove, { size: 18 }) }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().mergeOrSplit().run(), className: tableBtnClass, disabled: !inTable, title: labels.mergeOrSplit, children: _jsx(TbArrowMergeBoth, { size: 18 }) }), _jsx("div", { className: "w-px h-5 bg-border mx-0.5" }), _jsx("button", { type: "button", onClick: () => toggle('markdown'), className: tableBtnClass, title: labels.appendMarkdown, children: _jsx(LuClipboardPaste, { size: 18, style: { transform: 'scaleX(-1)' } }) }), _jsxs("div", { className: 'ml-auto flex items-center gap-0.5 ' + (isFullscreen ? 'pr-10' : ''), children: [_jsx("button", { type: "button", onClick: onCopy, title: "Copy as Markdown", className: tableBtnClass, children: copied ? _jsx(LuCheck, { size: 16, className: "text-green-500" }) : _jsx(LuCopy, { size: 16 }) }), _jsx("button", { type: "button", onClick: onToggleFullscreen, title: isFullscreen ? 'Exit fullscreen' : 'Fullscreen', className: tableBtnClass, children: isFullscreen ? _jsx(LuMinimize2, { size: 16 }) : _jsx(LuMaximize2, { size: 16 }) })] })] }), _jsx(InlinePanel, { panel: activePanel, onClose: () => setActivePanel(null), editor: editor, onUpdate: onUpdate, labels: labels })] }));
|
|
139
139
|
};
|
|
140
140
|
const DEFAULT_LABELS = {
|
|
141
141
|
bold: 'Bold',
|
|
@@ -176,6 +176,8 @@ export const MarkdownEditor = ({ content, editable, className, onUpdate, labels,
|
|
|
176
176
|
const { storage } = useRimori();
|
|
177
177
|
const mergedLabels = Object.assign(Object.assign({}, DEFAULT_LABELS), labels);
|
|
178
178
|
const lastEmittedRef = useRef(content !== null && content !== void 0 ? content : '');
|
|
179
|
+
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
180
|
+
const [copied, setCopied] = useState(false);
|
|
179
181
|
const stableUpload = useCallback((pngBlob) => __awaiter(void 0, void 0, void 0, function* () {
|
|
180
182
|
const { data, error } = yield storage.uploadImage(pngBlob);
|
|
181
183
|
if (error)
|
|
@@ -208,6 +210,14 @@ export const MarkdownEditor = ({ content, editable, className, onUpdate, labels,
|
|
|
208
210
|
onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(markdown);
|
|
209
211
|
},
|
|
210
212
|
});
|
|
213
|
+
const handleCopy = useCallback(() => {
|
|
214
|
+
if (!editor)
|
|
215
|
+
return;
|
|
216
|
+
navigator.clipboard.writeText(getMarkdown(editor)).then(() => {
|
|
217
|
+
setCopied(true);
|
|
218
|
+
setTimeout(() => setCopied(false), 2000);
|
|
219
|
+
});
|
|
220
|
+
}, [editor]);
|
|
211
221
|
// Sync external content changes (e.g. AI autofill) without triggering update loop.
|
|
212
222
|
// Pass false to setContent to prevent onUpdate from firing and re-normalizing the content.
|
|
213
223
|
useEffect(() => {
|
|
@@ -225,8 +235,11 @@ export const MarkdownEditor = ({ content, editable, className, onUpdate, labels,
|
|
|
225
235
|
return;
|
|
226
236
|
editor.setEditable(editable);
|
|
227
237
|
}, [editor, editable]);
|
|
228
|
-
|
|
238
|
+
const wrapperClass = isFullscreen
|
|
239
|
+
? 'text-md overflow-hidden rounded-lg border border-border bg-card shadow-sm fixed inset-0 z-50 flex flex-col'
|
|
240
|
+
: 'text-md overflow-hidden rounded-lg ' +
|
|
229
241
|
(editable ? 'border border-border bg-card shadow-sm' : 'bg-transparent') +
|
|
230
242
|
' ' +
|
|
231
|
-
(className !== null && className !== void 0 ? className : '')
|
|
243
|
+
(className !== null && className !== void 0 ? className : '');
|
|
244
|
+
return (_jsxs("div", { className: wrapperClass, onClick: onContentClick, children: [editor && editable && (_jsx(MenuBar, { editor: editor, onUpdate: onUpdate !== null && onUpdate !== void 0 ? onUpdate : (() => { }), uploadImage: stableUpload, labels: mergedLabels, onCopy: handleCopy, copied: copied, isFullscreen: isFullscreen, onToggleFullscreen: () => setIsFullscreen((v) => !v) })), _jsx(EditorContent, { editor: editor, className: isFullscreen ? 'flex-1 overflow-y-auto' : '' })] }));
|
|
232
245
|
};
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
export function useTheme(theme = 'system') {
|
|
2
2
|
const isDark = theme === 'system' ? systenUsesDarkMode() : theme === 'dark';
|
|
3
3
|
const dom = document.documentElement;
|
|
4
|
-
dom.style.background = 'hsl(var(--background))';
|
|
5
|
-
dom.classList.add('text-gray-900', 'dark:text-gray-200', 'bg-gray-50', 'dark:bg-gray-950');
|
|
6
4
|
dom.dataset.theme = isDark ? 'dark' : 'light';
|
|
7
5
|
dom.style.colorScheme = isDark ? 'dark' : 'light';
|
|
8
|
-
const root = document.querySelector('#root');
|
|
9
|
-
root.style.background = 'hsl(var(--background))';
|
|
10
6
|
dom.classList[isDark ? 'add' : 'remove']('dark');
|
|
7
|
+
const root = document.querySelector('#root');
|
|
8
|
+
root.classList.add('dark:bg-gradient-to-br', 'dark:from-gray-900', 'dark:to-gray-800', 'dark:text-white', 'min-h-screen', 'bg-fixed');
|
|
11
9
|
return { isDark, theme };
|
|
12
10
|
}
|
|
13
11
|
function systenUsesDarkMode() {
|
package/package.json
CHANGED
|
@@ -25,7 +25,18 @@ import {
|
|
|
25
25
|
} from 'react-icons/tb';
|
|
26
26
|
import { GoListOrdered } from 'react-icons/go';
|
|
27
27
|
import { AiOutlineUnorderedList } from 'react-icons/ai';
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
LuClipboardPaste,
|
|
30
|
+
LuHeading1,
|
|
31
|
+
LuHeading2,
|
|
32
|
+
LuHeading3,
|
|
33
|
+
LuLink,
|
|
34
|
+
LuUnlink,
|
|
35
|
+
LuCopy,
|
|
36
|
+
LuCheck,
|
|
37
|
+
LuMaximize2,
|
|
38
|
+
LuMinimize2,
|
|
39
|
+
} from 'react-icons/lu';
|
|
29
40
|
import { FaBold, FaCode, FaItalic, FaParagraph, FaStrikethrough } from 'react-icons/fa';
|
|
30
41
|
import { ImageUploadExtension, triggerImageUpload } from './ImageUploadExtension';
|
|
31
42
|
|
|
@@ -230,9 +241,22 @@ interface MenuBarProps {
|
|
|
230
241
|
onUpdate: (content: string) => void;
|
|
231
242
|
uploadImage?: (pngBlob: Blob) => Promise<string | null>;
|
|
232
243
|
labels: Required<EditorLabels>;
|
|
244
|
+
onCopy: () => void;
|
|
245
|
+
copied: boolean;
|
|
246
|
+
isFullscreen: boolean;
|
|
247
|
+
onToggleFullscreen: () => void;
|
|
233
248
|
}
|
|
234
249
|
|
|
235
|
-
const MenuBar = ({
|
|
250
|
+
const MenuBar = ({
|
|
251
|
+
editor,
|
|
252
|
+
onUpdate,
|
|
253
|
+
uploadImage,
|
|
254
|
+
labels,
|
|
255
|
+
onCopy,
|
|
256
|
+
copied,
|
|
257
|
+
isFullscreen,
|
|
258
|
+
onToggleFullscreen,
|
|
259
|
+
}: MenuBarProps): JSX.Element => {
|
|
236
260
|
const [activePanel, setActivePanel] = useState<PanelType>(null);
|
|
237
261
|
|
|
238
262
|
const toggle = (panel: PanelType): void => setActivePanel((prev) => (prev === panel ? null : panel));
|
|
@@ -453,8 +477,22 @@ const MenuBar = ({ editor, onUpdate, uploadImage, labels }: MenuBarProps): JSX.E
|
|
|
453
477
|
className={tableBtnClass}
|
|
454
478
|
title={labels.appendMarkdown}
|
|
455
479
|
>
|
|
456
|
-
<LuClipboardPaste size={18} />
|
|
480
|
+
<LuClipboardPaste size={18} style={{ transform: 'scaleX(-1)' }} />
|
|
457
481
|
</button>
|
|
482
|
+
|
|
483
|
+
<div className={'ml-auto flex items-center gap-0.5 ' + (isFullscreen ? 'pr-10' : '')}>
|
|
484
|
+
<button type="button" onClick={onCopy} title="Copy as Markdown" className={tableBtnClass}>
|
|
485
|
+
{copied ? <LuCheck size={16} className="text-green-500" /> : <LuCopy size={16} />}
|
|
486
|
+
</button>
|
|
487
|
+
<button
|
|
488
|
+
type="button"
|
|
489
|
+
onClick={onToggleFullscreen}
|
|
490
|
+
title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}
|
|
491
|
+
className={tableBtnClass}
|
|
492
|
+
>
|
|
493
|
+
{isFullscreen ? <LuMinimize2 size={16} /> : <LuMaximize2 size={16} />}
|
|
494
|
+
</button>
|
|
495
|
+
</div>
|
|
458
496
|
</div>
|
|
459
497
|
|
|
460
498
|
<InlinePanel
|
|
@@ -570,6 +608,8 @@ export const MarkdownEditor = ({
|
|
|
570
608
|
const { storage } = useRimori();
|
|
571
609
|
const mergedLabels: Required<EditorLabels> = { ...DEFAULT_LABELS, ...labels };
|
|
572
610
|
const lastEmittedRef = useRef(content ?? '');
|
|
611
|
+
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
612
|
+
const [copied, setCopied] = useState(false);
|
|
573
613
|
|
|
574
614
|
const stableUpload = useCallback(
|
|
575
615
|
async (pngBlob: Blob): Promise<string | null> => {
|
|
@@ -611,6 +651,14 @@ export const MarkdownEditor = ({
|
|
|
611
651
|
},
|
|
612
652
|
});
|
|
613
653
|
|
|
654
|
+
const handleCopy = useCallback(() => {
|
|
655
|
+
if (!editor) return;
|
|
656
|
+
navigator.clipboard.writeText(getMarkdown(editor)).then(() => {
|
|
657
|
+
setCopied(true);
|
|
658
|
+
setTimeout(() => setCopied(false), 2000);
|
|
659
|
+
});
|
|
660
|
+
}, [editor]);
|
|
661
|
+
|
|
614
662
|
// Sync external content changes (e.g. AI autofill) without triggering update loop.
|
|
615
663
|
// Pass false to setContent to prevent onUpdate from firing and re-normalizing the content.
|
|
616
664
|
useEffect(() => {
|
|
@@ -627,20 +675,28 @@ export const MarkdownEditor = ({
|
|
|
627
675
|
editor.setEditable(editable);
|
|
628
676
|
}, [editor, editable]);
|
|
629
677
|
|
|
678
|
+
const wrapperClass = isFullscreen
|
|
679
|
+
? 'text-md overflow-hidden rounded-lg border border-border bg-card shadow-sm fixed inset-0 z-50 flex flex-col'
|
|
680
|
+
: 'text-md overflow-hidden rounded-lg ' +
|
|
681
|
+
(editable ? 'border border-border bg-card shadow-sm' : 'bg-transparent') +
|
|
682
|
+
' ' +
|
|
683
|
+
(className ?? '');
|
|
684
|
+
|
|
630
685
|
return (
|
|
631
|
-
<div
|
|
632
|
-
className={
|
|
633
|
-
'text-md overflow-hidden rounded-lg ' +
|
|
634
|
-
(editable ? 'border border-border bg-card shadow-sm' : 'bg-transparent') +
|
|
635
|
-
' ' +
|
|
636
|
-
(className ?? '')
|
|
637
|
-
}
|
|
638
|
-
onClick={onContentClick}
|
|
639
|
-
>
|
|
686
|
+
<div className={wrapperClass} onClick={onContentClick}>
|
|
640
687
|
{editor && editable && (
|
|
641
|
-
<MenuBar
|
|
688
|
+
<MenuBar
|
|
689
|
+
editor={editor}
|
|
690
|
+
onUpdate={onUpdate ?? (() => {})}
|
|
691
|
+
uploadImage={stableUpload}
|
|
692
|
+
labels={mergedLabels}
|
|
693
|
+
onCopy={handleCopy}
|
|
694
|
+
copied={copied}
|
|
695
|
+
isFullscreen={isFullscreen}
|
|
696
|
+
onToggleFullscreen={() => setIsFullscreen((v) => !v)}
|
|
697
|
+
/>
|
|
642
698
|
)}
|
|
643
|
-
<EditorContent editor={editor} />
|
|
699
|
+
<EditorContent editor={editor} className={isFullscreen ? 'flex-1 overflow-y-auto' : ''} />
|
|
644
700
|
</div>
|
|
645
701
|
);
|
|
646
702
|
};
|
package/src/hooks/ThemeSetter.ts
CHANGED
|
@@ -4,16 +4,21 @@ export function useTheme(theme: Theme = 'system'): { isDark: boolean; theme: The
|
|
|
4
4
|
const isDark = theme === 'system' ? systenUsesDarkMode() : theme === 'dark';
|
|
5
5
|
|
|
6
6
|
const dom = document.documentElement;
|
|
7
|
-
dom.style.background = 'hsl(var(--background))';
|
|
8
|
-
dom.classList.add('text-gray-900', 'dark:text-gray-200', 'bg-gray-50', 'dark:bg-gray-950');
|
|
9
7
|
dom.dataset.theme = isDark ? 'dark' : 'light';
|
|
10
8
|
dom.style.colorScheme = isDark ? 'dark' : 'light';
|
|
11
9
|
|
|
12
|
-
const root = document.querySelector('#root') as HTMLDivElement;
|
|
13
|
-
root.style.background = 'hsl(var(--background))';
|
|
14
|
-
|
|
15
10
|
dom.classList[isDark ? 'add' : 'remove']('dark');
|
|
16
11
|
|
|
12
|
+
const root = document.querySelector('#root') as HTMLDivElement;
|
|
13
|
+
root.classList.add(
|
|
14
|
+
'dark:bg-gradient-to-br',
|
|
15
|
+
'dark:from-gray-900',
|
|
16
|
+
'dark:to-gray-800',
|
|
17
|
+
'dark:text-white',
|
|
18
|
+
'min-h-screen',
|
|
19
|
+
'bg-fixed',
|
|
20
|
+
);
|
|
21
|
+
|
|
17
22
|
return { isDark, theme };
|
|
18
23
|
}
|
|
19
24
|
|