CoolFace
Apppublic

WaledRashed24/comics

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
index.tsx309 linesDownload Raw Back to top-menu
1"use client"2 3import { useEffect, useState } from "react"4import { useSearchParams } from "next/navigation"5import { StaticImageData } from "next/image"6import { useLocalStorage } from "usehooks-ts"7 8import {9  Select,10  SelectContent,11  SelectItem,12  SelectTrigger,13  SelectValue,14} from "@/components/ui/select"15import { Label } from "@/components/ui/label"16import { cn } from "@/lib/utils"17import { FontName, defaultFont } from "@/lib/fonts"18import { Input } from "@/components/ui/input"19import { PresetName, defaultPreset, nonRandomPresets, presets } from "@/app/engine/presets"20import { useStore } from "@/app/store"21import { Button } from "@/components/ui/button"22import { LayoutName, defaultLayout, nonRandomLayouts } from "@/app/layouts"23import { Switch } from "@/components/ui/switch"24import { useOAuth } from "@/lib/useOAuth"25import { useIsBusy } from "@/lib/useIsBusy"26 27import { localStorageKeys } from "../settings-dialog/localStorageKeys"28import { defaultSettings } from "../settings-dialog/defaultSettings"29import { AuthWall } from "../auth-wall"30import { SelectLayout } from "../select-layout"31 32export function TopMenu() {33  const searchParams = useSearchParams()34 35  const requestedPreset = (searchParams?.get('preset') as PresetName) || defaultPreset36  const requestedFont = (searchParams?.get('font') as FontName) || defaultFont37  const requestedStylePrompt = (searchParams?.get('stylePrompt') as string) || ""38  const requestedStoryPrompt = (searchParams?.get('storyPrompt') as string) || ""39  const requestedLayout = (searchParams?.get('layout') as LayoutName) || defaultLayout40 41   // const font = useStore(s => s.font)42  // const setFont = useStore(s => s.setFont)43  const preset = useStore(s => s.preset)44  const prompt = useStore(s => s.prompt)45  const layout = useStore(s => s.layout)46  const setLayout = useStore(s => s.setLayout)47 48  const setShowSpeeches = useStore(s => s.setShowSpeeches)49  const showSpeeches = useStore(s => s.showSpeeches)50 51  const setShowCaptions = useStore(s => s.setShowCaptions)52  const showCaptions = useStore(s => s.showCaptions)53 54  const currentNbPages = useStore(s => s.currentNbPages)55  const setCurrentNbPages = useStore(s => s.setCurrentNbPages)56 57  const generate = useStore(s => s.generate)58 59  const isBusy = useIsBusy()60 61  const [lastDraftPromptA, setLastDraftPromptA] = useLocalStorage<string>(62    "AI_COMIC_FACTORY_LAST_DRAFT_PROMPT_A",63    requestedStylePrompt64  )65 66  const [lastDraftPromptB, setLastDraftPromptB] = useLocalStorage<string>(67    "AI_COMIC_FACTORY_LAST_DRAFT_PROMPT_B",68    requestedStoryPrompt69  )70 71  // TODO should be in the store72  const [draftPromptA, setDraftPromptA] = useState(lastDraftPromptA)73  const [draftPromptB, setDraftPromptB] = useState(lastDraftPromptB)74  const draftPrompt = `${draftPromptA}||${draftPromptB}`75 76  const [draftPreset, setDraftPreset] = useState<PresetName>(requestedPreset)77  const [draftLayout, setDraftLayout] = useState<LayoutName>(requestedLayout)78  79  const { isLoggedIn, enableOAuthWall } = useOAuth({ debug: false })80  81  const [hasGeneratedAtLeastOnce, setHasGeneratedAtLeastOnce] = useLocalStorage<boolean>(82    localStorageKeys.hasGeneratedAtLeastOnce,83    defaultSettings.hasGeneratedAtLeastOnce84  )85 86  const [showAuthWall, setShowAuthWall] = useState(false)87 88  // we synchronize the draft prompt with the local storage89  useEffect(() => { if (lastDraftPromptA !== draftPromptA) { setLastDraftPromptA(draftPromptA) } }, [draftPromptA])90  useEffect(() => { if (lastDraftPromptA !== draftPromptA) { setDraftPromptA(lastDraftPromptA) } }, [lastDraftPromptA])91  useEffect(() => { if (lastDraftPromptB !== draftPromptB) { setLastDraftPromptB(draftPromptB) } }, [draftPromptB])92  useEffect(() => { if (lastDraftPromptB !== draftPromptB) { setDraftPromptB(lastDraftPromptB) } }, [lastDraftPromptB])93 94  const handleSubmit = () => {95    if (enableOAuthWall && hasGeneratedAtLeastOnce && !isLoggedIn) {96      setShowAuthWall(true)97      return98    }99 100    const promptChanged = draftPrompt.trim() !== prompt.trim()101    const presetChanged = draftPreset !== preset.id102    const layoutChanged = draftLayout !== layout103    if (!isBusy && (promptChanged || presetChanged || layoutChanged)) {104      generate(draftPrompt, draftPreset, draftLayout)105    }106  }107 108  useEffect(() => {109    const layoutChanged = draftLayout !== layout110    if (layoutChanged && !isBusy) {111      setLayout(draftLayout)112    }113  }, [layout, draftLayout, isBusy])114    115  return (116    <div className={cn(117      `print:hidden`,118      `z-10 fixed top-0 left-0 right-0`,119      `flex flex-col md:flex-row w-full justify-between items-center`,120      `backdrop-blur-xl`,121      `transition-all duration-200 ease-in-out`,122      `px-2 py-2 border-b-1 border-gray-50 dark:border-gray-50`,123      //`bg-[#2d435c] dark:bg-[#2d435c] text-gray-50 dark:text-gray-50`,124      `bg-gradient-to-r from-[#102c4c] to-[#1a426f] dark:bg-gradient-to-r dark:from-[#102c4c] dark:to-[#1a426f]`,125      `space-y-2 md:space-y-0 md:space-x-3 lg:space-x-6`126    )}>127      <div className="flex flex-row space-x-2 md:space-x-3 w-full md:w-auto">128        <div className={cn(129          `transition-all duration-200 ease-in-out`,130          `flex flex-row items-center justify-start space-x-3`,131          `flex-grow`132          )}>133 134          {/* <Label className="flex text-2xs md:text-sm md:w-24">Style:</Label> */}135 136          <Select137            defaultValue={defaultPreset}138            onValueChange={(value) => { setDraftPreset(value as PresetName) }}139            disabled={isBusy}140            >141            <SelectTrigger className="flex-grow bg-gray-100 text-gray-700 dark:bg-gray-100 dark:text-gray-700">142              <SelectValue className="text-2xs md:text-sm" placeholder="Style" />143            </SelectTrigger>144            <SelectContent>145              {nonRandomPresets.map(key =>146                <SelectItem key={key} value={key}>{presets[key].label}</SelectItem>147              )}148            </SelectContent>149          </Select>150        </div>151        <div className={cn(152          `transition-all duration-200 ease-in-out`,153          `flex flex-row items-center justify-start space-x-3`,154          `w-40`155          )}>156 157          {/* <Label className="flex text-2xs md:text-sm md:w-24">Style:</Label> */}158 159          <SelectLayout160            defaultValue={defaultLayout}161            onLayoutChange={setDraftLayout}162            disabled={isBusy}163            layouts={nonRandomLayouts}164          />165        </div>166        <div className="flex flex-row items-center space-x-3">167        <Switch168          checked={showCaptions}169          onCheckedChange={setShowCaptions}170        />171        <Label className="text-gray-200 dark:text-gray-200">172          <span className="hidden md:inline">Caption</span>173          <span className="inline md:hidden">Cap.</span>174        </Label>175        </div>176        <div className="flex flex-row items-center space-x-3">177        <Switch178          checked={showSpeeches}179          onCheckedChange={setShowSpeeches}180        />181        <Label className="text-gray-200 dark:text-gray-200">182          <span className="hidden md:inline">Beta</span>183          <span className="inline md:hidden">Beta</span>184        </Label>185        </div>186        {/*187        <div className={cn(188          `transition-all duration-200 ease-in-out`,189          `flex flex-row items-center space-x-3 w-1/2 md:w-auto md:hidden`190        )}>191          <Label className="flex text-2xs md:text-sm md:w-24">Font:</Label>192          <Select193            defaultValue={fontList.includes(preset.font) ? preset.font : "cartoonist"}194            onValueChange={(value) => { setFont(value as FontName) }}195            disabled={atLeastOnePanelIsBusy}196            >197            <SelectTrigger className="flex-grow">198              <SelectValue className="text-2xs md:text-sm" placeholder="Type" />199            </SelectTrigger>200            <SelectContent>201              {Object.keys(fonts)202                .map((font) =>203                <SelectItem204                  key={font}205                  value={font}>{206                    font207                  }</SelectItem>208              )}209            </SelectContent>210          </Select>211        </div>212          */}213      </div>214      <div className={cn(215          `transition-all duration-200 ease-in-out`,216          `flex  flex-grow flex-col space-y-2 md:space-y-0 md:flex-row items-center md:space-x-3 w-full md:w-auto`217        )}>218        <div className="flex flex-row flex-grow w-full">219          <div className="flex flex-row flex-grow w-full">220            <Input221              id="top-menu-input-story-prompt"222              placeholder="1. Story (eg. detective dog)"223              className={cn(224                `w-1/2 rounded-r-none`,225                `bg-gray-100 text-gray-700 dark:bg-gray-100 dark:text-gray-700`,226                `border-r-stone-100`227              )}228              // disabled={atLeastOnePanelIsBusy}229              onChange={(e) => {230                setDraftPromptB(e.target.value)231              }}232              onKeyDown={({ key }) => {233                if (key === 'Enter') {234                  handleSubmit()235                }236              }}237              value={draftPromptB}238            />239            <Input240              id="top-menu-input-style-prompt"241              placeholder="2. Style (eg 'rain, shiba')"242              className={cn(243                `w-1/2`,244                `bg-gray-100 text-gray-700 dark:bg-gray-100 dark:text-gray-700`,245                `border-l-gray-300 rounded-l-none rounded-r-none`246              )}247              // disabled={atLeastOnePanelIsBusy}248              onChange={(e) => {249                setDraftPromptA(e.target.value)250              }}251              onKeyDown={({ key }) => {252                if (key === 'Enter') {253                  handleSubmit()254                }255              }}256              value={draftPromptA}257            />258          </div>259            <Button260            className={cn(261              `rounded-l-none cursor-pointer`,262              `transition-all duration-200 ease-in-out`,263              `text-xl`,264              `bg-[rgb(59,134,247)] hover:bg-[rgb(69,144,255)] disabled:bg-[rgb(59,134,247)]`265              )}266            onClick={() => {267              handleSubmit()268            }}269            disabled={!draftPrompt?.trim().length || isBusy}270          >271            Go272          </Button>273 274          <AuthWall show={showAuthWall} />275        </div>276      </div>277      {/*278        Let's add this feature later, because right now people279        are confused about why they can't activate it280      <div className={cn(281          `transition-all duration-200 ease-in-out`,282          `hidden md:flex flex-row items-center space-x-3 w-full md:w-auto`283      )}>284        <Label className="flex text-2xs md:text-sm w-24">Font:</Label>285        <Select286          defaultValue={fontList.includes(preset.font) ? preset.font : "actionman"}287          onValueChange={(value) => { setFont(value as FontName) }}288          // disabled={isBusy}289          disabled={true}290          >291          <SelectTrigger className="flex-grow">292            <SelectValue className="text-2xs md:text-sm" placeholder="Type" />293          </SelectTrigger>294          <SelectContent>295            {Object.keys(fonts)296              .map((font) =>297              <SelectItem298                key={font}299                value={font}>{300                  font301                }</SelectItem>302            )}303          </SelectContent>304        </Select>305      </div>306              */}307    </div>308  )309}