@weaverclub/render 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.
Files changed (64) hide show
  1. package/dist/entrypoint +0 -0
  2. package/package.json +6 -2
  3. package/.github/workflows/publish.yml +0 -44
  4. package/biome.json +0 -42
  5. package/build.ts +0 -62
  6. package/bun.lock +0 -733
  7. package/bunfig.toml +0 -3
  8. package/ideas.md +0 -11
  9. package/publish.ts +0 -62
  10. package/src/cli/command/renderCommand.ts +0 -112
  11. package/src/cli/entrypoint.ts +0 -25
  12. package/src/core/bundler.ts +0 -180
  13. package/src/core/control/arrayControl.ts +0 -15
  14. package/src/core/control/booleanControl.ts +0 -15
  15. package/src/core/control/control.ts +0 -7
  16. package/src/core/control/controlBuilder.ts +0 -87
  17. package/src/core/control/numberControl.ts +0 -15
  18. package/src/core/control/stringControl.ts +0 -15
  19. package/src/core/control/variantControl.ts +0 -18
  20. package/src/core/css/css.ts +0 -50
  21. package/src/core/css/tailwind.ts +0 -172
  22. package/src/core/html.ts +0 -63
  23. package/src/core/pkg.ts +0 -92
  24. package/src/core/story.ts +0 -52
  25. package/src/core/tsconfig.ts +0 -46
  26. package/src/react/react.ts +0 -2
  27. package/src/react/reactControlBuilder.ts +0 -130
  28. package/src/react/reactStory.ts +0 -36
  29. package/src/server/api/getStories.ts +0 -44
  30. package/src/server/api/renderIframe.ts +0 -66
  31. package/src/server/backend.ts +0 -104
  32. package/src/server/streaming.ts +0 -16
  33. package/src/ui/api.ts +0 -16
  34. package/src/ui/app.tsx +0 -23
  35. package/src/ui/cn.ts +0 -6
  36. package/src/ui/components/appSidebar.tsx +0 -76
  37. package/src/ui/components/button.stories.tsx +0 -32
  38. package/src/ui/components/button.tsx +0 -55
  39. package/src/ui/components/command.tsx +0 -187
  40. package/src/ui/components/contextMenu.tsx +0 -261
  41. package/src/ui/components/dialog.tsx +0 -153
  42. package/src/ui/components/input.tsx +0 -23
  43. package/src/ui/components/inputGroup.tsx +0 -157
  44. package/src/ui/components/kdb.tsx +0 -26
  45. package/src/ui/components/searchCommand.tsx +0 -5
  46. package/src/ui/components/separator.tsx +0 -22
  47. package/src/ui/components/sheet.tsx +0 -131
  48. package/src/ui/components/sidebar.tsx +0 -725
  49. package/src/ui/components/skeleton.tsx +0 -13
  50. package/src/ui/components/spinner.tsx +0 -15
  51. package/src/ui/components/tabButton.tsx +0 -80
  52. package/src/ui/components/tabContent.tsx +0 -20
  53. package/src/ui/components/tabList.tsx +0 -53
  54. package/src/ui/components/textarea.tsx +0 -17
  55. package/src/ui/components/tooltip.tsx +0 -67
  56. package/src/ui/frontend.tsx +0 -68
  57. package/src/ui/hooks/useMobile.ts +0 -23
  58. package/src/ui/index.html +0 -12
  59. package/src/ui/routeTree.gen.ts +0 -35
  60. package/src/ui/routes/__root.tsx +0 -9
  61. package/src/ui/styles.css +0 -123
  62. package/src/ui/tabs.tsx +0 -89
  63. package/tsconfig.json +0 -25
  64. package/tsr.config.json +0 -6
@@ -1,13 +0,0 @@
1
- import { cn } from '../cn'
2
-
3
- function Skeleton({ className, ...props }: React.ComponentProps<'div'>) {
4
- return (
5
- <div
6
- data-slot="skeleton"
7
- className={cn('bg-muted rounded-md animate-pulse', className)}
8
- {...props}
9
- />
10
- )
11
- }
12
-
13
- export { Skeleton }
@@ -1,15 +0,0 @@
1
- import { Loader2Icon } from 'lucide-react'
2
- import { cn } from '../cn'
3
-
4
- function Spinner({ className, ...props }: React.ComponentProps<'svg'>) {
5
- return (
6
- <Loader2Icon
7
- role="status"
8
- aria-label="Loading"
9
- className={cn('size-4 animate-spin', className)}
10
- {...props}
11
- />
12
- )
13
- }
14
-
15
- export { Spinner }
@@ -1,80 +0,0 @@
1
- import type { ComponentProps } from 'react'
2
- import { useActiveTab, useNewTab, useReplaceTab, useTabs } from '#ui/tabs'
3
- import {
4
- ContextMenu,
5
- ContextMenuContent,
6
- ContextMenuItem,
7
- ContextMenuTrigger
8
- } from './contextMenu'
9
- import { SidebarMenuButton } from './sidebar'
10
-
11
- export function TabButton({ story, ...props }: TabButtonProps) {
12
- const [tabs] = useTabs()
13
- const { activeTab, setActiveTab } = useActiveTab()
14
- const newTab = useNewTab()
15
- const replaceTab = useReplaceTab()
16
-
17
- function handleOpen(state: 'temporary' | 'permanent') {
18
- return () => {
19
- const existingTab = tabs.find((tab) => tab.path === story.id)
20
-
21
- if (existingTab) {
22
- return setActiveTab(existingTab.id)
23
- }
24
-
25
- if (activeTab?.temporary) {
26
- return replaceTab(activeTab.id, {
27
- name: story.name,
28
- path: story.id,
29
- temporary: state === 'temporary'
30
- })
31
- }
32
-
33
- return newTab({
34
- name: story.name,
35
- path: story.id,
36
- temporary: state === 'temporary'
37
- })
38
- }
39
- }
40
-
41
- function handleOpenInNewTab() {
42
- return () => {
43
- newTab({
44
- name: story.name,
45
- path: story.id,
46
- temporary: false
47
- })
48
- }
49
- }
50
-
51
- return (
52
- <ContextMenu>
53
- <ContextMenuTrigger
54
- render={
55
- <SidebarMenuButton
56
- onClick={handleOpen('temporary')}
57
- onDoubleClick={handleOpen('permanent')}
58
- {...props}
59
- />
60
- }
61
- />
62
-
63
- <ContextMenuContent>
64
- <ContextMenuItem onSelect={handleOpen('permanent')}>
65
- Open
66
- </ContextMenuItem>
67
- <ContextMenuItem onSelect={handleOpenInNewTab()}>
68
- Open in New Tab
69
- </ContextMenuItem>
70
- </ContextMenuContent>
71
- </ContextMenu>
72
- )
73
- }
74
-
75
- type TabButtonProps = ComponentProps<typeof SidebarMenuButton> & {
76
- story: {
77
- name: string
78
- id: string
79
- }
80
- }
@@ -1,20 +0,0 @@
1
- import { Tabs } from '@base-ui/react'
2
- import { useTabs } from '#ui/tabs'
3
-
4
- export function TabContent() {
5
- const [tabs] = useTabs()
6
-
7
- return (
8
- <>
9
- {tabs.map((tab) => (
10
- <Tabs.Panel key={tab.id} value={tab.id}>
11
- <iframe
12
- src={`/iframe/${tab.path}`}
13
- className="w-full h-full border-none bg-white"
14
- title={tab.name}
15
- />
16
- </Tabs.Panel>
17
- ))}
18
- </>
19
- )
20
- }
@@ -1,53 +0,0 @@
1
- import { Tabs } from '@base-ui/react/tabs'
2
- import { ArrowLeftIcon, ArrowRightIcon, XIcon } from 'lucide-react'
3
- import { useCloseTab, useMarkTabAsPermanent, useTabs } from '#ui/tabs'
4
- import { Button } from './button'
5
-
6
- export function TabList() {
7
- const [tabs] = useTabs()
8
- const markTabAsPermanent = useMarkTabAsPermanent()
9
- const closeTab = useCloseTab()
10
-
11
- return (
12
- <Tabs.List className="border-b h-8 bg-sidebar flex w-full">
13
- {tabs.length > 0 && (
14
- <div className="flex h-full items-center px-1.5 gap-0.5 border-r">
15
- <Button variant="ghost" size="icon-sm">
16
- <ArrowLeftIcon />
17
- </Button>
18
- <Button variant="ghost" size="icon-sm">
19
- <ArrowRightIcon />
20
- </Button>
21
- </div>
22
- )}
23
- {tabs.map((tab) => (
24
- <Tabs.Tab
25
- nativeButton={false}
26
- render={<div />}
27
- key={tab.id}
28
- value={tab.id}
29
- className="px-6 h-8 border-r text-xs flex items-center justify-center relative group data-[temporary=true]:italic select-none"
30
- data-temporary={tab.temporary}
31
- onClick={() => {
32
- if (tab.temporary) {
33
- markTabAsPermanent(tab.id)
34
- }
35
- }}
36
- >
37
- {tab.name}
38
- <Button
39
- size="icon-xs"
40
- variant="ghost"
41
- className="absolute right-1 invisible opacity-0 group-hover:visible group-hover:opacity-100 transition-opacity duration-200 p-0"
42
- onClick={(e) => {
43
- e.stopPropagation()
44
- closeTab(tab.id)
45
- }}
46
- >
47
- <XIcon />
48
- </Button>
49
- </Tabs.Tab>
50
- ))}
51
- </Tabs.List>
52
- )
53
- }
@@ -1,17 +0,0 @@
1
- import type * as React from 'react'
2
- import { cn } from '../cn'
3
-
4
- function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
5
- return (
6
- <textarea
7
- data-slot="textarea"
8
- className={cn(
9
- 'border-input bg-input/20 dark:bg-input/30 focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 resize-none rounded-md border px-2 py-2 text-sm transition-colors focus-visible:ring-2 aria-invalid:ring-2 md:text-xs/relaxed placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50',
10
- className
11
- )}
12
- {...props}
13
- />
14
- )
15
- }
16
-
17
- export { Textarea }
@@ -1,67 +0,0 @@
1
- import { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip'
2
- import { cn } from '../cn'
3
-
4
- function TooltipProvider({
5
- delay = 0,
6
- ...props
7
- }: TooltipPrimitive.Provider.Props) {
8
- return (
9
- <TooltipPrimitive.Provider
10
- data-slot="tooltip-provider"
11
- delay={delay}
12
- {...props}
13
- />
14
- )
15
- }
16
-
17
- function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
18
- return (
19
- <TooltipProvider>
20
- <TooltipPrimitive.Root data-slot="tooltip" {...props} />
21
- </TooltipProvider>
22
- )
23
- }
24
-
25
- function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
26
- return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
27
- }
28
-
29
- function TooltipContent({
30
- className,
31
- side = 'top',
32
- sideOffset = 4,
33
- align = 'center',
34
- alignOffset = 0,
35
- children,
36
- ...props
37
- }: TooltipPrimitive.Popup.Props &
38
- Pick<
39
- TooltipPrimitive.Positioner.Props,
40
- 'align' | 'alignOffset' | 'side' | 'sideOffset'
41
- >) {
42
- return (
43
- <TooltipPrimitive.Portal>
44
- <TooltipPrimitive.Positioner
45
- align={align}
46
- alignOffset={alignOffset}
47
- side={side}
48
- sideOffset={sideOffset}
49
- className="isolate z-50"
50
- >
51
- <TooltipPrimitive.Popup
52
- data-slot="tooltip-content"
53
- className={cn(
54
- 'data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 rounded-md px-3 py-1.5 text-xs **:data-[slot=kbd]:rounded-md bg-foreground text-background z-50 w-fit max-w-xs origin-(--transform-origin)',
55
- className
56
- )}
57
- {...props}
58
- >
59
- {children}
60
- <TooltipPrimitive.Arrow className="size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground z-50 data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
61
- </TooltipPrimitive.Popup>
62
- </TooltipPrimitive.Positioner>
63
- </TooltipPrimitive.Portal>
64
- )
65
- }
66
-
67
- export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
@@ -1,68 +0,0 @@
1
- import { createRoot, type Root } from 'react-dom/client'
2
- import './styles.css'
3
- import { App } from './app'
4
-
5
- const elem = document.getElementById('root')
6
-
7
- if (!elem) throw new Error('Root element not found')
8
-
9
- // HMR WebSocket client
10
- function setupHMR() {
11
- let reconnectAttempts = 0
12
- const maxReconnectAttempts = 10
13
-
14
- function refreshIframes() {
15
- // Find all iframes and refresh them by updating their src
16
- const iframes = document.querySelectorAll('iframe')
17
- iframes.forEach((iframe) => {
18
- const currentSrc = iframe.src
19
- // Add or update a cache-busting param
20
- const url = new URL(currentSrc)
21
- url.searchParams.set('_hmr', Date.now().toString())
22
- iframe.src = url.toString()
23
- })
24
- console.log(`[HMR] Refreshed ${iframes.length} iframe(s)`)
25
- }
26
-
27
- function connect() {
28
- const ws = new WebSocket(`ws://${location.host}/__hmr`)
29
-
30
- ws.onopen = () => {
31
- console.log('[HMR] Connected')
32
- reconnectAttempts = 0
33
- }
34
-
35
- ws.onmessage = (event) => {
36
- const data = JSON.parse(event.data)
37
- if (data.type === 'reload') {
38
- console.log('[HMR] Reloading iframes...')
39
- refreshIframes()
40
- }
41
- }
42
-
43
- ws.onclose = () => {
44
- console.log('[HMR] Disconnected')
45
- if (reconnectAttempts < maxReconnectAttempts) {
46
- reconnectAttempts++
47
- setTimeout(connect, 1000 * Math.min(reconnectAttempts, 5))
48
- }
49
- }
50
-
51
- ws.onerror = () => ws.close()
52
- }
53
-
54
- connect()
55
- }
56
-
57
- if (import.meta.hot) {
58
- let root: Root = import.meta.hot.data.root
59
-
60
- if (!root) root = import.meta.hot.data.root = createRoot(elem)
61
-
62
- root.render(<App />)
63
- } else {
64
- createRoot(elem).render(<App />)
65
- }
66
-
67
- // Always set up our custom WebSocket HMR
68
- setupHMR()
@@ -1,23 +0,0 @@
1
- import * as React from 'react'
2
-
3
- const MOBILE_BREAKPOINT = 768
4
-
5
- export function useIsMobile() {
6
- const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
-
8
- React.useEffect(() => {
9
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10
-
11
- const onChange = () => {
12
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
13
- }
14
-
15
- mql.addEventListener('change', onChange)
16
-
17
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
18
-
19
- return () => mql.removeEventListener('change', onChange)
20
- }, [])
21
-
22
- return !!isMobile
23
- }
package/src/ui/index.html DELETED
@@ -1,12 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Render</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="./frontend.tsx"></script>
11
- </body>
12
- </html>
@@ -1,35 +0,0 @@
1
- /* eslint-disable */
2
-
3
- // @ts-nocheck
4
-
5
- // noinspection JSUnusedGlobalSymbols
6
-
7
- // This file was automatically generated by TanStack Router.
8
- // You should NOT make any changes in this file as it will be overwritten.
9
- // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
-
11
- import { Route as rootRouteImport } from './routes/__root'
12
-
13
- export interface FileRoutesByFullPath {}
14
- export interface FileRoutesByTo {}
15
- export interface FileRoutesById {
16
- __root__: typeof rootRouteImport
17
- }
18
- export interface FileRouteTypes {
19
- fileRoutesByFullPath: FileRoutesByFullPath
20
- fullPaths: never
21
- fileRoutesByTo: FileRoutesByTo
22
- to: never
23
- id: '__root__'
24
- fileRoutesById: FileRoutesById
25
- }
26
- export interface RootRouteChildren {}
27
-
28
- declare module '@tanstack/react-router' {
29
- interface FileRoutesByPath {}
30
- }
31
-
32
- const rootRouteChildren: RootRouteChildren = {}
33
- export const routeTree = rootRouteImport
34
- ._addFileChildren(rootRouteChildren)
35
- ._addFileTypes<FileRouteTypes>()
@@ -1,9 +0,0 @@
1
- import { createRootRoute, Outlet } from '@tanstack/react-router'
2
-
3
- export const Route = createRootRoute({
4
- component: RootComponent
5
- })
6
-
7
- function RootComponent() {
8
- return <Outlet />
9
- }
package/src/ui/styles.css DELETED
@@ -1,123 +0,0 @@
1
- @import "tailwindcss";
2
- @import "tw-animate-css";
3
-
4
- @custom-variant dark (&:is(.dark *));
5
-
6
- :root {
7
- --background: oklch(1 0 0);
8
- --foreground: oklch(0.145 0 0);
9
- --card: oklch(1 0 0);
10
- --card-foreground: oklch(0.145 0 0);
11
- --popover: oklch(1 0 0);
12
- --popover-foreground: oklch(0.145 0 0);
13
- --primary: oklch(0.205 0 0);
14
- --primary-foreground: oklch(0.985 0 0);
15
- --secondary: oklch(0.97 0 0);
16
- --secondary-foreground: oklch(0.205 0 0);
17
- --muted: oklch(0.97 0 0);
18
- --muted-foreground: oklch(0.556 0 0);
19
- --accent: oklch(0.97 0 0);
20
- --accent-foreground: oklch(0.205 0 0);
21
- --destructive: oklch(0.577 0.245 27.325);
22
- --destructive-foreground: oklch(0.577 0.245 27.325);
23
- --border: oklch(0.922 0 0);
24
- --input: oklch(0.922 0 0);
25
- --ring: oklch(0.708 0 0);
26
- --chart-1: oklch(0.646 0.222 41.116);
27
- --chart-2: oklch(0.6 0.118 184.704);
28
- --chart-3: oklch(0.398 0.07 227.392);
29
- --chart-4: oklch(0.828 0.189 84.429);
30
- --chart-5: oklch(0.769 0.188 70.08);
31
- --radius: 0.625rem;
32
- --sidebar: oklch(0.985 0 0);
33
- --sidebar-foreground: oklch(0.145 0 0);
34
- --sidebar-primary: oklch(0.205 0 0);
35
- --sidebar-primary-foreground: oklch(0.985 0 0);
36
- --sidebar-accent: oklch(0.97 0 0);
37
- --sidebar-accent-foreground: oklch(0.205 0 0);
38
- --sidebar-border: oklch(0.922 0 0);
39
- --sidebar-ring: oklch(0.708 0 0);
40
- }
41
-
42
- .dark {
43
- --background: oklch(0.145 0 0);
44
- --foreground: oklch(0.985 0 0);
45
- --card: oklch(0.145 0 0);
46
- --card-foreground: oklch(0.985 0 0);
47
- --popover: oklch(0.145 0 0);
48
- --popover-foreground: oklch(0.985 0 0);
49
- --primary: oklch(0.985 0 0);
50
- --primary-foreground: oklch(0.205 0 0);
51
- --secondary: oklch(0.269 0 0);
52
- --secondary-foreground: oklch(0.985 0 0);
53
- --muted: oklch(0.269 0 0);
54
- --muted-foreground: oklch(0.708 0 0);
55
- --accent: oklch(0.269 0 0);
56
- --accent-foreground: oklch(0.985 0 0);
57
- --destructive: oklch(0.396 0.141 25.723);
58
- --destructive-foreground: oklch(0.637 0.237 25.331);
59
- --border: oklch(0.269 0 0);
60
- --input: oklch(0.269 0 0);
61
- --ring: oklch(0.439 0 0);
62
- --chart-1: oklch(0.488 0.243 264.376);
63
- --chart-2: oklch(0.696 0.17 162.48);
64
- --chart-3: oklch(0.769 0.188 70.08);
65
- --chart-4: oklch(0.627 0.265 303.9);
66
- --chart-5: oklch(0.645 0.246 16.439);
67
- --sidebar: oklch(0.205 0 0);
68
- --sidebar-foreground: oklch(0.985 0 0);
69
- --sidebar-primary: oklch(0.488 0.243 264.376);
70
- --sidebar-primary-foreground: oklch(0.985 0 0);
71
- --sidebar-accent: oklch(0.269 0 0);
72
- --sidebar-accent-foreground: oklch(0.985 0 0);
73
- --sidebar-border: oklch(0.269 0 0);
74
- --sidebar-ring: oklch(0.439 0 0);
75
- }
76
-
77
- @theme inline {
78
- --color-background: var(--background);
79
- --color-foreground: var(--foreground);
80
- --color-card: var(--card);
81
- --color-card-foreground: var(--card-foreground);
82
- --color-popover: var(--popover);
83
- --color-popover-foreground: var(--popover-foreground);
84
- --color-primary: var(--primary);
85
- --color-primary-foreground: var(--primary-foreground);
86
- --color-secondary: var(--secondary);
87
- --color-secondary-foreground: var(--secondary-foreground);
88
- --color-muted: var(--muted);
89
- --color-muted-foreground: var(--muted-foreground);
90
- --color-accent: var(--accent);
91
- --color-accent-foreground: var(--accent-foreground);
92
- --color-destructive: var(--destructive);
93
- --color-destructive-foreground: var(--destructive-foreground);
94
- --color-border: var(--border);
95
- --color-input: var(--input);
96
- --color-ring: var(--ring);
97
- --color-chart-1: var(--chart-1);
98
- --color-chart-2: var(--chart-2);
99
- --color-chart-3: var(--chart-3);
100
- --color-chart-4: var(--chart-4);
101
- --color-chart-5: var(--chart-5);
102
- --radius-sm: calc(var(--radius) - 4px);
103
- --radius-md: calc(var(--radius) - 2px);
104
- --radius-lg: var(--radius);
105
- --radius-xl: calc(var(--radius) + 4px);
106
- --color-sidebar: var(--sidebar);
107
- --color-sidebar-foreground: var(--sidebar-foreground);
108
- --color-sidebar-primary: var(--sidebar-primary);
109
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
110
- --color-sidebar-accent: var(--sidebar-accent);
111
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
112
- --color-sidebar-border: var(--sidebar-border);
113
- --color-sidebar-ring: var(--sidebar-ring);
114
- }
115
-
116
- @layer base {
117
- * {
118
- @apply border-border outline-ring/50;
119
- }
120
- body {
121
- @apply bg-background text-foreground;
122
- }
123
- }
package/src/ui/tabs.tsx DELETED
@@ -1,89 +0,0 @@
1
- import { createMemoryHistory, type RouterHistory } from '@tanstack/react-router'
2
- import { atom, useAtom } from 'jotai'
3
- import { atomWithStorage } from 'jotai/utils'
4
-
5
- export const activeTabIdAtom = atomWithStorage<string | null>(
6
- 'activeTabId',
7
- null
8
- )
9
- export const tabsAtom = atomWithStorage<Tab[]>('tabs', [])
10
- export const tabsHistoryAtom = atom<Record<string, RouterHistory>>((get) =>
11
- get(tabsAtom).reduce(
12
- (acc, tab) => {
13
- acc[tab.id] = createMemoryHistory({
14
- initialEntries: [tab.path]
15
- })
16
- return acc
17
- },
18
- {} as Record<string, RouterHistory>
19
- )
20
- )
21
-
22
- export function useTabs() {
23
- return useAtom(tabsAtom)
24
- }
25
-
26
- export function useActiveTab() {
27
- const [tabs] = useAtom(tabsAtom)
28
- const [activeTabId, setActiveTab] = useAtom(activeTabIdAtom)
29
- const [tabsHistory] = useAtom(tabsHistoryAtom)
30
-
31
- const activeTab = tabs.find((tab) => tab.id === activeTabId) ?? null
32
- const tabHistory = activeTabId ? tabsHistory[activeTabId] : null
33
-
34
- return { activeTab, setActiveTab, tabHistory }
35
- }
36
-
37
- export function useNewTab() {
38
- const [, setTabs] = useAtom(tabsAtom)
39
- const [, setActiveTab] = useAtom(activeTabIdAtom)
40
-
41
- return (tab: Omit<Tab, 'id'>) => {
42
- const id = crypto.randomUUID()
43
-
44
- setTabs((tabs) => [...tabs, { ...tab, id }])
45
- setActiveTab(id)
46
-
47
- return id
48
- }
49
- }
50
-
51
- export function useMarkTabAsPermanent() {
52
- const [tabs, setTabs] = useAtom(tabsAtom)
53
-
54
- return (id: string) => {
55
- setTabs(
56
- tabs.map((tab) => (tab.id === id ? { ...tab, temporary: false } : tab))
57
- )
58
- }
59
- }
60
-
61
- export function useCloseTab() {
62
- const [tabs, setTabs] = useAtom(tabsAtom)
63
- const [activeTabId, setActiveTab] = useAtom(activeTabIdAtom)
64
-
65
- return (id: string) => {
66
- setTabs(tabs.filter((tab) => tab.id !== id))
67
-
68
- if (activeTabId === id) {
69
- const tabIndex = tabs.findIndex((tab) => tab.id === id)
70
- const newActiveTab = tabs[tabIndex - 1] || tabs[tabIndex + 1] || null
71
- setActiveTab(newActiveTab ? newActiveTab.id : null)
72
- }
73
- }
74
- }
75
-
76
- export function useReplaceTab() {
77
- const [tabs, setTabs] = useAtom(tabsAtom)
78
-
79
- return (id: string, newTab: Omit<Tab, 'id'>) => {
80
- setTabs(tabs.map((tab) => (tab.id === id ? { ...newTab, id } : tab)))
81
- }
82
- }
83
-
84
- export type Tab = {
85
- id: string
86
- name: string
87
- path: string
88
- temporary: boolean
89
- }
package/tsconfig.json DELETED
@@ -1,25 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "module": "ESNext",
4
- "target": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "noUncheckedIndexedAccess": true,
8
- "baseUrl": ".",
9
- "skipLibCheck": true,
10
- "noFallthroughCasesInSwitch": true,
11
- "noImplicitOverride": true,
12
- "lib": ["ESNext", "DOM"],
13
- "moduleDetection": "force",
14
- "jsx": "react-jsx",
15
- "paths": {
16
- "#*": ["./src/*"]
17
- },
18
- "plugins": [
19
- {
20
- "name": "@effect/language-service"
21
- }
22
- ]
23
- },
24
- "exclude": ["dist", "node_modules"]
25
- }
package/tsr.config.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "routesDirectory": "./src/ui/routes",
3
- "generatedRouteTree": "./src/ui/routeTree.gen.ts",
4
- "routeFileIgnorePrefix": "-",
5
- "quoteStyle": "single"
6
- }