init
Initial mock up of the app
932
src/App.vue
Normal file
@@ -0,0 +1,932 @@
|
||||
<script setup lang="ts">
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { Slider } from '@/components/ui/slider'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { computed } from 'vue';
|
||||
import { Replace, Type, Cable, KeyboardMusic, Squircle, Keyboard, Bolt, GaugeCircle, AudioLines, AudioWaveform, Binary, Power, Bold, Italic, Underline, FileDigit, FileX } from 'lucide-vue-next'
|
||||
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
|
||||
import { Toggle } from '@/components/ui/toggle'
|
||||
import Pop from '@/components/patterns/Pop.vue'
|
||||
import QuickPreview from '@/components/patterns/QuickPreview.vue'
|
||||
|
||||
import {
|
||||
Menubar,
|
||||
MenubarContent,
|
||||
MenubarItem,
|
||||
MenubarMenu,
|
||||
MenubarSeparator,
|
||||
MenubarShortcut,
|
||||
MenubarTrigger,
|
||||
} from '@/components/ui/menubar'
|
||||
|
||||
import {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from '@/components/ui/command'
|
||||
|
||||
import { ref } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
const state = reactive({ count: 12 });
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Import JSON make it available for all components and views
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
|
||||
<main>
|
||||
|
||||
<div class="w-screen select-none ">
|
||||
<div class="flex">
|
||||
<Menubar class="w-full rounded-none bg-zinc-950">
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Device</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarItem>
|
||||
Disconnect <MenubarShortcut>⌘D</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem>About Device</MenubarItem>
|
||||
<MenubarSeparator />
|
||||
<MenubarItem>Preferences</MenubarItem>
|
||||
<MenubarSeparator />
|
||||
<MenubarItem>Export JSON<MenubarShortcut>⌘E</MenubarShortcut></MenubarItem>
|
||||
<MenubarItem>Export JSON<MenubarShortcut>⌘E</MenubarShortcut></MenubarItem>
|
||||
<MenubarSeparator />
|
||||
<MenubarItem>Quit<MenubarShortcut>⌘Q</MenubarShortcut></MenubarItem>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="border-solid border-0 border-r w-80 flex-none bg-zinc-900 bg-opacity-30">
|
||||
<div>
|
||||
<div class="space-y-1 p-6 pb-0">
|
||||
<h2 class="text-md leading-none">
|
||||
Profiles
|
||||
</h2>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
An open-source UI component library.
|
||||
</p>
|
||||
</div>
|
||||
<Separator class="my-4" />
|
||||
</div>
|
||||
<Pop/>
|
||||
|
||||
</div>
|
||||
<div class="border-0 shrink-0 border-r bg-zinc-900 bg-opacity-30">
|
||||
|
||||
|
||||
<Tabs default-value="haptic-config" orientation="vertical" class="flex flex-row">
|
||||
|
||||
|
||||
<!-- Tab Col 1 -->
|
||||
<div id="tablistmid" class="flex">
|
||||
<TabsList class="flex flex-col px-0 gap-0 w-96 py-0">
|
||||
<div class="flex flex-col">
|
||||
<div class="space-y-1 p-6">
|
||||
<h1 class="leading-none text-lg">
|
||||
Quick Preview
|
||||
</h1>
|
||||
<!-- <p class="text-xs text-muted-foreground">
|
||||
Pre-rendered preview with live feedback from current position.
|
||||
</p> -->
|
||||
</div>
|
||||
<QuickPreview/>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><Bolt class="h-4 w-4" /></div>
|
||||
<div clas="flex-initial"><h2 class="text-sm px-2 py-4">Configuration Options</h2></div>
|
||||
|
||||
</div>
|
||||
|
||||
<TabsTrigger value="prog-config" class="text-left rounded-none border-solid border-t data-[state=active]:bg-zinc-100 data-[state=active]:text-zinc-900 data-[state=active]:ring-none">
|
||||
<div class="p-4">
|
||||
<h1 class="leading-none text-lg">
|
||||
Program Settings
|
||||
</h1>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Operation mode and Profile Naming
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
|
||||
<TabsTrigger value="haptic-config" class="text-left rounded-none border-solid border-t data-[state=active]:bg-zinc-100 data-[state=active]:text-zinc-900 data-[state=active]:ring-none">
|
||||
<div class="p-4">
|
||||
<h1 class="leading-none text-lg pb-1">
|
||||
Feedback Designer
|
||||
</h1>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Feedback mode selector and parameter adjustment
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="map-config" class="text-left rounded-none border-solid border-t data-[state=active]:bg-zinc-100 data-[state=active]:text-zinc-900 data-[state=active]:ring-none">
|
||||
<div class="p-4">
|
||||
<h1 class="leading-none text-lg">
|
||||
Mapping Configuration
|
||||
</h1>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Assign function to Knob and Keys
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
|
||||
|
||||
|
||||
<TabsTrigger value="led-config" class="text-left rounded-none border-solid border-t data-[state=active]:bg-zinc-100 data-[state=active]:text-zinc-900 data-[state=active]:ring-none">
|
||||
<div class="p-4">
|
||||
<h1 class="leading-none text-lg">
|
||||
Light Designer
|
||||
</h1>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Adjust behavior of LED Ring. Turn On/Off.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="gui-config" class="text-left rounded-none border-solid border-t data-[state=active]:bg-zinc-100 data-[state=active]:text-zinc-900 data-[state=active]:ring-none" disabled="true">
|
||||
<div class="p-4">
|
||||
<Badge class="font-mono h-4 mb-1 rounded-full">COMING SOON</badge>
|
||||
<h1 class="leading-none text-muted-foreground text-lg">
|
||||
GUI Designer
|
||||
</h1>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Adjust graphic interface parameters
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
<!-- End Tab Col 1 -->
|
||||
<!-- Tab Col 2 -->
|
||||
<div id="tabcontentend" class="flex border-l-1 border-solid border-l">
|
||||
<TabsContent value="haptic-config" class="mt-0">
|
||||
<div class="w-96 bg-zinc-900 bg-opacity-40">
|
||||
|
||||
<div class="space-y-1 p-6">
|
||||
<h1 class="leading-none text-lg">
|
||||
Feedback Designer
|
||||
</h1>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Create or tune device haptic response
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<Separator/>
|
||||
<ScrollArea class="h-[720px]">
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><GaugeCircle class="h-4 w-4" /></div>
|
||||
<div clas="flex-initial"><h2 class="text-sm px-2 py-4">Feedback Type</h2></div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<Tabs default-value="fd">
|
||||
<TabsList class="grid grid-cols-4 h-auto text-muted-foreground">
|
||||
<TabsTrigger value="fd">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center ">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-fd.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Fine Detents
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="cd">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-cd.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Coarse Detents
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="vr">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-vf.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Viscous Rotation
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="rt">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-rc.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Return to Center
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
</Tabs>
|
||||
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono h-8 text-center">Total Positions</span>
|
||||
|
||||
<div class="flex w-full max-w-sm items-center gap-0">
|
||||
<Button @click="state.count--" type="submit" class="rounded-none text-xl font-pixellg align-middle font-bold">
|
||||
-
|
||||
</Button>
|
||||
<Input id="positions" class="rounded-none border-none text-5xl font-pixellg focus-visible:ring-0" type="number" placeholder="10" max="65535" min="10" v-model="state.count"/>
|
||||
<Button @click="state.count++" type="submit" class="rounded-none text-xl font-pixellg font-bold">
|
||||
+
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><AudioWaveform class="h-4 w-4" /></div>
|
||||
<div class="grow">
|
||||
<h2 class="text-sm px-2 py-4">Haptic Response</h2>
|
||||
</div>
|
||||
<div class="flex-none">
|
||||
<Toggle class="data-[state=on]:ring-emerald-600 data-[state=on]:ring-1" variant="outline" size="sm" defaultValue="true" aria-label="EnablePrimary">
|
||||
<Power class="w-4 h-4" />
|
||||
</Toggle>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Feedback Strength</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Bounce Back Strength</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Output Ramp Dampening</span>
|
||||
<Slider :default-value="[4]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><AudioLines class="h-4 w-4" /></div>
|
||||
<div class="grow"><h2 class="text-sm px-2 py-4"> Auditory Response</h2></div>
|
||||
<div class="flex-none">
|
||||
<Toggle class="data-[state=on]:ring-emerald-600 data-[state=on]:ring-1" variant="outline" size="sm" defaultValue="true" aria-label="EnablePrimary">
|
||||
<Power class="w-4 h-4" />
|
||||
</Toggle>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Auditory Haptic Level</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
|
||||
<span class="text-sm text-muted-foreground font-mono">Auditory Magnitude</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Faint</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-2">Soft</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-7">Medium</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Hard</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<Separator/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="map-config" class="mt-0">
|
||||
<div class="w-96 bg-zinc-900 bg-opacity-40">
|
||||
|
||||
<div class="space-y-1 p-6">
|
||||
<h1 class="leading-none text-lg">
|
||||
Mapping Configuration
|
||||
</h1>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Create or tune device haptic response
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<Separator/>
|
||||
<ScrollArea class="h-[720px]">
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><Keyboard class="h-4 w-4" /></div>
|
||||
<div clas="flex-initial"><h2 class="text-sm px-2 py-4">Key Mapping</h2></div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<Tabs default-value="fd">
|
||||
<TabsList class="grid grid-cols-4 h-auto text-muted-foreground">
|
||||
<TabsTrigger value="fd">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center ">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-key-o.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Switch A
|
||||
<Badge class="bg-orange-400 mt-2">Shift</Badge>
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="cd">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-key.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Switch B
|
||||
<Badge class="bg-zinc-400 mt-2">Fn1</Badge>
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="vr">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-key-g.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Switch C
|
||||
<Badge class="bg-zinc-400 mt-2">Fn2</Badge>
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="rt">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-key-d.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Switch D
|
||||
<Badge class="bg-zinc-400 mt-2">M0</Badge>
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
</Tabs>
|
||||
|
||||
<Separator/>
|
||||
<Command>
|
||||
|
||||
<CommandList>
|
||||
<CommandEmpty>Key or function not found :(
|
||||
|
||||
</CommandEmpty>
|
||||
<CommandInput placeholder="Find Key, Function or Macro..." />
|
||||
<CommandGroup heading="Common">
|
||||
<CommandItem value="backspace">
|
||||
<Squircle color="grey" class="w-4 h-4 mr-2"/> Backspace
|
||||
</CommandItem>
|
||||
<CommandItem value="delete">
|
||||
<Squircle color="grey" class="w-4 h-4 mr-2"/> Delete
|
||||
</CommandItem>
|
||||
<CommandItem value="enter">
|
||||
<Squircle color="grey" class="w-4 h-4 mr-2"/> Enter
|
||||
</CommandItem>
|
||||
<CommandItem value="end">
|
||||
<Squircle color="grey" class="w-4 h-4 mr-2"/> End
|
||||
</CommandItem>
|
||||
<CommandItem value="arrow up">
|
||||
<Squircle color="grey" class="w-4 h-4 mr-2"/> Arrow Up
|
||||
</CommandItem>
|
||||
<CommandItem value="arrow down">
|
||||
<Squircle color="grey" class="w-4 h-4 mr-2"/> Arrow Down
|
||||
</CommandItem>
|
||||
<CommandItem value="arrow left">
|
||||
<Squircle color="grey" class="w-4 h-4 mr-2"/> Arrow Left
|
||||
</CommandItem>
|
||||
<CommandItem value="arrow right">
|
||||
<Squircle color="grey" class="w-4 h-4 mr-2"/> Arrow Right
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="MIDI Control Changes">
|
||||
<CommandItem value="cc0">
|
||||
<KeyboardMusic color="grey" class="w-4 h-4 mr-2"/> Bank Select (CC0)
|
||||
</CommandItem>
|
||||
<CommandItem value="cc2">
|
||||
<KeyboardMusic color="grey" class="w-4 h-4 mr-2"/> Modulation (CC1)
|
||||
</CommandItem>
|
||||
<CommandItem value="cc3">
|
||||
<KeyboardMusic color="grey" class="w-4 h-4 mr-2"/> Foot Controller (CC4)
|
||||
</CommandItem>
|
||||
<CommandItem value="cc4">
|
||||
<KeyboardMusic color="grey" class="w-4 h-4 mr-2"/> Portamento (CC5)
|
||||
</CommandItem>
|
||||
<CommandItem value="cc5">
|
||||
<KeyboardMusic color="grey" class="w-4 h-4 mr-2"/> Volume (CC7)
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandGroup heading="Macros">
|
||||
<CommandItem value="Page Scroll">
|
||||
<Squircle color="grey" class="w-4 h-4 mr-2"/> Page Scroller (M0)
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
<CommandSeparator/>
|
||||
|
||||
</Command>
|
||||
<Separator/>
|
||||
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><GaugeCircle class="h-4 w-4" /></div>
|
||||
<div class="grow">
|
||||
<h2 class="text-sm px-2 py-4">Knob Mapping</h2>
|
||||
</div>
|
||||
<div class="flex-none">
|
||||
<Toggle class="data-[state=on]:ring-emerald-600 data-[state=on]:ring-1" variant="outline" size="sm" defaultValue="true" aria-label="EnablePrimary">
|
||||
<Power class="w-4 h-4" />
|
||||
</Toggle>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Feedback Strength</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Bounce Back Strength</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Output Ramp Dampening</span>
|
||||
<Slider :default-value="[4]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><AudioLines class="h-4 w-4" /></div>
|
||||
<div class="grow"><h2 class="text-sm px-2 py-4"> Auditory Response</h2></div>
|
||||
<div class="flex-none">
|
||||
<Toggle class="data-[state=on]:ring-emerald-600 data-[state=on]:ring-1" variant="outline" size="sm" defaultValue="true" aria-label="EnablePrimary">
|
||||
<Power class="w-4 h-4" />
|
||||
</Toggle>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Auditory Haptic Level</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
|
||||
<span class="text-sm text-muted-foreground font-mono">Auditory Magnitude</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Faint</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-2">Soft</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-7">Medium</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Hard</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<Separator/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="prog-config" class="mt-0">
|
||||
<div class="w-96 bg-zinc-900 bg-opacity-40">
|
||||
|
||||
<div class="space-y-1 p-6">
|
||||
<h1 class="leading-none text-lg">
|
||||
Program Settings
|
||||
</h1>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Create or tune device haptic response
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<Separator/>
|
||||
<ScrollArea class="h-[720px]">
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><Cable class="h-4 w-4" /></div>
|
||||
<div clas="flex-initial"><h2 class="text-sm px-2 py-4">Connection Type</h2></div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<Tabs default-value="fd">
|
||||
<TabsList class="grid grid-cols-2 h-auto text-muted-foreground">
|
||||
<TabsTrigger value="fd">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center ">
|
||||
<div class="w-24 size-w mb-2">
|
||||
<img src="@/assets/gui-ico/ico-usb-logo.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
USB (Virtual HID)
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="cd">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="w-24 size-w mb-2">
|
||||
<img src="@/assets/gui-ico/ico-midi-logo.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Standalone MIDI I/O
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
</Tabs>
|
||||
|
||||
|
||||
<Separator/>
|
||||
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><Type class="h-4 w-4" /></div>
|
||||
<div class="grow">
|
||||
<h2 class="text-sm px-2 py-4">Profile Properties</h2>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<div class="flex flex-col p-8 py-4">
|
||||
<span class="text-sm text-muted-foreground font-mono pb-4">Program Name</span>
|
||||
<Input type="text" placeholder="Program Name" class="text-xl border-0 text-center border-b rounded-none focus-visible:ring-0 focus-visible:border-emerald-500 font-pixelsm uppercase" defaultValue="Oscillator 1" maxlength="20"/>
|
||||
|
||||
<Label for="text" class="text-muted-foreground text-right mt-1 text-xs">16/20</Label>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 py-4">
|
||||
<span class="text-sm text-muted-foreground font-mono pb-4">Program Description</span>
|
||||
<Textarea class="text-lg px-3 bg-inherit text-center focus-visible:outline-none border-b focus-visible:border-emerald-500 resize-none font-pixelsm text-muted-foreground uppercase" placeholder="Program Description" defaultValue="Adjust Korg Oscillator Waveform " rows="2" maxlength="50"/>
|
||||
<Label for="textarea" class="text-muted-foreground text-right mt-1 text-xs">24/50</Label>
|
||||
<div class="flex items-center space-x-4 space-y-1">
|
||||
<Switch id="airplane-mode" defaultChecked="true"/>
|
||||
<Label for="airplane-mode" class="text-xs text-muted-foreground">Show Description in GUI</Label>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><Replace class="h-4 w-4" /></div>
|
||||
<div class="grow"><h2 class="text-sm px-2 py-4">Internal Profile Toggle</h2></div>
|
||||
<div class="flex-none">
|
||||
<Toggle class="data-[state=on]:ring-emerald-600 data-[state=on]:ring-1" variant="outline" size="sm" defaultValue="true" aria-label="EnablePrimary">
|
||||
<Power class="w-4 h-4" />
|
||||
</Toggle>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<p class="flex flex-col p-8 py-4 text-muted-foreground text-xs">
|
||||
Hardcoded macro that allows you to quickly toggle between stored profiles , comes handy if you want to operate device in Standalone mode.
|
||||
<Separator class="mt-4"/>
|
||||
<span class="space-y-4">Operation: <Badge class="bg-orange-500">SHIFT</Badge> + <Badge class="bg-zinc-500">Fn3</Badge> + <Badge>Rotation</Badge></span>
|
||||
<Separator class="my-4"/>
|
||||
<span>Warning: Overrides software defined macro if combination is the same</span>
|
||||
</p>
|
||||
|
||||
|
||||
</ScrollArea>
|
||||
<Separator/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="led-config" class="mt-0">
|
||||
<div class="w-96 bg-zinc-900 bg-opacity-40">
|
||||
|
||||
<div class="space-y-1 p-6">
|
||||
<h1 class="leading-none text-lg">
|
||||
Light Designer
|
||||
</h1>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Create or tune device haptic response
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<Separator/>
|
||||
<ScrollArea class="h-[720px]">
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><GaugeCircle class="h-4 w-4" /></div>
|
||||
<div clas="flex-initial"><h2 class="text-sm px-2 py-4">Feedback Type</h2></div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<Tabs default-value="fd">
|
||||
<TabsList class="grid grid-cols-4 h-auto text-muted-foreground">
|
||||
<TabsTrigger value="fd">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center ">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-fd.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Fine Detents
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="cd">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-cd.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Coarse Detents
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="vr">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-vf.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Viscous Rotation
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="rt">
|
||||
<div class="grid grid-flow-row auto-rows-max justify-items-center">
|
||||
<div class="size-16 mb-2">
|
||||
<img src="@/assets/gui-ico/ico-rc.svg"/>
|
||||
</div>
|
||||
<span class="text-xs leading-3 text-wrap">
|
||||
Return to Center
|
||||
</span>
|
||||
</div>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
</Tabs>
|
||||
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono h-8 text-center">Total Positions</span>
|
||||
|
||||
<div class="flex w-full max-w-sm items-center gap-0">
|
||||
<Button type="submit" class="rounded-l-full text-xl font-mono align-middle font-bold">
|
||||
-
|
||||
</Button>
|
||||
<Input id="positions" class="rounded-none text-xl font-pixellg" type="number" placeholder="10" defaultValue="60" max="65535" min="10"/>
|
||||
<Button type="submit" class="rounded-r-full text-xl font-mono font-bold">
|
||||
+
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><AudioWaveform class="h-4 w-4" /></div>
|
||||
<div class="grow">
|
||||
<h2 class="text-sm px-2 py-4">Haptic Response</h2>
|
||||
</div>
|
||||
<div class="flex-none">
|
||||
<Toggle class="data-[state=on]:ring-emerald-600 data-[state=on]:ring-1" variant="outline" size="sm" defaultValue="true" aria-label="EnablePrimary">
|
||||
<Power class="w-4 h-4" />
|
||||
</Toggle>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Feedback Strength</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Bounce Back Strength</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Output Ramp Dampening</span>
|
||||
<Slider :default-value="[4]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-row h-12 items-center px-4 text-sm bg-zinc-900">
|
||||
|
||||
<div class="flex-none"><AudioLines class="h-4 w-4" /></div>
|
||||
<div class="grow"><h2 class="text-sm px-2 py-4"> Auditory Response</h2></div>
|
||||
<div class="flex-none">
|
||||
<Toggle class="data-[state=on]:ring-emerald-600 data-[state=on]:ring-1" variant="outline" size="sm" defaultValue="true" aria-label="EnablePrimary">
|
||||
<Power class="w-4 h-4" />
|
||||
</Toggle>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
<span class="text-sm text-muted-foreground font-mono">Auditory Haptic Level</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Min</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-4">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-10">|</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Max</div>
|
||||
</div>
|
||||
</div>
|
||||
<Separator/>
|
||||
<div class="flex flex-col p-8 pt-4">
|
||||
|
||||
<span class="text-sm text-muted-foreground font-mono">Auditory Magnitude</span>
|
||||
<Slider :default-value="[2]" :max="4" :step="1" class="pt-4" />
|
||||
<div class="flex flex-row px-1 py-1.5">
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-left">Faint</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-2">Soft</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-3">Default</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono indent-7">Medium</div>
|
||||
<div class="flex-1 text-xs text-muted-foreground font-mono text-right">Hard</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<Separator/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
input[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
124
src/assets/base.css
Normal file
@@ -0,0 +1,124 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 240 10% 3.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 3.9%;
|
||||
|
||||
--primary: 240 5.9% 10%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
|
||||
--secondary: 240 4.8% 95.9%;
|
||||
--secondary-foreground: 240 5.9% 10%;
|
||||
|
||||
--muted: 240 4.8% 95.9%;
|
||||
--muted-foreground: 240 3.8% 46.1%;
|
||||
|
||||
--accent: 240 4.8% 95.9%;
|
||||
--accent-foreground: 240 5.9% 10%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
|
||||
--border: 240 5.9% 90%;
|
||||
--input: 240 5.9% 90%;
|
||||
--ring: 240 10% 3.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 240 10% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
|
||||
--card: 240 10% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
|
||||
--popover: 240 10% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 240 5.9% 10%;
|
||||
|
||||
--secondary: 240 3.7% 15.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
|
||||
--muted: 240 3.7% 15.9%;
|
||||
--muted-foreground: 240 5% 64.9%;
|
||||
|
||||
--accent: 240 3.7% 15.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 3.7% 15.9%;
|
||||
--ring: 240 4.9% 83.9%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'ProtoMono';
|
||||
src: url(gui-fonts/Proto-Mono-Semi-Bold.otf);
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'RenoMono';
|
||||
src: url(gui-fonts/RenoMono.otf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'PixelLg';
|
||||
src: url(gui-fonts/SG12.ttf);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'PixelSm';
|
||||
src: url(gui-fonts/andina.ttf);
|
||||
}
|
||||
|
||||
.font-pixellg{
|
||||
font-family: 'PixelLg';
|
||||
}
|
||||
|
||||
.font-pixelsm{
|
||||
font-family: 'PixelSm';
|
||||
}
|
||||
|
||||
.font-size-gui-extra{
|
||||
font-size: 48px;
|
||||
}
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
@apply font-heading;
|
||||
}
|
||||
|
||||
#scale div{
|
||||
width: 2px;
|
||||
margin-right: 2px;
|
||||
height: 5px;
|
||||
@apply bg-white;
|
||||
}
|
||||
|
||||
#scale div.active{
|
||||
@apply bg-orange-500;
|
||||
}
|
||||
#scale div.current{
|
||||
@apply bg-orange-500;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
BIN
src/assets/favico.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
src/assets/gfx-device/nanod.png
Normal file
|
After Width: | Height: | Size: 250 KiB |
BIN
src/assets/gui-fonts/Proto-Mono-Semi-Bold.otf
Normal file
BIN
src/assets/gui-fonts/RenoMono.otf
Normal file
BIN
src/assets/gui-fonts/SG12.ttf
Normal file
BIN
src/assets/gui-fonts/andina.ttf
Normal file
18
src/assets/gui-ico/ico-cd.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 68 68" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1;">
|
||||
<g transform="matrix(1,0,0,1,-75.1962,-1)">
|
||||
<g id="ico-cd" transform="matrix(1.0546,0,0,1.0625,75.1962,1)">
|
||||
<rect x="0" y="0" width="64.48" height="64" style="fill:none;"/>
|
||||
<g transform="matrix(0.75261,0.536708,-0.54073,0.747012,-499.862,-576.813)">
|
||||
<path d="M852.5,177C866.574,177 878,188.426 878,202.5C878,216.574 866.574,228 852.5,228C838.426,228 827,216.574 827,202.5C827,188.426 838.426,177 852.5,177ZM852.5,179.046C839.556,179.046 829.046,189.556 829.046,202.5C829.046,215.444 839.556,225.954 852.5,225.954C865.444,225.954 875.954,215.444 875.954,202.5C875.954,189.556 865.444,179.046 852.5,179.046Z" style="fill:white;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.374469,0.267045,-0.269046,0.371684,-225.586,-280.493)">
|
||||
<path d="M852.5,182L852.5,192" style="fill:none;stroke:white;stroke-width:4.11px;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.15275,0,0,1.14418,-950.479,-199.696)">
|
||||
<circle cx="852.5" cy="202.5" r="25.5" style="fill:none;stroke:rgb(92,92,92);stroke-width:1.65px;stroke-dasharray:0.66,14.81,0,0,0,0;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
20
src/assets/gui-ico/ico-fd.svg
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 68 68" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1;">
|
||||
<g id="ico-fd" transform="matrix(1.0546,0,0,1.0625,0,0)">
|
||||
<rect x="0" y="0" width="64.48" height="64" style="fill:none;"/>
|
||||
<g transform="matrix(0.946468,0,0,0.939428,-786.455,-170.513)">
|
||||
<g transform="matrix(1.21795,0,0,1.21795,-173.301,-31.064)">
|
||||
<circle cx="852.5" cy="202.5" r="25.5" style="fill:none;stroke:rgb(92,92,92);stroke-width:1.65px;stroke-dasharray:0.66,6.58,0,0,0,0;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.168979,1.20617,-1.20617,0.168979,965.195,-846.907)">
|
||||
<g transform="matrix(0.803922,0,0,0.803922,167.157,39.7059)">
|
||||
<path d="M852.5,177C866.574,177 878,188.426 878,202.5C878,216.574 866.574,228 852.5,228C838.426,228 827,216.574 827,202.5C827,188.426 838.426,177 852.5,177ZM852.5,179.046C839.556,179.046 829.046,189.556 829.046,202.5C829.046,215.444 839.556,225.954 852.5,225.954C865.444,225.954 875.954,215.444 875.954,202.5C875.954,189.556 865.444,179.046 852.5,179.046Z" style="fill:white;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.4,0,0,0.4,511.5,111.2)">
|
||||
<path d="M852.5,182L852.5,192" style="fill:none;stroke:white;stroke-width:4.11px;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
153
src/assets/gui-ico/ico-key-d.svg
Normal file
|
After Width: | Height: | Size: 35 KiB |
153
src/assets/gui-ico/ico-key-g.svg
Normal file
|
After Width: | Height: | Size: 35 KiB |
153
src/assets/gui-ico/ico-key-o.svg
Normal file
|
After Width: | Height: | Size: 35 KiB |
155
src/assets/gui-ico/ico-key.svg
Normal file
|
After Width: | Height: | Size: 35 KiB |
12
src/assets/gui-ico/ico-midi-logo.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 136 68" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-384.443,-1)">
|
||||
<g id="ico-key" transform="matrix(2.10919,0,0,1.0625,384.443,1)">
|
||||
<rect x="0" y="0" width="64.48" height="64" style="fill:none;"/>
|
||||
<g transform="matrix(2.11336,0,0,4.19528,6.87951,-18.3454)">
|
||||
<path d="M21.775,7.517L24,7.517L24,16.483L21.775,16.483L21.775,7.517ZM13.213,7.517L19.719,7.517C20.379,7.517 20.764,8.087 20.764,8.764L20.764,15.371C20.764,16.211 20.414,16.483 19.652,16.483L13.213,16.483L13.213,10.787L15.438,10.787L15.438,14.292L18.573,14.292L18.573,9.54L13.213,9.54L13.213,7.517ZM9.978,7.517L12.168,7.517L12.168,16.483L9.978,16.483L9.978,7.517ZM0,7.517L7.854,7.517C8.514,7.517 8.899,8.087 8.899,8.764L8.899,16.484L6.708,16.484L6.708,9.774L5.427,9.774L5.427,16.482L3.438,16.482L3.438,9.775L2.191,9.775L2.191,16.483L0,16.483L0,7.517Z" style="fill:rgb(235,235,235);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
36
src/assets/gui-ico/ico-rc.svg
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 68 68" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1;">
|
||||
<g transform="matrix(1,0,0,1,-226.869,-1)">
|
||||
<g id="ico-rt" transform="matrix(1.0546,0,0,1.0625,226.869,1)">
|
||||
<rect x="0" y="0" width="64.48" height="64" style="fill:none;"/>
|
||||
<g transform="matrix(0.94823,0,0,0.941176,-1090.41,-171.035)">
|
||||
<g transform="matrix(1.21795,0,0,1.21795,145.641,-30.8525)">
|
||||
<g transform="matrix(0.803922,0,0,0.803922,167.157,39.7059)">
|
||||
<path d="M852.5,177C866.574,177 878,188.426 878,202.5C878,216.574 866.574,228 852.5,228C838.426,228 827,216.574 827,202.5C827,188.426 838.426,177 852.5,177ZM852.5,179.043C839.554,179.043 829.043,189.554 829.043,202.5C829.043,215.446 839.554,225.957 852.5,225.957C865.446,225.957 875.957,215.446 875.957,202.5C875.957,189.554 865.446,179.043 852.5,179.043Z" style="fill:white;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.4,0,0,0.4,511.5,111.2)">
|
||||
<path d="M852.5,182L852.5,192" style="fill:none;stroke:white;stroke-width:4.11px;"/>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="matrix(1.21795,0,0,1.21795,145.641,-30.8525)">
|
||||
<path d="M852.5,177C866.574,177 878,188.426 878,202.5" style="fill:none;stroke:rgb(92,92,92);stroke-width:1.64px;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.21795,0,0,1.21795,145.641,-30.8525)">
|
||||
<path d="M827,202.5C827,188.426 838.426,177 852.5,177" style="fill:none;stroke:rgb(92,92,92);stroke-width:1.64px;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,68.9423,10.7244)">
|
||||
<circle cx="1115" cy="174" r="3" style="fill:rgb(92,92,92);"/>
|
||||
</g>
|
||||
<g transform="matrix(-1.21795,-1.49156e-16,1.49156e-16,-1.21795,2540.13,463.026)">
|
||||
<g transform="matrix(1,0,0,1,261,0)">
|
||||
<path d="M852.5,177C866.574,177 878,188.426 878,202.5" style="fill:none;stroke:rgb(92,92,92);stroke-width:1.64px;stroke-dasharray:0.66,3.28,0,0,0,0;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,261,0)">
|
||||
<path d="M827,202.5C827,188.426 838.426,177 852.5,177" style="fill:none;stroke:rgb(92,92,92);stroke-width:1.64px;stroke-dasharray:0.66,3.28,0,0,0,0;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
12
src/assets/gui-ico/ico-usb-logo.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 136 68" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-534.698,-1)">
|
||||
<g id="ico-usb" transform="matrix(2.10919,0,0,1.0625,534.698,1)">
|
||||
<rect x="0" y="0" width="64.48" height="64" style="fill:none;"/>
|
||||
<g transform="matrix(0.0491017,0,0,0.0974729,14.909,6.75176)">
|
||||
<path d="M641.5,256C641.5,259.1 639.8,262.1 637,263.5L547.9,317C546.5,317.8 545.1,318.4 543.4,318.4C542,318.4 540.3,318.1 538.9,317.3C536.1,315.6 534.4,312.8 534.4,309.5L534.4,273.9L295.7,273.9C321,313.5 336.2,380.8 365.3,380.8L392,380.8L392,354C392,349 395.9,345.1 400.9,345.1L490,345.1C495,345.1 498.9,349 498.9,354L498.9,443.1C498.9,448.1 495,452 490,452L400.9,452C395.9,452 392,448.1 392,443.1L392,416.4L365.3,416.4C289.9,416.4 284.2,273.9 240.6,273.9L140.3,273.9C132.2,304.5 104.4,327.4 71.3,327.4C32,327.3 0,295.3 0,256C0,216.7 32,184.7 71.3,184.7C104.4,184.7 132.3,207.5 140.3,238.2C179.4,238.2 184.2,247.7 214.9,177.8C255,88.7 273,95.7 323.8,95.7C331.3,74.8 350.8,60.1 374.2,60.1C403.7,60.1 427.7,84 427.7,113.6C427.7,143.2 403.8,167.1 374.2,167.1C350.8,167.1 331.3,152.3 323.8,131.5L294,131.5C264.9,131.5 249.7,198.9 224.4,238.4L534.5,238.4L534.5,202.8C534.5,199.5 536.2,196.7 539,195C541.8,193.3 545.4,193.6 547.9,195.3L637,248.8C639.8,249.9 641.5,252.9 641.5,256Z" style="fill:rgb(235,235,235);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
26
src/assets/gui-ico/ico-vf.svg
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 68 68" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1;">
|
||||
<g transform="matrix(1,0,0,1,-151.124,-1)">
|
||||
<g id="ico-vf" transform="matrix(1.0546,0,0,1.0625,151.124,1)">
|
||||
<rect x="0" y="0" width="64.48" height="64" style="fill:none;"/>
|
||||
<g transform="matrix(1,0,0,1,1.89646,1.88235)">
|
||||
<g transform="matrix(-0.939446,0.666736,-0.671733,-0.932458,967.247,-349.452)">
|
||||
<g transform="matrix(0.803922,0,0,0.803922,167.157,39.7059)">
|
||||
<path d="M852.5,177C866.574,177 878,188.426 878,202.5C878,216.574 866.574,228 852.5,228C838.426,228 827,216.574 827,202.5C827,188.426 838.426,177 852.5,177ZM852.5,179.043C839.554,179.043 829.043,189.554 829.043,202.5C829.043,215.446 839.554,225.957 852.5,225.957C865.446,225.957 875.957,215.446 875.957,202.5C875.957,189.554 865.446,179.043 852.5,179.043Z" style="fill:white;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.4,0,0,0.4,511.5,111.2)">
|
||||
<path d="M852.5,182L852.5,192" style="fill:none;stroke:white;stroke-width:4.11px;"/>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="matrix(1.1549,0,0,1.1463,-954.205,-202.009)">
|
||||
<g transform="matrix(0.821053,-0,-0,0.821053,824.584,174.584)">
|
||||
<path d="M37.221,0.181C35.57,0.054 34.127,1.291 34,2.942C33.873,4.593 35.111,6.036 36.762,6.163C38.413,6.29 39.856,5.052 39.982,3.401C40.109,1.75 38.872,0.307 37.221,0.181Z" style="fill:rgb(92,92,92);"/>
|
||||
<path d="M27.788,0.41L34,2.942L28.247,6.392L27.788,0.41Z" style="fill:rgb(92,92,92);"/>
|
||||
<path d="M38.709,3.804C38.437,3.761 38.25,3.506 38.292,3.233C38.334,2.96 38.59,2.773 38.862,2.815C46.467,3.994 53.177,7.89 57.968,13.48C62.699,18.999 65.558,26.168 65.558,34C65.558,42.709 62.023,50.598 56.31,56.31C50.598,62.023 42.709,65.558 34,65.558C25.291,65.558 17.402,62.023 11.69,56.31C5.977,50.598 2.442,42.709 2.442,34C2.442,26.168 5.301,18.999 10.032,13.48C14.823,7.89 21.533,3.994 29.138,2.815C29.41,2.773 29.666,2.96 29.708,3.233C29.75,3.506 29.563,3.761 29.291,3.804C21.928,4.944 15.43,8.718 10.791,14.131C6.211,19.475 3.442,26.417 3.442,34C3.442,42.433 6.865,50.072 12.397,55.603C17.928,61.135 25.567,64.558 34,64.558C42.433,64.558 50.072,61.135 55.603,55.603C61.135,50.072 64.558,42.433 64.558,34C64.558,26.417 61.789,19.475 57.209,14.131C52.57,8.718 46.072,4.944 38.709,3.804Z" style="fill:rgb(92,92,92);"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
40
src/assets/gui-ico/xl-bg-ico.svg
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 301 301" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;">
|
||||
<g transform="matrix(1,0,0,1,-406.435,-188.7)">
|
||||
<g transform="matrix(1,0,0,1,272.791,-68.96)">
|
||||
<g transform="matrix(1.76453,0,0,1.76453,-791.267,-245.177)">
|
||||
<g transform="matrix(0.12,0,0,0.12,0,-54.8614)">
|
||||
<path d="M4811.28,4001.73C5065.82,4147.93 5390.68,4060.11 5536.88,3805.57C5621.18,3658.82 5630.54,3480.7 5562.1,3325.91" style="fill:none;fill-rule:nonzero;stroke:white;stroke-width:2.83px;"/>
|
||||
</g>
|
||||
<g transform="matrix(-0.0800815,-0.0893697,-0.0893697,0.0800815,1472.57,474.872)">
|
||||
<path d="M5288.11,4270.32C5394.91,4235.59 5509.97,4235.59 5616.77,4270.32" style="fill:none;fill-rule:nonzero;stroke:white;stroke-width:2.83px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0,-0.12,-0.12,0,1081.2,979.52)">
|
||||
<path d="M5078,3228.5C4689.47,3228.5 4374.5,3543.47 4374.5,3932C4374.5,4320.53 4689.47,4635.5 5078,4635.5C5466.53,4635.5 5781.5,4320.53 5781.5,3932C5781.5,3543.47 5466.53,3228.5 5078,3228.5" style="fill:none;fill-rule:nonzero;stroke:rgb(92,92,92);stroke-width:2.83px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.12,0,0,0.12,0,-119.458)">
|
||||
<path d="M5342.77,3619.45C5088.89,3472.12 4763.64,3558.49 4616.3,3812.38C4468.97,4066.26 4555.34,4391.52 4809.23,4538.85C4809.91,4539.25 4810.59,4539.64 4811.28,4540.03" style="fill:none;fill-rule:nonzero;stroke:white;stroke-width:2.83px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.12,0,0,0.12,0,-84.1415)">
|
||||
<path d="M4811.23,4245.55C5065.12,4392.88 5390.37,4306.5 5537.7,4052.62C5685.03,3798.73 5598.66,3473.48 5344.77,3326.14C5344.09,3325.75 5343.41,3325.36 5342.73,3324.97" style="fill:none;fill-rule:nonzero;stroke:white;stroke-width:2.83px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0,-0.12,-0.12,0,1081.08,979.16)">
|
||||
<path d="M5076,3420.5C4792.95,3420.5 4563.5,3649.95 4563.5,3933C4563.5,4216.05 4792.95,4445.5 5076,4445.5C5359.05,4445.5 5588.5,4216.05 5588.5,3933C5588.5,3649.95 5359.05,3420.5 5076,3420.5" style="fill-rule:nonzero;stroke:black;stroke-width:2.83px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0,-0.12,-0.12,0,1081.2,979.52)">
|
||||
<path d="M5078,3332C4746.63,3332 4478,3600.63 4478,3932C4478,4263.37 4746.63,4532 5078,4532C5409.37,4532 5678,4263.37 5678,3932C5678,3600.63 5409.37,3332 5078,3332" style="fill:none;fill-rule:nonzero;stroke:rgb(92,92,92);stroke-width:2.83px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0,-0.12,-0.12,0,1081.2,979.52)">
|
||||
<path d="M5078,3374.5C4770.1,3374.5 4520.5,3624.1 4520.5,3932C4520.5,4239.9 4770.1,4489.5 5078,4489.5C5385.9,4489.5 5635.5,4239.9 5635.5,3932C5635.5,3624.1 5385.9,3374.5 5078,3374.5" style="fill:none;fill-rule:nonzero;stroke:rgb(92,92,92);stroke-width:2.83px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0,-0.12,-0.12,0,1081.2,979.52)">
|
||||
<path d="M5078,3318C4738.9,3318 4464,3592.9 4464,3932C4464,4271.1 4738.9,4546 5078,4546C5417.1,4546 5692,4271.1 5692,3932C5692,3592.9 5417.1,3318 5078,3318" style="fill:none;fill-rule:nonzero;stroke:rgb(92,92,92);stroke-width:2.83px;"/>
|
||||
</g>
|
||||
<g transform="matrix(0,-0.12,-0.12,0,1081.2,979.52)">
|
||||
<path d="M5078,3223.5C4686.71,3223.5 4369.5,3540.71 4369.5,3932C4369.5,4323.29 4686.71,4640.5 5078,4640.5C5469.29,4640.5 5786.5,4323.29 5786.5,3932C5786.5,3540.71 5469.29,3223.5 5078,3223.5" style="fill:none;fill-rule:nonzero;stroke:rgb(92,92,92);stroke-width:2.83px;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
79
src/assets/index.css
Normal file
@@ -0,0 +1,79 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
|
||||
--muted: 240 4.8% 95.9%;
|
||||
--muted-foreground: 240 3.8% 46.1%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 3.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 240 10% 3.9%;
|
||||
|
||||
--border: 240 5.9% 90%;
|
||||
--input: 240 5.9% 90%;
|
||||
|
||||
--primary: 240 5.9% 10%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
|
||||
--secondary: 240 4.8% 95.9%;
|
||||
--secondary-foreground: 240 5.9% 10%;
|
||||
|
||||
--accent: 240 4.8% 95.9%;
|
||||
--accent-foreground: 240 5.9% 10%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
|
||||
--ring: 240 10% 3.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 240 10% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
|
||||
--muted: 240 3.7% 15.9%;
|
||||
--muted-foreground: 240 5% 64.9%;
|
||||
|
||||
--popover: 240 10% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
|
||||
--card: 240 10% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 3.7% 15.9%;
|
||||
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 240 5.9% 10%;
|
||||
|
||||
--secondary: 240 3.7% 15.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
|
||||
--accent: 240 3.7% 15.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
|
||||
--ring: 240 4.9% 83.9%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
1
src/assets/logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
||||
|
After Width: | Height: | Size: 276 B |
40
src/assets/main.css
Normal file
@@ -0,0 +1,40 @@
|
||||
@import './base.css';
|
||||
|
||||
#app {
|
||||
|
||||
margin: 0 auto;
|
||||
padding: 0rem 0rem!important;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a,
|
||||
.green {
|
||||
text-decoration: none;
|
||||
color: hsla(160, 100%, 37%, 1);
|
||||
transition: 0.4s;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.text-xs{
|
||||
font-size: 0.625rem;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
a:hover {
|
||||
background-color: hsla(160, 100%, 37%, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
body {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
#app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
}
|
||||
81
src/background.js
Normal file
@@ -0,0 +1,81 @@
|
||||
'use strict'
|
||||
|
||||
import { app, protocol, BrowserWindow } from 'electron'
|
||||
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
|
||||
import installExtension, { VUEJS3_DEVTOOLS } from 'electron-devtools-installer'
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
|
||||
// Scheme must be registered before the app is ready
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: 'app', privileges: { secure: true, standard: true } }
|
||||
])
|
||||
|
||||
async function createWindow() {
|
||||
// Create the browser window.
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
|
||||
// Use pluginOptions.nodeIntegration, leave this alone
|
||||
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
|
||||
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
|
||||
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
|
||||
}
|
||||
})
|
||||
|
||||
if (process.env.WEBPACK_DEV_SERVER_URL) {
|
||||
// Load the url of the dev server if in development mode
|
||||
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
|
||||
if (!process.env.IS_TEST) win.webContents.openDevTools()
|
||||
} else {
|
||||
createProtocol('app')
|
||||
// Load the index.html when not in development
|
||||
win.loadURL('app://./index.html')
|
||||
}
|
||||
}
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', () => {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', async () => {
|
||||
if (isDevelopment && !process.env.IS_TEST) {
|
||||
// Install Vue Devtools
|
||||
try {
|
||||
await installExtension(VUEJS3_DEVTOOLS)
|
||||
} catch (e) {
|
||||
console.error('Vue Devtools failed to install:', e.toString())
|
||||
}
|
||||
}
|
||||
createWindow()
|
||||
})
|
||||
|
||||
// Exit cleanly on request from parent process in development mode.
|
||||
if (isDevelopment) {
|
||||
if (process.platform === 'win32') {
|
||||
process.on('message', (data) => {
|
||||
if (data === 'graceful-exit') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
process.on('SIGTERM', () => {
|
||||
app.quit()
|
||||
})
|
||||
}
|
||||
}
|
||||
7
src/components/icons/IconCommunity.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
7
src/components/icons/IconDocumentation.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
|
||||
<path
|
||||
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
7
src/components/icons/IconEcosystem.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
7
src/components/icons/IconSupport.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
|
||||
<path
|
||||
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
19
src/components/icons/IconTooling.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
class="iconify iconify--mdi"
|
||||
width="24"
|
||||
height="24"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
||||
140
src/components/patterns/Pop.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<script setup>
|
||||
import { FileDigit } from 'lucide-vue-next'
|
||||
import {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from '@/components/ui/command'
|
||||
import { Input } from '@/components/ui/input'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
v-model="defaultName"
|
||||
@keyup.enter="addNewProfile"
|
||||
aria-label="Add Profile"
|
||||
placeholder="add Profile"
|
||||
/>
|
||||
<Command>
|
||||
|
||||
<CommandList>
|
||||
|
||||
<CommandInput placeholder="Search Profile..." />
|
||||
<CommandEmpty>No profile found</CommandEmpty>
|
||||
<CommandGroup v-for="(profileTag, index) in tags" :key="index" :heading="profileTag">
|
||||
<CommandItem class="cursor-pointer" v-for="(name, id, innerIndex) in names(profileTag)" :key="innerIndex" :value="name.id">
|
||||
<FileDigit color="grey" class="w-4 h-4 mr-2"/> {{ name.name }} <span class="text-xs pl-2 text-muted-foreground text-right">uID: {{ name.id }} </span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
<CommandSeparator/>
|
||||
|
||||
</Command>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: "nanoConfig",
|
||||
data() {
|
||||
return {
|
||||
profiles: [],
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
try {
|
||||
const res = await axios.get('http://localhost:3001/profiles');
|
||||
this.profiles = res.data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tags() {
|
||||
const tags = new Set();
|
||||
this.profiles.forEach(tag => tags.add(tag.profileTag));
|
||||
return Array.from(tags);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
names(profileTag) {
|
||||
return this.profiles
|
||||
.filter(tag => tag.profileTag === profileTag)
|
||||
.map(tag => ({name: tag.name, id: tag.id}));
|
||||
},
|
||||
async addNewProfile() {
|
||||
try {
|
||||
const res = await axios.post('http://localhost:3001/profiles',
|
||||
{
|
||||
|
||||
name: this.defaultName,
|
||||
profileTag: "Uncategorized",
|
||||
profileConfig: {
|
||||
profileDesc: "",
|
||||
profileType: 1,
|
||||
showDesc: true,
|
||||
},
|
||||
feedbackConfig: {
|
||||
feedbackEn: true,
|
||||
feedbackType: "fd",
|
||||
multiRev: false,
|
||||
feedbackStrength: 1,
|
||||
endstopStrength: 1,
|
||||
outputRamp: 10000,
|
||||
minMaxPos: [0, 156],
|
||||
secondaryHaptic: true,
|
||||
secondaryVol: 5,
|
||||
},
|
||||
mappingConfig: {
|
||||
internalMacro: false,
|
||||
knobMap: "arrL",
|
||||
switchA: "shift",
|
||||
switchB: "ctrl",
|
||||
switchC: "alt",
|
||||
switchD: "esc",
|
||||
},
|
||||
ledConfig: {
|
||||
ledEnable: true,
|
||||
ledMode: 1,
|
||||
primary: {
|
||||
h: 100,
|
||||
s: 100,
|
||||
l: 100,
|
||||
},
|
||||
secondary: {
|
||||
h: 120,
|
||||
s: 120,
|
||||
l: 120,
|
||||
},
|
||||
pointer: {
|
||||
h: 255,
|
||||
s: 255,
|
||||
l: 255,
|
||||
},
|
||||
},
|
||||
guiConfig: {
|
||||
guiEnable: true,
|
||||
}
|
||||
});
|
||||
|
||||
this.profiles = [...this.profiles, res.data];
|
||||
|
||||
this.defaultName = "";
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
75
src/components/patterns/QuickPreview.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex self-center bg-cover w-72 h-72 mb-7" style="background-image: url(src/assets/gui-ico/xl-bg-ico.svg)">
|
||||
<div v-if="profiles" class="flex flex-col w-full justify-center p-10 rounded-full overflow-hidden">
|
||||
<div class="self-center w-8 mb-1 opacity-50">
|
||||
<img src="@/assets/gui-ico/ico-midi-logo.svg"/>
|
||||
</div>
|
||||
<h2 v-for="feedbackConfig in profiles" class="self-center font-pixellg text-5xl ">{{ feedbackConfig.pos }}</h2>
|
||||
|
||||
<div class="self-center font-pixelsm text-md pt-1 pb-2">{{ profiles.name }}</div>
|
||||
<div id="scales" class="flex self-center text-xs py-0"></div>
|
||||
|
||||
<div v-for="profileConfig in profiles" class="self-center text-center text-muted-foreground font-pixelsm text-xs pt-0.5 w-40">{{ profileConfig.profileDesc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
export default {
|
||||
props: ['id'],
|
||||
name: "nanoConfig",
|
||||
data() {
|
||||
return {
|
||||
profiles: []
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
try {
|
||||
const res = await axios.get('http://localhost:3001/profiles/5867');
|
||||
this.profiles = res.data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// var startPos = 0;
|
||||
// var totalPos = 340;
|
||||
// var currentPos = 156;
|
||||
// var minRange = 0;
|
||||
// var maxRange = 40;
|
||||
|
||||
|
||||
// document.addEventListener("DOMContentLoaded", function(){
|
||||
// //....
|
||||
|
||||
|
||||
|
||||
// // Quick Preview GUI indicator Render
|
||||
// var scale = document.getElementById("scale");
|
||||
|
||||
// Number.prototype.map = function (in_min, in_max, out_min, out_max) {
|
||||
// return (this - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
// }
|
||||
|
||||
// var guiCurrentPos = Math.round(currentPos.map(startPos, totalPos, minRange, maxRange));
|
||||
|
||||
// for(var i = 0; i < 40; i=i+1){
|
||||
// scale.innerHTML += "<div class='bg-white'></div>";
|
||||
// if (i - 1 < guiCurrentPos) {
|
||||
// scale.getElementsByTagName("div")[i].classList.add("active");
|
||||
// if (i == guiCurrentPos) {
|
||||
// scale.getElementsByTagName("div")[guiCurrentPos].classList.add("current");
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
// });
|
||||
</script>
|
||||
22
src/components/ui/accordion/Accordion.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script setup>
|
||||
import { AccordionRoot, useEmitAsProps } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
type: { type: String, required: true },
|
||||
modelValue: { type: [String, Array], required: false },
|
||||
defaultValue: { type: [String, Array], required: false },
|
||||
collapsible: { type: Boolean, required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
dir: { type: String, required: false },
|
||||
orientation: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AccordionRoot v-bind="{ ...props, ...useEmitAsProps(emits) }">
|
||||
<slot />
|
||||
</AccordionRoot>
|
||||
</template>
|
||||
26
src/components/ui/accordion/AccordionContent.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script setup>
|
||||
import { AccordionContent } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AccordionContent
|
||||
v-bind="props"
|
||||
:class="
|
||||
cn(
|
||||
'overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
<div class="pb-4 pt-0">
|
||||
<slot />
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</template>
|
||||
18
src/components/ui/accordion/AccordionItem.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import { AccordionItem } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
disabled: { type: Boolean, required: false },
|
||||
value: { type: String, required: true },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AccordionItem v-bind="props" :class="cn('border-b', props.class ?? '')">
|
||||
<slot />
|
||||
</AccordionItem>
|
||||
</template>
|
||||
30
src/components/ui/accordion/AccordionTrigger.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<script setup>
|
||||
import { AccordionHeader, AccordionTrigger } from "radix-vue";
|
||||
import { ChevronDownIcon } from "@radix-icons/vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AccordionHeader class="flex" as="div">
|
||||
<AccordionTrigger
|
||||
v-bind="props"
|
||||
:class="
|
||||
cn(
|
||||
'flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
<ChevronDownIcon
|
||||
class="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200"
|
||||
/>
|
||||
</AccordionTrigger>
|
||||
</AccordionHeader>
|
||||
</template>
|
||||
4
src/components/ui/accordion/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export { default as Accordion } from "./Accordion.vue";
|
||||
export { default as AccordionContent } from "./AccordionContent.vue";
|
||||
export { default as AccordionItem } from "./AccordionItem.vue";
|
||||
export { default as AccordionTrigger } from "./AccordionTrigger.vue";
|
||||
17
src/components/ui/alert-dialog/AlertDialog.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup>
|
||||
import { AlertDialogRoot, useForwardPropsEmits } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
open: { type: Boolean, required: false },
|
||||
defaultOpen: { type: Boolean, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:open"]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AlertDialogRoot v-bind="forwarded">
|
||||
<slot />
|
||||
</AlertDialogRoot>
|
||||
</template>
|
||||
19
src/components/ui/alert-dialog/AlertDialogAction.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup>
|
||||
import { AlertDialogAction } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AlertDialogAction
|
||||
v-bind="props"
|
||||
:class="cn(buttonVariants(), $attrs.class ?? '')"
|
||||
>
|
||||
<slot />
|
||||
</AlertDialogAction>
|
||||
</template>
|
||||
25
src/components/ui/alert-dialog/AlertDialogCancel.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<script setup>
|
||||
import { AlertDialogCancel } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AlertDialogCancel
|
||||
v-bind="props"
|
||||
:class="
|
||||
cn(
|
||||
buttonVariants({ variant: 'outline' }),
|
||||
'mt-2 sm:mt-0',
|
||||
$attrs.class ?? ''
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</AlertDialogCancel>
|
||||
</template>
|
||||
49
src/components/ui/alert-dialog/AlertDialogContent.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<script setup>
|
||||
import {
|
||||
AlertDialogContent,
|
||||
AlertDialogOverlay,
|
||||
AlertDialogPortal,
|
||||
useEmitAsProps,
|
||||
} from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
forceMount: { type: Boolean, required: false },
|
||||
trapFocus: { type: Boolean, required: false },
|
||||
disableOutsidePointerEvents: { type: Boolean, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
|
||||
const emits = defineEmits([
|
||||
"escapeKeyDown",
|
||||
"pointerDownOutside",
|
||||
"focusOutside",
|
||||
"interactOutside",
|
||||
"dismiss",
|
||||
"openAutoFocus",
|
||||
"closeAutoFocus",
|
||||
]);
|
||||
|
||||
const emitsAsProps = useEmitAsProps(emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay
|
||||
class="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
/>
|
||||
<AlertDialogContent
|
||||
v-bind="{ ...props, ...emitsAsProps }"
|
||||
:class="
|
||||
cn(
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</AlertDialogContent>
|
||||
</AlertDialogPortal>
|
||||
</template>
|
||||
19
src/components/ui/alert-dialog/AlertDialogDescription.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup>
|
||||
import { AlertDialogDescription } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AlertDialogDescription
|
||||
:class="cn('text-muted-foreground text-sm', props.class)"
|
||||
:as-child="props.asChild"
|
||||
>
|
||||
<slot />
|
||||
</AlertDialogDescription>
|
||||
</template>
|
||||
23
src/components/ui/alert-dialog/AlertDialogFooter.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="
|
||||
cn(
|
||||
'flex flex-col space-y-2 sm:space-y-0 mt-3.5 sm:flex-row sm:justify-end sm:space-x-2',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
18
src/components/ui/alert-dialog/AlertDialogHeader.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="cn('flex flex-col space-y-2 text-center sm:text-left', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
19
src/components/ui/alert-dialog/AlertDialogTitle.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup>
|
||||
import { AlertDialogTitle } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AlertDialogTitle
|
||||
:as-child="props.asChild"
|
||||
:class="cn('text-lg text-foreground font-semibold', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</AlertDialogTitle>
|
||||
</template>
|
||||
14
src/components/ui/alert-dialog/AlertDialogTrigger.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { AlertDialogTrigger } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AlertDialogTrigger v-bind="props">
|
||||
<slot />
|
||||
</AlertDialogTrigger>
|
||||
</template>
|
||||
9
src/components/ui/alert-dialog/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
export { default as AlertDialog } from "./AlertDialog.vue";
|
||||
export { default as AlertDialogTrigger } from "./AlertDialogTrigger.vue";
|
||||
export { default as AlertDialogContent } from "./AlertDialogContent.vue";
|
||||
export { default as AlertDialogHeader } from "./AlertDialogHeader.vue";
|
||||
export { default as AlertDialogTitle } from "./AlertDialogTitle.vue";
|
||||
export { default as AlertDialogDescription } from "./AlertDialogDescription.vue";
|
||||
export { default as AlertDialogFooter } from "./AlertDialogFooter.vue";
|
||||
export { default as AlertDialogAction } from "./AlertDialogAction.vue";
|
||||
export { default as AlertDialogCancel } from "./AlertDialogCancel.vue";
|
||||
15
src/components/ui/alert/Alert.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup>
|
||||
import { alertVariants } from ".";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
variant: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn(alertVariants({ variant }), props.class ?? '')">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
13
src/components/ui/alert/AlertDescription.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: String,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('text-sm [&_p]:leading-relaxed', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
13
src/components/ui/alert/AlertTitle.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h5
|
||||
:class="
|
||||
cn('mb-1 font-medium leading-none tracking-tight', $attrs.class ?? '')
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</h5>
|
||||
</template>
|
||||
21
src/components/ui/alert/index.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import { cva } from "class-variance-authority";
|
||||
|
||||
export { default as Alert } from "./Alert.vue";
|
||||
export { default as AlertTitle } from "./AlertTitle.vue";
|
||||
export { default as AlertDescription } from "./AlertDescription.vue";
|
||||
|
||||
export const alertVariants = cva(
|
||||
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-background text-foreground",
|
||||
destructive:
|
||||
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
);
|
||||
14
src/components/ui/badge/Badge.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { badgeVariants } from ".";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
defineProps({
|
||||
variant: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn(badgeVariants({ variant }), $attrs.class ?? '')">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
23
src/components/ui/badge/index.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { cva } from "class-variance-authority";
|
||||
|
||||
export { default as Badge } from "./Badge.vue";
|
||||
|
||||
export const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
);
|
||||
22
src/components/ui/button/Button.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<script setup>
|
||||
import { Primitive } from "radix-vue";
|
||||
import { buttonVariants } from ".";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
defineProps({
|
||||
variant: { type: null, required: false },
|
||||
size: { type: null, required: false },
|
||||
as: { type: String, required: false, default: "button" },
|
||||
asChild: { type: Boolean, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Primitive
|
||||
:as="as"
|
||||
:as-child="asChild"
|
||||
:class="cn(buttonVariants({ variant, size }), $attrs.class ?? '')"
|
||||
>
|
||||
<slot />
|
||||
</Primitive>
|
||||
</template>
|
||||
33
src/components/ui/button/index.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { cva } from "class-variance-authority";
|
||||
|
||||
export { default as Button } from "./Button.vue";
|
||||
|
||||
export const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
);
|
||||
20
src/components/ui/card/Card.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="
|
||||
cn('rounded-lg border bg-card text-card-foreground shadow', props.class)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
16
src/components/ui/card/CardContent.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('p-6 pt-0', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
16
src/components/ui/card/CardDescription.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p :class="cn('text-sm text-muted-foreground', props.class)">
|
||||
<slot />
|
||||
</p>
|
||||
</template>
|
||||
16
src/components/ui/card/CardFooter.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('flex items-center p-6 pt-0', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
16
src/components/ui/card/CardHeader.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('flex flex-col space-y-1.5 p-6', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
16
src/components/ui/card/CardTitle.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h3 :class="cn('font-semibold leading-none tracking-tight', props.class)">
|
||||
<slot />
|
||||
</h3>
|
||||
</template>
|
||||
6
src/components/ui/card/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export { default as Card } from "./Card.vue";
|
||||
export { default as CardHeader } from "./CardHeader.vue";
|
||||
export { default as CardTitle } from "./CardTitle.vue";
|
||||
export { default as CardDescription } from "./CardDescription.vue";
|
||||
export { default as CardContent } from "./CardContent.vue";
|
||||
export { default as CardFooter } from "./CardFooter.vue";
|
||||
42
src/components/ui/checkbox/Checkbox.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script setup>
|
||||
import {
|
||||
CheckboxIndicator,
|
||||
CheckboxRoot,
|
||||
useForwardPropsEmits,
|
||||
} from "radix-vue";
|
||||
import { CheckIcon } from "@radix-icons/vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
defaultChecked: { type: Boolean, required: false },
|
||||
checked: { type: [Boolean, String], required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
required: { type: Boolean, required: false },
|
||||
name: { type: String, required: false },
|
||||
value: { type: String, required: false },
|
||||
id: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:checked"]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CheckboxRoot
|
||||
v-bind="forwarded"
|
||||
:class="
|
||||
cn(
|
||||
'peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
||||
$attrs.class ?? ''
|
||||
)
|
||||
"
|
||||
>
|
||||
<CheckboxIndicator
|
||||
class="flex h-full w-full items-center justify-center text-current"
|
||||
>
|
||||
<CheckIcon class="h-4 w-4" />
|
||||
</CheckboxIndicator>
|
||||
</CheckboxRoot>
|
||||
</template>
|
||||
1
src/components/ui/checkbox/index.js
Normal file
@@ -0,0 +1 @@
|
||||
export { default as Checkbox } from "./Checkbox.vue";
|
||||
21
src/components/ui/collapsible/Collapsible.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup>
|
||||
import { CollapsibleRoot, useEmitAsProps } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
defaultOpen: { type: Boolean, required: false },
|
||||
open: { type: Boolean, required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:open"]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CollapsibleRoot
|
||||
v-slot="{ open }"
|
||||
v-bind="{ ...props, ...useEmitAsProps(emits) }"
|
||||
>
|
||||
<slot :open="open" />
|
||||
</CollapsibleRoot>
|
||||
</template>
|
||||
18
src/components/ui/collapsible/CollapsibleContent.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import { CollapsibleContent } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
forceMount: { type: Boolean, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CollapsibleContent
|
||||
v-bind="props"
|
||||
class="overflow-hidden transition-all data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down"
|
||||
>
|
||||
<slot />
|
||||
</CollapsibleContent>
|
||||
</template>
|
||||
14
src/components/ui/collapsible/CollapsibleTrigger.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { CollapsibleTrigger } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CollapsibleTrigger v-bind="props">
|
||||
<slot />
|
||||
</CollapsibleTrigger>
|
||||
</template>
|
||||
3
src/components/ui/collapsible/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as Collapsible } from "./Collapsible.vue";
|
||||
export { default as CollapsibleTrigger } from "./CollapsibleTrigger.vue";
|
||||
export { default as CollapsibleContent } from "./CollapsibleContent.vue";
|
||||
42
src/components/ui/command/Command.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script setup>
|
||||
import { ComboboxRoot, useForwardPropsEmits } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: null, required: false },
|
||||
defaultValue: { type: null, required: false },
|
||||
open: { type: Boolean, required: false },
|
||||
defaultOpen: { type: Boolean, required: false },
|
||||
searchTerm: { type: String, required: false },
|
||||
multiple: { type: Boolean, required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
name: { type: String, required: false },
|
||||
dir: { type: String, required: false },
|
||||
filterFunction: { type: Function, required: false },
|
||||
displayValue: { type: Function, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
const emits = defineEmits([
|
||||
"update:modelValue",
|
||||
"update:open",
|
||||
"update:searchTerm",
|
||||
]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxRoot
|
||||
v-bind="forwarded"
|
||||
:open="true"
|
||||
:class="
|
||||
cn(
|
||||
'flex h-full w-full flex-col overflow-hidden rounded-md text-popover-foreground',
|
||||
$attrs.class ?? ''
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxRoot>
|
||||
</template>
|
||||
26
src/components/ui/command/CommandDialog.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script setup>
|
||||
import { useEmitAsProps } from "radix-vue";
|
||||
import Command from "./Command.vue";
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog";
|
||||
|
||||
const props = defineProps({
|
||||
open: { type: Boolean, required: false },
|
||||
defaultOpen: { type: Boolean, required: false },
|
||||
modal: { type: Boolean, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:open"]);
|
||||
|
||||
const emitsAsProps = useEmitAsProps(emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-bind="{ ...props, ...emitsAsProps }">
|
||||
<DialogContent class="overflow-hidden p-0 shadow-lg">
|
||||
<Command
|
||||
class="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"
|
||||
>
|
||||
<slot />
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
18
src/components/ui/command/CommandEmpty.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import { ComboboxEmpty } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxEmpty
|
||||
v-bind="props"
|
||||
:class="cn('py-6 text-center text-sm', $attrs.class ?? '')"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxEmpty>
|
||||
</template>
|
||||
25
src/components/ui/command/CommandGroup.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<script setup>
|
||||
import { ComboboxGroup, ComboboxLabel } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
heading: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxGroup
|
||||
v-bind="props"
|
||||
:class="cn('overflow-hidden p-1 text-foreground', $attrs.class ?? '')"
|
||||
>
|
||||
<ComboboxLabel
|
||||
v-if="heading"
|
||||
class="px-2 py-1.5 text-xs font-medium text-muted-foreground"
|
||||
>
|
||||
{{ heading }}
|
||||
</ComboboxLabel>
|
||||
<slot />
|
||||
</ComboboxGroup>
|
||||
</template>
|
||||
35
src/components/ui/command/CommandInput.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<script setup>
|
||||
import { MagnifyingGlassIcon } from "@radix-icons/vue";
|
||||
import { ComboboxInput } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
type: { type: String, required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
autoFocus: { type: Boolean, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center border-b px-3" cmdk-input-wrapper>
|
||||
<MagnifyingGlassIcon class="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<ComboboxInput
|
||||
v-bind="{ ...props, ...$attrs }"
|
||||
auto-focus
|
||||
:class="
|
||||
cn(
|
||||
'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
|
||||
$attrs.class ?? ''
|
||||
)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
30
src/components/ui/command/CommandItem.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<script setup>
|
||||
import { ComboboxItem, useEmitAsProps } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
value: { type: null, required: true },
|
||||
disabled: { type: Boolean, required: false },
|
||||
textValue: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
const emits = defineEmits(["select"]);
|
||||
|
||||
const emitsAsProps = useEmitAsProps(emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxItem
|
||||
v-bind="{ ...props, ...emitsAsProps }"
|
||||
:class="
|
||||
cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
$attrs.class ?? ''
|
||||
)
|
||||
"
|
||||
@select.prevent
|
||||
>
|
||||
<slot />
|
||||
</ComboboxItem>
|
||||
</template>
|
||||
48
src/components/ui/command/CommandList.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<script setup>
|
||||
import { ComboboxContent, useForwardPropsEmits } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
forceMount: { type: Boolean, required: false },
|
||||
position: { type: String, required: false },
|
||||
bodyLock: { type: Boolean, required: false },
|
||||
disableOutsidePointerEvents: { type: Boolean, required: false },
|
||||
side: { type: null, required: false },
|
||||
sideOffset: { type: Number, required: false },
|
||||
align: { type: null, required: false },
|
||||
alignOffset: { type: Number, required: false },
|
||||
avoidCollisions: { type: Boolean, required: false },
|
||||
collisionBoundary: { type: null, required: false },
|
||||
collisionPadding: { type: [Number, Object], required: false },
|
||||
arrowPadding: { type: Number, required: false },
|
||||
sticky: { type: String, required: false },
|
||||
hideWhenDetached: { type: Boolean, required: false },
|
||||
updatePositionStrategy: { type: String, required: false },
|
||||
onPlaced: { type: Function, required: false },
|
||||
prioritizePosition: { type: Boolean, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
const emits = defineEmits([
|
||||
"escapeKeyDown",
|
||||
"pointerDownOutside",
|
||||
"focusOutside",
|
||||
"interactOutside",
|
||||
"dismiss",
|
||||
]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxContent
|
||||
v-bind="forwarded"
|
||||
:class="
|
||||
cn('max-h-[500px] max-h-full overflow-y-auto overflow-x-hidden', $attrs.class ?? '')
|
||||
"
|
||||
>
|
||||
<div role="presentation">
|
||||
<slot />
|
||||
</div>
|
||||
</ComboboxContent>
|
||||
</template>
|
||||
18
src/components/ui/command/CommandSeparator.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import { ComboboxSeparator } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxSeparator
|
||||
v-bind="props"
|
||||
:class="cn('-mx-1 h-px bg-border', $attrs.class ?? '')"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxSeparator>
|
||||
</template>
|
||||
16
src/components/ui/command/CommandShortcut.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
:class="
|
||||
cn(
|
||||
'ml-auto text-xs tracking-widest text-muted-foreground',
|
||||
$attrs.class ?? ''
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
</template>
|
||||
9
src/components/ui/command/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
export { default as Command } from "./Command.vue";
|
||||
export { default as CommandDialog } from "./CommandDialog.vue";
|
||||
export { default as CommandEmpty } from "./CommandEmpty.vue";
|
||||
export { default as CommandGroup } from "./CommandGroup.vue";
|
||||
export { default as CommandInput } from "./CommandInput.vue";
|
||||
export { default as CommandItem } from "./CommandItem.vue";
|
||||
export { default as CommandList } from "./CommandList.vue";
|
||||
export { default as CommandSeparator } from "./CommandSeparator.vue";
|
||||
export { default as CommandShortcut } from "./CommandShortcut.vue";
|
||||
17
src/components/ui/context-menu/ContextMenu.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup>
|
||||
import { ContextMenuRoot, useForwardPropsEmits } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
dir: { type: String, required: false },
|
||||
modal: { type: Boolean, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:open"]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuRoot v-bind="forwarded">
|
||||
<slot />
|
||||
</ContextMenuRoot>
|
||||
</template>
|
||||
40
src/components/ui/context-menu/ContextMenuCheckboxItem.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<script setup>
|
||||
import {
|
||||
ContextMenuCheckboxItem,
|
||||
ContextMenuItemIndicator,
|
||||
useEmitAsProps,
|
||||
} from "radix-vue";
|
||||
import { CheckIcon } from "@radix-icons/vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
checked: { type: [Boolean, String], required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
textValue: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
const emits = defineEmits(["select", "update:checked"]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuCheckboxItem
|
||||
v-bind="{ ...props, ...useEmitAsProps(emits) }"
|
||||
:class="[
|
||||
cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
props.class
|
||||
),
|
||||
]"
|
||||
>
|
||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<ContextMenuItemIndicator
|
||||
class="absolute left-1.5 inline-flex w-4 h-4 items-center justify-center"
|
||||
>
|
||||
<CheckIcon class="h-4 w-4" />
|
||||
</ContextMenuItemIndicator>
|
||||
</span>
|
||||
<slot />
|
||||
</ContextMenuCheckboxItem>
|
||||
</template>
|
||||
51
src/components/ui/context-menu/ContextMenuContent.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<script setup>
|
||||
import {
|
||||
ContextMenuContent,
|
||||
ContextMenuPortal,
|
||||
useForwardPropsEmits,
|
||||
} from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
forceMount: { type: Boolean, required: false },
|
||||
loop: { type: Boolean, required: false },
|
||||
alignOffset: { type: Number, required: false },
|
||||
avoidCollisions: { type: Boolean, required: false },
|
||||
collisionBoundary: { type: null, required: false },
|
||||
collisionPadding: { type: [Number, Object], required: false },
|
||||
sticky: { type: String, required: false },
|
||||
hideWhenDetached: { type: Boolean, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
const emits = defineEmits([
|
||||
"escapeKeyDown",
|
||||
"pointerDownOutside",
|
||||
"focusOutside",
|
||||
"interactOutside",
|
||||
"dismiss",
|
||||
"entryFocus",
|
||||
"openAutoFocus",
|
||||
"closeAutoFocus",
|
||||
]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuPortal>
|
||||
<ContextMenuContent
|
||||
:align-offset="props.alignOffset"
|
||||
:class="[
|
||||
cn(
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
props.class
|
||||
),
|
||||
]"
|
||||
v-bind="forwarded"
|
||||
>
|
||||
<slot />
|
||||
</ContextMenuContent>
|
||||
</ContextMenuPortal>
|
||||
</template>
|
||||
14
src/components/ui/context-menu/ContextMenuGroup.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { ContextMenuGroup } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuGroup v-bind="props">
|
||||
<slot />
|
||||
</ContextMenuGroup>
|
||||
</template>
|
||||
29
src/components/ui/context-menu/ContextMenuItem.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup>
|
||||
import { ContextMenuItem, useEmitAsProps } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
disabled: { type: Boolean, required: false },
|
||||
textValue: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
inset: { type: Boolean, required: false },
|
||||
});
|
||||
const emits = defineEmits(["select"]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuItem
|
||||
v-bind="{ ...props, ...useEmitAsProps(emits) }"
|
||||
:class="[
|
||||
cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
inset && 'pl-8',
|
||||
props.class
|
||||
),
|
||||
]"
|
||||
>
|
||||
<slot />
|
||||
</ContextMenuItem>
|
||||
</template>
|
||||
26
src/components/ui/context-menu/ContextMenuLabel.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script setup>
|
||||
import { ContextMenuLabel } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
inset: { type: Boolean, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuLabel
|
||||
v-bind="props"
|
||||
:class="
|
||||
cn(
|
||||
'px-2 py-1.5 text-sm font-semibold text-foreground',
|
||||
inset && 'pl-8',
|
||||
props.class ?? ''
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</ContextMenuLabel>
|
||||
</template>
|
||||
15
src/components/ui/context-menu/ContextMenuPortal.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup>
|
||||
import { ContextMenuPortal } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
to: { type: null, required: false },
|
||||
disabled: { type: Boolean, required: false },
|
||||
forceMount: { type: Boolean, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuPortal v-bind="props">
|
||||
<slot />
|
||||
</ContextMenuPortal>
|
||||
</template>
|
||||
18
src/components/ui/context-menu/ContextMenuRadioGroup.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import { ContextMenuRadioGroup, useForwardPropsEmits } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuRadioGroup v-bind="forwarded">
|
||||
<slot />
|
||||
</ContextMenuRadioGroup>
|
||||
</template>
|
||||
40
src/components/ui/context-menu/ContextMenuRadioItem.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<script setup>
|
||||
import {
|
||||
ContextMenuItemIndicator,
|
||||
ContextMenuRadioItem,
|
||||
useForwardPropsEmits,
|
||||
} from "radix-vue";
|
||||
import { DotFilledIcon } from "@radix-icons/vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
value: { type: String, required: true },
|
||||
disabled: { type: Boolean, required: false },
|
||||
textValue: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
const emits = defineEmits(["select"]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuRadioItem
|
||||
v-bind="forwarded"
|
||||
:class="[
|
||||
cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
props.class
|
||||
),
|
||||
]"
|
||||
>
|
||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<ContextMenuItemIndicator>
|
||||
<DotFilledIcon class="h-4 w-4 fill-current" />
|
||||
</ContextMenuItemIndicator>
|
||||
</span>
|
||||
<slot />
|
||||
</ContextMenuRadioItem>
|
||||
</template>
|
||||
16
src/components/ui/context-menu/ContextMenuSeparator.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
import { ContextMenuSeparator } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuSeparator
|
||||
v-bind="props"
|
||||
:class="cn('-mx-1 my-1 h-px bg-border', $attrs.class ?? '')"
|
||||
/>
|
||||
</template>
|
||||
16
src/components/ui/context-menu/ContextMenuShortcut.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
:class="
|
||||
cn(
|
||||
'ml-auto text-xs tracking-widest text-muted-foreground',
|
||||
$attrs.class ?? ''
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
</template>
|
||||
17
src/components/ui/context-menu/ContextMenuSub.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup>
|
||||
import { ContextMenuSub, useForwardPropsEmits } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
open: { type: Boolean, required: false },
|
||||
defaultOpen: { type: Boolean, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:open"]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuSub v-bind="forwarded">
|
||||
<slot />
|
||||
</ContextMenuSub>
|
||||
</template>
|
||||
53
src/components/ui/context-menu/ContextMenuSubContent.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<script setup>
|
||||
import { ContextMenuSubContent, useForwardPropsEmits } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
forceMount: { type: Boolean, required: false },
|
||||
loop: { type: Boolean, required: false },
|
||||
disableOutsidePointerEvents: { type: Boolean, required: false },
|
||||
disableOutsideScroll: { type: Boolean, required: false },
|
||||
trapFocus: { type: Boolean, required: false },
|
||||
side: { type: null, required: false },
|
||||
sideOffset: { type: Number, required: false },
|
||||
align: { type: null, required: false },
|
||||
alignOffset: { type: Number, required: false },
|
||||
avoidCollisions: { type: Boolean, required: false },
|
||||
collisionBoundary: { type: null, required: false },
|
||||
collisionPadding: { type: [Number, Object], required: false },
|
||||
arrowPadding: { type: Number, required: false },
|
||||
sticky: { type: String, required: false },
|
||||
hideWhenDetached: { type: Boolean, required: false },
|
||||
updatePositionStrategy: { type: String, required: false },
|
||||
prioritizePosition: { type: Boolean, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
const emits = defineEmits([
|
||||
"escapeKeyDown",
|
||||
"pointerDownOutside",
|
||||
"focusOutside",
|
||||
"interactOutside",
|
||||
"dismiss",
|
||||
"entryFocus",
|
||||
"openAutoFocus",
|
||||
"closeAutoFocus",
|
||||
]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuSubContent
|
||||
v-bind="forwarded"
|
||||
:class="
|
||||
cn(
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</ContextMenuSubContent>
|
||||
</template>
|
||||
30
src/components/ui/context-menu/ContextMenuSubTrigger.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<script setup>
|
||||
import { ContextMenuSubTrigger } from "radix-vue";
|
||||
import { ChevronRightIcon } from "@radix-icons/vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
disabled: { type: Boolean, required: false },
|
||||
textValue: { type: String, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
inset: { type: Boolean, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuSubTrigger
|
||||
v-bind="props"
|
||||
:class="[
|
||||
cn(
|
||||
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
|
||||
inset && 'pl-8',
|
||||
props.class
|
||||
),
|
||||
]"
|
||||
>
|
||||
<slot />
|
||||
<ChevronRightIcon class="ml-auto h-4 w-4" />
|
||||
</ContextMenuSubTrigger>
|
||||
</template>
|
||||
15
src/components/ui/context-menu/ContextMenuTrigger.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup>
|
||||
import { ContextMenuTrigger } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
disabled: { type: Boolean, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ContextMenuTrigger v-bind="props">
|
||||
<slot />
|
||||
</ContextMenuTrigger>
|
||||
</template>
|
||||
14
src/components/ui/context-menu/index.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export { default as ContextMenu } from "./ContextMenu.vue";
|
||||
export { default as ContextMenuTrigger } from "./ContextMenuTrigger.vue";
|
||||
export { default as ContextMenuContent } from "./ContextMenuContent.vue";
|
||||
export { default as ContextMenuGroup } from "./ContextMenuGroup.vue";
|
||||
export { default as ContextMenuRadioGroup } from "./ContextMenuRadioGroup.vue";
|
||||
export { default as ContextMenuItem } from "./ContextMenuItem.vue";
|
||||
export { default as ContextMenuCheckboxItem } from "./ContextMenuCheckboxItem.vue";
|
||||
export { default as ContextMenuRadioItem } from "./ContextMenuRadioItem.vue";
|
||||
export { default as ContextMenuShortcut } from "./ContextMenuShortcut.vue";
|
||||
export { default as ContextMenuSeparator } from "./ContextMenuSeparator.vue";
|
||||
export { default as ContextMenuLabel } from "./ContextMenuLabel.vue";
|
||||
export { default as ContextMenuSub } from "./ContextMenuSub.vue";
|
||||
export { default as ContextMenuSubTrigger } from "./ContextMenuSubTrigger.vue";
|
||||
export { default as ContextMenuSubContent } from "./ContextMenuSubContent.vue";
|
||||
18
src/components/ui/dialog/Dialog.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import { DialogRoot, useForwardPropsEmits } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
open: { type: Boolean, required: false },
|
||||
defaultOpen: { type: Boolean, required: false },
|
||||
modal: { type: Boolean, required: false },
|
||||
});
|
||||
const emits = defineEmits(["update:open"]);
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogRoot v-bind="forwarded">
|
||||
<slot />
|
||||
</DialogRoot>
|
||||
</template>
|
||||
14
src/components/ui/dialog/DialogClose.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { DialogClose } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogClose v-bind="props">
|
||||
<slot />
|
||||
</DialogClose>
|
||||
</template>
|
||||
57
src/components/ui/dialog/DialogContent.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<script setup>
|
||||
import {
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogOverlay,
|
||||
DialogPortal,
|
||||
useEmitAsProps,
|
||||
} from "radix-vue";
|
||||
import { Cross2Icon } from "@radix-icons/vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
forceMount: { type: Boolean, required: false },
|
||||
trapFocus: { type: Boolean, required: false },
|
||||
disableOutsidePointerEvents: { type: Boolean, required: false },
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
const emits = defineEmits([
|
||||
"escapeKeyDown",
|
||||
"pointerDownOutside",
|
||||
"focusOutside",
|
||||
"interactOutside",
|
||||
"dismiss",
|
||||
"openAutoFocus",
|
||||
"closeAutoFocus",
|
||||
]);
|
||||
|
||||
const emitsAsProps = useEmitAsProps(emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogPortal>
|
||||
<DialogOverlay
|
||||
class="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||
/>
|
||||
<DialogContent
|
||||
:class="
|
||||
cn(
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
v-bind="{ ...props, ...emitsAsProps }"
|
||||
>
|
||||
<slot />
|
||||
|
||||
<DialogClose
|
||||
class="absolute top-4 right-4 p-0.5 transition-colors rounded-md hover:bg-secondary"
|
||||
>
|
||||
<Cross2Icon class="w-4 h-4" />
|
||||
<span class="sr-only">Close</span>
|
||||
</DialogClose>
|
||||
</DialogContent>
|
||||
</DialogPortal>
|
||||
</template>
|
||||
19
src/components/ui/dialog/DialogDescription.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup>
|
||||
import { DialogDescription } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogDescription
|
||||
v-bind="props"
|
||||
:class="cn('text-muted-foreground text-sm', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</DialogDescription>
|
||||
</template>
|
||||
20
src/components/ui/dialog/DialogFooter.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="
|
||||
cn(
|
||||
'flex flex-col space-y-2 sm:space-y-0 mt-1.5 sm:flex-row sm:justify-end sm:space-x-2',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
15
src/components/ui/dialog/DialogHeader.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup>
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="cn('flex flex-col space-y-2 text-center sm:text-left', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
24
src/components/ui/dialog/DialogTitle.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<script setup>
|
||||
import { DialogTitle } from "radix-vue";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
class: { type: String, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogTitle
|
||||
v-bind="props"
|
||||
:class="
|
||||
cn(
|
||||
'text-lg text-foreground font-semibold leading-none tracking-tight',
|
||||
props.class
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</DialogTitle>
|
||||
</template>
|
||||
14
src/components/ui/dialog/DialogTrigger.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
import { DialogTrigger } from "radix-vue";
|
||||
|
||||
const props = defineProps({
|
||||
asChild: { type: Boolean, required: false },
|
||||
as: { type: null, required: false },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogTrigger v-bind="props">
|
||||
<slot />
|
||||
</DialogTrigger>
|
||||
</template>
|
||||