create-bubbles 0.1.25 → 0.1.26

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 (203) hide show
  1. package/dist/index.js +3 -9
  2. package/package.json +1 -1
  3. package/template-nextjs-vinext-eslint/Dockerfile +4 -4
  4. package/template-nextjs-vinext-eslint/README.md +6 -2
  5. package/template-nextjs-vinext-eslint/docker-compose.yaml +4 -4
  6. package/template-nextjs-vinext-eslint/eslint.config.js +2 -0
  7. package/template-nextjs-vinext-eslint/package.json +28 -26
  8. package/template-nextjs-vinext-eslint/pnpm-workspace.yaml +13 -1
  9. package/template-nextjs-vinext-eslint/src/utils/request/core/index.ts +63 -45
  10. package/template-nextjs-vinext-eslint/src/utils/request/core/utils.ts +12 -6
  11. package/template-nextjs-vinext-eslint/vite.config.ts +1 -1
  12. package/template-react-rsbuild-biome/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  13. package/template-react-rsbuild-biome/AGENTS.md +11 -0
  14. package/template-react-rsbuild-biome/index.html +2 -2
  15. package/template-react-rsbuild-biome/package.json +25 -24
  16. package/template-react-rsbuild-biome/pnpm-workspace.yaml +5 -0
  17. package/template-react-rsbuild-biome/rsbuild.config.ts +1 -1
  18. package/template-react-rsbuild-biome/src/assets/icon/logo.svg +1 -1
  19. package/template-react-rsbuild-biome/src/assets/svg/draft.svg +4 -0
  20. package/template-react-rsbuild-biome/src/components/Icon/svg-icon/README.md +37 -0
  21. package/template-react-rsbuild-biome/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  22. package/template-react-rsbuild-biome/src/env.d.ts +7 -0
  23. package/template-react-rsbuild-biome/src/utils/request/index.ts +3 -4
  24. package/template-react-rsbuild-biome/tsconfig.json +1 -2
  25. package/template-taro-react-oxc/.oxlintrc.json +0 -1
  26. package/template-taro-react-oxc/package.json +53 -52
  27. package/template-taro-react-oxc/pnpm-workspace.yaml +46 -0
  28. package/template-taro-vue-eslint/package.json +56 -56
  29. package/template-vp-monorepo-react-hono/apps/web/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  30. package/template-vp-monorepo-react-hono/apps/web/AGENTS.md +11 -0
  31. package/template-vp-monorepo-react-hono/apps/web/package.json +1 -0
  32. package/template-vp-monorepo-react-hono/apps/web/src/assets/svg/draft.svg +4 -0
  33. package/template-vp-monorepo-react-hono/apps/web/src/components/Icon/svg-icon/README.md +37 -0
  34. package/template-vp-monorepo-react-hono/apps/web/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  35. package/template-vp-monorepo-react-hono/apps/web/tsconfig.json +1 -1
  36. package/template-vp-monorepo-react-hono/apps/web/vite.config.ts +2 -0
  37. package/template-vp-monorepo-react-hono/pnpm-workspace.yaml +1 -0
  38. package/template-vp-monorepo-react-nestjs/.agents/rules//344/273/243/347/240/201/350/256/276/350/256/241.md +4 -0
  39. package/template-vp-monorepo-react-nestjs/.agents/rules//345/205/261/344/272/253/344/273/243/347/240/201.md +4 -0
  40. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//351/234/200/346/261/202/346/226/207/346/241/243.md +177 -0
  41. package/template-vp-monorepo-react-nestjs/.spaces/server/04.upload.md +4504 -0
  42. package/template-vp-monorepo-react-nestjs/.spaces/server/05./344/270/212/344/274/240/346/224/271/351/200/240/346/226/271/346/241/210/README.md +858 -0
  43. package/template-vp-monorepo-react-nestjs/.spaces/server/06./345/205/254/345/205/261/351/230/237/345/210/227/346/216/245/345/205/245/346/226/271/346/241/210/README.md +1890 -0
  44. package/template-vp-monorepo-react-nestjs/.spaces/server/06./345/205/254/345/205/261/351/230/237/345/210/227/346/216/245/345/205/245/346/226/271/346/241/210//344/270/212/344/274/240/346/270/205/347/220/206.md +1465 -0
  45. package/template-vp-monorepo-react-nestjs/AGENTS.md +8 -12
  46. package/template-vp-monorepo-react-nestjs/apps/server/.agents/rules/error-handling.md +84 -0
  47. package/template-vp-monorepo-react-nestjs/apps/server/.env.development +60 -0
  48. package/template-vp-monorepo-react-nestjs/apps/server/.env.production +16 -0
  49. package/template-vp-monorepo-react-nestjs/apps/server/AGENTS.md +9 -0
  50. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0000_military_colonel_america.sql +11 -0
  51. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0001_loud_siren.sql +27 -0
  52. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0000_snapshot.json +97 -0
  53. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0001_snapshot.json +354 -0
  54. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/_journal.json +20 -0
  55. package/template-vp-monorepo-react-nestjs/apps/server/package.json +4 -0
  56. package/template-vp-monorepo-react-nestjs/apps/server/src/app.module.ts +14 -2
  57. package/template-vp-monorepo-react-nestjs/apps/server/src/common/adapters/fastify.adapter.ts +6 -0
  58. package/template-vp-monorepo-react-nestjs/apps/server/src/config/index.ts +2 -0
  59. package/template-vp-monorepo-react-nestjs/apps/server/src/config/queue.config.ts +105 -0
  60. package/template-vp-monorepo-react-nestjs/apps/server/src/config/storage.config.ts +33 -0
  61. package/template-vp-monorepo-react-nestjs/apps/server/src/database/schema.ts +57 -1
  62. package/template-vp-monorepo-react-nestjs/apps/server/src/main.ts +1 -0
  63. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.service.ts +1 -3
  64. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/dto/auth-repsponse.dto.ts +2 -2
  65. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/queue-worker.bootstrap.ts +24 -0
  66. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.constants.ts +24 -0
  67. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.contracts.ts +35 -0
  68. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.module.ts +56 -0
  69. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.processor.ts +62 -0
  70. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.service.ts +58 -0
  71. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/error-catelog.spec.ts +34 -0
  72. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/dto/initiate-mutipart-upload.dto.ts +26 -0
  73. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/dto/upload-params.dto.ts +15 -0
  74. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/exact-size.transform.ts +66 -0
  75. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/minio-storage.adapter.ts +239 -0
  76. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/storage.port.ts +61 -0
  77. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.constants.ts +23 -0
  78. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.controller.ts +109 -0
  79. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.errors.ts +80 -0
  80. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.module.ts +20 -0
  81. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.reponsitory.ts +166 -0
  82. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.service.ts +696 -0
  83. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/utils/object-key.ts +10 -0
  84. package/template-vp-monorepo-react-nestjs/apps/server/test/task-queue.integration.spec.ts +120 -0
  85. package/template-vp-monorepo-react-nestjs/apps/server/test/task-queue.processor.spec.ts +63 -0
  86. package/template-vp-monorepo-react-nestjs/apps/server/test/task-queue.service.spec.ts +106 -0
  87. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  88. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//345/274/271/347/252/227/347/273/204/344/273/266.md +4 -0
  89. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//346/226/207/344/273/266/346/213/206/345/210/206.md +4 -0
  90. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//347/273/204/344/273/266/345/221/275/345/220/215.md +3 -0
  91. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//350/241/250/346/240/274/351/241/265/351/235/242.md +11 -0
  92. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//351/241/265/351/235/242/346/216/245/345/217/243.md +3 -0
  93. package/template-vp-monorepo-react-nestjs/apps/web/.env.dev +1 -1
  94. package/template-vp-monorepo-react-nestjs/apps/web/AGENTS.md +16 -0
  95. package/template-vp-monorepo-react-nestjs/apps/web/README.MD +153 -0
  96. package/template-vp-monorepo-react-nestjs/apps/web/index.html +3 -2
  97. package/template-vp-monorepo-react-nestjs/apps/web/package.json +6 -1
  98. package/template-vp-monorepo-react-nestjs/apps/web/public/favicon.svg +9 -1
  99. package/template-vp-monorepo-react-nestjs/apps/web/src/App.module.css +5 -0
  100. package/template-vp-monorepo-react-nestjs/apps/web/src/App.tsx +16 -9
  101. package/template-vp-monorepo-react-nestjs/apps/web/src/api/auth.ts +9 -0
  102. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/draft.svg +4 -0
  103. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/DraftProTable.module.css +78 -0
  104. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/DraftProTable.tsx +99 -0
  105. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/README.md +34 -0
  106. package/template-vp-monorepo-react-nestjs/apps/web/src/components/FullHeightProTable/FullHeightProTable.module.css +54 -0
  107. package/template-vp-monorepo-react-nestjs/apps/web/src/components/FullHeightProTable/FullHeightProTable.tsx +41 -0
  108. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/svg-icon/README.md +37 -0
  109. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  110. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Loading/PageLoading.module.css +7 -0
  111. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Loading/PageLoading.tsx +2 -1
  112. package/template-vp-monorepo-react-nestjs/apps/web/src/config/theme.ts +20 -0
  113. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/BasicLayout.module.css +17 -0
  114. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/BasicLayout.tsx +106 -0
  115. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/i18n/index.module.css +23 -0
  116. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/i18n/index.tsx +53 -0
  117. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/components/ProjectFormDialog.tsx +132 -0
  118. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/columns.tsx +121 -0
  119. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/index.ts +77 -0
  120. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/components/DraftProjectFormDialog.tsx +140 -0
  121. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/columns.tsx +127 -0
  122. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/index.ts +39 -0
  123. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/projects.ts +48 -0
  124. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/index.module.css +49 -0
  125. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/index.tsx +163 -0
  126. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/index.module.css +53 -0
  127. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/index.tsx +135 -0
  128. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/home/index.module.css +23 -0
  129. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/home/index.tsx +26 -43
  130. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/api.ts +11 -0
  131. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/index.tsx +183 -0
  132. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/login.css +164 -0
  133. package/template-vp-monorepo-react-nestjs/apps/web/src/router/index.tsx +36 -12
  134. package/template-vp-monorepo-react-nestjs/apps/web/src/styles/index.css +11 -4
  135. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/index.ts +55 -47
  136. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/index.ts +10 -5
  137. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/cookie.ts +50 -0
  138. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/session.ts +33 -0
  139. package/template-vp-monorepo-react-nestjs/apps/web/test/draft-projects.spec.ts +89 -0
  140. package/template-vp-monorepo-react-nestjs/apps/web/test/request.spec.ts +145 -0
  141. package/template-vp-monorepo-react-nestjs/apps/web/test/storage.spec.ts +108 -0
  142. package/template-vp-monorepo-react-nestjs/apps/web/test/tsconfig.json +7 -0
  143. package/template-vp-monorepo-react-nestjs/apps/web/tsconfig.json +1 -1
  144. package/template-vp-monorepo-react-nestjs/apps/web/vite.config.ts +7 -0
  145. package/template-vp-monorepo-react-nestjs/apps/web-vue/tsconfig.tsbuildinfo +1 -0
  146. package/template-vp-monorepo-react-nestjs/docker-compose.yml +19 -0
  147. package/template-vp-monorepo-react-nestjs/mise.toml +1 -1
  148. package/template-vp-monorepo-react-nestjs/package.json +1 -6
  149. package/template-vp-monorepo-react-nestjs/pnpm-workspace.yaml +9 -1
  150. package/template-vp-react/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  151. package/template-vp-react/AGENTS.md +11 -0
  152. package/template-vp-react/commitlint.config.js +0 -0
  153. package/template-vp-react/package.json +21 -26
  154. package/template-vp-react/pnpm-workspace.yaml +6 -0
  155. package/template-vp-react/src/assets/svg/draft.svg +4 -0
  156. package/template-vp-react/src/components/Icon/svg-icon/README.md +37 -0
  157. package/template-vp-react/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  158. package/template-vp-react/src/utils/request/index.ts +18 -5
  159. package/template-vp-react/tsconfig.json +2 -3
  160. package/template-vp-react/vite.config.ts +2 -0
  161. package/template-vp-react-shadcn/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  162. package/template-vp-react-shadcn/.vscode/settings.json +2 -2
  163. package/template-vp-react-shadcn/{agents.md → AGENTS.md} +12 -2
  164. package/template-vp-react-shadcn/README.md +41 -0
  165. package/template-vp-react-shadcn/commitlint.config.js +1 -1
  166. package/template-vp-react-shadcn/components.json +1 -1
  167. package/template-vp-react-shadcn/package.json +25 -32
  168. package/template-vp-react-shadcn/pnpm-workspace.yaml +10 -0
  169. package/template-vp-react-shadcn/src/App.tsx +10 -10
  170. package/template-vp-react-shadcn/src/assets/svg/draft.svg +4 -0
  171. package/template-vp-react-shadcn/src/components/Icon/svg-icon/README.md +37 -0
  172. package/template-vp-react-shadcn/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  173. package/template-vp-react-shadcn/src/components/Loading/PageLoading.tsx +4 -4
  174. package/template-vp-react-shadcn/src/components/Player/VideoJS/index.tsx +94 -78
  175. package/template-vp-react-shadcn/src/components/Player/index.ts +1 -1
  176. package/template-vp-react-shadcn/src/components/ui/button.tsx +25 -32
  177. package/template-vp-react-shadcn/src/components/ui/spinner.tsx +8 -7
  178. package/template-vp-react-shadcn/src/components/ui/toast.tsx +229 -0
  179. package/template-vp-react-shadcn/src/lib/utils.ts +3 -3
  180. package/template-vp-react-shadcn/src/main.tsx +5 -4
  181. package/template-vp-react-shadcn/src/pages/home/index.tsx +43 -35
  182. package/template-vp-react-shadcn/src/router/index.tsx +15 -15
  183. package/template-vp-react-shadcn/src/styles/index.css +4 -4
  184. package/template-vp-react-shadcn/src/styles/shadcn.css +2 -2
  185. package/template-vp-react-shadcn/src/utils/env/index.tsx +2 -2
  186. package/template-vp-react-shadcn/src/utils/request/alova-core/index.ts +102 -30
  187. package/template-vp-react-shadcn/src/utils/request/alova-core/utils.ts +5 -2
  188. package/template-vp-react-shadcn/src/utils/request/index.ts +32 -19
  189. package/template-vp-react-shadcn/src/utils/request/readme.md +41 -38
  190. package/template-vp-react-shadcn/tsconfig.json +2 -3
  191. package/template-vp-react-shadcn/vite.config.ts +29 -15
  192. package/template-vp-vue-eslint-vapor/package.json +26 -33
  193. package/template-vp-vue-eslint-vapor/pnpm-workspace.yaml +29 -1
  194. package/template-vue-vp-eslint/README.md +3 -10
  195. package/template-vue-vp-eslint/package.json +27 -34
  196. package/template-vue-vp-eslint/pnpm-workspace.yaml +27 -2
  197. package/template-vue-vp-eslint/src/layout/default/index.vue +4 -3
  198. package/template-vp-monorepo-react-nestjs/.agents/auth.config.ts +0 -0
  199. package/template-vp-monorepo-react-nestjs/.spaces/server/todo.md +0 -991
  200. package/template-vp-monorepo-react-nestjs/apps/server/README.md +0 -3
  201. package/template-vp-react-shadcn/.oxfmtrc.jsonc +0 -8
  202. package/template-vp-react-shadcn/.oxlintrc.jsonc +0 -3
  203. package/template-vp-react-shadcn/src/components/ui/sonner.tsx +0 -43
@@ -1,97 +1,109 @@
1
- import { createPlayer } from "@videojs/react";
2
- import { HlsVideo } from "@videojs/react/media/hls-video";
3
- import { Video, VideoSkin, videoFeatures } from "@videojs/react/video";
4
- import "@videojs/react/video/skin.css";
5
- import type { ReactNode, VideoHTMLAttributes } from "react";
1
+ import { createPlayer } from '@videojs/react'
2
+ import { HlsJsVideo } from '@videojs/react/media/hlsjs-video'
3
+ import { Video, VideoSkin, videoFeatures } from '@videojs/react/video'
6
4
 
7
- import { cn } from "@/lib/utils";
5
+ import '@videojs/react/video/skin.css'
6
+ import type { ReactNode, VideoHTMLAttributes } from 'react'
7
+
8
+ import { cn } from '@/lib/utils'
8
9
 
9
10
  export const VIDEO_JS_SOURCE_TYPES = {
10
- AUTO: "auto",
11
- HLS: "hls",
12
- MP4: "mp4",
13
- NATIVE: "native",
14
- } as const;
11
+ AUTO: 'auto',
12
+ HLS: 'hls',
13
+ MP4: 'mp4',
14
+ NATIVE: 'native',
15
+ } as const
15
16
 
16
- export type VideoJSSourceType = (typeof VIDEO_JS_SOURCE_TYPES)[keyof typeof VIDEO_JS_SOURCE_TYPES];
17
+ export type VideoJSSourceType =
18
+ (typeof VIDEO_JS_SOURCE_TYPES)[keyof typeof VIDEO_JS_SOURCE_TYPES]
17
19
 
18
20
  export type VideoJSSource = {
19
- src: string;
20
- type?: string;
21
- sourceType?: Exclude<VideoJSSourceType, "auto">;
22
- };
21
+ src: string
22
+ type?: string
23
+ sourceType?: Exclude<VideoJSSourceType, 'auto'>
24
+ }
23
25
 
24
- type VideoJSPreload = "" | "none" | "metadata" | "auto";
26
+ type VideoJSPreload = '' | 'none' | 'metadata' | 'auto'
25
27
 
26
28
  type NativeVideoProps = Omit<
27
29
  VideoHTMLAttributes<HTMLVideoElement>,
28
- "children" | "className" | "controls" | "poster" | "preload" | "src"
29
- >;
30
+ 'children' | 'className' | 'controls' | 'poster' | 'preload' | 'src'
31
+ >
30
32
 
31
33
  export type VideoJSProps = NativeVideoProps & {
32
- src?: string;
33
- type?: string;
34
- sources?: VideoJSSource[];
35
- sourceType?: VideoJSSourceType;
36
- poster?: string;
37
- className?: string;
38
- videoClassName?: string;
39
- preload?: VideoJSPreload;
40
- hlsConfig?: Record<string, unknown>;
41
- hlsDebug?: boolean;
42
- preferPlayback?: "mse" | "native";
43
- children?: ReactNode;
44
- };
34
+ src?: string
35
+ type?: string
36
+ sources?: VideoJSSource[]
37
+ sourceType?: VideoJSSourceType
38
+ poster?: string
39
+ className?: string
40
+ videoClassName?: string
41
+ preload?: VideoJSPreload
42
+ hlsConfig?: Record<string, unknown>
43
+ hlsDebug?: boolean
44
+ preferPlayback?: 'mse' | 'native'
45
+ children?: ReactNode
46
+ }
45
47
 
46
48
  const VideoJSPlayer = createPlayer({
47
49
  features: videoFeatures,
48
- displayName: "VideoJS",
49
- });
50
+ displayName: 'VideoJS',
51
+ })
50
52
 
51
- const HLS_MIME_TYPES = new Set(["application/vnd.apple.mpegurl", "application/x-mpegurl"]);
53
+ const HLS_MIME_TYPES = new Set([
54
+ 'application/vnd.apple.mpegurl',
55
+ 'application/x-mpegurl',
56
+ ])
52
57
 
53
- const MP4_MIME_TYPES = new Set(["video/mp4", "application/mp4"]);
58
+ const MP4_MIME_TYPES = new Set(['video/mp4', 'application/mp4'])
54
59
 
55
- const getSourceList = ({ src, type, sources }: Pick<VideoJSProps, "src" | "type" | "sources">) => {
60
+ const getSourceList = ({
61
+ src,
62
+ type,
63
+ sources,
64
+ }: Pick<VideoJSProps, 'src' | 'type' | 'sources'>) => {
56
65
  if (sources?.length) {
57
- return sources;
66
+ return sources
58
67
  }
59
68
 
60
- return src ? [{ src, type }] : [];
61
- };
69
+ return src ? [{ src, type }] : []
70
+ }
62
71
 
63
- const getUrlPath = (src: string) => src.split(/[?#]/)[0]?.toLowerCase() ?? "";
72
+ const getUrlPath = (src: string) => src.split(/[?#]/)[0]?.toLowerCase() ?? ''
64
73
 
65
- const inferSourceType = (source: VideoJSSource, fallback: VideoJSSourceType) => {
74
+ const inferSourceType = (
75
+ source: VideoJSSource,
76
+ fallback: VideoJSSourceType,
77
+ ) => {
66
78
  if (source.sourceType) {
67
- return source.sourceType;
79
+ return source.sourceType
68
80
  }
69
81
 
70
82
  if (fallback !== VIDEO_JS_SOURCE_TYPES.AUTO) {
71
- return fallback;
83
+ return fallback
72
84
  }
73
85
 
74
- const mimeType = source.type?.toLowerCase();
75
- const path = getUrlPath(source.src);
86
+ const mimeType = source.type?.toLowerCase()
87
+ const path = getUrlPath(source.src)
76
88
 
77
89
  if (mimeType && HLS_MIME_TYPES.has(mimeType)) {
78
- return VIDEO_JS_SOURCE_TYPES.HLS;
90
+ return VIDEO_JS_SOURCE_TYPES.HLS
79
91
  }
80
92
 
81
- if (path.endsWith(".m3u8")) {
82
- return VIDEO_JS_SOURCE_TYPES.HLS;
93
+ if (path.endsWith('.m3u8')) {
94
+ return VIDEO_JS_SOURCE_TYPES.HLS
83
95
  }
84
96
 
85
97
  if (mimeType && MP4_MIME_TYPES.has(mimeType)) {
86
- return VIDEO_JS_SOURCE_TYPES.MP4;
98
+ return VIDEO_JS_SOURCE_TYPES.MP4
87
99
  }
88
100
 
89
- if (path.endsWith(".mp4")) {
90
- return VIDEO_JS_SOURCE_TYPES.MP4;
101
+ if (path.endsWith('.mp4')) {
102
+ return VIDEO_JS_SOURCE_TYPES.MP4
91
103
  }
92
104
 
93
- return VIDEO_JS_SOURCE_TYPES.NATIVE;
94
- };
105
+ return VIDEO_JS_SOURCE_TYPES.NATIVE
106
+ }
95
107
 
96
108
  const VideoJS = ({
97
109
  src,
@@ -101,63 +113,67 @@ const VideoJS = ({
101
113
  poster,
102
114
  className,
103
115
  videoClassName,
104
- preload = "metadata",
116
+ preload = 'metadata',
105
117
  playsInline = true,
106
118
  hlsConfig,
107
119
  hlsDebug = false,
108
- preferPlayback = "mse",
120
+ preferPlayback = 'mse',
109
121
  children,
110
122
  ...videoProps
111
123
  }: VideoJSProps) => {
112
- const sourceList = getSourceList({ src, type, sources });
113
- const primarySource = sourceList[0];
124
+ const sourceList = getSourceList({ src, type, sources })
125
+ const primarySource = sourceList[0]
114
126
 
115
127
  if (!primarySource) {
116
- return null;
128
+ return null
117
129
  }
118
130
 
119
- const resolvedSourceType = inferSourceType(primarySource, sourceType);
120
- const isHls = resolvedSourceType === VIDEO_JS_SOURCE_TYPES.HLS;
131
+ const resolvedSourceType = inferSourceType(primarySource, sourceType)
132
+ const isHls = resolvedSourceType === VIDEO_JS_SOURCE_TYPES.HLS
121
133
 
122
134
  return (
123
- <VideoJSPlayer.Provider>
135
+ <VideoJSPlayer.Player poster={poster}>
124
136
  <VideoSkin
125
- poster={poster}
126
137
  className={cn(
127
- "aspect-video w-full overflow-hidden rounded-lg bg-black shadow-sm",
138
+ 'aspect-video w-full overflow-hidden rounded-lg bg-black shadow-sm',
128
139
  className,
129
140
  )}
130
141
  >
131
142
  {isHls ? (
132
- <HlsVideo
143
+ <HlsJsVideo
133
144
  {...videoProps}
134
- src={primarySource.src}
135
- type={primarySource.type ?? "application/vnd.apple.mpegurl"}
145
+ source={{
146
+ src: primarySource.src,
147
+ type: 'hls',
148
+ preferPlayback,
149
+ engine: { hlsJs: { ...hlsConfig, debug: hlsDebug } },
150
+ }}
136
151
  preload={preload}
137
152
  playsInline={playsInline}
138
- config={hlsConfig}
139
- debug={hlsDebug}
140
- preferPlayback={preferPlayback}
141
- className={cn("h-full w-full", videoClassName)}
153
+ className={cn('h-full w-full', videoClassName)}
142
154
  >
143
155
  {children}
144
- </HlsVideo>
156
+ </HlsJsVideo>
145
157
  ) : (
146
158
  <Video
147
159
  {...videoProps}
148
160
  preload={preload}
149
161
  playsInline={playsInline}
150
- className={cn("h-full w-full", videoClassName)}
162
+ className={cn('h-full w-full', videoClassName)}
151
163
  >
152
164
  {sourceList.map((source) => (
153
- <source key={`${source.src}-${source.type}`} src={source.src} type={source.type} />
165
+ <source
166
+ key={`${source.src}-${source.type}`}
167
+ src={source.src}
168
+ type={source.type}
169
+ />
154
170
  ))}
155
171
  {children}
156
172
  </Video>
157
173
  )}
158
174
  </VideoSkin>
159
- </VideoJSPlayer.Provider>
160
- );
161
- };
175
+ </VideoJSPlayer.Player>
176
+ )
177
+ }
162
178
 
163
- export default VideoJS;
179
+ export default VideoJS
@@ -4,4 +4,4 @@ export {
4
4
  type VideoJSProps,
5
5
  type VideoJSSource,
6
6
  type VideoJSSourceType,
7
- } from "./VideoJS";
7
+ } from './VideoJS'
@@ -1,67 +1,60 @@
1
- import * as React from "react";
2
- import { cva, type VariantProps } from "class-variance-authority";
3
- import { Slot } from "radix-ui";
1
+ import { Button as ButtonPrimitive } from '@base-ui/react/button'
2
+ import { cva, type VariantProps } from 'class-variance-authority'
4
3
 
5
- import { cn } from "@/lib/utils";
4
+ import { cn } from '@/lib/utils'
6
5
 
7
6
  const buttonVariants = cva(
8
7
  "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
9
8
  {
10
9
  variants: {
11
10
  variant: {
12
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
11
+ default: 'bg-primary text-primary-foreground hover:bg-primary/80',
13
12
  outline:
14
- "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
13
+ 'border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',
15
14
  secondary:
16
- "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
15
+ 'bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',
17
16
  ghost:
18
- "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
17
+ 'hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50',
19
18
  destructive:
20
- "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
21
- link: "text-primary underline-offset-4 hover:underline",
19
+ 'bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40',
20
+ link: 'text-primary underline-offset-4 hover:underline',
22
21
  },
23
22
  size: {
24
23
  default:
25
- "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
24
+ 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
26
25
  xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
27
26
  sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
28
- lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
29
- icon: "size-8",
30
- "icon-xs":
27
+ lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
28
+ icon: 'size-8',
29
+ 'icon-xs':
31
30
  "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
32
- "icon-sm":
33
- "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
34
- "icon-lg": "size-9",
31
+ 'icon-sm':
32
+ 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',
33
+ 'icon-lg': 'size-9',
35
34
  },
36
35
  },
37
36
  defaultVariants: {
38
- variant: "default",
39
- size: "default",
37
+ variant: 'default',
38
+ size: 'default',
40
39
  },
41
40
  },
42
- );
41
+ )
43
42
 
44
43
  function Button({
45
44
  className,
46
- variant = "default",
47
- size = "default",
48
- asChild = false,
45
+ variant = 'default',
46
+ size = 'default',
49
47
  ...props
50
- }: React.ComponentProps<"button"> &
51
- VariantProps<typeof buttonVariants> & {
52
- asChild?: boolean;
53
- }) {
54
- const Comp = asChild ? Slot.Root : "button";
55
-
48
+ }: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
56
49
  return (
57
- <Comp
50
+ <ButtonPrimitive
58
51
  data-slot="button"
59
52
  data-variant={variant}
60
53
  data-size={size}
61
54
  className={cn(buttonVariants({ variant, size, className }))}
62
55
  {...props}
63
56
  />
64
- );
57
+ )
65
58
  }
66
59
 
67
- export { Button, buttonVariants };
60
+ export { Button, buttonVariants }
@@ -1,17 +1,18 @@
1
- import { Loader2Icon } from "lucide-react";
2
- import type { ComponentProps } from "react";
1
+ /* oxlint-disable jsx-a11y/prefer-tag-over-role -- SVG 加载图标需要显式声明状态角色。 */
2
+ import { Loader2Icon } from 'lucide-react'
3
+ import type { ComponentProps } from 'react'
3
4
 
4
- import { cn } from "@/lib/utils";
5
+ import { cn } from '@/lib/utils'
5
6
 
6
- function Spinner({ className, ...props }: ComponentProps<"svg">) {
7
+ function Spinner({ className, ...props }: ComponentProps<'svg'>) {
7
8
  return (
8
9
  <Loader2Icon
9
10
  role="status"
10
11
  aria-label="Loading"
11
- className={cn("size-4 animate-spin", className)}
12
+ className={cn('size-4 animate-spin', className)}
12
13
  {...props}
13
14
  />
14
- );
15
+ )
15
16
  }
16
17
 
17
- export { Spinner };
18
+ export { Spinner }
@@ -0,0 +1,229 @@
1
+ 'use client'
2
+
3
+ import { Toast as ToastPrimitive } from '@base-ui/react/toast'
4
+ import {
5
+ XIcon,
6
+ CircleCheckIcon,
7
+ InfoIcon,
8
+ TriangleAlertIcon,
9
+ OctagonXIcon,
10
+ Loader2Icon,
11
+ } from 'lucide-react'
12
+ import * as React from 'react'
13
+
14
+ import { Button } from '@/components/ui/button'
15
+ import { cn } from '@/lib/utils'
16
+
17
+ const toast = ToastPrimitive.createToastManager()
18
+
19
+ function ToastProvider({ ...props }: ToastPrimitive.Provider.Props) {
20
+ return <ToastPrimitive.Provider {...props} />
21
+ }
22
+
23
+ function ToastPortal({ ...props }: ToastPrimitive.Portal.Props) {
24
+ return <ToastPrimitive.Portal data-slot="toast-portal" {...props} />
25
+ }
26
+
27
+ function ToastViewport({ className, ...props }: ToastPrimitive.Viewport.Props) {
28
+ return (
29
+ <ToastPrimitive.Viewport
30
+ data-slot="toast-viewport"
31
+ className={cn(
32
+ 'pointer-events-none fixed inset-x-4 bottom-4 z-50 mx-auto w-auto max-w-sm outline-none sm:right-4 sm:left-auto sm:mx-0 sm:w-full',
33
+ className,
34
+ )}
35
+ {...props}
36
+ />
37
+ )
38
+ }
39
+
40
+ function Toast({ className, ...props }: ToastPrimitive.Root.Props) {
41
+ return (
42
+ <ToastPrimitive.Root
43
+ data-slot="toast"
44
+ className={cn(
45
+ 'group/toast pointer-events-auto absolute right-0 bottom-0 z-[calc(1000-var(--toast-index))] w-full origin-bottom rounded-2xl border bg-popover text-popover-foreground shadow-lg will-change-transform outline-none select-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
46
+ '[--gap:0.75rem] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))]',
47
+ 'h-(--height) [transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] [transition:transform_500ms_cubic-bezier(0.22,1,0.36,1),opacity_500ms,height_150ms]',
48
+ "after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']",
49
+ 'data-expanded:h-(--toast-height) data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(var(--offset-y))]',
50
+ 'data-limited:opacity-0 data-starting-style:[transform:translateY(150%)]',
51
+ '[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(150%)]',
52
+ 'data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]',
53
+ 'data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]',
54
+ 'data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]',
55
+ 'data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]',
56
+ 'data-expanded:data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]',
57
+ 'data-expanded:data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]',
58
+ 'data-expanded:data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]',
59
+ 'data-expanded:data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]',
60
+ className,
61
+ )}
62
+ {...props}
63
+ />
64
+ )
65
+ }
66
+
67
+ function ToastContent({ className, ...props }: ToastPrimitive.Content.Props) {
68
+ return (
69
+ <ToastPrimitive.Content
70
+ data-slot="toast-content"
71
+ className={cn(
72
+ 'flex h-full items-center gap-3 overflow-hidden p-4 transition-opacity duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] data-behind:opacity-0 data-expanded:opacity-100',
73
+ className,
74
+ )}
75
+ {...props}
76
+ />
77
+ )
78
+ }
79
+
80
+ function ToastTitle({ className, ...props }: ToastPrimitive.Title.Props) {
81
+ return (
82
+ <ToastPrimitive.Title
83
+ data-slot="toast-title"
84
+ className={cn('text-sm font-medium', className)}
85
+ {...props}
86
+ />
87
+ )
88
+ }
89
+
90
+ function ToastDescription({
91
+ className,
92
+ ...props
93
+ }: ToastPrimitive.Description.Props) {
94
+ return (
95
+ <ToastPrimitive.Description
96
+ data-slot="toast-description"
97
+ className={cn('text-sm text-muted-foreground', className)}
98
+ {...props}
99
+ />
100
+ )
101
+ }
102
+
103
+ function ToastAction({
104
+ className,
105
+ render = <Button variant="outline" size="sm" />,
106
+ ...props
107
+ }: ToastPrimitive.Action.Props) {
108
+ return (
109
+ <ToastPrimitive.Action
110
+ data-slot="toast-action"
111
+ render={render}
112
+ className={cn('shrink-0', className)}
113
+ {...props}
114
+ />
115
+ )
116
+ }
117
+
118
+ function ToastClose({
119
+ className,
120
+ children,
121
+ render = <Button variant="ghost" size="icon-sm" />,
122
+ ...props
123
+ }: ToastPrimitive.Close.Props) {
124
+ return (
125
+ <ToastPrimitive.Close
126
+ data-slot="toast-close"
127
+ aria-label="Close toast"
128
+ render={render}
129
+ className={cn(
130
+ "relative shrink-0 text-muted-foreground after:absolute after:-inset-2 after:content-[''] hover:text-foreground",
131
+ className,
132
+ )}
133
+ {...props}
134
+ >
135
+ {children ?? <XIcon aria-hidden="true" />}
136
+ </ToastPrimitive.Close>
137
+ )
138
+ }
139
+
140
+ function ToastIcon({ type }: { type: string | undefined }) {
141
+ let icon: React.ReactNode = null
142
+
143
+ if (type === 'success') {
144
+ icon = <CircleCheckIcon aria-hidden="true" />
145
+ }
146
+
147
+ if (type === 'info') {
148
+ icon = <InfoIcon aria-hidden="true" />
149
+ }
150
+
151
+ if (type === 'warning') {
152
+ icon = <TriangleAlertIcon aria-hidden="true" />
153
+ }
154
+
155
+ if (type === 'error') {
156
+ icon = <OctagonXIcon className="text-destructive" aria-hidden="true" />
157
+ }
158
+
159
+ if (type === 'loading') {
160
+ icon = <Loader2Icon className="animate-spin" aria-hidden="true" />
161
+ }
162
+
163
+ if (!icon) {
164
+ return null
165
+ }
166
+
167
+ return (
168
+ <span
169
+ data-slot="toast-icon"
170
+ className="shrink-0 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4"
171
+ >
172
+ {icon}
173
+ </span>
174
+ )
175
+ }
176
+
177
+ function ToastList() {
178
+ const { toasts } = ToastPrimitive.useToastManager()
179
+
180
+ return toasts.map((toastItem) => (
181
+ <Toast key={toastItem.id} toast={toastItem}>
182
+ <ToastContent>
183
+ <ToastIcon type={toastItem.type} />
184
+ <div className="flex min-w-0 flex-1 flex-col gap-1">
185
+ <ToastTitle />
186
+ <ToastDescription />
187
+ </div>
188
+ <ToastAction />
189
+ <ToastClose />
190
+ </ToastContent>
191
+ </Toast>
192
+ ))
193
+ }
194
+
195
+ function Toaster({
196
+ children,
197
+ toastManager = toast,
198
+ ...props
199
+ }: ToastPrimitive.Provider.Props) {
200
+ return (
201
+ <ToastProvider toastManager={toastManager} {...props}>
202
+ {children}
203
+ <ToastPortal>
204
+ <ToastViewport>
205
+ <ToastList />
206
+ </ToastViewport>
207
+ </ToastPortal>
208
+ </ToastProvider>
209
+ )
210
+ }
211
+
212
+ const createToastManager = ToastPrimitive.createToastManager
213
+ const useToastManager = ToastPrimitive.useToastManager
214
+
215
+ export {
216
+ Toaster,
217
+ Toast,
218
+ ToastAction,
219
+ ToastClose,
220
+ ToastContent,
221
+ ToastDescription,
222
+ ToastPortal,
223
+ ToastProvider,
224
+ ToastTitle,
225
+ ToastViewport,
226
+ createToastManager,
227
+ toast,
228
+ useToastManager,
229
+ }
@@ -1,6 +1,6 @@
1
- import { clsx, type ClassValue } from "clsx";
2
- import { twMerge } from "tailwind-merge";
1
+ import { clsx, type ClassValue } from 'clsx'
2
+ import { twMerge } from 'tailwind-merge'
3
3
 
4
4
  export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs));
5
+ return twMerge(clsx(inputs))
6
6
  }
@@ -1,5 +1,6 @@
1
- import { createRoot } from "react-dom/client";
2
- import "./styles/index.css";
3
- import App from "./App.tsx";
1
+ import { createRoot } from 'react-dom/client'
4
2
 
5
- createRoot(document.getElementById("root")!).render(<App />);
3
+ import './styles/index.css'
4
+ import App from './App.tsx'
5
+
6
+ createRoot(document.getElementById('root')!).render(<App />)