diff --git a/apps/web/content/data/docs/configuration/fields/color.json b/apps/web/content/data/docs/configuration/fields/color.json new file mode 100644 index 000000000..6aa54402b --- /dev/null +++ b/apps/web/content/data/docs/configuration/fields/color.json @@ -0,0 +1,52 @@ +{ + "id": "28kmDpbLx4KS1dyZlDsYoeyJNwn", + "type": "Doc", + "root": "data", + "index": "a3l", + "title": "Color", + "blocks": [ + { + "id": "28kmG0zsccVgkCiTagVdZhVePWV", + "index": "a0", + "type": "TextBlock", + "text": [ + { + "type": "heading", + "level": 1, + "content": [ + { + "type": "text", + "text": "Color" + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "A color field is used to input a hex color code." + } + ] + }, + { + "id": "28kmYRWE9qZv5cEHmEmFtHaIzlu", + "type": "CodeBlock", + "code": "color('My color field', {\n initialValue: '#4a63e7'\n})", + "compact": false + } + ] + }, + { + "id": "28kmocDvCZt990Xf4Ws6ZqBwiGL", + "index": "a1", + "type": "TypesBlock", + "types": "ColorOptions" + } + ], + "parents": [ + "docs", + "259Ey7LXgqL7ZDGJ8XK1vBJmZrh", + "24yE2mu6Xq959jrP135Sdb4e3lG" + ] +} \ No newline at end of file diff --git a/apps/web/content/data/index.json b/apps/web/content/data/index.json index ff1b9b9b3..560ef7445 100644 --- a/apps/web/content/data/index.json +++ b/apps/web/content/data/index.json @@ -4,6 +4,7 @@ "root": "data", "index": "Zy", "title": "Home", + "parents": [], "headline": "Structure\ncontent fast", "byline": "Structure, edit and query content with any web framework.\nFully typed and organized in your repository.", "action": [ @@ -15,13 +16,5 @@ "label": "Getting started" } ], - "links": [ - { - "id": "263wlTQJl4GPVikrzGKCxRKuJTg", - "index": "a0", - "type": "entry", - "entry": "20580nQzbOBR3Lt4kIdxyRGglc6", - "title": "Docs" - } - ] + "links": [] } \ No newline at end of file diff --git a/apps/web/src/view/HomePage.tsx b/apps/web/src/view/HomePage.tsx index 6ea3f0fd1..b1c10e244 100644 --- a/apps/web/src/view/HomePage.tsx +++ b/apps/web/src/view/HomePage.tsx @@ -1,4 +1,5 @@ import {fromModule, HStack, px, Typo, VStack} from '@alinea/ui' + import {IcRoundOpenInNew} from '@alinea/ui/icons/IcRoundOpenInNew' import css from './HomePage.module.scss' import {HomePageSchema} from './HomePage.schema' @@ -6,7 +7,7 @@ import {Hero} from './layout/Hero' const styles = fromModule(css) -const exampleCode = `schema('Blog', { +const exampleCode = `schema('Blog', {0 BlogEntry: type('Blog entry', { title: text('Title'), author: link('Author', {type: 'entry'}), diff --git a/packages/input/color/package.json b/packages/input/color/package.json new file mode 100644 index 000000000..07294a966 --- /dev/null +++ b/packages/input/color/package.json @@ -0,0 +1,38 @@ +{ + "name": "@alinea/input.color", + "version": "0.0.0", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/alineacms/alinea.git" + }, + "type": "module", + "exports": { + ".": { + "browser": "./dist/view.js", + "default": "./dist/index.js" + }, + "./*": "./dist/*.js", + "./index.css": "./dist/index.css" + }, + "files": [ + "dist" + ], + "sideEffects": false, + "typesVersions": { + "*": { + "*": [ + "./dist/*" + ] + } + }, + "dependencies": { + "@alinea/core": "0.0.0", + "@alinea/editor": "0.0.0", + "@alinea/ui": "0.0.0", + "react-colorful": "^5.5.1" + }, + "peerDependencies": { + "react": "*" + } +} diff --git a/packages/input/color/src/ColorField.tsx b/packages/input/color/src/ColorField.tsx new file mode 100644 index 000000000..13d348475 --- /dev/null +++ b/packages/input/color/src/ColorField.tsx @@ -0,0 +1,35 @@ +import {Field, Label, Shape} from '@alinea/core' + +/** Optional settings to configure a color field */ +export type ColorOptions = { + /** Width of the field in the dashboard UI (0-1) */ + width?: number + /** Add instructional text to a field */ + help?: Label + /** Field is optional */ + optional?: boolean + /** Display a minimal version */ + inline?: boolean + /** A default value */ + initialValue?: string + /** List of allowed hex codes */ + allowedColors?: Array +} + +/** Internal representation of a text field */ +export interface ColorField extends Field.Scalar { + label: Label + options: ColorOptions +} + +/** Create a text field configuration */ +export function createColor( + label: Label, + options: ColorOptions = {} +): ColorField { + return { + shape: Shape.Scalar(label), + label, + options + } +} diff --git a/packages/input/color/src/ColorInput.module.scss b/packages/input/color/src/ColorInput.module.scss new file mode 100644 index 000000000..fe29281a0 --- /dev/null +++ b/packages/input/color/src/ColorInput.module.scss @@ -0,0 +1,82 @@ +.root { + &-button { + display: flex; + align-items: center; + justify-content: center; + height: 25px; + width: 25px; + border-radius: 50%; + border: none; + cursor: pointer; + + &-check { + height: 18px; + width: 18px; + } + } + + &-popover { + position: relative; + + &-button { + border: none; + background-color: var(--alinea-background); + } + + &-clear { + margin-left: 8px; + } + + &-panel { + position: absolute; + left: 38px; + } + + &-color { + width: 38px; + height: 38px; + border-radius: 8px 0 0 8px; + + &.is-empty { + box-shadow: var(--alinea-fields-shadow); + background: linear-gradient( + to top left, + rgba(0, 0, 0, 0) 0%, + rgba(0, 0, 0, 0) calc(50% - 0.8px), + var(--alinea-fields-foreground) 50%, + rgba(0, 0, 0, 0) calc(50% + 0.8px), + rgba(0, 0, 0, 0) 100% + ), + linear-gradient( + to top right, + rgba(0, 0, 0, 0) 0%, + rgba(0, 0, 0, 0) calc(50% - 0.8px), + var(--alinea-fields-foreground) 50%, + rgba(0, 0, 0, 0) calc(50% + 0.8px), + rgba(0, 0, 0, 0) 100% + ); + } + } + + &-input { + display: block; + background: transparent; + border: none; + color: inherit; + font: inherit; + width: 100%; + resize: none; + padding: 9px 16px; + border-radius: 0 8px 8px 0; + line-height: 1.5; + background: var(--alinea-fields); + box-shadow: var(--alinea-fields-shadow); + + &.is-open, + &:focus { + background: var(--alinea-fields-selected); + outline: 2px solid var(--alinea-fields-focus); + } + } + } +} diff --git a/packages/input/color/src/ColorInput.tsx b/packages/input/color/src/ColorInput.tsx new file mode 100644 index 000000000..c2fd1c879 --- /dev/null +++ b/packages/input/color/src/ColorInput.tsx @@ -0,0 +1,121 @@ +import {InputLabel, InputState, useInput} from '@alinea/editor' +import {fromModule, HStack, IconButton} from '@alinea/ui' +import {useContrastColor} from '@alinea/ui/hook/UseContrastColor' +import {IcRoundCheck} from '@alinea/ui/icons/IcRoundCheck' +import {IcRoundClear} from '@alinea/ui/icons/IcRoundClear' +import {IcRoundColorLens} from '@alinea/ui/icons/IcRoundColorLens' +import {Popover} from '@headlessui/react' +import {HexColorInput, HexColorPicker} from 'react-colorful' +import {ColorField} from './ColorField' +import css from './ColorInput.module.scss' + +const styles = fromModule(css) + +type AllowedColorPickerProps = { + selectedColor: string | undefined + colors: Array + onClick: (color: string) => void +} + +function AllowedColorPicker({ + selectedColor, + colors, + onClick +}: AllowedColorPickerProps) { + const contrastColor = useContrastColor(selectedColor) + return ( + <> + + {colors.map(color => ( + + ))} + {selectedColor && ( + onClick('')} /> + )} + + + ) +} + +type AllColorPickerProps = { + color: string | undefined + onChange: (color: string) => void +} + +function AllColorPicker({color, onChange}: AllColorPickerProps) { + return ( + + {({open}) => ( + <> + + +
+ + {color && ( + onChange('')} + /> + )} + + + + + + + )} + + ) +} + +export type ColorInputProps = { + state: InputState> + field: ColorField +} + +export function ColorInput({state, field}: ColorInputProps) { + const {width, inline, optional, help, initialValue, allowedColors} = + field.options + const [value = initialValue, setValue] = useInput(state) + return ( + + {allowedColors ? ( + + ) : ( + + )} + + ) +} diff --git a/packages/input/color/src/index.ts b/packages/input/color/src/index.ts new file mode 100644 index 000000000..fb4698770 --- /dev/null +++ b/packages/input/color/src/index.ts @@ -0,0 +1,4 @@ +import {createColor} from './ColorField' +export * from './ColorField' +/** Create a check field configuration */ +export const color = createColor diff --git a/packages/input/color/src/view.ts b/packages/input/color/src/view.ts new file mode 100644 index 000000000..7275cb524 --- /dev/null +++ b/packages/input/color/src/view.ts @@ -0,0 +1,6 @@ +import {Field} from '@alinea/core' +import {createColor} from './ColorField' +import {ColorInput} from './ColorInput' +export * from './ColorField' +export * from './ColorInput' +export const color = Field.withView(createColor, ColorInput) diff --git a/packages/ui/src/icons/IcRoundClear.tsx b/packages/ui/src/icons/IcRoundClear.tsx new file mode 100644 index 000000000..63a03d561 --- /dev/null +++ b/packages/ui/src/icons/IcRoundClear.tsx @@ -0,0 +1,12 @@ +import React, {SVGProps} from 'react' + +export function IcRoundClear(props: SVGProps) { + return ( + + + + ) +} diff --git a/packages/ui/src/icons/IcRoundColorLens.tsx b/packages/ui/src/icons/IcRoundColorLens.tsx new file mode 100644 index 000000000..4a5154e43 --- /dev/null +++ b/packages/ui/src/icons/IcRoundColorLens.tsx @@ -0,0 +1,8 @@ +import React, { SVGProps } from 'react' + +export function IcRoundColorLens(props: SVGProps) { + return ( + + ) +} +export default IcRoundColorLens \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 7755999a7..9386a2200 100644 --- a/yarn.lock +++ b/yarn.lock @@ -212,6 +212,19 @@ __metadata: languageName: unknown linkType: soft +"@alinea/input.color@workspace:packages/input/color": + version: 0.0.0-use.local + resolution: "@alinea/input.color@workspace:packages/input/color" + dependencies: + "@alinea/core": 0.0.0 + "@alinea/editor": 0.0.0 + "@alinea/ui": 0.0.0 + react-colorful: ^5.5.1 + peerDependencies: + react: "*" + languageName: unknown + linkType: soft + "@alinea/input.link@0.0.0, @alinea/input.link@workspace:packages/input/link": version: 0.0.0-use.local resolution: "@alinea/input.link@workspace:packages/input/link" @@ -6738,6 +6751,16 @@ fsevents@~2.3.2: languageName: node linkType: hard +"react-colorful@npm:^5.5.1": + version: 5.5.1 + resolution: "react-colorful@npm:5.5.1" + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: e60811781716e57f0990379eff20d6f22d4d35b9e858c47ecf857c1dc1c1a2274c924ded7248bad5f1e2fbf2aab06e59b12852910c8dee5e6850f8e4df293670 + languageName: node + linkType: hard + "react-dom@npm:^18.1.0": version: 18.1.0 resolution: "react-dom@npm:18.1.0"