diff --git a/src/design-tokens.cg b/src/design-tokens.cg new file mode 100644 index 0000000..ea0b546 --- /dev/null +++ b/src/design-tokens.cg @@ -0,0 +1,38 @@ +colors = { + primary = "#0066cc", + primaryDark = "#0052a3", + danger = "#dc3545", + success = "#28a745", + bg = "#ffffff", + bgGray = "#f8f9fa", + text = "#212529", + textLight = "#6c757d", + border = "#dee2e6" +}; + +spacing = { + xs = 4, + sm = 8, + md = 16, + lg = 32, + xl = 64 +}; + +primaryStyle = { + bg = colors.primary, + fg = colors.bg, + px = spacing.md, + py = spacing.sm +}; + +dangerStyle = { + bg = colors.danger, + fg = colors.bg, + px = spacing.md, + py = spacing.sm +}; + +theme = { + colors = colors, + spacing = spacing +}; diff --git a/src/main.ts b/src/main.ts index 4a76306..4901bd8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,18 +5,21 @@ import { Parser } from './parser' import { runApp } from './runtime'; import { builtins } from './builtins'; -import counterApp from './counter.cg?raw'; import stdlibCode from './stdlib.cg?raw'; +import designTokensCode from './design-tokens.cg?raw'; import uiComponentsCode from './ui-components.cg?raw'; + import textInputCode from './textinput-test.cg?raw'; import testCode from './test.cg?raw'; +import counterApp from './counter.cg?raw'; const canvas = document.createElement('canvas'); canvas.width = 800; canvas.height = 600; +canvas.style.border = "1px solid #000"; document.body.appendChild(canvas); -const cgCode = stdlibCode + '\n' + uiComponentsCode + '\n' + textInputCode; +const cgCode = stdlibCode + '\n' + designTokensCode + '\n' + uiComponentsCode + '\n' + textInputCode; const tokens = tokenize(cgCode); const parser = new Parser(tokens); diff --git a/src/runtime.ts b/src/runtime.ts index 42a5613..8750c28 100644 --- a/src/runtime.ts +++ b/src/runtime.ts @@ -16,7 +16,7 @@ export function runApp(app: App, canvas: HTMLCanvasElement) { if (app.view.kind !== 'closure') throw new Error('view must be a function'); - const viewport = { + const viewport: Value = { kind: 'record', fields: { width: { kind: 'int', value: canvas.width }, @@ -61,13 +61,9 @@ export function runApp(app: App, canvas: HTMLCanvasElement) { return; } - const eventName = hitTest(x, y); - if (eventName) { - const event: Value = { - kind: 'constructor', - name: eventName, - args: [] - } + + const event = hitTest(x, y); + if (event) { handleEvent(event); } }); diff --git a/src/textinput-test.cg b/src/textinput-test.cg index 58ef6be..ddb268e 100644 --- a/src/textinput-test.cg +++ b/src/textinput-test.cg @@ -2,17 +2,22 @@ init = { text = "" }; update = state event \ event | UpdateText newText \ state.{ text = newText } - | Submit _ \ state.{ text = "" }; - # | _ \ state; + | Submit _ \ state.{ text = "" } + | Go \ state.{ text = "" }; view = state viewport \ Column { gap = 20, children = [ + Text { + content = "window: " & str(viewport.width) & " x " & str(viewport.height), + x = 0, + y = 20 + }, Text { content = "You typed: " & state.text, x = 0, y = 20 }, Stack { children = [ - Rect { w = 300, h = 40, color = "white" }, + Rect { w = viewport.width, h = 40, color = "blue" }, TextInput { value = state.text, placeholder = "Type something...", @@ -24,9 +29,9 @@ view = state viewport \ onInput = UpdateText, onSubmit = Submit } - # button ({ label = "Go", event = Go }) ] - } + }, + button { label = "Go", event = Go, theme = theme } ] }; diff --git a/src/types.ts b/src/types.ts index d622b97..3b467c6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -51,7 +51,7 @@ export type UIValue = | { kind: 'text', content: string, x: number, y: number } | { kind: 'row', children: UIValue[], gap: number } | { kind: 'column', children: UIValue[], gap: number } - | { kind: 'clickable', child: UIValue, event: string } + | { kind: 'clickable', child: UIValue, event: Value } | { kind: 'padding', child: UIValue, amount: number } | { kind: 'stack', children: UIValue[] } | { kind: 'text-input', value: string, placeholder: string, x: number, y: number, w: number, h: number, focused: boolean, onInput: Value, onSubmit: Value } diff --git a/src/ui-components.cg b/src/ui-components.cg index 1874853..d1a4616 100644 --- a/src/ui-components.cg +++ b/src/ui-components.cg @@ -1,10 +1,11 @@ +# button : Record -> UI button = config \ Clickable { event = config.event, child = Stack { children = [ - Rect { w = 100, h = 40, color = "blue" }, - Text { content = config.label, x = 10, y = 25} + Rect { w = 100, h = 40, color = config.theme.colors.primary }, + Text { content = config.label, x = 10, y = 25, color = config.theme.colors.bg } ] } }; diff --git a/src/ui.ts b/src/ui.ts index 114ba66..c7f98d0 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -5,7 +5,7 @@ type ClickRegion = { y: number; width: number; height: number; - event: string; + event: Value; }; type TextInputRegion = { @@ -171,14 +171,12 @@ function measure(ui: UIValue): { width: number, height: number } { case 'text-input': return { width: ui.w, height: ui.h }; } - - // return { width: 0, height: 0 }; } -export function hitTest(x: number, y: number): string | null { +export function hitTest(x: number, y: number): Value | null { for (const region of clickRegions) { if (x >= region.x && x < region.x + region.width && - x >= region.y && y < region.y + region.height) { + y >= region.y && y < region.y + region.height) { return region.event; } } diff --git a/src/valueToUI.ts b/src/valueToUI.ts index 24e7b13..cfc2ef4 100644 --- a/src/valueToUI.ts +++ b/src/valueToUI.ts @@ -57,10 +57,10 @@ export function valueToUI(value: Value): UIValue { const child = fields.child; const event = fields.event; - if (event.kind !== 'string') - throw new Error('Invalid Clickable fields'); + if (event.kind !== 'constructor') + throw new Error('Clickable event must be a constructor'); - return { kind: 'clickable', event: event.value, child: valueToUI(child) }; + return { kind: 'clickable', event: event, child: valueToUI(child) }; } case 'Padding': {