diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index eed0982..8ab8c04 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -21,6 +21,12 @@ jobs: # This is important to fetch the changes to the previous commit fetch-depth: 0 + steps: + - uses: pnpm/action-setup@v4 + with: + version: 9 + run_install: true + - name: Prettier Action uses: creyD/prettier_action@v4.3 with: diff --git a/.prettierrc b/.prettierrc index dddf1b3..cf830cf 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,10 +1,22 @@ { - "trailingComma": "all", - "tabWidth": 2, - "printWidth": 100, - "semi": false, - "singleQuote": true, - "useTabs": false, - "arrowParens": "avoid", - "bracketSpacing": true + "trailingComma": "all", + "tabWidth": 2, + "printWidth": 100, + "semi": false, + "singleQuote": true, + "useTabs": false, + "arrowParens": "avoid", + "bracketSpacing": true, + "plugins": ["@trivago/prettier-plugin-sort-imports"], + "importOrder": [ + "^solid-js(.*)$", + "^solid-(.*)$", + "^shiki(.*)$", + "^~/components/ui/(.*)$", + "^~/(.*)$", + "^[./]" + ], + "importOrderGroupNamespaceSpecifiers": true, + "importOrderSeparation": true, + "importOrderSortSpecifiers": true } diff --git a/package.json b/package.json index 313bad5..4dc6f92 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "postinstall": "pnpm build", "dev": "pnpm run --filter ./playgrounds/app dev", - "build": "cd packages/shikicode && pnpm build && cd ../shiki-magic-move && pnpm build && cd ../../playgrounds/app && pnpm build", + "build": "cd packages/shikicode && pnpm build && cd ../shiki-magic-move && pnpm build", "test": "turbo run test --filter=./packages/*", "typecheck": "turbo run typecheck --filter=./packages/*", "build-test": "turbo run build test --filter=./packages/*", @@ -22,6 +22,7 @@ }, "devDependencies": { "@changesets/cli": "^2.26.0", + "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/node": "^18.11.18", "concurrently": "^7.6.0", "jsdom": "^21.0.0", diff --git a/packages/shiki-magic-move/src/solid/ShikiMagicMove.tsx b/packages/shiki-magic-move/src/solid/ShikiMagicMove.tsx index 7dcdb91..6f5fb18 100644 --- a/packages/shiki-magic-move/src/solid/ShikiMagicMove.tsx +++ b/packages/shiki-magic-move/src/solid/ShikiMagicMove.tsx @@ -19,31 +19,40 @@ export interface ShikiMagicMoveProps { } export function ShikiMagicMove(props: ShikiMagicMoveProps) { - const codeToTokens = (code: string, lineNumbers?: boolean) => - codeToKeyedTokens( - props.highlighter, - code, - { - lang: props.lang, - theme: props.theme, - }, - lineNumbers, - ) + const codeToTokens = createMemo(() => { + return (code: string, lineNumbers?: boolean) => + codeToKeyedTokens( + props.highlighter, + code, + { + lang: props.lang, + theme: props.theme, + }, + lineNumbers, + ) + }) - const machine = createMagicMoveMachine((code, lineNumbers) => codeToTokens(code, lineNumbers)) + const machine = createMemo(() => { + const newCodeToTokens = codeToTokens() + return createMagicMoveMachine((code, lineNumbers) => newCodeToTokens(code, lineNumbers)) + }) const result = createMemo(() => { const lineNumbers = props.options?.lineNumbers ?? false if ( - props.code === machine.current.code && - props.theme === machine.current.themeName && - props.lang === machine.current.lang && - lineNumbers === machine.current.lineNumbers + props.code === machine().current.code && + props.theme === machine().current.themeName && + props.lang === machine().current.lang && + lineNumbers === machine().current.lineNumbers ) { - return machine + return machine() + } + try { + return machine().commit(props.code, props.options) + // eslint-disable-next-line unused-imports/no-unused-vars + } catch (e) { + return machine() } - - return machine.commit(props.code, props.options) }) return ( diff --git a/packages/shiki-magic-move/src/solid/ShikiMagicMoveRenderer.tsx b/packages/shiki-magic-move/src/solid/ShikiMagicMoveRenderer.tsx index c1cfc35..ea30dbb 100644 --- a/packages/shiki-magic-move/src/solid/ShikiMagicMoveRenderer.tsx +++ b/packages/shiki-magic-move/src/solid/ShikiMagicMoveRenderer.tsx @@ -21,15 +21,16 @@ export interface ShikiMagicMoveRendererProps { * A wrapper component to `MagicMoveRenderer` */ export function ShikiMagicMoveRenderer(props: ShikiMagicMoveRendererProps) { - let container: HTMLPreElement - let renderer: Renderer + // eslint-disable-next-line no-undef-init, prefer-const + let container: HTMLPreElement | undefined = undefined + // eslint-disable-next-line no-undef-init + let renderer: Renderer | undefined = undefined const [isMounted, setIsMounted] = createSignal(false) createEffect(() => { - if (!container) return - if (!isMounted()) { + if (container !== undefined && !isMounted()) { // Remove previous content - container.innerHTML = '' + ;(container as HTMLPreElement).innerHTML = '' setIsMounted(true) renderer = new Renderer(container) } @@ -37,16 +38,21 @@ export function ShikiMagicMoveRenderer(props: ShikiMagicMoveRendererProps) { createEffect(() => { async function render() { - if (!renderer) return + if (!renderer) { + return + } Object.assign(renderer.options, props.options) if (props.animate === undefined || props.animate === true) { - if (props.previous) renderer.replace(props.previous) + if (props.previous) { + renderer.replace(props.previous) + } props.onStart?.() await renderer.render(props.tokens) props.onEnd?.() + // eslint-disable-next-line style/brace-style } else { renderer.replace(props.tokens) } @@ -57,7 +63,6 @@ export function ShikiMagicMoveRenderer(props: ShikiMagicMoveRendererProps) { return (
=18"
   },
   "devDependencies": {
+    "@trivago/prettier-plugin-sort-imports": "^4.3.0",
     "@types/jsonwebtoken": "^9.0.7",
     "drizzle-kit": "^0.26.2",
     "tsx": "^4.19.1"
diff --git a/playgrounds/app/src/app.css b/playgrounds/app/src/app.css
index 75b00aa..f963b25 100644
--- a/playgrounds/app/src/app.css
+++ b/playgrounds/app/src/app.css
@@ -102,9 +102,7 @@
 
   body {
     @apply bg-background text-foreground;
-    font-feature-settings:
-      'rlig' 1,
-      'calt' 1;
+    font-feature-settings: 'rlig' 1, 'calt' 1;
   }
 }
 
@@ -148,3 +146,27 @@
 #app {
   @apply min-h-screen flex flex-col;
 }
+
+.collapsible__content {
+  overflow: hidden;
+  animation: slideUp 300ms ease-out;
+}
+.collapsible__content[data-expanded] {
+  animation: slideDown 300ms ease-out;
+}
+@keyframes slideDown {
+  from {
+    height: 0;
+  }
+  to {
+    height: var(--kb-collapsible-content-height);
+  }
+}
+@keyframes slideUp {
+  from {
+    height: var(--kb-collapsible-content-height);
+  }
+  to {
+    height: 0;
+  }
+}
diff --git a/playgrounds/app/src/app.tsx b/playgrounds/app/src/app.tsx
index 5e8df30..5479ae9 100644
--- a/playgrounds/app/src/app.tsx
+++ b/playgrounds/app/src/app.tsx
@@ -1,11 +1,14 @@
-import { Suspense } from 'solid-js'
+import '@fontsource/bungee-inline'
+import '@fontsource/roboto'
 import { Router } from '@solidjs/router'
 import { FileRoutes } from '@solidjs/start/router'
+
+import { Suspense } from 'solid-js'
+
 import { Toaster } from 'solid-sonner'
+
 import Header from '~/components/Header'
-import Footer from './components/Footer'
-import '@fontsource/bungee-inline'
-import '@fontsource/roboto'
+
 import './app.css'
 
 export default function App() {
diff --git a/playgrounds/app/src/components/Editor.tsx b/playgrounds/app/src/components/Editor.tsx
index a081b87..fa7598e 100644
--- a/playgrounds/app/src/components/Editor.tsx
+++ b/playgrounds/app/src/components/Editor.tsx
@@ -1,21 +1,57 @@
-import { interpolate, interpolateColors, Easing } from 'remotion'
+import wasmURL from '@ffmpeg/core/wasm?url'
+import coreURL from '@ffmpeg/core?url'
+import { FFmpeg } from '@ffmpeg/ffmpeg'
+import { fetchFile, toBlobURL } from '@ffmpeg/util'
+import { useNavigate } from '@solidjs/router'
+import clsx from 'clsx'
+import { openDB } from 'idb'
 import { encode } from 'modern-gif'
 import workerUrl from 'modern-gif/worker?url'
+import { Easing, interpolate, interpolateColors } from 'remotion'
+
+import { Show, createEffect, createMemo, createSignal, onCleanup, onMount } from 'solid-js'
+import { SetStoreFunction } from 'solid-js/store'
+
+import { FaSolidCaretDown, FaSolidCaretUp } from 'solid-icons/fa'
+import { HiOutlineCog } from 'solid-icons/hi'
+import { toast } from 'solid-sonner'
+
+import type { HighlighterGeneric } from 'shiki'
+import { bundledLanguages, bundledThemes, createHighlighter } from 'shiki'
 import 'shiki-magic-move/dist/style.css'
+import { ShikiMagicMove } from 'shiki-magic-move/solid'
+import { MagicMoveElement } from 'shiki-magic-move/types'
+
 import {
-  ComboboxItem,
-  ComboboxItemLabel,
-  ComboboxItemIndicator,
+  Accordion,
+  AccordionContent,
+  AccordionItem,
+  AccordionTrigger,
+} from '~/components/ui/accordion'
+import { Button } from '~/components/ui/button'
+import { Checkbox } from '~/components/ui/checkbox'
+import { Collapsible, CollapsibleContent } from '~/components/ui/collapsible'
+import {
+  Combobox,
+  ComboboxContent,
   ComboboxControl,
   ComboboxInput,
+  ComboboxItem,
+  ComboboxItemIndicator,
+  ComboboxItemLabel,
   ComboboxTrigger,
-  ComboboxContent,
-  Combobox,
 } from '~/components/ui/combobox'
-import { Button } from '~/components/ui/button'
-import { Tabs, TabsContent, TabsList, TabsTrigger } from '~/components/ui/tabs'
-import { TextField, TextFieldInput } from '~/components/ui/text-field'
-import { MagicMoveElement } from 'shiki-magic-move/types'
+import { Dialog, DialogContent, DialogFooter } from '~/components/ui/dialog'
+import { Label } from '~/components/ui/label'
+import { ProgressCircle } from '~/components/ui/progress-circle'
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+} from '~/components/ui/select'
+import { Separator } from '~/components/ui/separator'
 import {
   Slider,
   SliderFill,
@@ -24,38 +60,14 @@ import {
   SliderTrack,
   SliderValueLabel,
 } from '~/components/ui/slider'
-import clsx from 'clsx'
-import { Checkbox } from '~/components/ui/checkbox'
-import { Label } from '~/components/ui/label'
-import {
-  Dialog,
-  DialogContent,
-  DialogDescription,
-  DialogFooter,
-  DialogHeader,
-  DialogTitle,
-} from '~/components/ui/dialog'
-import {
-  createEffect,
-  createMemo,
-  createResource,
-  createSignal,
-  onCleanup,
-  Setter,
-  Show,
-} from 'solid-js'
-import { createHighlighter, bundledThemes, bundledLanguages } from 'shiki'
-import { ShikiMagicMove } from 'shiki-magic-move/solid'
-import { AnimationFrameConfig, SnippetSettings } from '~/types'
-import { authFetch } from '~/lib/utils'
-import { useNavigate } from '@solidjs/router'
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '~/components/ui/tabs'
+import { TextField, TextFieldInput } from '~/components/ui/text-field'
+
 import { authToken } from '~/lib/store'
-import { toast } from 'solid-sonner'
-import { Separator } from './ui/separator'
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select'
-import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './ui/accordion'
+import { authFetch } from '~/lib/utils'
+import { AnimationFrameConfig, SnippetSettings } from '~/types'
+
 import { ShikiCodeBlock } from './ShikiCodeBlock'
-import { SetStoreFunction } from 'solid-js/store'
 
 const animationSeconds = 1
 const animationFPS = 30
@@ -106,14 +118,29 @@ export default function Editor(props: EditorProps) {
   const [isShowingGifDialog, setIsShowingGifDialog] = createSignal(false)
   const [title, setTitle] = createSignal(props.snippetSettings.title)
   const [isSaving, setIsSaving] = createSignal(false)
+  const [highlighter, setHighlighter] = createSignal | undefined>()
+
+  const [isShowingFfmpegDialog, setIsShowingFfmpegDialog] = createSignal(false)
+  const [ffmpegLoaded, setFfmpegLoaded] = createSignal(false)
+  const [isDownloadingFfmpeg, setIsDownloadingFfmpeg] = createSignal(false)
+  const [isGeneratingVideo, setIsGeneratingVideo] = createSignal(false)
+  const [videoProgress, setVideoProgress] = createSignal(0)
+  const ffmpeg = new FFmpeg()
+  const [settingsCollapsed, setSettingsCollapsed] = createSignal(false)
+
+  onMount(() => {
+    if (document.body.clientWidth < 768) {
+      setSettingsCollapsed(true)
+    }
+  })
 
-  const [highlighter] = createResource(async () => {
-    const newHighlighter = await createHighlighter({
-      themes: Object.keys(bundledThemes),
-      langs: Object.keys(bundledLanguages),
+  createEffect(() => {
+    createHighlighter({
+      themes: [props.snippetSettings.theme],
+      langs: [props.snippetSettings.language],
+    }).then(newHighlighter => {
+      setHighlighter(newHighlighter)
     })
-
-    return newHighlighter
   })
 
   createEffect(() => {
@@ -127,6 +154,8 @@ export default function Editor(props: EditorProps) {
       props.snippetSettings.codeLeft !== '' &&
       props.snippetSettings.codeRight !== '' &&
       !isResizing() &&
+      !isShowingGifDialog() &&
+      !isShowingFfmpegDialog() &&
       isLooping()
     ) {
       if (toggled()) {
@@ -251,413 +280,427 @@ export default function Editor(props: EditorProps) {
 
   return (
     <>
-      
-
-
- - props.setSnippetSettings('theme', newTheme || '')} - placeholder="Search a theme..." - itemComponent={props => ( - - {props.item.rawValue} - - - )} - > - - - - - - -
- -
- - props.setSnippetSettings('language', newLanguage || '')} - placeholder="Search a Language..." - itemComponent={props => ( - - {props.item.rawValue} - - - )} - > - - - - - - -
- - - - +
+ + + +
+ + props.setSnippetSettings('theme', newTheme || '')} + placeholder="Search a theme..." + itemComponent={props => ( + + {props.item.rawValue} + + + )} + > + + + + + + +
+ +
+ + props.setSnippetSettings('language', newLanguage || '')} + placeholder="Search a Language..." + itemComponent={props => ( + + {props.item.rawValue} + + + )} + > + + + + + + +
+ + + + + + Background + +
+
+ + + + id="bg-type" + value={bgTypeOptions.find( + option => option.value === props.snippetSettings.bgType, + )} + optionValue="value" + optionTextValue="label" + onChange={newType => + newType && + props.setSnippetSettings( + 'bgType', + newType.value as 'solid' | 'linearGradient', + ) + } + options={bgTypeOptions} + itemComponent={props => ( + {props.item.rawValue.label} + )} + > + + > + {state => state.selectedOption()?.label} + + + + +
+ + {props.snippetSettings.bgType === 'linearGradient' && ( + <> +
+ + { + props.setSnippetSettings('bgGradientColorStart', e.target.value) + }} + /> +
+
+ + { + props.setSnippetSettings('bgGradientColorEnd', e.target.value) + }} + /> +
+ { + props.setSnippetSettings('bgGradientDirection', e[0]) + }} + > +
+ Direction + +
+ + deg +
+
+ + + + +
+ )} - optionValue="value" - optionTextValue="label" - onChange={newType => - newType && - props.setSnippetSettings( - 'bgType', - newType.value as 'solid' | 'linearGradient', - ) - } - options={bgTypeOptions} - itemComponent={props => ( - {props.item.rawValue.label} + {props.snippetSettings.bgType === 'solid' && ( +
+ + { + props.setSnippetSettings('bgColor', e.target.value) + }} + /> +
)} - > - + + + + + Layout + +
+ { + props.setSnippetSettings('snippetWidth', e[0]) + }} > - > - {state => state.selectedOption()?.label} - - - - -
+
+ Width +
+ + px +
+
+ + + + + + + { + props.setSnippetSettings('yPadding', e[0]) + }} + > +
+ Padding (y) +
+ + px +
+
+ + + + +
+ + { + props.setSnippetSettings('xPadding', e[0]) + }} + > +
+ Padding (x) +
+ + px +
+
+ + + + +
+
+
+
- {props.snippetSettings.bgType === 'linearGradient' && ( - <> + + Shadow + +
-
+
-
+
+ { + props.setSnippetSettings('shadowOpacity', e[0]) + }} + > +
+ Opacity + +
+ + + + +
+
+
+ { + props.setSnippetSettings('shadowOffsetY', e[0]) + }} + > +
+ Offset Y +
+ + px +
+
+ + + + +
+
+
+ { + props.setSnippetSettings('shadowBlur', e[0]) + }} + > +
+ Blur +
+ + px +
+
+ + + + +
+
+
+
+
+ + + Font + +
+
+ + + + id="font-family" + value={supportedFontFamilies.find( + option => option.name === props.snippetSettings.fontFamily, + )} + optionValue="name" + optionTextValue="name" + onChange={newFamily => + newFamily && props.setSnippetSettings('fontFamily', newFamily.name) + } + options={supportedFontFamilies} + itemComponent={props => ( + {props.item.rawValue.name} + )} + > + + > + {state => state.selectedOption()?.name} + + + + +
+ { - props.setSnippetSettings('bgGradientDirection', e[0]) + props.setSnippetSettings('fontSize', e[0]) }} > -
- Direction - +
+ Size
- deg + px
- + - - )} - {props.snippetSettings.bgType === 'solid' && ( -
- - { - props.setSnippetSettings('bgColor', e.target.value) - }} - /> -
- )} -
- - - - - Layout - -
- { - props.setSnippetSettings('snippetWidth', e[0]) - }} - > -
- Width -
- - px -
- - - - -
- - { - props.setSnippetSettings('yPadding', e[0]) - }} - > -
- Padding (y) -
- - px -
-
- - - - -
- - { - props.setSnippetSettings('xPadding', e[0]) - }} - > -
- Padding (x) -
- - px -
-
- - - - -
-
-
-
- - - Shadow - -
-
- - { - props.setSnippetSettings( - 'shadowEnabled', - !props.snippetSettings.shadowEnabled, - ) - }} - /> -
- -
- - - props.setSnippetSettings('shadowColor', e.target.value)} - /> -
-
- { - props.setSnippetSettings('shadowOpacity', e[0]) - }} - > -
- Opacity - -
- - - - -
-
-
- { - props.setSnippetSettings('shadowOffsetY', e[0]) - }} - > -
- Offset Y -
- - px -
-
- - - - -
-
-
- { - props.setSnippetSettings('shadowBlur', e[0]) - }} - > -
- Blur -
- - px -
-
- - - - -
-
-
-
-
- - - Font - -
-
- - - - id="font-family" - value={supportedFontFamilies.find( - option => option.name === props.snippetSettings.fontFamily, - )} - optionValue="name" - optionTextValue="name" - onChange={newFamily => - newFamily && props.setSnippetSettings('fontFamily', newFamily.name) - } - options={supportedFontFamilies} - itemComponent={props => ( - {props.item.rawValue.name} - )} - > - - > - {state => state.selectedOption()?.name} - - - - -
- - { - props.setSnippetSettings('fontSize', e[0]) - }} - > -
- Size -
- - px -
-
- - - - -
-
-
-
- + + + + +
- Download + Download GIF + + { + setIsShowingFfmpegDialog(true) + }} + > + Enable Video + + } + > + + + + + Downloading...

}> +

+ To create video, must download ffmpeg.wasm. It's approximately 30MB. If you have + downloaded it here before, your browser cache should kick in. +

+
+ + + + +
+
) } +function dataURItoUInt8Array(dataURI: string) { + // convert base64 to raw binary data held in a string + // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this + var byteString = atob(dataURI.split(',')[1]) + + // separate out the mime component + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] + + // write the bytes of the string to an ArrayBuffer + var ab = new ArrayBuffer(byteString.length) + + // create a view into the buffer + var ia = new Uint8Array(ab) + + // set the bytes of the buffer to the correct values + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i) + } + + return ia +} + function dataURItoBlob(dataURI: string) { // convert base64 to raw binary data held in a string // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this @@ -1031,6 +1191,11 @@ async function createAnimationFrame( canvas.width = width + xPadding * 2 canvas.height = height + yPadding * 2 + const textCanvas = document.createElement('canvas') + const textCtx = textCanvas.getContext('2d', { alpha: true })! + textCanvas.width = width + xPadding - 4 + textCanvas.height = height + yPadding + if (backgroundType === 'linearGradient') { // Convert angle to match CSS gradient angle (0deg = to top, 90deg = to right) const cssAngle = (backgroundGradientDirection + 90) % 360 @@ -1101,12 +1266,24 @@ async function createAnimationFrame( [el.color.start || 'rgba(0,0,0,0)', el.color.end || 'rgba(0,0,0,0)'], ) - ctx.font = `${fontSize} ${fontFamily}` - ctx.fillStyle = color - ctx.globalAlpha = opacity - ctx.fillText(htmlDecode(el.el.innerHTML), x, y, width - x + xPadding / 2) + textCtx.font = `${fontSize} ${fontFamily}` + textCtx.fillStyle = color + textCtx.globalAlpha = opacity + textCtx.fillText(htmlDecode(el.el.innerHTML), x, y) }) await Promise.all(elementPromises) + ctx.drawImage(textCanvas, 0, 0) + return ctx.getImageData(0, 0, canvas.width, canvas.height) } + +// Not actually necessary since the browser will cache the wasm file +async function wrappedToBlobURL(url: string, mimeType: string) { + const storeName = 'ffmpegCache' + const db = await openDB(storeName, 1, {}) + + return db.get(storeName, url).catch(() => { + return toBlobURL(url, mimeType) + }) +} diff --git a/playgrounds/app/src/components/Footer.tsx b/playgrounds/app/src/components/Footer.tsx index 2d3b2b4..f6cf86e 100644 --- a/playgrounds/app/src/components/Footer.tsx +++ b/playgrounds/app/src/components/Footer.tsx @@ -1,4 +1,5 @@ import { A } from '@solidjs/router' + import { linkStyles } from '~/lib/styles' export default function Footer() { diff --git a/playgrounds/app/src/components/Header.tsx b/playgrounds/app/src/components/Header.tsx index 89cbe89..b8edec7 100644 --- a/playgrounds/app/src/components/Header.tsx +++ b/playgrounds/app/src/components/Header.tsx @@ -1,29 +1,31 @@ +import { makePersisted } from '@solid-primitives/storage' import { A } from '@solidjs/router' -import { Button } from './ui/button' + +import { Show, createSignal } from 'solid-js' + +import { FaSolidMoon, FaSolidSun } from 'solid-icons/fa' import { OcMarkgithub2, OcQuestion2 } from 'solid-icons/oc' -import { FaSolidSun, FaSolidMoon } from 'solid-icons/fa' -import { createThemeSwitcher } from '~/components/theme-switcher' -import { authToken } from '~/lib/store' -import { createSignal, Show } from 'solid-js' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '~/components/ui/dropdown-menu' -import { user } from '~/lib/store' import { TbCode, TbDoorExit, TbQuestionMark } from 'solid-icons/tb' -import { linkStyles } from '~/lib/styles' + +import { Button } from '~/components/ui/button' import { Dialog, DialogContent, DialogDescription, - DialogFooter, DialogHeader, DialogTitle, - DialogTrigger, } from '~/components/ui/dialog' -import { makePersisted } from '@solid-primitives/storage' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '~/components/ui/dropdown-menu' + +import { createThemeSwitcher } from '~/components/theme-switcher' +import { authToken } from '~/lib/store' +import { user } from '~/lib/store' +import { linkStyles } from '~/lib/styles' export default function Header() { const [isShowingHelpDialog, setIsShowingHelpDialog] = makePersisted(createSignal(true), { @@ -113,7 +115,7 @@ export default function Header() { alt={user()?.githubUsername} class="w-6 h-6 rounded-full" /> - {user()?.githubUsername} + diff --git a/playgrounds/app/src/components/ShikiCodeBlock.tsx b/playgrounds/app/src/components/ShikiCodeBlock.tsx index e9bf3b0..11bd2c2 100644 --- a/playgrounds/app/src/components/ShikiCodeBlock.tsx +++ b/playgrounds/app/src/components/ShikiCodeBlock.tsx @@ -1,7 +1,8 @@ -import { createSignal, onMount, createEffect } from 'solid-js' +import { createEffect, createSignal, onMount } from 'solid-js' + import { createHighlighter } from 'shiki' -import { autoload, hookClosingPairs, hookTab, ShikiCode } from 'shikicode/plugins' import { shikiCode } from 'shikicode' +import { ShikiCode, autoload, hookClosingPairs, hookTab } from 'shikicode/plugins' import { cn } from '~/lib/utils' diff --git a/playgrounds/app/src/components/SnippetPreview.tsx b/playgrounds/app/src/components/SnippetPreview.tsx index bec23cb..ce0662b 100644 --- a/playgrounds/app/src/components/SnippetPreview.tsx +++ b/playgrounds/app/src/components/SnippetPreview.tsx @@ -1,5 +1,6 @@ import { Highlighter } from 'shiki' import { ShikiMagicMove } from 'shiki-magic-move/solid' + import { Snippet } from '~/types' interface SnippetPreviewProps { diff --git a/playgrounds/app/src/components/theme-switcher.tsx b/playgrounds/app/src/components/theme-switcher.tsx index 6f17fbb..019b139 100644 --- a/playgrounds/app/src/components/theme-switcher.tsx +++ b/playgrounds/app/src/components/theme-switcher.tsx @@ -1,6 +1,7 @@ -import { createSignal, createEffect } from 'solid-js' import { makePersisted } from '@solid-primitives/storage' +import { createEffect, createSignal } from 'solid-js' + export function createThemeSwitcher() { const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)') const [isDarkMode, setIsDarkMode] = makePersisted(createSignal(prefersDarkScheme.matches), { diff --git a/playgrounds/app/src/components/ui/collapsible.tsx b/playgrounds/app/src/components/ui/collapsible.tsx new file mode 100644 index 0000000..995ee34 --- /dev/null +++ b/playgrounds/app/src/components/ui/collapsible.tsx @@ -0,0 +1,9 @@ +import * as CollapsiblePrimitive from '@kobalte/core/collapsible' + +const Collapsible = CollapsiblePrimitive.Root + +const CollapsibleTrigger = CollapsiblePrimitive.Trigger + +const CollapsibleContent = CollapsiblePrimitive.Content + +export { Collapsible, CollapsibleTrigger, CollapsibleContent } diff --git a/playgrounds/app/src/components/ui/progress-circle.tsx b/playgrounds/app/src/components/ui/progress-circle.tsx new file mode 100644 index 0000000..851fbee --- /dev/null +++ b/playgrounds/app/src/components/ui/progress-circle.tsx @@ -0,0 +1,94 @@ +import type { Component, ComponentProps } from 'solid-js' +import { mergeProps, splitProps } from 'solid-js' + +import { cn } from '~/lib/utils' + +type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl' + +const sizes: Record = { + xs: { radius: 15, strokeWidth: 3 }, + sm: { radius: 19, strokeWidth: 4 }, + md: { radius: 32, strokeWidth: 6 }, + lg: { radius: 52, strokeWidth: 8 }, + xl: { radius: 80, strokeWidth: 10 }, +} + +type ProgressCircleProps = ComponentProps<'div'> & { + value?: number + size?: Size + radius?: number + strokeWidth?: number + showAnimation?: boolean +} + +const ProgressCircle: Component = rawProps => { + const props = mergeProps({ size: 'md' as Size, showAnimation: true }, rawProps) + const [local, others] = splitProps(props, [ + 'class', + 'children', + 'value', + 'size', + 'radius', + 'strokeWidth', + 'showAnimation', + ]) + + const value = () => getLimitedValue(local.value) + const radius = () => local.radius ?? sizes[local.size].radius + const strokeWidth = () => local.strokeWidth ?? sizes[local.size].strokeWidth + const normalizedRadius = () => radius() - strokeWidth() / 2 + const circumference = () => normalizedRadius() * 2 * Math.PI + const strokeDashoffset = () => (value() / 100) * circumference() + const offset = () => circumference() - strokeDashoffset() + + return ( +
+ + + {value() >= 0 ? ( + + ) : null} + +
{local.children}
+
+ ) +} + +function getLimitedValue(input: number | undefined) { + if (input === undefined) { + return 0 + } else if (input > 100) { + return 100 + } + return input +} + +export { ProgressCircle } diff --git a/playgrounds/app/src/db/client.ts b/playgrounds/app/src/db/client.ts index 656d4b3..a1656c1 100644 --- a/playgrounds/app/src/db/client.ts +++ b/playgrounds/app/src/db/client.ts @@ -1,5 +1,6 @@ import 'dotenv/config' import { drizzle } from 'drizzle-orm/libsql' + import { schema } from './schema' export const db = drizzle({ diff --git a/playgrounds/app/src/db/schema.ts b/playgrounds/app/src/db/schema.ts index 2bc4bb5..97069ed 100644 --- a/playgrounds/app/src/db/schema.ts +++ b/playgrounds/app/src/db/schema.ts @@ -1,4 +1,4 @@ -import { int, sqliteTable, text, real } from 'drizzle-orm/sqlite-core' +import { int, real, sqliteTable, text } from 'drizzle-orm/sqlite-core' export const usersTable = sqliteTable('users_table', { id: text().primaryKey(), diff --git a/playgrounds/app/src/entry-client.tsx b/playgrounds/app/src/entry-client.tsx index 46acd52..ffccf40 100644 --- a/playgrounds/app/src/entry-client.tsx +++ b/playgrounds/app/src/entry-client.tsx @@ -1,4 +1,4 @@ // @refresh reload -import { mount, StartClient } from '@solidjs/start/client' +import { StartClient, mount } from '@solidjs/start/client' mount(() => , document.getElementById('app')!) diff --git a/playgrounds/app/src/entry-server.tsx b/playgrounds/app/src/entry-server.tsx index 0626e99..4c02775 100644 --- a/playgrounds/app/src/entry-server.tsx +++ b/playgrounds/app/src/entry-server.tsx @@ -1,5 +1,5 @@ // @refresh reload -import { createHandler, StartServer } from '@solidjs/start/server' +import { StartServer, createHandler } from '@solidjs/start/server' export default createHandler(() => ( { const user = await getUser(event) diff --git a/playgrounds/app/src/routes/api/snippets/[snippetId].ts b/playgrounds/app/src/routes/api/snippets/[snippetId].ts index c5e2c62..11b1dd4 100644 --- a/playgrounds/app/src/routes/api/snippets/[snippetId].ts +++ b/playgrounds/app/src/routes/api/snippets/[snippetId].ts @@ -1,5 +1,6 @@ import type { APIEvent } from '@solidjs/start/server' import { and, eq } from 'drizzle-orm' + import { db } from '~/db/client' import { snippetsTable } from '~/db/schema' import { getUser } from '~/lib/middleware' diff --git a/playgrounds/app/src/routes/index.tsx b/playgrounds/app/src/routes/index.tsx index 9419fce..8ee38f0 100644 --- a/playgrounds/app/src/routes/index.tsx +++ b/playgrounds/app/src/routes/index.tsx @@ -1,8 +1,9 @@ -import { createSignal } from 'solid-js' import { makePersisted } from '@solid-primitives/storage' + +import { createStore } from 'solid-js/store' + import Editor from '~/components/Editor' import { SnippetSettings } from '~/types' -import { createStore } from 'solid-js/store' const left = ` import { render } from "solid-js/web"; diff --git a/playgrounds/app/src/routes/logged-out.tsx b/playgrounds/app/src/routes/logged-out.tsx index e21a2a7..873ea29 100644 --- a/playgrounds/app/src/routes/logged-out.tsx +++ b/playgrounds/app/src/routes/logged-out.tsx @@ -1,6 +1,9 @@ -import { Button } from '~/components/ui/button' -import { OcMarkgithub2 } from 'solid-icons/oc' import { onMount } from 'solid-js' + +import { OcMarkgithub2 } from 'solid-icons/oc' + +import { Button } from '~/components/ui/button' + import { setAuthToken } from '~/lib/store' export default function LoggedOut() { diff --git a/playgrounds/app/src/routes/oauth.tsx b/playgrounds/app/src/routes/oauth.tsx index 9e3db2b..3e41429 100644 --- a/playgrounds/app/src/routes/oauth.tsx +++ b/playgrounds/app/src/routes/oauth.tsx @@ -1,5 +1,7 @@ import { useNavigate, useSearchParams } from '@solidjs/router' -import { createSignal, onMount, Show } from 'solid-js' + +import { Show, createSignal, onMount } from 'solid-js' + import { setAuthToken, setUser, user } from '~/lib/store' export default function OAuth() { diff --git a/playgrounds/app/src/routes/snippets/[snippetId].tsx b/playgrounds/app/src/routes/snippets/[snippetId].tsx index fefc9be..0f8a46b 100644 --- a/playgrounds/app/src/routes/snippets/[snippetId].tsx +++ b/playgrounds/app/src/routes/snippets/[snippetId].tsx @@ -1,5 +1,6 @@ -import { createEffect, createResource, Show } from 'solid-js' +import { Show, createEffect, createResource } from 'solid-js' import { createStore } from 'solid-js/store' + import Editor from '~/components/Editor' import { authFetch } from '~/lib/utils' import { Snippet, SnippetSettings } from '~/types' diff --git a/playgrounds/app/src/routes/snippets/index.tsx b/playgrounds/app/src/routes/snippets/index.tsx index 3305343..6eaaaea 100644 --- a/playgrounds/app/src/routes/snippets/index.tsx +++ b/playgrounds/app/src/routes/snippets/index.tsx @@ -1,6 +1,9 @@ import { A } from '@solidjs/router' -import { createHighlighter, bundledThemes, bundledLanguages } from 'shiki' -import { createResource, Show } from 'solid-js' + +import { Show, createResource } from 'solid-js' + +import { bundledLanguages, bundledThemes, createHighlighter } from 'shiki' + import { SnippetPreview } from '~/components/SnippetPreview' import { authFetch } from '~/lib/utils' import { Snippet } from '~/types' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2823d32..f267481 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@changesets/cli': specifier: ^2.26.0 version: 2.27.9 + '@trivago/prettier-plugin-sort-imports': + specifier: ^4.3.0 + version: 4.3.0(@vue/compiler-sfc@3.5.12)(prettier@2.8.3) '@types/node': specifier: ^18.11.18 version: 18.19.55 @@ -195,6 +198,15 @@ importers: '@corvu/resizable': specifier: ^0.2.3 version: 0.2.3(solid-js@1.9.2) + '@ffmpeg/core': + specifier: ^0.12.6 + version: 0.12.6 + '@ffmpeg/ffmpeg': + specifier: ^0.12.10 + version: 0.12.10 + '@ffmpeg/util': + specifier: ^0.12.1 + version: 0.12.1 '@fontsource/bungee-inline': specifier: ^5.1.0 version: 5.1.0 @@ -207,6 +219,9 @@ importers: '@libsql/client': specifier: ^0.14.0 version: 0.14.0 + '@solid-primitives/media': + specifier: ^2.2.9 + version: 2.2.9(solid-js@1.9.2) '@solid-primitives/storage': specifier: ^4.2.1 version: 4.2.1(solid-js@1.9.2) @@ -240,6 +255,9 @@ importers: drizzle-orm: specifier: ^0.35.3 version: 0.35.3(@libsql/client-wasm@0.14.0)(@libsql/client@0.14.0)(@types/react@18.3.11)(react@18.3.1) + idb: + specifier: ^8.0.0 + version: 8.0.0 jsonwebtoken: specifier: ^9.0.2 version: 9.0.2 @@ -295,6 +313,9 @@ importers: specifier: ^3.23.8 version: 3.23.8 devDependencies: + '@trivago/prettier-plugin-sort-imports': + specifier: ^4.3.0 + version: 4.3.0(@vue/compiler-sfc@3.5.12)(prettier@2.8.3) '@types/jsonwebtoken': specifier: ^9.0.7 version: 9.0.7 @@ -383,6 +404,10 @@ packages: resolution: {integrity: sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==} engines: {node: '>=6.9.0'} + '@babel/generator@7.17.7': + resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.25.7': resolution: {integrity: sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==} engines: {node: '>=6.9.0'} @@ -401,6 +426,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-environment-visitor@7.24.7': + resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.24.7': + resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.24.7': + resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-member-expression-to-functions@7.25.7': resolution: {integrity: sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==} engines: {node: '>=6.9.0'} @@ -441,6 +478,10 @@ packages: resolution: {integrity: sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==} engines: {node: '>=6.9.0'} + '@babel/helper-split-export-declaration@7.24.7': + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.25.7': resolution: {integrity: sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==} engines: {node: '>=6.9.0'} @@ -538,10 +579,18 @@ packages: resolution: {integrity: sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.23.2': + resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.25.7': resolution: {integrity: sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==} engines: {node: '>=6.9.0'} + '@babel/types@7.17.0': + resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} + engines: {node: '>=6.9.0'} + '@babel/types@7.25.8': resolution: {integrity: sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==} engines: {node: '>=6.9.0'} @@ -1738,6 +1787,22 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + '@ffmpeg/core@0.12.6': + resolution: {integrity: sha512-PrjWBTfGn2WVn9T7wGnzfFwChbqWeZc7tM9vvJZVRadYFUDakfzy7W0LpYC0cvvK0xT82qlBsk38lQhJ/Hps5A==} + engines: {node: '>=16.x'} + + '@ffmpeg/ffmpeg@0.12.10': + resolution: {integrity: sha512-lVtk8PW8e+NUzGZhPTWj2P1J4/NyuCrbDD3O9IGpSeLYtUZKBqZO8CNj1WYGghep/MXoM8e1qVY1GztTkf8YYQ==} + engines: {node: '>=18.x'} + + '@ffmpeg/types@0.12.2': + resolution: {integrity: sha512-NJtxwPoLb60/z1Klv0ueshguWQ/7mNm106qdHkB4HL49LXszjhjCCiL+ldHJGQ9ai2Igx0s4F24ghigy//ERdA==} + engines: {node: '>=16.x'} + + '@ffmpeg/util@0.12.1': + resolution: {integrity: sha512-10jjfAKWaDyb8+nAkijcsi9wgz/y26LOc1NKJradNMyCIl6usQcBbhkjX5qhALrSBcOy6TOeksunTYa+a03qNQ==} + engines: {node: '>=18.x'} + '@floating-ui/core@1.6.8': resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} @@ -2382,6 +2447,15 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} + '@trivago/prettier-plugin-sort-imports@4.3.0': + resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} + peerDependencies: + '@vue/compiler-sfc': 3.x + prettier: 2.x - 3.x + peerDependenciesMeta: + '@vue/compiler-sfc': + optional: true + '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -4370,6 +4444,9 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + idb@8.0.0: + resolution: {integrity: sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw==} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -4534,6 +4611,9 @@ packages: resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==} engines: {node: 20 || >=22} + javascript-natural-sort@0.7.1: + resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} + jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4604,6 +4684,11 @@ packages: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} hasBin: true + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -4689,6 +4774,7 @@ packages: libsql@0.4.6: resolution: {integrity: sha512-F5M+ltteK6dCcpjMahrkgT96uFJvVI8aQ4r9f2AzHQjC7BkAYtvfMSTWGvRBezRgMUIU2h1Sy0pF9nOGOD5iyA==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lilconfig@2.1.0: @@ -6052,6 +6138,10 @@ packages: source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -7104,6 +7194,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/generator@7.17.7': + dependencies: + '@babel/types': 7.25.8 + jsesc: 2.5.2 + source-map: 0.5.7 + '@babel/generator@7.25.7': dependencies: '@babel/types': 7.25.8 @@ -7136,6 +7232,19 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-environment-visitor@7.24.7': + dependencies: + '@babel/types': 7.25.8 + + '@babel/helper-function-name@7.24.7': + dependencies: + '@babel/template': 7.25.7 + '@babel/types': 7.25.8 + + '@babel/helper-hoist-variables@7.24.7': + dependencies: + '@babel/types': 7.25.8 + '@babel/helper-member-expression-to-functions@7.25.7': dependencies: '@babel/traverse': 7.25.7 @@ -7193,6 +7302,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-split-export-declaration@7.24.7': + dependencies: + '@babel/types': 7.25.8 + '@babel/helper-string-parser@7.25.7': {} '@babel/helper-validator-identifier@7.25.7': {} @@ -7309,6 +7422,21 @@ snapshots: '@babel/parser': 7.25.8 '@babel/types': 7.25.8 + '@babel/traverse@7.23.2': + dependencies: + '@babel/code-frame': 7.25.7 + '@babel/generator': 7.25.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/parser': 7.25.8 + '@babel/types': 7.25.8 + debug: 4.3.7 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + '@babel/traverse@7.25.7': dependencies: '@babel/code-frame': 7.25.7 @@ -7321,6 +7449,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/types@7.17.0': + dependencies: + '@babel/helper-validator-identifier': 7.25.7 + to-fast-properties: 2.0.0 + '@babel/types@7.25.8': dependencies: '@babel/helper-string-parser': 7.25.7 @@ -8193,6 +8326,16 @@ snapshots: '@fastify/busboy@2.1.1': {} + '@ffmpeg/core@0.12.6': {} + + '@ffmpeg/ffmpeg@0.12.10': + dependencies: + '@ffmpeg/types': 0.12.2 + + '@ffmpeg/types@0.12.2': {} + + '@ffmpeg/util@0.12.1': {} + '@floating-ui/core@1.6.8': dependencies: '@floating-ui/utils': 0.2.8 @@ -8890,6 +9033,20 @@ snapshots: '@tootallnate/once@2.0.0': {} + '@trivago/prettier-plugin-sort-imports@4.3.0(@vue/compiler-sfc@3.5.12)(prettier@2.8.3)': + dependencies: + '@babel/generator': 7.17.7 + '@babel/parser': 7.25.8 + '@babel/traverse': 7.23.2 + '@babel/types': 7.17.0 + javascript-natural-sort: 0.7.1 + lodash: 4.17.21 + prettier: 2.8.3 + optionalDependencies: + '@vue/compiler-sfc': 3.5.12 + transitivePeerDependencies: + - supports-color + '@trysound/sax@0.2.0': {} '@types/babel__core@7.20.5': @@ -11333,6 +11490,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 + idb@8.0.0: {} + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -11487,6 +11646,8 @@ snapshots: dependencies: '@isaacs/cliui': 8.0.2 + javascript-natural-sort@0.7.1: {} + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -11584,6 +11745,8 @@ snapshots: jsesc@0.5.0: {} + jsesc@2.5.2: {} + jsesc@3.0.2: {} json-buffer@3.0.1: {} @@ -13240,6 +13403,8 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 + source-map@0.5.7: {} + source-map@0.6.1: {} source-map@0.7.4: {}