199 lines
6.5 KiB
TypeScript
199 lines
6.5 KiB
TypeScript
|
|
import { Input } from '@/components/ui/input'
|
||
|
|
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'
|
||
|
|
import { Separator } from '@/components/ui/separator'
|
||
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||
|
|
import { TooltipProvider } from '@/components/ui/tooltip'
|
||
|
|
import { cn } from '@/lib/utils'
|
||
|
|
import { type Recipe01, type Recipes } from '@/models/recipe/schema'
|
||
|
|
import { memo, useMemo, useState } from 'react'
|
||
|
|
import AndroidSwitcher from './android-switcher'
|
||
|
|
import { Search, CupSoda, Wheat, Dessert, Cherry, WineOff } from 'lucide-react'
|
||
|
|
import Nav from './nav'
|
||
|
|
import RecipeList from './recipe-list'
|
||
|
|
import { isBefore, isToday } from 'date-fns'
|
||
|
|
import RecipeDisplay from './recipe-display'
|
||
|
|
|
||
|
|
interface RecipeMenuProps {
|
||
|
|
recipes: Recipes
|
||
|
|
recipe01: Recipe01[]
|
||
|
|
defaultSize?: number
|
||
|
|
isDevBranch: boolean
|
||
|
|
}
|
||
|
|
const RecipeMenu: React.FC<RecipeMenuProps> = memo(({ recipes, recipe01, defaultSize, isDevBranch }) => {
|
||
|
|
recipe01 = useMemo(() => {
|
||
|
|
return recipe01.sort((a, b) => (a.LastChange && b.LastChange && isBefore(a.LastChange, b.LastChange) ? 1 : -1))
|
||
|
|
}, [recipe01])
|
||
|
|
|
||
|
|
return (
|
||
|
|
<>
|
||
|
|
<ResizablePanel defaultSize={defaultSize} minSize={30}>
|
||
|
|
<Tabs defaultValue="all">
|
||
|
|
<div className="flex items-center px-4 py-2">
|
||
|
|
<h1 className="text-xl font-bold">
|
||
|
|
Recipe Version: {recipes.MachineSetting.configNumber} {isDevBranch ? '(Dev)' : ''}
|
||
|
|
</h1>
|
||
|
|
<TabsList className="ml-auto">
|
||
|
|
<TabsTrigger value="all" className="text-zinc-600 dark:text-zinc-200">
|
||
|
|
All Menu
|
||
|
|
</TabsTrigger>
|
||
|
|
<TabsTrigger value="today" className="text-zinc-600 dark:text-zinc-200">
|
||
|
|
Today
|
||
|
|
</TabsTrigger>
|
||
|
|
</TabsList>
|
||
|
|
</div>
|
||
|
|
<Separator />
|
||
|
|
<div className="bg-background/95 p-4 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
||
|
|
<form>
|
||
|
|
<div className="relative">
|
||
|
|
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
|
||
|
|
<Input placeholder="Search" className="pl-8" />
|
||
|
|
</div>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
<TabsContent value="all" className="m-0">
|
||
|
|
<RecipeList items={recipe01} />
|
||
|
|
</TabsContent>
|
||
|
|
<TabsContent value="today" className="m-0">
|
||
|
|
<RecipeList items={recipe01.filter(item => item.LastChange && isToday(item.LastChange))} />
|
||
|
|
</TabsContent>
|
||
|
|
</Tabs>
|
||
|
|
</ResizablePanel>
|
||
|
|
<ResizableHandle withHandle />
|
||
|
|
<ResizablePanel defaultSize={defaultSize}>
|
||
|
|
<RecipeDisplay recipes={recipes} />
|
||
|
|
</ResizablePanel>
|
||
|
|
</>
|
||
|
|
)
|
||
|
|
})
|
||
|
|
|
||
|
|
interface RecipeEditorProps {
|
||
|
|
androids: {
|
||
|
|
label: string
|
||
|
|
deviceName: string
|
||
|
|
serial: string
|
||
|
|
icon: React.ReactNode
|
||
|
|
}[]
|
||
|
|
isDevBranch: boolean
|
||
|
|
recipes: Recipes
|
||
|
|
defaultLayout: number[] | undefined
|
||
|
|
defaultCollapsed?: boolean
|
||
|
|
navCollapsedSize: number
|
||
|
|
}
|
||
|
|
|
||
|
|
export const RecipeEditor: React.FC<RecipeEditorProps> = ({
|
||
|
|
androids,
|
||
|
|
recipes,
|
||
|
|
isDevBranch,
|
||
|
|
defaultLayout = [265, 440, 655],
|
||
|
|
defaultCollapsed = false,
|
||
|
|
navCollapsedSize
|
||
|
|
}) => {
|
||
|
|
const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed)
|
||
|
|
|
||
|
|
const [showListIndex, setShowListIndex] = useState(0)
|
||
|
|
|
||
|
|
const { recipesEnable, recipeDisable } = useMemo(() => {
|
||
|
|
return {
|
||
|
|
recipesEnable: recipes.Recipe01.filter(r => r.isUse),
|
||
|
|
recipeDisable: recipes.Recipe01.filter(r => !r.isUse)
|
||
|
|
}
|
||
|
|
}, [recipes])
|
||
|
|
|
||
|
|
return (
|
||
|
|
<TooltipProvider delayDuration={0}>
|
||
|
|
<ResizablePanelGroup
|
||
|
|
direction="horizontal"
|
||
|
|
onLayout={(sizes: number[]) => {
|
||
|
|
document.cookie = `react-resizable-panels:layout=${JSON.stringify(sizes)}`
|
||
|
|
}}
|
||
|
|
className="h-full max-h-[800px] items-stretch"
|
||
|
|
>
|
||
|
|
<ResizablePanel
|
||
|
|
defaultSize={defaultLayout[0]}
|
||
|
|
collapsedSize={navCollapsedSize}
|
||
|
|
collapsible={true}
|
||
|
|
minSize={15}
|
||
|
|
maxSize={20}
|
||
|
|
onCollapse={() => {
|
||
|
|
setIsCollapsed(true)
|
||
|
|
document.cookie = `react-resizable-panels:collapsed=${JSON.stringify(true)}`
|
||
|
|
}}
|
||
|
|
onExpand={() => {
|
||
|
|
setIsCollapsed(false)
|
||
|
|
document.cookie = `react-resizable-panels:collapsed=${JSON.stringify(false)}`
|
||
|
|
}}
|
||
|
|
className={cn(isCollapsed && 'min-w-[50px] transition-all duration-300 ease-in-out')}
|
||
|
|
>
|
||
|
|
<div className={cn('flex h-[52px] items-center justify-center', isCollapsed ? 'h-[52px]' : 'px-2')}>
|
||
|
|
<AndroidSwitcher isCollapsed={isCollapsed} androids={androids} />
|
||
|
|
</div>
|
||
|
|
<Separator />
|
||
|
|
<Nav
|
||
|
|
isCollapsed={isCollapsed}
|
||
|
|
showListIndex={showListIndex}
|
||
|
|
setShowListIndex={setShowListIndex}
|
||
|
|
links={[
|
||
|
|
{
|
||
|
|
index: 0,
|
||
|
|
title: 'Menu (Enabled)',
|
||
|
|
label: recipesEnable.length.toString(),
|
||
|
|
icon: CupSoda
|
||
|
|
},
|
||
|
|
{
|
||
|
|
index: 1,
|
||
|
|
title: 'Menu (Disabled)',
|
||
|
|
label: recipeDisable.length.toString(),
|
||
|
|
icon: WineOff
|
||
|
|
}
|
||
|
|
]}
|
||
|
|
/>
|
||
|
|
<Separator />
|
||
|
|
<Nav
|
||
|
|
isCollapsed={isCollapsed}
|
||
|
|
showListIndex={showListIndex}
|
||
|
|
setShowListIndex={setShowListIndex}
|
||
|
|
links={[
|
||
|
|
{
|
||
|
|
index: 2,
|
||
|
|
title: 'Materials',
|
||
|
|
label: recipes.MaterialSetting.length.toString(),
|
||
|
|
icon: Wheat
|
||
|
|
},
|
||
|
|
{
|
||
|
|
index: 3,
|
||
|
|
title: 'ToppingsGroups',
|
||
|
|
label: recipes.Topping.ToppingGroup.length.toString(),
|
||
|
|
icon: Dessert
|
||
|
|
},
|
||
|
|
{
|
||
|
|
index: 4,
|
||
|
|
title: 'ToppingsList',
|
||
|
|
label: recipes.Topping.ToppingList.length.toString(),
|
||
|
|
icon: Cherry
|
||
|
|
}
|
||
|
|
]}
|
||
|
|
/>
|
||
|
|
</ResizablePanel>
|
||
|
|
<ResizableHandle withHandle />
|
||
|
|
{showListIndex === 0 ? (
|
||
|
|
<RecipeMenu
|
||
|
|
recipes={recipes}
|
||
|
|
recipe01={recipesEnable}
|
||
|
|
defaultSize={defaultLayout[1]}
|
||
|
|
isDevBranch={isDevBranch}
|
||
|
|
/>
|
||
|
|
) : showListIndex === 1 ? (
|
||
|
|
<RecipeMenu
|
||
|
|
recipes={recipes}
|
||
|
|
recipe01={recipeDisable}
|
||
|
|
defaultSize={defaultLayout[1]}
|
||
|
|
isDevBranch={isDevBranch}
|
||
|
|
/>
|
||
|
|
) : null}
|
||
|
|
</ResizablePanelGroup>
|
||
|
|
</TooltipProvider>
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
export default RecipeEditor
|