@motiadev/workbench 0.5.11-beta.120-433270 → 0.5.11-beta.120-110250

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.
Files changed (48) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.html +21 -1
  3. package/dist/index.js +1 -0
  4. package/dist/middleware.js +15 -2
  5. package/dist/src/App.js +6 -27
  6. package/dist/src/components/flow/hooks/use-get-flow-state.js +1 -0
  7. package/dist/src/components/flow/node-organizer.js +4 -38
  8. package/dist/src/components/header/header.js +1 -1
  9. package/dist/src/components/logs/logs-page.js +1 -1
  10. package/dist/src/components/observability/trace-item/trace-item.js +1 -1
  11. package/dist/src/components/observability/traces-groups.js +1 -1
  12. package/dist/src/components/sidebar/sidebar.js +1 -1
  13. package/dist/src/components/tutorial/engine/tutorial-engine.d.ts +12 -0
  14. package/dist/src/components/tutorial/engine/tutorial-engine.js +36 -0
  15. package/dist/src/components/tutorial/engine/tutorial-types.d.ts +22 -0
  16. package/dist/src/components/tutorial/engine/tutorial-types.js +1 -0
  17. package/dist/src/components/tutorial/engine/workbench-xpath.d.ts +39 -0
  18. package/dist/src/components/tutorial/engine/workbench-xpath.js +39 -0
  19. package/dist/src/components/tutorial/hooks/tutorial-utils.d.ts +1 -0
  20. package/dist/src/components/tutorial/hooks/tutorial-utils.js +17 -0
  21. package/dist/src/components/tutorial/hooks/use-tutorial-engine.d.ts +14 -0
  22. package/dist/src/components/tutorial/hooks/use-tutorial-engine.js +162 -0
  23. package/dist/src/components/tutorial/hooks/use-tutorial.d.ts +5 -0
  24. package/dist/src/components/tutorial/hooks/use-tutorial.js +10 -0
  25. package/dist/src/components/tutorial/tutorial-button.js +20 -0
  26. package/dist/src/components/tutorial/tutorial-step.d.ts +14 -0
  27. package/dist/src/components/tutorial/tutorial-step.js +18 -0
  28. package/dist/src/components/tutorial/tutorial.d.ts +2 -0
  29. package/dist/src/components/tutorial/tutorial.js +8 -0
  30. package/dist/src/components/ui/theme-toggle.js +0 -8
  31. package/dist/src/publicComponents/base-node/base-node.js +3 -1
  32. package/dist/src/publicComponents/base-node/code-display.d.ts +9 -0
  33. package/dist/src/publicComponents/base-node/code-display.js +64 -0
  34. package/dist/src/publicComponents/base-node/feature-card.d.ts +9 -0
  35. package/dist/src/publicComponents/base-node/feature-card.js +5 -0
  36. package/dist/src/publicComponents/base-node/node-sidebar.d.ts +2 -0
  37. package/dist/src/publicComponents/base-node/node-sidebar.js +4 -5
  38. package/dist/src/stores/use-flow-store.d.ts +3 -5
  39. package/dist/src/stores/use-global-store.d.ts +3 -5
  40. package/dist/src/stores/use-tabs-store.d.ts +3 -5
  41. package/dist/src/stores/use-theme-store.d.ts +5 -6
  42. package/dist/src/types/file.d.ts +7 -0
  43. package/dist/src/types/file.js +1 -0
  44. package/dist/tsconfig.app.tsbuildinfo +1 -1
  45. package/dist/tsconfig.node.tsbuildinfo +1 -1
  46. package/package.json +13 -12
  47. package/dist/src/components/ui/tutorial-button.js +0 -69
  48. /package/dist/src/components/{ui → tutorial}/tutorial-button.d.ts +0 -0
@@ -0,0 +1,10 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { MotiaTutorial } from '../engine/tutorial-engine';
3
+ export const useTutorial = () => {
4
+ const open = () => MotiaTutorial.open();
5
+ const [steps, setSteps] = useState([]);
6
+ useEffect(() => {
7
+ MotiaTutorial.onStepsRegistered(() => setSteps(MotiaTutorial.steps));
8
+ }, []);
9
+ return { open, steps };
10
+ };
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@motiadev/ui';
3
+ import { Book } from 'lucide-react';
4
+ import { useTutorial } from './hooks/use-tutorial';
5
+ import { Tooltip } from '../ui/tooltip';
6
+ export const TutorialButton = () => {
7
+ const { open, steps } = useTutorial();
8
+ const isTutorialFlowMissing = steps.length === 0;
9
+ const onTutorialButtonClick = () => {
10
+ if (!isTutorialFlowMissing) {
11
+ open();
12
+ }
13
+ };
14
+ console.log(isTutorialFlowMissing);
15
+ const trigger = (_jsxs(Button, { "data-testid": "tutorial-trigger", variant: "default", onClick: () => onTutorialButtonClick(), children: [_jsx(Book, { className: "h-4 w-4" }), "Tutorial"] }));
16
+ if (isTutorialFlowMissing) {
17
+ return (_jsx(Tooltip, { content: _jsxs("div", { className: "flex flex-col gap-4 p-4 max-w-[320px]", children: [_jsx("p", { className: "text-sm wrap-break-word p-0 m-0", children: "In order to start the tutorial, you need to download the tutorial steps using the Motia CLI. In your terminal execute the following command to create a new project:" }), _jsx("pre", { className: "text-sm font-bold", children: "npx motia@latest create" })] }), children: trigger }));
18
+ }
19
+ return trigger;
20
+ };
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { TutorialImage } from './engine/tutorial-types';
3
+ type TutorialStepProps = {
4
+ step: number;
5
+ totalSteps: number;
6
+ title: string;
7
+ description: React.ReactNode;
8
+ link?: string;
9
+ image?: TutorialImage;
10
+ onNext: () => void;
11
+ onClose: () => void;
12
+ };
13
+ export declare const TutorialStep: React.ForwardRefExoticComponent<TutorialStepProps & React.RefAttributes<HTMLDivElement>>;
14
+ export {};
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useEffect } from 'react';
3
+ export const TutorialStep = forwardRef(({ step, totalSteps, title, description, link, image, onNext, onClose }, ref) => {
4
+ useEffect(() => {
5
+ const handleKeyDown = (e) => {
6
+ if (e.key === 'Escape') {
7
+ onClose();
8
+ }
9
+ else if (e.key === 'ArrowRight') {
10
+ onNext();
11
+ }
12
+ };
13
+ window.addEventListener('keydown', handleKeyDown);
14
+ return () => window.removeEventListener('keydown', handleKeyDown);
15
+ }, [onClose, onNext]);
16
+ return (_jsxs("div", { ref: ref, className: "driver-popover", children: [image && (_jsx("img", { src: image.src, alt: "Step visual", className: "driver-popover-image object-cover", style: { height: image.height, width: '100%' } })), _jsx("div", { className: "driver-popover-title", children: _jsx("h2", { className: "popover-title", children: title }) }), _jsx("div", { className: "driver-popover-description", children: description }), link && (_jsx("a", { href: link, target: "_blank", className: "text-foreground text-xs font-semibold px-4 hover:underline", children: "Learn more" })), _jsxs("div", { className: "driver-popover-footer flex items-center justify-between", children: [_jsxs("div", { className: "text-sm text-muted-foreground font-semibold", children: [step, " ", _jsx("span", { className: "text-foreground", children: "/" }), " ", totalSteps] }), _jsx("div", { className: "driver-popover-navigation-btns flex gap-2", children: _jsx("button", { className: "driver-popover-next-btn", onClick: onNext, children: step < totalSteps ? 'Continue' : 'Finish' }) })] }), step < totalSteps && (_jsx("div", { className: "tutorial-opt-out-container", children: _jsx("button", { className: "tutorial-opt-out-button", onClick: onClose, children: "Close" }) }))] }));
17
+ });
18
+ TutorialStep.displayName = 'TutorialStep';
@@ -0,0 +1,2 @@
1
+ import './tutorial.css';
2
+ export declare const Tutorial: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useTutorialEngine } from './hooks/use-tutorial-engine';
3
+ import { TutorialStep } from './tutorial-step';
4
+ import './tutorial.css';
5
+ export const Tutorial = () => {
6
+ const engine = useTutorialEngine();
7
+ return (_jsxs("div", { children: [_jsx("div", { className: "fixed inset-0 z-[9999]" }), _jsx("div", { className: "absolute top-5 left-5 w-full h-full rounded-lg shadow-[0_0_0_9999px_rgba(0,0,0,0.5)] z-[10000] pointer-events-none", ref: engine.highlighterRef }), _jsx(TutorialStep, { ref: engine.ref, step: engine.currentStep, totalSteps: engine.totalSteps, title: engine.title, description: engine.description, link: engine.link, image: engine.image, onNext: () => engine.moveStep(engine.currentStepRef.current + 1), onClose: engine.onClose })] }));
8
+ };
@@ -2,19 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Moon, Sun } from 'lucide-react';
3
3
  import { useThemeStore } from '@/stores/use-theme-store';
4
4
  import { cn } from '@/lib/utils';
5
- import { useEffect } from 'react';
6
5
  export const ThemeToggle = () => {
7
6
  const theme = useThemeStore((state) => state.theme);
8
7
  const setTheme = useThemeStore((state) => state.setTheme);
9
8
  const toggleTheme = () => {
10
9
  setTheme(theme === 'light' ? 'dark' : 'light');
11
10
  };
12
- useEffect(() => {
13
- const url = new URL(window.location.href);
14
- const colorScheme = url.searchParams.get('color-scheme');
15
- if (colorScheme) {
16
- setTheme(colorScheme);
17
- }
18
- }, [setTheme]);
19
11
  return (_jsxs("button", { onClick: toggleTheme, className: "relative flex items-center cursor-pointer w-16 h-8 border bg-muted-foreground/10 rounded-full p-1 transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", "aria-label": `Switch to ${theme === 'light' ? 'dark' : 'light'} theme`, children: [_jsx("div", { className: cn('absolute w-6 h-6 bg-background border border-border rounded-full shadow-sm transition-transform duration-200 ease-in-out', theme === 'dark' ? 'translate-x-8' : 'translate-x-0') }), _jsx("div", { className: "flex items-center justify-center w-6 h-6 z-10", children: _jsx(Sun, { className: cn('h-3.5 w-3.5 transition-colors duration-200', theme === 'light' ? 'text-foreground' : 'text-muted-foreground') }) }), _jsx("div", { className: "flex items-center justify-center w-6 h-6 z-10 ml-2", children: _jsx(Moon, { className: cn('h-3.5 w-3.5 transition-colors duration-200', theme === 'dark' ? 'text-foreground' : 'text-muted-foreground') }) })] }));
20
12
  };
@@ -10,10 +10,12 @@ export const BaseNode = ({ title, variant, children, disableSourceHandle, disabl
10
10
  const [isOpen, setIsOpen] = useState(false);
11
11
  const { sourcePosition, targetPosition, toggleTargetPosition, toggleSourcePosition } = useHandlePositions(data);
12
12
  const [content, setContent] = useState(null);
13
+ const [features, setFeatures] = useState([]);
13
14
  const fetchContent = useCallback(async () => {
14
15
  const response = await fetch(`/step/${data.id}`);
15
16
  const responseData = await response.json();
16
17
  setContent(responseData.content);
18
+ setFeatures(responseData.features);
17
19
  }, [data.id]);
18
20
  useEffect(() => {
19
21
  if (data.id && isOpen) {
@@ -24,5 +26,5 @@ export const BaseNode = ({ title, variant, children, disableSourceHandle, disabl
24
26
  'bg-muted-foreground/20': isOpen,
25
27
  }), children: [_jsx("div", { className: "rounded-lg bg-background border-1 border-muted-foreground/30 border-solid", "data-testid": `node-${title?.toLowerCase().replace(/ /g, '-')}`, children: _jsxs("div", { className: "group relative", children: [_jsx(NodeHeader, { text: title, variant: variant, className: "border-b-2 border-muted-foreground/10", children: _jsx("div", { className: "flex justify-end", children: _jsx(Button, { "data-testid": `open-code-preview-button-${title?.toLowerCase()}`, variant: "ghost", className: "h-5 p-0.5", onClick: () => setIsOpen(true), children: _jsx(ScanSearch, { className: "w-4 h-4" }) }) }) }), subtitle && _jsx("div", { className: "py-4 px-6 text-sm text-muted-foreground", children: subtitle }), children && (_jsx("div", { className: "p-2", children: _jsx("div", { className: cn('space-y-3 p-4 text-sm text-muted-foreground', {
26
28
  'bg-card': variant !== 'noop',
27
- }), children: children }) })), !disableTargetHandle && (_jsx(BaseHandle, { type: "target", position: targetPosition, onTogglePosition: toggleTargetPosition })), !disableSourceHandle && (_jsx(BaseHandle, { type: "source", position: sourcePosition, onTogglePosition: toggleSourcePosition }))] }) }), content && (_jsx(NodeSidebar, { content: content, title: title, subtitle: subtitle, variant: variant, language: language, isOpen: isOpen, onClose: () => setIsOpen(false) }))] }));
29
+ }), children: children }) })), !disableTargetHandle && (_jsx(BaseHandle, { type: "target", position: targetPosition, onTogglePosition: toggleTargetPosition })), !disableSourceHandle && (_jsx(BaseHandle, { type: "source", position: sourcePosition, onTogglePosition: toggleSourcePosition }))] }) }), content && (_jsx(NodeSidebar, { features: features, content: content, title: title, subtitle: subtitle, variant: variant, language: language, isOpen: isOpen, onClose: () => setIsOpen(false) }))] }));
28
30
  };
@@ -0,0 +1,9 @@
1
+ import { Feature } from '@/types/file';
2
+ import React from 'react';
3
+ type CodeDisplayProps = {
4
+ code: string;
5
+ language?: string;
6
+ features?: Feature[];
7
+ };
8
+ export declare const CodeDisplay: React.FC<CodeDisplayProps>;
9
+ export {};
@@ -0,0 +1,64 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useThemeStore } from '@/stores/use-theme-store';
3
+ import { FeatureCard } from './feature-card';
4
+ import { useRef, useState } from 'react';
5
+ import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
6
+ import { dracula, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
7
+ import { LanguageIndicator } from './language-indicator';
8
+ const codeTagProps = {
9
+ style: {
10
+ fontFamily: 'DM Mono, monospace',
11
+ fontSize: '16px',
12
+ },
13
+ };
14
+ const customStyle = {
15
+ margin: 0,
16
+ borderRadius: 0,
17
+ padding: 0,
18
+ };
19
+ const isHighlighted = (lines, lineNumber) => {
20
+ return lines.some((line) => {
21
+ const [start, end] = line.split('-').map((num) => parseInt(num, 10));
22
+ if (end !== undefined) {
23
+ return lineNumber >= start && lineNumber <= end;
24
+ }
25
+ return lineNumber == start;
26
+ });
27
+ };
28
+ const getFirstLineNumber = (line) => {
29
+ const [start] = line.split('-').map((num) => parseInt(num, 10));
30
+ return start;
31
+ };
32
+ export const CodeDisplay = ({ code, language, features }) => {
33
+ const theme = useThemeStore((state) => state.theme);
34
+ const themeStyle = theme === 'dark' ? dracula : oneLight;
35
+ const [highlightedLines, setHighlightedLines] = useState([]);
36
+ const [selectedFeature, setSelectedFeature] = useState(null);
37
+ const ref = useRef(null);
38
+ const handleFeatureClick = (feature) => {
39
+ setSelectedFeature(feature);
40
+ setHighlightedLines(feature.lines);
41
+ const lineNumber = getFirstLineNumber(feature.lines[0]);
42
+ const line = ref.current?.querySelector(`[data-line-number="${lineNumber}"]`);
43
+ if (line) {
44
+ line.scrollIntoView({ behavior: 'smooth', block: 'center' });
45
+ }
46
+ };
47
+ return (_jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [_jsxs("div", { className: "flex items-center py-2 px-5 dark:bg-[#1e1e1e] gap-2 justify-center", children: [_jsx("div", { className: "text-sm text-muted-foreground", children: "Read only" }), _jsx("div", { className: "flex-1" }), _jsx(LanguageIndicator, { language: language, className: "w-4 h-4", size: 16, showLabel: true })] }), _jsxs("div", { className: "flex flex-row h-[calc(100%-36px)]", children: [features && features.length > 0 && (_jsx("div", { className: "flex flex-col gap-2 p-2 bg-card overflow-y-auto min-w-[200px] w-[300px]", children: features.map((feature, index) => (_jsx(FeatureCard, { feature: feature, highlighted: selectedFeature === feature, onClick: () => handleFeatureClick(feature), onHover: () => handleFeatureClick(feature) }, index))) })), _jsx("div", { className: "overflow-y-auto", ref: ref, children: _jsx(SyntaxHighlighter, { showLineNumbers: true, language: language, style: themeStyle, codeTagProps: codeTagProps, customStyle: customStyle, wrapLines: true, lineProps: (lineNumber) => {
48
+ if (isHighlighted(highlightedLines, lineNumber)) {
49
+ return {
50
+ 'data-line-number': lineNumber,
51
+ style: {
52
+ borderLeft: '2px solid var(--accent-1000)',
53
+ backgroundColor: 'rgb(from var(--accent-1000) r g b / 0.2)',
54
+ },
55
+ };
56
+ }
57
+ return {
58
+ 'data-line-number': lineNumber,
59
+ style: {
60
+ borderLeft: '2px solid transparent',
61
+ },
62
+ };
63
+ }, children: code }) })] })] }));
64
+ };
@@ -0,0 +1,9 @@
1
+ import { Feature } from '@/types/file';
2
+ type Props = {
3
+ feature: Feature;
4
+ highlighted: boolean;
5
+ onClick: () => void;
6
+ onHover: () => void;
7
+ };
8
+ export declare const FeatureCard: React.FC<Props>;
9
+ export {};
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '@/lib/utils';
3
+ export const FeatureCard = ({ feature, highlighted, onClick, onHover }) => {
4
+ return (_jsxs("div", { "data-feature-id": feature.id, className: cn('p-4 rounded-lg bg-card shadow-sm cursor-pointer hover:bg-card/50 border-2 border-transparent', highlighted && 'border-2 border-accent-1000 bg-accent-100'), onClick: onClick, onMouseEnter: onHover, children: [_jsx("div", { className: "text-md font-semibold text-foreground leading-tight whitespace-nowrap mb-2", children: feature.title }), _jsx("div", { className: "text-sm font-medium text-muted-foreground leading-tight", children: feature.description }), feature.link && (_jsx("div", { className: "text-sm font-medium text-muted-foreground leading-tight", children: _jsx("a", { href: feature.link, children: "Learn more" }) }))] }));
5
+ };
@@ -1,6 +1,8 @@
1
+ import { Feature } from '@/types/file';
1
2
  import React from 'react';
2
3
  type NodeSidebarProps = {
3
4
  content: string;
5
+ features: Feature[];
4
6
  title: string;
5
7
  subtitle?: string;
6
8
  variant: 'event' | 'api' | 'noop' | 'cron';
@@ -1,10 +1,9 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { JsonEditor } from '@/components/endpoints/json-editor';
1
+ import { jsx as _jsx } from "react/jsx-runtime";
3
2
  import { Sidebar } from '@/components/sidebar/sidebar';
4
3
  import { X } from 'lucide-react';
5
- import { LanguageIndicator } from './language-indicator';
6
- export const NodeSidebar = ({ content, title, subtitle, language, isOpen, onClose }) => {
4
+ import { CodeDisplay } from './code-display';
5
+ export const NodeSidebar = ({ content, title, subtitle, language, isOpen, onClose, features, }) => {
7
6
  if (!isOpen)
8
7
  return null;
9
- return (_jsxs(Sidebar, { title: title, subtitle: subtitle, initialWidth: 600, contentClassName: "p-0 h-full gap-0", onClose: onClose, actions: [{ icon: _jsx(X, {}), onClick: onClose, label: 'Close' }], children: [_jsxs("div", { className: "flex items-center py-2 px-5 dark:bg-[#1e1e1e] gap-2 justify-center", children: [_jsx("div", { className: "text-sm text-muted-foreground", children: "Read only" }), _jsx("div", { className: "flex-1" }), _jsx(LanguageIndicator, { language: language, className: "w-4 h-4", size: 16, showLabel: true })] }), _jsx(JsonEditor, { value: content, language: language, height: 'calc(100vh - 160px)', readOnly: true })] }));
8
+ return (_jsx(Sidebar, { title: title, subtitle: subtitle, initialWidth: 900, contentClassName: "p-0 h-full gap-0", onClose: onClose, actions: [{ icon: _jsx(X, {}), onClick: onClose, label: 'Close' }], children: _jsx(CodeDisplay, { code: content, language: language, features: features }) }));
10
9
  };
@@ -4,17 +4,15 @@ type UseFlowStore = {
4
4
  flows: string[];
5
5
  setFlows: (flows: string[]) => void;
6
6
  };
7
- export declare const useFlowStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<UseFlowStore>, "setState" | "persist"> & {
8
- setState(partial: UseFlowStore | Partial<UseFlowStore> | ((state: UseFlowStore) => UseFlowStore | Partial<UseFlowStore>), replace?: false | undefined): unknown;
9
- setState(state: UseFlowStore | ((state: UseFlowStore) => UseFlowStore), replace: true): unknown;
7
+ export declare const useFlowStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<UseFlowStore>, "persist"> & {
10
8
  persist: {
11
- setOptions: (options: Partial<import("zustand/middleware").PersistOptions<UseFlowStore, UseFlowStore, unknown>>) => void;
9
+ setOptions: (options: Partial<import("zustand/middleware").PersistOptions<UseFlowStore, UseFlowStore>>) => void;
12
10
  clearStorage: () => void;
13
11
  rehydrate: () => Promise<void> | void;
14
12
  hasHydrated: () => boolean;
15
13
  onHydrate: (fn: (state: UseFlowStore) => void) => () => void;
16
14
  onFinishHydration: (fn: (state: UseFlowStore) => void) => () => void;
17
- getOptions: () => Partial<import("zustand/middleware").PersistOptions<UseFlowStore, UseFlowStore, unknown>>;
15
+ getOptions: () => Partial<import("zustand/middleware").PersistOptions<UseFlowStore, UseFlowStore>>;
18
16
  };
19
17
  }>;
20
18
  export {};
@@ -10,17 +10,15 @@ type UseGlobalStore = {
10
10
  selectedLogId?: string;
11
11
  selectLogId: (logId?: string) => void;
12
12
  };
13
- export declare const useGlobalStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<UseGlobalStore>, "setState" | "persist"> & {
14
- setState(partial: UseGlobalStore | Partial<UseGlobalStore> | ((state: UseGlobalStore) => UseGlobalStore | Partial<UseGlobalStore>), replace?: false | undefined): unknown;
15
- setState(state: UseGlobalStore | ((state: UseGlobalStore) => UseGlobalStore), replace: true): unknown;
13
+ export declare const useGlobalStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<UseGlobalStore>, "persist"> & {
16
14
  persist: {
17
- setOptions: (options: Partial<import("zustand/middleware").PersistOptions<UseGlobalStore, UseGlobalStore, unknown>>) => void;
15
+ setOptions: (options: Partial<import("zustand/middleware").PersistOptions<UseGlobalStore, UseGlobalStore>>) => void;
18
16
  clearStorage: () => void;
19
17
  rehydrate: () => Promise<void> | void;
20
18
  hasHydrated: () => boolean;
21
19
  onHydrate: (fn: (state: UseGlobalStore) => void) => () => void;
22
20
  onFinishHydration: (fn: (state: UseGlobalStore) => void) => () => void;
23
- getOptions: () => Partial<import("zustand/middleware").PersistOptions<UseGlobalStore, UseGlobalStore, unknown>>;
21
+ getOptions: () => Partial<import("zustand/middleware").PersistOptions<UseGlobalStore, UseGlobalStore>>;
24
22
  };
25
23
  }>;
26
24
  export {};
@@ -3,17 +3,15 @@ interface TabsState {
3
3
  setTopTab: (tab: string) => void;
4
4
  setBottomTab: (tab: string) => void;
5
5
  }
6
- export declare const useTabsStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<TabsState>, "setState" | "persist"> & {
7
- setState(partial: TabsState | Partial<TabsState> | ((state: TabsState) => TabsState | Partial<TabsState>), replace?: false | undefined): unknown;
8
- setState(state: TabsState | ((state: TabsState) => TabsState), replace: true): unknown;
6
+ export declare const useTabsStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<TabsState>, "persist"> & {
9
7
  persist: {
10
- setOptions: (options: Partial<import("zustand/middleware").PersistOptions<TabsState, TabsState, unknown>>) => void;
8
+ setOptions: (options: Partial<import("zustand/middleware").PersistOptions<TabsState, TabsState>>) => void;
11
9
  clearStorage: () => void;
12
10
  rehydrate: () => Promise<void> | void;
13
11
  hasHydrated: () => boolean;
14
12
  onHydrate: (fn: (state: TabsState) => void) => () => void;
15
13
  onFinishHydration: (fn: (state: TabsState) => void) => () => void;
16
- getOptions: () => Partial<import("zustand/middleware").PersistOptions<TabsState, TabsState, unknown>>;
14
+ getOptions: () => Partial<import("zustand/middleware").PersistOptions<TabsState, TabsState>>;
17
15
  };
18
16
  }>;
19
17
  export {};
@@ -1,18 +1,17 @@
1
- export type Theme = 'dark' | 'light' | 'system';
1
+ type Theme = 'dark' | 'light' | 'system';
2
2
  export type ThemeState = {
3
3
  theme: Theme;
4
4
  setTheme: (theme: Theme) => void;
5
5
  };
6
- export declare const useThemeStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<ThemeState>, "setState" | "persist"> & {
7
- setState(partial: ThemeState | Partial<ThemeState> | ((state: ThemeState) => ThemeState | Partial<ThemeState>), replace?: false | undefined): unknown;
8
- setState(state: ThemeState | ((state: ThemeState) => ThemeState), replace: true): unknown;
6
+ export declare const useThemeStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<ThemeState>, "persist"> & {
9
7
  persist: {
10
- setOptions: (options: Partial<import("zustand/middleware").PersistOptions<ThemeState, unknown, unknown>>) => void;
8
+ setOptions: (options: Partial<import("zustand/middleware").PersistOptions<ThemeState, unknown>>) => void;
11
9
  clearStorage: () => void;
12
10
  rehydrate: () => Promise<void> | void;
13
11
  hasHydrated: () => boolean;
14
12
  onHydrate: (fn: (state: ThemeState) => void) => () => void;
15
13
  onFinishHydration: (fn: (state: ThemeState) => void) => () => void;
16
- getOptions: () => Partial<import("zustand/middleware").PersistOptions<ThemeState, unknown, unknown>>;
14
+ getOptions: () => Partial<import("zustand/middleware").PersistOptions<ThemeState, unknown>>;
17
15
  };
18
16
  }>;
17
+ export {};
@@ -0,0 +1,7 @@
1
+ export type Feature = {
2
+ id?: string;
3
+ title: string;
4
+ description: string;
5
+ lines: string[];
6
+ link?: string;
7
+ };
@@ -0,0 +1 @@
1
+ export {};