diff --git a/website/package.json b/website/package.json index dad280dc2..ba6d5232c 100644 --- a/website/package.json +++ b/website/package.json @@ -26,6 +26,7 @@ "@mdx-js/react": "^3.1.1", "@next/mdx": "^16.2.1", "@tailwindcss/postcss": "^4.2.2", + "@uiw/react-color-chrome": "^2.9.6", "framer-motion": "^12.38.0", "is-lite": "^2.0.0", "lucide-react": "^0.577.0", diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml index 3ff791ac8..e53ca0d96 100644 --- a/website/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -47,6 +47,9 @@ importers: '@tailwindcss/postcss': specifier: ^4.2.2 version: 4.2.2 + '@uiw/react-color-chrome': + specifier: ^2.9.6 + version: 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) framer-motion: specifier: ^12.38.0 version: 12.38.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -2108,6 +2111,81 @@ packages: resolution: {integrity: sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@uiw/color-convert@2.9.6': + resolution: {integrity: sha512-w8TpU3MRcquurQJxWR1daKcRygu/a0hLP/VGsLMA3ebb41sAZGxMQLHtS+zC/e3ciFNB7BbPrSPlzOcz6w6cRg==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + + '@uiw/react-color-alpha@2.9.6': + resolution: {integrity: sha512-DNzEVHZ0Izp4NAwzKqTcl4rLdPjSFjyZCP6Q2vKJEglugZ/bdPsmZaos9IYOrgnd1kPDmTSKZ/p8nI7vBIATGw==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@uiw/react-color-chrome@2.9.6': + resolution: {integrity: sha512-ah9H6ZpCHyvHdDzS3qrK4UcvWhj0ZaSfbAE4WLSv/m70E0i/uivjtS242jrPG2Kg02wkgd+jyfmOvpgGkGF3FA==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@uiw/react-color-editable-input-hsla@2.9.6': + resolution: {integrity: sha512-qZOUf5/2ilD9ToLnEctHsmvEvrjZhDMfzwI4Ii63q68rF/mD1fUbbKy3tCFn+JgGSKvMdEAMhAGjwtCsWkpFtg==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@uiw/react-color-editable-input-rgba@2.9.6': + resolution: {integrity: sha512-vzC+uBl6ZaGESVOUbglPqfOACsmwIwMQcmvdELhVw9KiKWp168fE4LqSQf57a2BHaPM9Jl8Lh8GLXn284bWRyw==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@uiw/react-color-editable-input@2.9.6': + resolution: {integrity: sha512-KrbXonGXxSPxGNTcZY1QZ6QCon9/ekNxdMDlAvBgapUjrrcwqZ+nkgsAsUe+BNa6Ods3KnA2OKcOs99v6nIJ8A==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@uiw/react-color-github@2.9.6': + resolution: {integrity: sha512-Yk7Q4B+WVAA4wz15i4EPo02SJSr8oPFi4mWnB157+v/DnKakcXrIN/Y9z3fi9qlDRo3LsZUfmzJMz4e4W/Fhrg==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@uiw/react-color-hue@2.9.6': + resolution: {integrity: sha512-B99dW2/AHMD3py83BrXl94bhXeGCZR1FMpU/FNbIIbUrV9QTiIXDs2/SB/tMD9ltcSP59RD5Sc5m2vCb/8anjw==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@uiw/react-color-saturation@2.9.6': + resolution: {integrity: sha512-R1tiKbTG2WiJXerkmuaKnBFfzgyZUn08q9OjQSvNH1f3ov2/YeUVlOwQY9MbQE7ytZv+9x+1h0Lpk4QG7AdulQ==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@uiw/react-color-swatch@2.9.6': + resolution: {integrity: sha512-ekhCz55GdB+Al/na2tj3GxjaoMd6NRtqosYNFZA3axXxhnREG5TfaaOvR8r96yZswo/sKSSFuX2gpmro7BcBSA==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@uiw/react-drag-event-interactive@2.9.6': + resolution: {integrity: sha512-jXzt3Xis/BIYap2Hj2++gB3aEUD0mZoVNGfckurrwjAwxasxNiwkmTGxV5er3due0ZgaVKdOAfTRoYKlgZukSg==} + peerDependencies: + '@babel/runtime': '>=7.19.0' + react: '>=16.9.0' + react-dom: '>=16.9.0' + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -7139,6 +7217,91 @@ snapshots: '@typescript-eslint/types': 8.56.0 eslint-visitor-keys: 5.0.0 + '@uiw/color-convert@2.9.6(@babel/runtime@7.28.6)': + dependencies: + '@babel/runtime': 7.28.6 + + '@uiw/react-color-alpha@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@uiw/color-convert': 2.9.6(@babel/runtime@7.28.6) + '@uiw/react-drag-event-interactive': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@uiw/react-color-chrome@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@uiw/color-convert': 2.9.6(@babel/runtime@7.28.6) + '@uiw/react-color-alpha': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@uiw/react-color-editable-input': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@uiw/react-color-editable-input-hsla': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@uiw/react-color-editable-input-rgba': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@uiw/react-color-github': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@uiw/react-color-hue': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@uiw/react-color-saturation': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@uiw/react-color-editable-input-hsla@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@uiw/color-convert': 2.9.6(@babel/runtime@7.28.6) + '@uiw/react-color-editable-input-rgba': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@uiw/react-color-editable-input-rgba@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@uiw/color-convert': 2.9.6(@babel/runtime@7.28.6) + '@uiw/react-color-editable-input': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@uiw/react-color-editable-input@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@uiw/react-color-github@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@uiw/color-convert': 2.9.6(@babel/runtime@7.28.6) + '@uiw/react-color-swatch': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@uiw/react-color-hue@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@uiw/color-convert': 2.9.6(@babel/runtime@7.28.6) + '@uiw/react-color-alpha': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@uiw/react-color-saturation@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@uiw/color-convert': 2.9.6(@babel/runtime@7.28.6) + '@uiw/react-drag-event-interactive': 2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@uiw/react-color-swatch@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@uiw/color-convert': 2.9.6(@babel/runtime@7.28.6) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@uiw/react-drag-event-interactive@2.9.6(@babel/runtime@7.28.6)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + '@ungap/structured-clone@1.3.0': {} '@unrs/resolver-binding-android-arm-eabi@1.11.1': diff --git a/website/src/app/demos/modal/HeroModal.tsx b/website/src/app/demos/modal/HeroModal.tsx index 8c7e717b9..c3d5f9b4f 100644 --- a/website/src/app/demos/modal/HeroModal.tsx +++ b/website/src/app/demos/modal/HeroModal.tsx @@ -34,7 +34,6 @@ export default function HeroModal(props: HeroModalProps) { backdrop: '!z-[80]', wrapper: '!z-[90]', }} - isDismissable={false} isOpen={activeModal === 'heroui'} onOpenChange={onOpenChange} size="3xl" diff --git a/website/src/app/demos/modal/Modal.tsx b/website/src/app/demos/modal/Modal.tsx index 581b6c221..d9f567149 100644 --- a/website/src/app/demos/modal/Modal.tsx +++ b/website/src/app/demos/modal/Modal.tsx @@ -259,6 +259,7 @@ export default function Modal() { +
); } diff --git a/website/src/components/ColorPicker.tsx b/website/src/components/ColorPicker.tsx index f05af064e..82521a7c7 100644 --- a/website/src/components/ColorPicker.tsx +++ b/website/src/components/ColorPicker.tsx @@ -1,49 +1,57 @@ -import { type ChangeEventHandler, useRef } from 'react'; -import { Button, cn } from '@heroui/react'; +import { Button, cn, Popover, PopoverContent, PopoverTrigger, useDisclosure } from '@heroui/react'; +import Chrome, { ChromeInputType } from '@uiw/react-color-chrome'; -interface ColorPickerProps { +export interface ColorPickerProps { className?: string; color: string; isDisabled?: boolean; - onChange: ChangeEventHandler; + onChange: (value: string) => void; + showAlpha?: boolean; size?: 'sm' | 'md' | 'lg'; } export default function ColorPicker(props: ColorPickerProps) { - const { className, color, isDisabled, onChange, size = 'md', ...rest } = props; - const colorInputRef = useRef(null); - - const left = { - sm: 'left-8', - md: 'left-10', - lg: 'left-12', - }; + const { className, color, isDisabled, onChange, showAlpha = false, size = 'sm', ...rest } = props; + const { isOpen, onOpenChange } = useDisclosure(); return (
- -
); } diff --git a/website/src/components/ColorSelector.tsx b/website/src/components/ColorSelector.tsx new file mode 100644 index 000000000..f2579605d --- /dev/null +++ b/website/src/components/ColorSelector.tsx @@ -0,0 +1,36 @@ +import { cn } from '@heroui/react'; +import { CircleXIcon } from 'lucide-react'; + +import ColorPicker, { type ColorPickerProps } from '~/components/ColorPicker'; + +interface ColorSelectorProps extends ColorPickerProps { + fallback: string; + initialColor?: string; + label: string; +} + +export default function ColorSelector(props: ColorSelectorProps) { + const { className, color, fallback, initialColor, label, onChange, ...rest } = props; + + const isCustomized = initialColor && initialColor !== color; + + return ( +
+ {label} +
+ + {isCustomized && ( + + )} +
+
+ ); +} diff --git a/website/src/components/ConfigPanel/panels/Appearance.tsx b/website/src/components/ConfigPanel/panels/Appearance.tsx index ee5677a92..fb0581aaf 100644 --- a/website/src/components/ConfigPanel/panels/Appearance.tsx +++ b/website/src/components/ConfigPanel/panels/Appearance.tsx @@ -1,13 +1,12 @@ import React from 'react'; import { objectEntries, pick } from '@gilbarbara/helpers'; import { Checkbox, Slider, Switch } from '@heroui/react'; -import { CircleXIcon } from 'lucide-react'; import { defaultOptions } from '~/config/defaults'; import type { ConfigContextValue } from '~/context/ConfigContext'; import ButtonsToggle from '~/components/ButtonsToggle'; -import ColorPicker from '~/components/ColorPicker'; +import ColorSelector from '~/components/ColorSelector'; interface AppearancePanelProps extends Pick< ConfigContextValue, @@ -31,94 +30,45 @@ export default function AppearancePanel(props: AppearancePanelProps) { pick(defaultOptions, 'arrowColor', 'backgroundColor', 'primaryColor', 'textColor'), ).map(([key, fallback]) => { const currentValue = getConfigValue(key); - const isCustomized = initialOptions[key] && initialOptions[key] !== currentValue; - let resetButton = null; - - if (isCustomized) { - resetButton = ( - - ); - } return ( -
- {key} -
- { - const { value } = event.target; - - setOption(key, value); - - if (syncColors) { - switch (key) { - case 'backgroundColor': { - setOption('arrowColor', value); - - break; - } - case 'arrowColor': { - setOption('backgroundColor', value); - - break; - } - case 'primaryColor': { - setOption('textColor', value); - - break; - } - case 'textColor': { - setOption('primaryColor', value); - - break; - } - // No default - } + { + setOption(key, value); + + if (syncColors) { + switch (key) { + case 'backgroundColor': { + setOption('arrowColor', value); + + break; } - }} - size="sm" - /> - {resetButton} -
-
+ case 'arrowColor': { + setOption('backgroundColor', value); + + break; + } + case 'primaryColor': { + setOption('textColor', value); + + break; + } + case 'textColor': { + setOption('primaryColor', value); + + break; + } + // No default + } + } + }} + /> ); })} diff --git a/website/src/components/ConfigPanel/panels/Overlay.tsx b/website/src/components/ConfigPanel/panels/Overlay.tsx index ba8fa32e4..ca470a61b 100644 --- a/website/src/components/ConfigPanel/panels/Overlay.tsx +++ b/website/src/components/ConfigPanel/panels/Overlay.tsx @@ -1,29 +1,39 @@ -import { Input, Slider, Switch } from '@heroui/react'; +import { Slider, Switch } from '@heroui/react'; +import { defaultOptions } from '~/config/defaults'; import type { ConfigContextValue } from '~/context/ConfigContext'; +import ColorSelector from '~/components/ColorSelector'; + interface OverlayPanelProps extends Pick { setOption: (key: string, value: unknown) => void; } export default function OverlayPanel(props: OverlayPanelProps) { - const { getConfigValue, setOption } = props; + const { getConfigValue, initialConfig, setOption } = props; + const initialOptions = initialConfig.options ?? {}; return (
- setOption('overlayColor', value)} - size="sm" - value={getConfigValue('overlayColor')} - /> - ('hideOverlay')} - onValueChange={value => setOption('hideOverlay', value)} - size="sm" - > - hideOverlay - +
+ ('overlayColor')} + fallback={defaultOptions.overlayColor} + initialColor={initialOptions.overlayColor} + label="overlayColor" + onChange={value => setOption('overlayColor', value)} + showAlpha + /> + ('hideOverlay')} + onValueChange={value => setOption('hideOverlay', value)} + size="sm" + > + hideOverlay + +
div:nth-child(3) { + padding-bottom: 8px !important; + } +} + .star-burst { align-items: center; color: #000000; diff --git a/website/src/css/react-color.css b/website/src/css/react-color.css new file mode 100644 index 000000000..59f82fd7d --- /dev/null +++ b/website/src/css/react-color.css @@ -0,0 +1,20 @@ +html.dark { + .w-color-editable-input { + --editable-input-label-color: var(--color-gray-400) !important; + --editable-input-box-shadow: #616161 0px 0px 0px 1px inset !important; + --editable-input-color: #fff !important; + } + + .w-color-github { + --github-border: 0 !important; + --github-background-color: var(--color-zinc-900) !important; + --github-box-shadow: unset !important; + } + + .w-color-alpha { + --alpha-pointer-background-color: #6a6a6a !important; + --alpha-pointer-box-shadow: rgb(0 0 0 / 37%) 0px 1px 4px 0px !important; + } +} + +