Skip to content

Commit

Permalink
docs
Browse files Browse the repository at this point in the history
  • Loading branch information
zbeyens committed Nov 20, 2024
1 parent f471256 commit 6e5e67e
Show file tree
Hide file tree
Showing 5 changed files with 8 additions and 386 deletions.
4 changes: 2 additions & 2 deletions apps/www/public/r/styles/default/editor-ai.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
{
"content": "'use client';\n\nimport { type ReactNode, createContext, useContext, useState } from 'react';\n\nimport { cn } from '@udecode/cn';\nimport { CopilotPlugin } from '@udecode/plate-ai/react';\nimport { useEditorPlugin } from '@udecode/plate-common/react';\nimport {\n Check,\n ChevronsUpDown,\n ExternalLinkIcon,\n Eye,\n EyeOff,\n Settings,\n Wand2Icon,\n} from 'lucide-react';\n\nimport { Button } from '@/components/plate-ui/button';\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/components/plate-ui/command';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/components/plate-ui/dialog';\nimport { Input } from '@/components/plate-ui/input';\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/plate-ui/popover';\n\ninterface Model {\n label: string;\n value: string;\n}\n\ninterface SettingsContextType {\n keys: Record<string, string>;\n model: Model;\n setKey: (service: string, key: string) => void;\n setModel: (model: Model) => void;\n}\n\nexport const models: Model[] = [\n { label: 'gpt-4o-mini', value: 'gpt-4o-mini' },\n { label: 'gpt-4o', value: 'gpt-4o' },\n { label: 'gpt-4-turbo', value: 'gpt-4-turbo' },\n { label: 'gpt-4', value: 'gpt-4' },\n { label: 'gpt-3.5-turbo', value: 'gpt-3.5-turbo' },\n { label: 'gpt-3.5-turbo-instruct', value: 'gpt-3.5-turbo-instruct' },\n];\n\nconst SettingsContext = createContext<SettingsContextType | undefined>(\n undefined\n);\n\nexport function SettingsProvider({ children }: { children: ReactNode }) {\n const [keys, setKeys] = useState({\n openai: '',\n uploadthing: '',\n });\n const [model, setModel] = useState<Model>(models[0]);\n\n const setKey = (service: string, key: string) => {\n setKeys((prev) => ({ ...prev, [service]: key }));\n };\n\n return (\n <SettingsContext.Provider value={{ keys, model, setKey, setModel }}>\n {children}\n </SettingsContext.Provider>\n );\n}\n\nexport function useSettings() {\n const context = useContext(SettingsContext);\n\n return (\n context ?? {\n keys: {\n openai: '',\n uploadthing: '',\n },\n model: models[0],\n setKey: () => {},\n setModel: () => {},\n }\n );\n}\n\nexport function SettingsDialog() {\n const { keys, model, setKey, setModel } = useSettings();\n const [tempKeys, setTempKeys] = useState(keys);\n const [showKey, setShowKey] = useState<Record<string, boolean>>({});\n const [open, setOpen] = useState(false);\n const [openModel, setOpenModel] = useState(false);\n\n const { getOptions, setOption } = useEditorPlugin(CopilotPlugin);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n Object.entries(tempKeys).forEach(([service, key]) => {\n setKey(service, key);\n });\n setOpen(false);\n\n // Update AI options if needed\n const completeOptions = getOptions().completeOptions ?? {};\n setOption('completeOptions', {\n ...completeOptions,\n body: {\n ...completeOptions.body,\n apiKey: tempKeys.openai,\n model: model.value,\n },\n });\n };\n\n const toggleKeyVisibility = (key: string) => {\n setShowKey((prev) => ({ ...prev, [key]: !prev[key] }));\n };\n\n const renderApiKeyInput = (service: string, label: string) => (\n <div className=\"group relative\">\n <div className=\"flex items-center justify-between\">\n <label\n className=\"absolute top-1/2 block -translate-y-1/2 cursor-text px-1 text-sm text-muted-foreground/70 transition-all group-focus-within:pointer-events-none group-focus-within:top-0 group-focus-within:cursor-default group-focus-within:text-xs group-focus-within:font-medium group-focus-within:text-foreground has-[+input:not(:placeholder-shown)]:pointer-events-none has-[+input:not(:placeholder-shown)]:top-0 has-[+input:not(:placeholder-shown)]:cursor-default has-[+input:not(:placeholder-shown)]:text-xs has-[+input:not(:placeholder-shown)]:font-medium has-[+input:not(:placeholder-shown)]:text-foreground\"\n htmlFor={label}\n >\n <span className=\"inline-flex bg-background px-2\">{label}</span>\n </label>\n <Button\n asChild\n size=\"icon\"\n variant=\"ghost\"\n className=\"absolute right-[28px] top-0 h-full\"\n >\n <a\n className=\"flex items-center\"\n href={\n service === 'openai'\n ? 'https://platform.openai.com/api-keys'\n : 'https://uploadthing.com/dashboard'\n }\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n <ExternalLinkIcon className=\"size-4\" />\n <span className=\"sr-only\">Get {label}</span>\n </a>\n </Button>\n </div>\n\n <Input\n id={label}\n className=\"pr-10\"\n value={tempKeys[service]}\n onChange={(e) =>\n setTempKeys((prev) => ({ ...prev, [service]: e.target.value }))\n }\n placeholder=\"\"\n data-1p-ignore\n type={showKey[service] ? 'text' : 'password'}\n />\n <Button\n size=\"icon\"\n variant=\"ghost\"\n className=\"absolute right-0 top-0 h-full\"\n onClick={() => toggleKeyVisibility(service)}\n type=\"button\"\n >\n {showKey[service] ? (\n <EyeOff className=\"size-4\" />\n ) : (\n <Eye className=\"size-4\" />\n )}\n <span className=\"sr-only\">\n {showKey[service] ? 'Hide' : 'Show'} {label}\n </span>\n </Button>\n </div>\n );\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button\n size=\"icon\"\n variant=\"default\"\n className={cn(\n 'group fixed bottom-4 right-4 z-50 size-10 overflow-hidden',\n 'rounded-full shadow-md hover:shadow-lg',\n 'transition-all duration-300 ease-in-out hover:w-[106px]'\n )}\n data-block-hide\n >\n <div className=\"flex size-full items-center justify-start gap-2\">\n <Settings className=\"ml-1.5 size-4\" />\n <span\n className={cn(\n 'whitespace-nowrap opacity-0 transition-all duration-300 ease-in-out',\n 'group-hover:translate-x-0 group-hover:opacity-100',\n '-translate-x-2'\n )}\n >\n Settings\n </span>\n </div>\n </Button>\n </DialogTrigger>\n <DialogContent>\n <DialogHeader>\n <DialogTitle className=\"text-xl\">Settings</DialogTitle>\n <DialogDescription>\n Configure your API keys and preferences.\n </DialogDescription>\n </DialogHeader>\n\n <form className=\"space-y-10\" onSubmit={handleSubmit}>\n {/* AI Settings Group */}\n <div className=\"space-y-4\">\n <div className=\"flex items-center gap-2\">\n <div className=\"size-8 rounded-full bg-purple-100 p-2 dark:bg-purple-900\">\n <Wand2Icon className=\"size-4 text-purple-600 dark:text-purple-400\" />\n </div>\n <h4 className=\"font-semibold\">AI</h4>\n </div>\n\n <div className=\"space-y-4\">\n {renderApiKeyInput('openai', 'OpenAI API key')}\n\n <div className=\"group relative\">\n <label\n className=\"absolute start-1 top-0 z-10 block -translate-y-1/2 bg-background px-2 text-xs font-medium text-foreground group-has-[:disabled]:opacity-50\"\n htmlFor=\"select-model\"\n >\n Model\n </label>\n <Popover open={openModel} onOpenChange={setOpenModel}>\n <PopoverTrigger id=\"select-model\" asChild>\n <Button\n size=\"lg\"\n variant=\"outline\"\n className=\"w-full justify-between\"\n aria-expanded={openModel}\n role=\"combobox\"\n >\n <code>{model.label}</code>\n <ChevronsUpDown className=\"ml-2 size-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-full p-0\">\n <Command>\n <CommandInput placeholder=\"Search model...\" />\n <CommandEmpty>No model found.</CommandEmpty>\n <CommandList>\n <CommandGroup>\n {models.map((m) => (\n <CommandItem\n key={m.value}\n value={m.value}\n onSelect={() => {\n setModel(m);\n setOpenModel(false);\n }}\n >\n <Check\n className={cn(\n 'mr-2 size-4',\n model.value === m.value\n ? 'opacity-100'\n : 'opacity-0'\n )}\n />\n <code>{m.label}</code>\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </div>\n </div>\n </div>\n\n {/* Upload Settings Group */}\n {/* <div className=\"space-y-4\">\n <div className=\"flex items-center gap-2\">\n <div className=\"size-8 rounded-full bg-red-100 p-2 dark:bg-red-900\">\n <Upload className=\"size-4 text-red-600 dark:text-red-400\" />\n </div>\n <h4 className=\"font-semibold\">Upload</h4>\n </div>\n\n <div className=\"space-y-4\">\n {renderApiKeyInput('uploadthing', 'Uploadthing API key')}\n </div>\n </div> */}\n\n <Button size=\"lg\" className=\"w-full\" type=\"submit\">\n Save changes\n </Button>\n </form>\n\n <p className=\"text-sm text-muted-foreground\">\n Not stored anywhere. Used only for current session requests.\n </p>\n </DialogContent>\n </Dialog>\n );\n}\n",
"path": "components/editor/settings.tsx",
"target": "components/settings.tsx",
"type": "registry:block"
"target": "components/editor/settings.tsx",
"type": "registry:component"
}
],
"name": "editor-ai",
Expand Down
6 changes: 5 additions & 1 deletion apps/www/src/registry/registry-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ export const blocks: Registry = [
target: 'components/editor/use-create-editor.ts',
type: 'registry:component',
},
'components/editor/settings.tsx',
{
path: 'components/editor/settings.tsx',
target: 'components/editor/settings.tsx',
type: 'registry:component',
},
],
name: 'editor-ai',
registryDependencies: [
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export function SettingsDialog() {
<div className="group relative">
<div className="flex items-center justify-between">
<label
className="origin-start absolute top-1/2 block -translate-y-1/2 cursor-text px-1 text-sm text-muted-foreground/70 transition-all group-focus-within:pointer-events-none group-focus-within:top-0 group-focus-within:cursor-default group-focus-within:text-xs group-focus-within:font-medium group-focus-within:text-foreground has-[+input:not(:placeholder-shown)]:pointer-events-none has-[+input:not(:placeholder-shown)]:top-0 has-[+input:not(:placeholder-shown)]:cursor-default has-[+input:not(:placeholder-shown)]:text-xs has-[+input:not(:placeholder-shown)]:font-medium has-[+input:not(:placeholder-shown)]:text-foreground"
className="absolute top-1/2 block -translate-y-1/2 cursor-text px-1 text-sm text-muted-foreground/70 transition-all group-focus-within:pointer-events-none group-focus-within:top-0 group-focus-within:cursor-default group-focus-within:text-xs group-focus-within:font-medium group-focus-within:text-foreground has-[+input:not(:placeholder-shown)]:pointer-events-none has-[+input:not(:placeholder-shown)]:top-0 has-[+input:not(:placeholder-shown)]:cursor-default has-[+input:not(:placeholder-shown)]:text-xs has-[+input:not(:placeholder-shown)]:font-medium has-[+input:not(:placeholder-shown)]:text-foreground"
htmlFor={label}
>
<span className="inline-flex bg-background px-2">{label}</span>
Expand Down
Loading

0 comments on commit 6e5e67e

Please sign in to comment.