diff --git a/.changeset/chilled-students-relate.md b/.changeset/chilled-students-relate.md new file mode 100644 index 000000000..98463c27c --- /dev/null +++ b/.changeset/chilled-students-relate.md @@ -0,0 +1,7 @@ +--- +'@keystar/ui': patch +--- + +Improve prose styles: +- style `kbd` elements +- basic table styles diff --git a/.changeset/fast-chicken-look.md b/.changeset/fast-chicken-look.md new file mode 100644 index 000000000..0b9602f52 --- /dev/null +++ b/.changeset/fast-chicken-look.md @@ -0,0 +1,5 @@ +--- +'@keystatic/core': patch +--- + +Document editor features, within footer actions. diff --git a/design-system/pkg/src/typography/Kbd.tsx b/design-system/pkg/src/typography/Kbd.tsx index 048fd6c1e..166215523 100644 --- a/design-system/pkg/src/typography/Kbd.tsx +++ b/design-system/pkg/src/typography/Kbd.tsx @@ -13,6 +13,7 @@ import { DOMProps } from '@react-types/shared'; import { useSlotProps } from '@keystar/ui/slots'; import { BaseStyleProps, css } from '@keystar/ui/style'; +import { TextProps } from '@keystar/ui/types'; import { useTextStyles } from './text'; @@ -50,7 +51,8 @@ export type KbdProps = { * @default 'kbd' */ slot?: string; -} & DOMProps & +} & Pick & + DOMProps & BaseStyleProps; /** Represents text that specifies a keyboard command. */ diff --git a/design-system/pkg/src/typography/Prose.tsx b/design-system/pkg/src/typography/Prose.tsx index f9e4186df..c064655c8 100644 --- a/design-system/pkg/src/typography/Prose.tsx +++ b/design-system/pkg/src/typography/Prose.tsx @@ -117,10 +117,20 @@ export function useProseStyleProps(props: ProseProps) { a: { color: tokenSchema.color.foreground.accent, }, + kbd: { + backgroundColor: tokenSchema.color.alias.backgroundIdle, + borderRadius: tokenSchema.size.radius.small, + border: `${tokenSchema.size.border.regular} solid ${tokenSchema.color.alias.borderIdle}`, + color: tokenSchema.color.foreground.neutralEmphasis, + display: 'inline', + fontSize: '0.85em', + fontFamily: tokenSchema.typography.fontFamily.code, + padding: '.2em .4em', + }, // code block pre: { - backgroundColor: tokenSchema.color.background.surface, + backgroundColor: tokenSchema.color.alias.backgroundIdle, borderRadius: tokenSchema.size.radius.medium, color: tokenSchema.color.foreground.neutralEmphasis, fontFamily: tokenSchema.typography.fontFamily.code, @@ -137,13 +147,13 @@ export function useProseStyleProps(props: ProseProps) { }, // inline code '& :not(pre) > code': { - backgroundColor: tokenSchema.color.background.accent, + backgroundColor: tokenSchema.color.alias.backgroundSelected, borderRadius: tokenSchema.size.radius.small, color: tokenSchema.color.foreground.neutralEmphasis, - display: 'inline-block', + display: 'inline', fontSize: '0.85em', fontFamily: tokenSchema.typography.fontFamily.code, - paddingInline: tokenSchema.size.space.small, + padding: '.2em .4em', }, // Headings @@ -183,6 +193,30 @@ export function useProseStyleProps(props: ProseProps) { fontWeight: tokenSchema.typography.fontWeight.semibold, letterSpacing: '0.0125em', }, + + // Tables + // --------------------------------------------------------------------- + table: { + borderCollapse: 'collapse', + borderSpacing: 0, + width: '100%', + // tableLayout: 'fixed', + }, + th: { + fontWeight: tokenSchema.typography.fontWeight.semibold, + padding: '0.5rem', + textAlign: 'start', + verticalAlign: 'top', + }, + ':where(th:first-child)': { paddingInlineStart: 0 }, + ':where(th:last-child)': { paddingInlineEnd: 0 }, + td: { + padding: '0.5rem', + verticalAlign: 'top', + }, + ':where(td:first-child)': { paddingInlineStart: 0 }, + ':where(td:last-child)': { paddingInlineEnd: 0 }, + ...getListStyles(), }), styleProps.className diff --git a/packages/keystatic/src/form/fields/markdoc/editor/editor-footer.tsx b/packages/keystatic/src/form/fields/markdoc/editor/editor-footer.tsx new file mode 100644 index 000000000..c1a0556f2 --- /dev/null +++ b/packages/keystatic/src/form/fields/markdoc/editor/editor-footer.tsx @@ -0,0 +1,218 @@ +import { useCallback, useMemo } from 'react'; + +import { ActionButton } from '@keystar/ui/button'; +import { Dialog, DialogTrigger } from '@keystar/ui/dialog'; +import { Icon } from '@keystar/ui/icon'; +import { imageIcon } from '@keystar/ui/icon/icons/imageIcon'; +import { typeIcon } from '@keystar/ui/icon/icons/typeIcon'; +import { HStack } from '@keystar/ui/layout'; +import { Content, SlotProvider } from '@keystar/ui/slots'; +import { Heading, Kbd, Prose, Text } from '@keystar/ui/typography'; + +import { getUploadedFileObject } from '../../image/ui'; +import { useEditorDispatchCommand } from './editor-view'; +import { readFileAsDataUrl } from './images'; + +export function EditorFooter() { + const runCommand = useEditorDispatchCommand(); + const handleImagePress = useCallback(async () => { + const file = await getUploadedFileObject('image/*'); + if (!file) return; + const src = await readFileAsDataUrl(file); + runCommand((state, dispatch) => { + if (dispatch) { + dispatch( + state.tr.replaceSelectionWith( + state.schema.nodes.image.createChecked({ + src, + filename: file.name, + }) + ) + ); + } + return true; + }); + }, [runCommand]); + + const slots = useMemo( + () => ({ icon: { size: 'small' }, text: { size: 'small' } }) as const, + [] + ); + + return ( + + + + + + Markdown support + + + + + + + + Paste, drop, or click to add images + + + + ); +} + +function MarkdownDialog() { + return ( + + Basic writing and formatting syntax + + +

+ Markdown is a way to style text; it is intended to be as + easy-to-read and easy-to-write as is feasible. +

+ +

Headings

+

+ To create a heading, add one to six # symbols before + your heading text. The number of # you use will + determine the hierarchy level and typeface size of the heading. +

+
+            {`# A first-level heading\n## A second-level heading\n### A third-level heading`}
+          
+ +

Styling text

+

+ You can indicate emphasis with bold, italic, or strikethrough text. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StyleSyntaxShortcutExampleOutput
Bold + ** ** + + + B + + + **This is bold text** + + This is bold text +
Italic + _ _ + + + I + + + _This text is italicized_ + + This text is italicized +
Strikethrough + ~~ ~~ + None + ~~This was mistaken text~~ + + This was mistaken text +
Nested emphasis + ** ** and _ _ + None + **This text is _extremely_ important** + + + This text is extremely important + +
+ +

Lists

+

+ You can make an unordered (bulleted) list by preceding one or more + lines of text with -, or *. +

+
+            {`- Red\n- Green\n- Blue`}
+          
+ +

+ Create an ordered (numbered) list by preceding each line with a + number. +

+
+            {`1. Red\n1. Green\n1. Blue`}
+          
+ +

Quoting text

+

+ You can quote text with a {'>'}. +

+
+            {`Text that is not a quote\n\n> Text that is a quote`}
+          
+ +

Quoting code

+

+ You can call out code or a command within a sentence with single + backticks {'`'}. The text within the backticks will not + be formatted. +

+
+            {`Use \`npm create @keystatic@latest\` to start editing static files today.`}
+          
+ +

+ To format code or text into its own distinct block, use triple + backticks {'```'}. +

+
+            {`Keystatic projects expect an exported config:
+
+\`\`\`
+import { config } from '@keystatic/core'
+
+export default config({
+  ...
+})
+\`\`\``}
+          
+
+
+
+ ); +} diff --git a/packages/keystatic/src/form/fields/markdoc/editor/index.tsx b/packages/keystatic/src/form/fields/markdoc/editor/index.tsx index 6a144340b..0c7dc52ec 100644 --- a/packages/keystatic/src/form/fields/markdoc/editor/index.tsx +++ b/packages/keystatic/src/form/fields/markdoc/editor/index.tsx @@ -25,6 +25,7 @@ import { } from './context'; import { useEntryLayoutSplitPaneContext } from '../../../../app/entry-form'; import { useContentPanelSize } from '../../../../app/shell/context'; +import { EditorFooter } from './editor-footer'; import { yCursorPluginKey, ySyncPluginKey } from 'y-prosemirror'; import * as Y from 'yjs'; @@ -119,16 +120,15 @@ export const Editor = forwardRef(function Editor( })} > -
- -
+ +