howone 0.0.3 → 0.0.5

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 (167) hide show
  1. package/package.json +1 -1
  2. package/templates/nextjs/.prettierignore +7 -0
  3. package/templates/nextjs/.prettierrc +11 -0
  4. package/templates/nextjs/README.md +12 -27
  5. package/templates/nextjs/app/globals.css +123 -40
  6. package/templates/nextjs/app/layout.tsx +19 -19
  7. package/templates/nextjs/app/page.tsx +13 -60
  8. package/templates/nextjs/bun.lock +925 -53
  9. package/templates/nextjs/components/.gitkeep +0 -0
  10. package/templates/nextjs/components/theme-provider.tsx +71 -0
  11. package/templates/nextjs/components/ui/accordion.tsx +81 -0
  12. package/templates/nextjs/components/ui/alert-dialog.tsx +199 -0
  13. package/templates/nextjs/components/ui/alert.tsx +76 -0
  14. package/templates/nextjs/components/ui/aspect-ratio.tsx +11 -0
  15. package/templates/nextjs/components/ui/avatar.tsx +112 -0
  16. package/templates/nextjs/components/ui/badge.tsx +49 -0
  17. package/templates/nextjs/components/ui/breadcrumb.tsx +122 -0
  18. package/templates/nextjs/components/ui/button-group.tsx +83 -0
  19. package/templates/nextjs/components/ui/button.tsx +67 -0
  20. package/templates/nextjs/components/ui/calendar.tsx +222 -0
  21. package/templates/nextjs/components/ui/card.tsx +103 -0
  22. package/templates/nextjs/components/ui/carousel.tsx +242 -0
  23. package/templates/nextjs/components/ui/chart.tsx +373 -0
  24. package/templates/nextjs/components/ui/checkbox.tsx +33 -0
  25. package/templates/nextjs/components/ui/collapsible.tsx +33 -0
  26. package/templates/nextjs/components/ui/combobox.tsx +299 -0
  27. package/templates/nextjs/components/ui/command.tsx +195 -0
  28. package/templates/nextjs/components/ui/context-menu.tsx +263 -0
  29. package/templates/nextjs/components/ui/dialog.tsx +168 -0
  30. package/templates/nextjs/components/ui/direction.tsx +22 -0
  31. package/templates/nextjs/components/ui/drawer.tsx +134 -0
  32. package/templates/nextjs/components/ui/dropdown-menu.tsx +269 -0
  33. package/templates/nextjs/components/ui/empty.tsx +104 -0
  34. package/templates/nextjs/components/ui/field.tsx +238 -0
  35. package/templates/nextjs/components/ui/hover-card.tsx +44 -0
  36. package/templates/nextjs/components/ui/input-group.tsx +156 -0
  37. package/templates/nextjs/components/ui/input-otp.tsx +87 -0
  38. package/templates/nextjs/components/ui/input.tsx +19 -0
  39. package/templates/nextjs/components/ui/item.tsx +196 -0
  40. package/templates/nextjs/components/ui/kbd.tsx +26 -0
  41. package/templates/nextjs/components/ui/label.tsx +24 -0
  42. package/templates/nextjs/components/ui/menubar.tsx +280 -0
  43. package/templates/nextjs/components/ui/native-select.tsx +61 -0
  44. package/templates/nextjs/components/ui/navigation-menu.tsx +164 -0
  45. package/templates/nextjs/components/ui/pagination.tsx +129 -0
  46. package/templates/nextjs/components/ui/popover.tsx +89 -0
  47. package/templates/nextjs/components/ui/progress.tsx +31 -0
  48. package/templates/nextjs/components/ui/radio-group.tsx +44 -0
  49. package/templates/nextjs/components/ui/resizable.tsx +50 -0
  50. package/templates/nextjs/components/ui/scroll-area.tsx +55 -0
  51. package/templates/nextjs/components/ui/select.tsx +192 -0
  52. package/templates/nextjs/components/ui/separator.tsx +28 -0
  53. package/templates/nextjs/components/ui/sheet.tsx +147 -0
  54. package/templates/nextjs/components/ui/sidebar.tsx +702 -0
  55. package/templates/nextjs/components/ui/skeleton.tsx +13 -0
  56. package/templates/nextjs/components/ui/slider.tsx +59 -0
  57. package/templates/nextjs/components/ui/sonner.tsx +49 -0
  58. package/templates/nextjs/components/ui/spinner.tsx +10 -0
  59. package/templates/nextjs/components/ui/switch.tsx +33 -0
  60. package/templates/nextjs/components/ui/table.tsx +116 -0
  61. package/templates/nextjs/components/ui/tabs.tsx +90 -0
  62. package/templates/nextjs/components/ui/textarea.tsx +18 -0
  63. package/templates/nextjs/components/ui/toggle-group.tsx +89 -0
  64. package/templates/nextjs/components/ui/toggle.tsx +47 -0
  65. package/templates/nextjs/components/ui/tooltip.tsx +57 -0
  66. package/templates/nextjs/components.json +25 -0
  67. package/templates/nextjs/hooks/.gitkeep +0 -0
  68. package/templates/nextjs/hooks/use-mobile.ts +19 -0
  69. package/templates/nextjs/lib/.gitkeep +0 -0
  70. package/templates/nextjs/lib/sdk.ts +7 -0
  71. package/templates/nextjs/lib/utils.ts +6 -0
  72. package/templates/nextjs/next.config.mjs +4 -0
  73. package/templates/vite/.prettierignore +7 -0
  74. package/templates/vite/.prettierrc +11 -0
  75. package/templates/vite/AGENTS.md +0 -0
  76. package/templates/vite/README.md +12 -64
  77. package/templates/vite/bun.lock +1478 -0
  78. package/templates/vite/components.json +25 -0
  79. package/templates/vite/eslint.config.js +1 -0
  80. package/templates/vite/index.html +2 -2
  81. package/templates/vite/package.json +39 -13
  82. package/templates/vite/public/vite.svg +1 -0
  83. package/templates/vite/src/App.tsx +6 -115
  84. package/templates/vite/src/components/theme-provider.tsx +230 -0
  85. package/templates/vite/src/components/ui/accordion.tsx +79 -0
  86. package/templates/vite/src/components/ui/alert-dialog.tsx +197 -0
  87. package/templates/vite/src/components/ui/alert.tsx +76 -0
  88. package/templates/vite/src/components/ui/aspect-ratio.tsx +11 -0
  89. package/templates/vite/src/components/ui/avatar.tsx +110 -0
  90. package/templates/vite/src/components/ui/badge.tsx +49 -0
  91. package/templates/vite/src/components/ui/breadcrumb.tsx +122 -0
  92. package/templates/vite/src/components/ui/button-group.tsx +83 -0
  93. package/templates/vite/src/components/ui/button.tsx +67 -0
  94. package/templates/vite/src/components/ui/calendar.tsx +222 -0
  95. package/templates/vite/src/components/ui/card.tsx +103 -0
  96. package/templates/vite/src/components/ui/carousel.tsx +240 -0
  97. package/templates/vite/src/components/ui/chart.tsx +373 -0
  98. package/templates/vite/src/components/ui/checkbox.tsx +31 -0
  99. package/templates/vite/src/components/ui/collapsible.tsx +33 -0
  100. package/templates/vite/src/components/ui/combobox.tsx +299 -0
  101. package/templates/vite/src/components/ui/command.tsx +193 -0
  102. package/templates/vite/src/components/ui/context-menu.tsx +261 -0
  103. package/templates/vite/src/components/ui/dialog.tsx +168 -0
  104. package/templates/vite/src/components/ui/direction.tsx +22 -0
  105. package/templates/vite/src/components/ui/drawer.tsx +132 -0
  106. package/templates/vite/src/components/ui/dropdown-menu.tsx +269 -0
  107. package/templates/vite/src/components/ui/empty.tsx +104 -0
  108. package/templates/vite/src/components/ui/field.tsx +238 -0
  109. package/templates/vite/src/components/ui/hover-card.tsx +42 -0
  110. package/templates/vite/src/components/ui/input-group.tsx +154 -0
  111. package/templates/vite/src/components/ui/input-otp.tsx +87 -0
  112. package/templates/vite/src/components/ui/input.tsx +19 -0
  113. package/templates/vite/src/components/ui/item.tsx +196 -0
  114. package/templates/vite/src/components/ui/kbd.tsx +26 -0
  115. package/templates/vite/src/components/ui/label.tsx +22 -0
  116. package/templates/vite/src/components/ui/menubar.tsx +280 -0
  117. package/templates/vite/src/components/ui/native-select.tsx +61 -0
  118. package/templates/vite/src/components/ui/navigation-menu.tsx +164 -0
  119. package/templates/vite/src/components/ui/pagination.tsx +129 -0
  120. package/templates/vite/src/components/ui/popover.tsx +87 -0
  121. package/templates/vite/src/components/ui/progress.tsx +31 -0
  122. package/templates/vite/src/components/ui/radio-group.tsx +42 -0
  123. package/templates/vite/src/components/ui/resizable.tsx +50 -0
  124. package/templates/vite/src/components/ui/scroll-area.tsx +53 -0
  125. package/templates/vite/src/components/ui/select.tsx +192 -0
  126. package/templates/vite/src/components/ui/separator.tsx +26 -0
  127. package/templates/vite/src/components/ui/sheet.tsx +145 -0
  128. package/templates/vite/src/components/ui/sidebar.tsx +700 -0
  129. package/templates/vite/src/components/ui/skeleton.tsx +13 -0
  130. package/templates/vite/src/components/ui/slider.tsx +59 -0
  131. package/templates/vite/src/components/ui/sonner.tsx +47 -0
  132. package/templates/vite/src/components/ui/spinner.tsx +10 -0
  133. package/templates/vite/src/components/ui/switch.tsx +33 -0
  134. package/templates/vite/src/components/ui/table.tsx +114 -0
  135. package/templates/vite/src/components/ui/tabs.tsx +90 -0
  136. package/templates/vite/src/components/ui/textarea.tsx +18 -0
  137. package/templates/vite/src/components/ui/toggle-group.tsx +89 -0
  138. package/templates/vite/src/components/ui/toggle.tsx +45 -0
  139. package/templates/vite/src/components/ui/tooltip.tsx +57 -0
  140. package/templates/vite/src/hooks/use-mobile.ts +19 -0
  141. package/templates/vite/src/index.css +125 -103
  142. package/templates/vite/src/lib/sdk.ts +7 -0
  143. package/templates/vite/src/lib/utils.ts +6 -0
  144. package/templates/vite/src/main.tsx +11 -7
  145. package/templates/vite/tsconfig.app.json +11 -4
  146. package/templates/vite/tsconfig.json +7 -1
  147. package/templates/vite/tsconfig.node.json +5 -3
  148. package/templates/vite/vite.config.ts +10 -3
  149. package/templates/nextjs/AGENTS.md +0 -5
  150. package/templates/nextjs/CLAUDE.md +0 -1
  151. package/templates/nextjs/app/page.module.css +0 -142
  152. package/templates/nextjs/gitignore +0 -41
  153. package/templates/nextjs/next-env.d.ts +0 -6
  154. package/templates/nextjs/next.config.ts +0 -7
  155. package/templates/nextjs/package.json +0 -32
  156. package/templates/nextjs/public/file.svg +0 -1
  157. package/templates/nextjs/public/globe.svg +0 -1
  158. package/templates/nextjs/public/next.svg +0 -1
  159. package/templates/nextjs/public/vercel.svg +0 -1
  160. package/templates/nextjs/public/window.svg +0 -1
  161. package/templates/nextjs/tsconfig.json +0 -34
  162. package/templates/vite/gitignore +0 -24
  163. package/templates/vite/public/favicon.svg +0 -1
  164. package/templates/vite/public/icons.svg +0 -24
  165. package/templates/vite/src/App.css +0 -184
  166. package/templates/vite/src/assets/hero.png +0 -0
  167. package/templates/vite/src/assets/vite.svg +0 -1
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "radix-nova",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/index.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "iconLibrary": "lucide",
14
+ "rtl": false,
15
+ "aliases": {
16
+ "components": "@/components",
17
+ "utils": "@/lib/utils",
18
+ "ui": "@/components/ui",
19
+ "lib": "@/lib",
20
+ "hooks": "@/hooks"
21
+ },
22
+ "menuColor": "default",
23
+ "menuAccent": "subtle",
24
+ "registries": {}
25
+ }
@@ -16,6 +16,7 @@ export default defineConfig([
16
16
  reactRefresh.configs.vite,
17
17
  ],
18
18
  languageOptions: {
19
+ ecmaVersion: 2020,
19
20
  globals: globals.browser,
20
21
  },
21
22
  },
@@ -2,9 +2,9 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>howone-vite-template-new</title>
7
+ <title>vite-app</title>
8
8
  </head>
9
9
  <body>
10
10
  <div id="root"></div>
@@ -1,30 +1,56 @@
1
1
  {
2
- "name": "howone-vite-app",
2
+ "name": "vite",
3
3
  "private": true,
4
- "version": "0.0.0",
4
+ "version": "0.0.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "tsc -b && vite build",
9
9
  "lint": "eslint .",
10
+ "format": "prettier --write \"**/*.{ts,tsx}\"",
11
+ "typecheck": "tsc --noEmit",
10
12
  "preview": "vite preview"
11
13
  },
12
14
  "dependencies": {
13
- "react": "^19.2.5",
14
- "react-dom": "^19.2.5"
15
+ "@base-ui/react": "^1.4.1",
16
+ "@fontsource-variable/inter": "^5.2.8",
17
+ "@howone/sdk": "2.0.0-beta.0",
18
+ "@tailwindcss/vite": "^4.2.1",
19
+ "class-variance-authority": "^0.7.1",
20
+ "clsx": "^2.1.1",
21
+ "cmdk": "^1.1.1",
22
+ "date-fns": "^4.1.0",
23
+ "embla-carousel-react": "^8.6.0",
24
+ "input-otp": "^1.4.2",
25
+ "lucide-react": "^1.14.0",
26
+ "next-themes": "^0.4.6",
27
+ "radix-ui": "^1.4.3",
28
+ "react": "^19.2.4",
29
+ "react-day-picker": "^9.14.0",
30
+ "react-dom": "^19.2.4",
31
+ "react-resizable-panels": "^4.11.0",
32
+ "recharts": "3.8.0",
33
+ "shadcn": "^4.7.0",
34
+ "sonner": "^2.0.7",
35
+ "tailwind-merge": "^3.5.0",
36
+ "tailwindcss": "^4.2.1",
37
+ "tw-animate-css": "^1.4.0",
38
+ "vaul": "^1.1.2"
15
39
  },
16
40
  "devDependencies": {
17
- "@eslint/js": "^10.0.1",
18
- "@types/node": "^24.12.2",
41
+ "@eslint/js": "^9.39.4",
42
+ "@types/node": "^24.12.0",
19
43
  "@types/react": "^19.2.14",
20
44
  "@types/react-dom": "^19.2.3",
21
- "@vitejs/plugin-react": "^6.0.1",
22
- "eslint": "^10.2.1",
23
- "eslint-plugin-react-hooks": "^7.1.1",
45
+ "@vitejs/plugin-react": "^5.2.0",
46
+ "eslint": "^9.39.4",
47
+ "eslint-plugin-react-hooks": "^7.0.1",
24
48
  "eslint-plugin-react-refresh": "^0.5.2",
25
- "globals": "^17.5.0",
26
- "typescript": "~6.0.2",
27
- "typescript-eslint": "^8.58.2",
28
- "vite": "^8.0.10"
49
+ "globals": "^16.5.0",
50
+ "prettier": "^3.8.1",
51
+ "prettier-plugin-tailwindcss": "^0.7.2",
52
+ "typescript": "~5.9.3",
53
+ "typescript-eslint": "^8.57.1",
54
+ "vite": "^7.3.1"
29
55
  }
30
56
  }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
@@ -1,121 +1,12 @@
1
- import { useState } from 'react'
2
- import reactLogo from './assets/react.svg'
3
- import viteLogo from './assets/vite.svg'
4
- import heroImg from './assets/hero.png'
5
- import './App.css'
1
+ import { HowOneProvider } from '@howone/sdk'
6
2
 
7
3
  function App() {
8
- const [count, setCount] = useState(0)
9
-
10
4
  return (
11
- <>
12
- <section id="center">
13
- <div className="hero">
14
- <img src={heroImg} className="base" width="170" height="179" alt="" />
15
- <img src={reactLogo} className="framework" alt="React logo" />
16
- <img src={viteLogo} className="vite" alt="Vite logo" />
17
- </div>
18
- <div>
19
- <h1>Get started</h1>
20
- <p>
21
- Edit <code>src/App.tsx</code> and save to test <code>HMR</code>
22
- </p>
23
- </div>
24
- <button
25
- type="button"
26
- className="counter"
27
- onClick={() => setCount((count) => count + 1)}
28
- >
29
- Count is {count}
30
- </button>
31
- </section>
32
-
33
- <div className="ticks"></div>
34
-
35
- <section id="next-steps">
36
- <div id="docs">
37
- <svg className="icon" role="presentation" aria-hidden="true">
38
- <use href="/icons.svg#documentation-icon"></use>
39
- </svg>
40
- <h2>Documentation</h2>
41
- <p>Your questions, answered</p>
42
- <ul>
43
- <li>
44
- <a href="https://vite.dev/" target="_blank">
45
- <img className="logo" src={viteLogo} alt="" />
46
- Explore Vite
47
- </a>
48
- </li>
49
- <li>
50
- <a href="https://react.dev/" target="_blank">
51
- <img className="button-icon" src={reactLogo} alt="" />
52
- Learn more
53
- </a>
54
- </li>
55
- </ul>
56
- </div>
57
- <div id="social">
58
- <svg className="icon" role="presentation" aria-hidden="true">
59
- <use href="/icons.svg#social-icon"></use>
60
- </svg>
61
- <h2>Connect with us</h2>
62
- <p>Join the Vite community</p>
63
- <ul>
64
- <li>
65
- <a href="https://github.com/vitejs/vite" target="_blank">
66
- <svg
67
- className="button-icon"
68
- role="presentation"
69
- aria-hidden="true"
70
- >
71
- <use href="/icons.svg#github-icon"></use>
72
- </svg>
73
- GitHub
74
- </a>
75
- </li>
76
- <li>
77
- <a href="https://chat.vite.dev/" target="_blank">
78
- <svg
79
- className="button-icon"
80
- role="presentation"
81
- aria-hidden="true"
82
- >
83
- <use href="/icons.svg#discord-icon"></use>
84
- </svg>
85
- Discord
86
- </a>
87
- </li>
88
- <li>
89
- <a href="https://x.com/vite_js" target="_blank">
90
- <svg
91
- className="button-icon"
92
- role="presentation"
93
- aria-hidden="true"
94
- >
95
- <use href="/icons.svg#x-icon"></use>
96
- </svg>
97
- X.com
98
- </a>
99
- </li>
100
- <li>
101
- <a href="https://bsky.app/profile/vite.dev" target="_blank">
102
- <svg
103
- className="button-icon"
104
- role="presentation"
105
- aria-hidden="true"
106
- >
107
- <use href="/icons.svg#bluesky-icon"></use>
108
- </svg>
109
- Bluesky
110
- </a>
111
- </li>
112
- </ul>
113
- </div>
114
- </section>
115
-
116
- <div className="ticks"></div>
117
- <section id="spacer"></section>
118
- </>
5
+ <HowOneProvider>
6
+ <div className="App">
7
+ <h1>Hello HowOne</h1>
8
+ </div>
9
+ </HowOneProvider>
119
10
  )
120
11
  }
121
12
 
@@ -0,0 +1,230 @@
1
+ /* eslint-disable react-refresh/only-export-components */
2
+ import * as React from "react"
3
+
4
+ type Theme = "dark" | "light" | "system"
5
+ type ResolvedTheme = "dark" | "light"
6
+
7
+ type ThemeProviderProps = {
8
+ children: React.ReactNode
9
+ defaultTheme?: Theme
10
+ storageKey?: string
11
+ disableTransitionOnChange?: boolean
12
+ }
13
+
14
+ type ThemeProviderState = {
15
+ theme: Theme
16
+ setTheme: (theme: Theme) => void
17
+ }
18
+
19
+ const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)"
20
+ const THEME_VALUES: Theme[] = ["dark", "light", "system"]
21
+
22
+ const ThemeProviderContext = React.createContext<
23
+ ThemeProviderState | undefined
24
+ >(undefined)
25
+
26
+ function isTheme(value: string | null): value is Theme {
27
+ if (value === null) {
28
+ return false
29
+ }
30
+
31
+ return THEME_VALUES.includes(value as Theme)
32
+ }
33
+
34
+ function getSystemTheme(): ResolvedTheme {
35
+ if (window.matchMedia(COLOR_SCHEME_QUERY).matches) {
36
+ return "dark"
37
+ }
38
+
39
+ return "light"
40
+ }
41
+
42
+ function disableTransitionsTemporarily() {
43
+ const style = document.createElement("style")
44
+ style.appendChild(
45
+ document.createTextNode(
46
+ "*,*::before,*::after{-webkit-transition:none!important;transition:none!important}"
47
+ )
48
+ )
49
+ document.head.appendChild(style)
50
+
51
+ return () => {
52
+ window.getComputedStyle(document.body)
53
+ requestAnimationFrame(() => {
54
+ requestAnimationFrame(() => {
55
+ style.remove()
56
+ })
57
+ })
58
+ }
59
+ }
60
+
61
+ function isEditableTarget(target: EventTarget | null) {
62
+ if (!(target instanceof HTMLElement)) {
63
+ return false
64
+ }
65
+
66
+ if (target.isContentEditable) {
67
+ return true
68
+ }
69
+
70
+ const editableParent = target.closest(
71
+ "input, textarea, select, [contenteditable='true']"
72
+ )
73
+ if (editableParent) {
74
+ return true
75
+ }
76
+
77
+ return false
78
+ }
79
+
80
+ export function ThemeProvider({
81
+ children,
82
+ defaultTheme = "system",
83
+ storageKey = "theme",
84
+ disableTransitionOnChange = true,
85
+ ...props
86
+ }: ThemeProviderProps) {
87
+ const [theme, setThemeState] = React.useState<Theme>(() => {
88
+ const storedTheme = localStorage.getItem(storageKey)
89
+ if (isTheme(storedTheme)) {
90
+ return storedTheme
91
+ }
92
+
93
+ return defaultTheme
94
+ })
95
+
96
+ const setTheme = React.useCallback(
97
+ (nextTheme: Theme) => {
98
+ localStorage.setItem(storageKey, nextTheme)
99
+ setThemeState(nextTheme)
100
+ },
101
+ [storageKey]
102
+ )
103
+
104
+ const applyTheme = React.useCallback(
105
+ (nextTheme: Theme) => {
106
+ const root = document.documentElement
107
+ const resolvedTheme =
108
+ nextTheme === "system" ? getSystemTheme() : nextTheme
109
+ const restoreTransitions = disableTransitionOnChange
110
+ ? disableTransitionsTemporarily()
111
+ : null
112
+
113
+ root.classList.remove("light", "dark")
114
+ root.classList.add(resolvedTheme)
115
+
116
+ if (restoreTransitions) {
117
+ restoreTransitions()
118
+ }
119
+ },
120
+ [disableTransitionOnChange]
121
+ )
122
+
123
+ React.useEffect(() => {
124
+ applyTheme(theme)
125
+
126
+ if (theme !== "system") {
127
+ return undefined
128
+ }
129
+
130
+ const mediaQuery = window.matchMedia(COLOR_SCHEME_QUERY)
131
+ const handleChange = () => {
132
+ applyTheme("system")
133
+ }
134
+
135
+ mediaQuery.addEventListener("change", handleChange)
136
+
137
+ return () => {
138
+ mediaQuery.removeEventListener("change", handleChange)
139
+ }
140
+ }, [theme, applyTheme])
141
+
142
+ React.useEffect(() => {
143
+ const handleKeyDown = (event: KeyboardEvent) => {
144
+ if (event.repeat) {
145
+ return
146
+ }
147
+
148
+ if (event.metaKey || event.ctrlKey || event.altKey) {
149
+ return
150
+ }
151
+
152
+ if (isEditableTarget(event.target)) {
153
+ return
154
+ }
155
+
156
+ if (event.key.toLowerCase() !== "d") {
157
+ return
158
+ }
159
+
160
+ setThemeState((currentTheme) => {
161
+ const nextTheme =
162
+ currentTheme === "dark"
163
+ ? "light"
164
+ : currentTheme === "light"
165
+ ? "dark"
166
+ : getSystemTheme() === "dark"
167
+ ? "light"
168
+ : "dark"
169
+
170
+ localStorage.setItem(storageKey, nextTheme)
171
+ return nextTheme
172
+ })
173
+ }
174
+
175
+ window.addEventListener("keydown", handleKeyDown)
176
+
177
+ return () => {
178
+ window.removeEventListener("keydown", handleKeyDown)
179
+ }
180
+ }, [storageKey])
181
+
182
+ React.useEffect(() => {
183
+ const handleStorageChange = (event: StorageEvent) => {
184
+ if (event.storageArea !== localStorage) {
185
+ return
186
+ }
187
+
188
+ if (event.key !== storageKey) {
189
+ return
190
+ }
191
+
192
+ if (isTheme(event.newValue)) {
193
+ setThemeState(event.newValue)
194
+ return
195
+ }
196
+
197
+ setThemeState(defaultTheme)
198
+ }
199
+
200
+ window.addEventListener("storage", handleStorageChange)
201
+
202
+ return () => {
203
+ window.removeEventListener("storage", handleStorageChange)
204
+ }
205
+ }, [defaultTheme, storageKey])
206
+
207
+ const value = React.useMemo(
208
+ () => ({
209
+ theme,
210
+ setTheme,
211
+ }),
212
+ [theme, setTheme]
213
+ )
214
+
215
+ return (
216
+ <ThemeProviderContext.Provider {...props} value={value}>
217
+ {children}
218
+ </ThemeProviderContext.Provider>
219
+ )
220
+ }
221
+
222
+ export const useTheme = () => {
223
+ const context = React.useContext(ThemeProviderContext)
224
+
225
+ if (context === undefined) {
226
+ throw new Error("useTheme must be used within a ThemeProvider")
227
+ }
228
+
229
+ return context
230
+ }
@@ -0,0 +1,79 @@
1
+ import * as React from "react"
2
+ import { Accordion as AccordionPrimitive } from "radix-ui"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
6
+
7
+ function Accordion({
8
+ className,
9
+ ...props
10
+ }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
11
+ return (
12
+ <AccordionPrimitive.Root
13
+ data-slot="accordion"
14
+ className={cn("flex w-full flex-col", className)}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ function AccordionItem({
21
+ className,
22
+ ...props
23
+ }: React.ComponentProps<typeof AccordionPrimitive.Item>) {
24
+ return (
25
+ <AccordionPrimitive.Item
26
+ data-slot="accordion-item"
27
+ className={cn("not-last:border-b", className)}
28
+ {...props}
29
+ />
30
+ )
31
+ }
32
+
33
+ function AccordionTrigger({
34
+ className,
35
+ children,
36
+ ...props
37
+ }: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
38
+ return (
39
+ <AccordionPrimitive.Header className="flex">
40
+ <AccordionPrimitive.Trigger
41
+ data-slot="accordion-trigger"
42
+ className={cn(
43
+ "group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring disabled:pointer-events-none disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
44
+ className
45
+ )}
46
+ {...props}
47
+ >
48
+ {children}
49
+ <ChevronDownIcon data-slot="accordion-trigger-icon" className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden" />
50
+ <ChevronUpIcon data-slot="accordion-trigger-icon" className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline" />
51
+ </AccordionPrimitive.Trigger>
52
+ </AccordionPrimitive.Header>
53
+ )
54
+ }
55
+
56
+ function AccordionContent({
57
+ className,
58
+ children,
59
+ ...props
60
+ }: React.ComponentProps<typeof AccordionPrimitive.Content>) {
61
+ return (
62
+ <AccordionPrimitive.Content
63
+ data-slot="accordion-content"
64
+ className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
65
+ {...props}
66
+ >
67
+ <div
68
+ className={cn(
69
+ "h-(--radix-accordion-content-height) pt-0 pb-2.5 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4",
70
+ className
71
+ )}
72
+ >
73
+ {children}
74
+ </div>
75
+ </AccordionPrimitive.Content>
76
+ )
77
+ }
78
+
79
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }