diff --git a/packages/react/package.json b/packages/react/package.json index adfdc9bf..445910f8 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -37,6 +37,8 @@ "@codemirror/state": "^6.2.0", "@codemirror/view": "^6.7.3", "@lezer/highlight": "^1.1.3", + "@replit/codemirror-emacs": "^6.0.0", + "@replit/codemirror-vim": "^6.0.6", "@strudel.cycles/core": "workspace:*", "@strudel.cycles/transpiler": "workspace:*", "@strudel.cycles/webaudio": "workspace:*", diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx index 06b95de0..319fb7f7 100644 --- a/packages/react/src/components/CodeMirror6.jsx +++ b/packages/react/src/components/CodeMirror6.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import _CodeMirror from '@uiw/react-codemirror'; import { EditorView, Decoration } from '@codemirror/view'; import { StateField, StateEffect } from '@codemirror/state'; @@ -8,6 +8,8 @@ import './style.css'; import { useCallback } from 'react'; import { autocompletion } from '@codemirror/autocomplete'; import { strudelAutocomplete } from './Autocomplete'; +import { vim } from '@replit/codemirror-vim'; +import { emacs } from '@replit/codemirror-emacs'; export const setFlash = StateEffect.define(); const flashField = StateField.define({ @@ -56,15 +58,15 @@ const highlightField = StateField.define({ haps .map((hap) => (hap.context.locations || []).map(({ start, end }) => { - const color = hap.context.color || e.value.color || '#FFCA28'; + // const color = hap.context.color || e.value.color || '#FFCA28'; let from = tr.newDoc.line(start.line).from + start.column; let to = tr.newDoc.line(end.line).from + end.column; const l = tr.newDoc.length; if (from > l || to > l) { return; // dont mark outside of range, as it will throw an error } - // const mark = Decoration.mark({ attributes: { style: `outline: 1px solid ${color}` } }); - const mark = Decoration.mark({ attributes: { style: `outline: 1.5px solid ${color};` } }); + //const mark = Decoration.mark({ attributes: { style: `outline: 2px solid ${color};` } }); + const mark = Decoration.mark({ attributes: { class: `outline outline-2 outline-foreground` } }); return mark.range(from, to); }), ) @@ -82,7 +84,7 @@ const highlightField = StateField.define({ provide: (f) => EditorView.decorations.from(f), }); -const extensions = [ +const staticExtensions = [ javascript(), highlightField, flashField, @@ -97,6 +99,9 @@ export default function CodeMirror({ onViewChanged, onSelectionChange, theme, + keybindings, + fontSize = 18, + fontFamily = 'monospace', options, editorDidMount, }) { @@ -120,8 +125,18 @@ export default function CodeMirror({ }, [onSelectionChange], ); + const extensions = useMemo(() => { + let bindings = { + vim, + emacs, + }; + if (bindings[keybindings]) { + return [...staticExtensions, bindings[keybindings]()]; + } + return staticExtensions; + }, [keybindings]); return ( - <> +
<_CodeMirror value={value} theme={theme || strudelTheme} @@ -130,7 +145,7 @@ export default function CodeMirror({ onUpdate={handleOnUpdate} extensions={extensions} /> - +
); } diff --git a/packages/react/src/components/MiniRepl.jsx b/packages/react/src/components/MiniRepl.jsx index 27d17983..ae91bbb0 100644 --- a/packages/react/src/components/MiniRepl.jsx +++ b/packages/react/src/components/MiniRepl.jsx @@ -23,7 +23,6 @@ export function MiniRepl({ punchcard, canvasHeight = 200, theme, - highlightColor, }) { drawTime = drawTime || (punchcard ? [0, 4] : undefined); const evalOnMount = !!drawTime; @@ -72,7 +71,6 @@ export function MiniRepl({ pattern, active: started && !activeCode?.includes('strudel disable-highlighting'), getTime: () => scheduler.now(), - color: highlightColor, }); // keyboard shortcuts diff --git a/packages/react/src/components/style.css b/packages/react/src/components/style.css index f2db01cc..ae33a5d2 100644 --- a/packages/react/src/components/style.css +++ b/packages/react/src/components/style.css @@ -2,11 +2,11 @@ background-color: transparent !important; height: 100%; z-index: 11; - font-size: 18px; } .cm-theme { width: 100%; + height: 100%; } .cm-theme-light { diff --git a/packages/react/src/hooks/useHighlighting.mjs b/packages/react/src/hooks/useHighlighting.mjs index 84262583..6e336586 100644 --- a/packages/react/src/hooks/useHighlighting.mjs +++ b/packages/react/src/hooks/useHighlighting.mjs @@ -1,7 +1,7 @@ import { useEffect, useRef } from 'react'; import { setHighlights } from '../components/CodeMirror6'; -function useHighlighting({ view, pattern, active, getTime, color }) { +function useHighlighting({ view, pattern, active, getTime }) { const highlights = useRef([]); const lastEnd = useRef(0); useEffect(() => { @@ -19,7 +19,7 @@ function useHighlighting({ view, pattern, active, getTime, color }) { highlights.current = highlights.current.filter((hap) => hap.whole.end > audioTime); // keep only highlights that are still active const haps = pattern.queryArc(...span).filter((hap) => hap.hasOnset()); highlights.current = highlights.current.concat(haps); // add potential new onsets - view.dispatch({ effects: setHighlights.of({ haps: highlights.current, color }) }); // highlight all still active + new active haps + view.dispatch({ effects: setHighlights.of({ haps: highlights.current }) }); // highlight all still active + new active haps } catch (err) { view.dispatch({ effects: setHighlights.of({ haps: [] }) }); } @@ -33,7 +33,7 @@ function useHighlighting({ view, pattern, active, getTime, color }) { view.dispatch({ effects: setHighlights.of({ haps: [] }) }); } } - }, [pattern, active, view, color]); + }, [pattern, active, view]); } export default useHighlighting; diff --git a/packages/react/src/hooks/useStrudel.mjs b/packages/react/src/hooks/useStrudel.mjs index 527aa708..b0b1062c 100644 --- a/packages/react/src/hooks/useStrudel.mjs +++ b/packages/react/src/hooks/useStrudel.mjs @@ -10,7 +10,6 @@ function useStrudel({ getTime, evalOnMount = false, initialCode = '', - autolink = false, beforeEval, afterEval, editPattern, @@ -51,15 +50,13 @@ function useStrudel({ setCode(code); beforeEval?.(); }, - afterEval: ({ pattern: _pattern, code }) => { + afterEval: (res) => { + const { pattern: _pattern, code } = res; setActiveCode(code); setPattern(_pattern); setEvalError(); setSchedulerError(); - if (autolink) { - window.location.hash = '#' + encodeURIComponent(btoa(code)); - } - afterEval?.(); + afterEval?.(res); }, onToggle: (v) => { setStarted(v); diff --git a/packages/react/src/themes/algoboy.js b/packages/react/src/themes/algoboy.js new file mode 100644 index 00000000..b4db09de --- /dev/null +++ b/packages/react/src/themes/algoboy.js @@ -0,0 +1,39 @@ +import { tags as t } from '@lezer/highlight'; +import { createTheme } from '@uiw/codemirror-themes'; +export const settings = { + background: '#9bbc0f', + foreground: '#0f380f', // whats that? + caret: '#0f380f', + selection: '#306230', + selectionMatch: '#ffffff26', + lineHighlight: '#8bac0f', + lineBackground: '#9bbc0f50', + //lineBackground: 'transparent', + gutterBackground: 'transparent', + gutterForeground: '#0f380f', + light: true, +}; +export default createTheme({ + theme: 'light', + settings, + styles: [ + { tag: t.keyword, color: '#0f380f' }, + { tag: t.operator, color: '#0f380f' }, + { tag: t.special(t.variableName), color: '#0f380f' }, + { tag: t.typeName, color: '#0f380f' }, + { tag: t.atom, color: '#0f380f' }, + { tag: t.number, color: '#0f380f' }, + { tag: t.definition(t.variableName), color: '#0f380f' }, + { tag: t.string, color: '#0f380f' }, + { tag: t.special(t.string), color: '#0f380f' }, + { tag: t.comment, color: '#0f380f' }, + { tag: t.variableName, color: '#0f380f' }, + { tag: t.tagName, color: '#0f380f' }, + { tag: t.bracket, color: '#0f380f' }, + { tag: t.meta, color: '#0f380f' }, + { tag: t.attributeName, color: '#0f380f' }, + { tag: t.propertyName, color: '#0f380f' }, + { tag: t.className, color: '#0f380f' }, + { tag: t.invalid, color: '#0f380f' }, + ], +}); diff --git a/packages/react/src/themes/blackscreen.js b/packages/react/src/themes/blackscreen.js new file mode 100644 index 00000000..ac9627c3 --- /dev/null +++ b/packages/react/src/themes/blackscreen.js @@ -0,0 +1,37 @@ +import { tags as t } from '@lezer/highlight'; +import { createTheme } from '@uiw/codemirror-themes'; +export const settings = { + background: 'black', + foreground: 'white', // whats that? + caret: 'white', + selection: '#ffffff20', + selectionMatch: '#036dd626', + lineHighlight: '#ffffff10', + lineBackground: '#00000050', + gutterBackground: 'transparent', + gutterForeground: '#8a919966', +}; +export default createTheme({ + theme: 'dark', + settings, + styles: [ + { tag: t.keyword, color: 'white' }, + { tag: t.operator, color: 'white' }, + { tag: t.special(t.variableName), color: 'white' }, + { tag: t.typeName, color: 'white' }, + { tag: t.atom, color: 'white' }, + { tag: t.number, color: 'white' }, + { tag: t.definition(t.variableName), color: 'white' }, + { tag: t.string, color: 'white' }, + { tag: t.special(t.string), color: 'white' }, + { tag: t.comment, color: 'white' }, + { tag: t.variableName, color: 'white' }, + { tag: t.tagName, color: 'white' }, + { tag: t.bracket, color: 'white' }, + { tag: t.meta, color: 'white' }, + { tag: t.attributeName, color: 'white' }, + { tag: t.propertyName, color: 'white' }, + { tag: t.className, color: 'white' }, + { tag: t.invalid, color: 'white' }, + ], +}); diff --git a/packages/react/src/themes/bluescreen.js b/packages/react/src/themes/bluescreen.js new file mode 100644 index 00000000..4f72d8c5 --- /dev/null +++ b/packages/react/src/themes/bluescreen.js @@ -0,0 +1,40 @@ +import { tags as t } from '@lezer/highlight'; +import { createTheme } from '@uiw/codemirror-themes'; +export const settings = { + background: '#051DB5', + lineBackground: '#051DB550', + foreground: 'white', // whats that? + caret: 'white', + selection: 'rgba(128, 203, 196, 0.5)', + selectionMatch: '#036dd626', + // lineHighlight: '#8a91991a', // original + lineHighlight: '#00000050', + gutterBackground: 'transparent', + // gutterForeground: '#8a919966', + gutterForeground: '#8a919966', +}; + +export default createTheme({ + theme: 'dark', + settings, + styles: [ + { tag: t.keyword, color: 'white' }, + { tag: t.operator, color: 'white' }, + { tag: t.special(t.variableName), color: 'white' }, + { tag: t.typeName, color: 'white' }, + { tag: t.atom, color: 'white' }, + { tag: t.number, color: 'white' }, + { tag: t.definition(t.variableName), color: 'white' }, + { tag: t.string, color: 'white' }, + { tag: t.special(t.string), color: 'white' }, + { tag: t.comment, color: 'white' }, + { tag: t.variableName, color: 'white' }, + { tag: t.tagName, color: 'white' }, + { tag: t.bracket, color: 'white' }, + { tag: t.meta, color: 'white' }, + { tag: t.attributeName, color: 'white' }, + { tag: t.propertyName, color: 'white' }, + { tag: t.className, color: 'white' }, + { tag: t.invalid, color: 'white' }, + ], +}); diff --git a/packages/react/src/themes/terminal.js b/packages/react/src/themes/terminal.js new file mode 100644 index 00000000..1374bb86 --- /dev/null +++ b/packages/react/src/themes/terminal.js @@ -0,0 +1,36 @@ +import { tags as t } from '@lezer/highlight'; +import { createTheme } from '@uiw/codemirror-themes'; +export const settings = { + background: 'black', + foreground: '#41FF00', // whats that? + caret: '#41FF00', + selection: '#ffffff20', + selectionMatch: '#036dd626', + lineHighlight: '#ffffff10', + gutterBackground: 'transparent', + gutterForeground: '#8a919966', +}; +export default createTheme({ + theme: 'dark', + settings, + styles: [ + { tag: t.keyword, color: '#41FF00' }, + { tag: t.operator, color: '#41FF00' }, + { tag: t.special(t.variableName), color: '#41FF00' }, + { tag: t.typeName, color: '#41FF00' }, + { tag: t.atom, color: '#41FF00' }, + { tag: t.number, color: '#41FF00' }, + { tag: t.definition(t.variableName), color: '#41FF00' }, + { tag: t.string, color: '#41FF00' }, + { tag: t.special(t.string), color: '#41FF00' }, + { tag: t.comment, color: '#41FF00' }, + { tag: t.variableName, color: '#41FF00' }, + { tag: t.tagName, color: '#41FF00' }, + { tag: t.bracket, color: '#41FF00' }, + { tag: t.meta, color: '#41FF00' }, + { tag: t.attributeName, color: '#41FF00' }, + { tag: t.propertyName, color: '#41FF00' }, + { tag: t.className, color: '#41FF00' }, + { tag: t.invalid, color: '#41FF00' }, + ], +}); diff --git a/packages/react/src/themes/whitescreen.js b/packages/react/src/themes/whitescreen.js new file mode 100644 index 00000000..22abad9e --- /dev/null +++ b/packages/react/src/themes/whitescreen.js @@ -0,0 +1,38 @@ +import { tags as t } from '@lezer/highlight'; +import { createTheme } from '@uiw/codemirror-themes'; +export const settings = { + background: 'white', + foreground: 'black', // whats that? + caret: 'black', + selection: 'rgba(128, 203, 196, 0.5)', + selectionMatch: '#ffffff26', + lineHighlight: '#cccccc50', + lineBackground: '#ffffff50', + gutterBackground: 'transparent', + gutterForeground: 'black', + light: true, +}; +export default createTheme({ + theme: 'light', + settings, + styles: [ + { tag: t.keyword, color: 'black' }, + { tag: t.operator, color: 'black' }, + { tag: t.special(t.variableName), color: 'black' }, + { tag: t.typeName, color: 'black' }, + { tag: t.atom, color: 'black' }, + { tag: t.number, color: 'black' }, + { tag: t.definition(t.variableName), color: 'black' }, + { tag: t.string, color: 'black' }, + { tag: t.special(t.string), color: 'black' }, + { tag: t.comment, color: 'black' }, + { tag: t.variableName, color: 'black' }, + { tag: t.tagName, color: 'black' }, + { tag: t.bracket, color: 'black' }, + { tag: t.meta, color: 'black' }, + { tag: t.attributeName, color: 'black' }, + { tag: t.propertyName, color: 'black' }, + { tag: t.className, color: 'black' }, + { tag: t.invalid, color: 'black' }, + ], +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 97aa6c81..df59deb2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -164,6 +164,8 @@ importers: '@codemirror/state': ^6.2.0 '@codemirror/view': ^6.7.3 '@lezer/highlight': ^1.1.3 + '@replit/codemirror-emacs': ^6.0.0 + '@replit/codemirror-vim': ^6.0.6 '@strudel.cycles/core': workspace:* '@strudel.cycles/transpiler': workspace:* '@strudel.cycles/webaudio': workspace:* @@ -185,6 +187,8 @@ importers: '@codemirror/state': 6.2.0 '@codemirror/view': 6.7.3 '@lezer/highlight': 1.1.3 + '@replit/codemirror-emacs': 6.0.0_cgfc5aojxuwjajwhkrgidrzxoa + '@replit/codemirror-vim': 6.0.6_a4vbhepr4qhxm5cldqd4jpyase '@strudel.cycles/core': link:../core '@strudel.cycles/transpiler': link:../transpiler '@strudel.cycles/webaudio': link:../webaudio @@ -358,6 +362,8 @@ importers: '@docsearch/react': ^3.1.0 '@headlessui/react': ^1.7.7 '@heroicons/react': ^2.0.13 + '@nanostores/persistent': ^0.7.0 + '@nanostores/react': ^0.4.1 '@strudel.cycles/core': workspace:* '@strudel.cycles/csound': workspace:* '@strudel.cycles/midi': workspace:* @@ -371,6 +377,7 @@ importers: '@strudel.cycles/webaudio': workspace:* '@strudel.cycles/xen': workspace:* '@supabase/supabase-js': ^1.35.3 + '@tailwindcss/forms': ^0.5.3 '@tailwindcss/typography': ^0.5.8 '@types/node': ^18.0.0 '@types/react': ^18.0.26 @@ -382,6 +389,7 @@ importers: fraction.js: ^4.2.0 html-escaper: ^3.0.3 nanoid: ^4.0.0 + nanostores: ^0.7.4 preact: ^10.7.3 react: ^18.2.0 react-dom: ^18.2.0 @@ -402,6 +410,8 @@ importers: '@docsearch/react': 3.3.2_y6lbs4o5th67cuzjdmtw5eqh7a '@headlessui/react': 1.7.8_biqbaboplfbrettd7655fr4n2y '@heroicons/react': 2.0.14_react@18.2.0 + '@nanostores/persistent': 0.7.0_nanostores@0.7.4 + '@nanostores/react': 0.4.1_nkfnbc2tpc77iht7asm3uqwau4 '@strudel.cycles/core': link:../packages/core '@strudel.cycles/csound': link:../packages/csound '@strudel.cycles/midi': link:../packages/midi @@ -415,6 +425,7 @@ importers: '@strudel.cycles/webaudio': link:../packages/webaudio '@strudel.cycles/xen': link:../packages/xen '@supabase/supabase-js': 1.35.7 + '@tailwindcss/forms': 0.5.3_tailwindcss@3.2.4 '@tailwindcss/typography': 0.5.9_tailwindcss@3.2.4 '@types/node': 18.11.18 '@types/react': 18.0.27 @@ -424,6 +435,7 @@ importers: canvas: 2.11.0 fraction.js: 4.2.0 nanoid: 4.0.0 + nanostores: 0.7.4 preact: 10.11.3 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 @@ -3164,6 +3176,27 @@ packages: - supports-color dev: false + /@nanostores/persistent/0.7.0_nanostores@0.7.4: + resolution: {integrity: sha512-4PAInL/T1hbftZUJ0cmgdFHBMalUoq7BUXFBy7QfyMv/8X3LPTYNh/yxspL7+J+XM3UNvVI7IFRMMs6FBasjhQ==} + engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} + peerDependencies: + nanostores: ^0.7.0 + dependencies: + nanostores: 0.7.4 + dev: false + + /@nanostores/react/0.4.1_nkfnbc2tpc77iht7asm3uqwau4: + resolution: {integrity: sha512-lsv0CYrMxczbXtoV/mxFVEoL/uVjEjseoP89srO/5yNAOkJka+dSFS7LYyWEbuvCPO7EgbtkvRpO5V+OztKQOw==} + engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} + peerDependencies: + nanostores: ^0.7.0 + react: '>=18.0.0' + dependencies: + nanostores: 0.7.4 + react: 18.2.0 + use-sync-external-store: 1.2.0_react@18.2.0 + dev: false + /@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -3400,6 +3433,33 @@ packages: tsm: 2.3.0 dev: false + /@replit/codemirror-emacs/6.0.0_cgfc5aojxuwjajwhkrgidrzxoa: + resolution: {integrity: sha512-zxSDg3UKm7811hjqNtgvK9G0IBtCWf82Idb9nZQo0ldmGl4d9SV7oCSuXQ58NmOG4AV7coD7kgFSZhEqHhyQhA==} + peerDependencies: + '@codemirror/autocomplete': ^6.0.2 + '@codemirror/commands': ^6.0.0 + '@codemirror/search': ^6.0.0 + '@codemirror/state': ^6.0.1 + '@codemirror/view': ^6.0.2 + dependencies: + '@codemirror/autocomplete': 6.4.0_a4vbhepr4qhxm5cldqd4jpyase + '@codemirror/state': 6.2.0 + '@codemirror/view': 6.7.3 + dev: false + + /@replit/codemirror-vim/6.0.6_a4vbhepr4qhxm5cldqd4jpyase: + resolution: {integrity: sha512-/Lc+5AmV+T5pTm5P+rWpL+gseNHNye7xaUWpULczHai5ZLVg/ZE3+MBwK3Ai+/SmZKR/mK2YuXgNKnTGToEGYg==} + peerDependencies: + '@codemirror/commands': ^6.0.0 + '@codemirror/language': ^6.1.0 + '@codemirror/search': ^6.2.0 + '@codemirror/state': ^6.0.1 + '@codemirror/view': ^6.0.3 + dependencies: + '@codemirror/state': 6.2.0 + '@codemirror/view': 6.7.3 + dev: false + /@rollup/plugin-babel/5.3.1_3dsfpkpoyvuuxyfgdbpn4j4uzm: resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} engines: {node: '>= 10.0.0'} @@ -3560,6 +3620,15 @@ packages: string.prototype.matchall: 4.0.8 dev: true + /@tailwindcss/forms/0.5.3_tailwindcss@3.2.4: + resolution: {integrity: sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==} + peerDependencies: + tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' + dependencies: + mini-svg-data-uri: 1.4.4 + tailwindcss: 3.2.4 + dev: false + /@tailwindcss/typography/0.5.9_tailwindcss@3.2.4: resolution: {integrity: sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg==} peerDependencies: @@ -9371,6 +9440,11 @@ packages: engines: {node: '>=4'} dev: true + /mini-svg-data-uri/1.4.4: + resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} + hasBin: true + dev: false + /minimatch/3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -9599,6 +9673,11 @@ packages: hasBin: true dev: false + /nanostores/0.7.4: + resolution: {integrity: sha512-MBeUVt7NBcXqh7AGT+KSr3O0X/995CZsvcP2QEMP+PXFwb07qv3Vjyq+EX0yS8f12Vv3Tn2g/BvK/OZoMhJlOQ==} + engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} + dev: false + /napi-build-utils/1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} dev: true @@ -10413,17 +10492,6 @@ packages: - supports-color dev: true - /postcss-import/14.1.0: - resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} - engines: {node: '>=10.0.0'} - peerDependencies: - postcss: ^8.0.0 - dependencies: - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.1 - dev: false - /postcss-import/14.1.0_postcss@8.4.21: resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} engines: {node: '>=10.0.0'} @@ -10434,16 +10502,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.1 - dev: true - - /postcss-js/4.0.0: - resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.3.3 - dependencies: - camelcase-css: 2.0.1 - dev: false /postcss-js/4.0.0_postcss@8.4.21: resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} @@ -10453,23 +10511,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.21 - dev: true - - /postcss-load-config/3.1.4: - resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} - engines: {node: '>= 10'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - dependencies: - lilconfig: 2.0.6 - yaml: 1.10.2 - dev: false /postcss-load-config/3.1.4_postcss@8.4.21: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} @@ -10487,15 +10528,6 @@ packages: postcss: 8.4.21 yaml: 1.10.2 - /postcss-nested/6.0.0: - resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 - dependencies: - postcss-selector-parser: 6.0.11 - dev: false - /postcss-nested/6.0.0_postcss@8.4.21: resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==} engines: {node: '>=12.0'} @@ -10504,7 +10536,6 @@ packages: dependencies: postcss: 8.4.21 postcss-selector-parser: 6.0.11 - dev: true /postcss-selector-parser/6.0.10: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} @@ -12127,8 +12158,6 @@ packages: resolution: {integrity: sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==} engines: {node: '>=12.13.0'} hasBin: true - peerDependencies: - postcss: ^8.0.9 dependencies: arg: 5.0.2 chokidar: 3.5.3 @@ -12145,10 +12174,10 @@ packages: object-hash: 3.0.0 picocolors: 1.0.0 postcss: 8.4.21 - postcss-import: 14.1.0 - postcss-js: 4.0.0 - postcss-load-config: 3.1.4 - postcss-nested: 6.0.0 + postcss-import: 14.1.0_postcss@8.4.21 + postcss-js: 4.0.0_postcss@8.4.21 + postcss-load-config: 3.1.4_postcss@8.4.21 + postcss-nested: 6.0.0_postcss@8.4.21 postcss-selector-parser: 6.0.11 postcss-value-parser: 4.2.0 quick-lru: 5.1.1 @@ -12854,6 +12883,14 @@ packages: punycode: 2.3.0 dev: true + /use-sync-external-store/1.2.0_react@18.2.0: + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /utf-8-validate/5.0.10: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} diff --git a/website/package.json b/website/package.json index f8c466d3..8d85481c 100644 --- a/website/package.json +++ b/website/package.json @@ -21,6 +21,8 @@ "@docsearch/react": "^3.1.0", "@headlessui/react": "^1.7.7", "@heroicons/react": "^2.0.13", + "@nanostores/persistent": "^0.7.0", + "@nanostores/react": "^0.4.1", "@strudel.cycles/core": "workspace:*", "@strudel.cycles/csound": "workspace:*", "@strudel.cycles/midi": "workspace:*", @@ -34,6 +36,7 @@ "@strudel.cycles/webaudio": "workspace:*", "@strudel.cycles/xen": "workspace:*", "@supabase/supabase-js": "^1.35.3", + "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.8", "@types/node": "^18.0.0", "@types/react": "^18.0.26", @@ -43,6 +46,7 @@ "canvas": "^2.11.0", "fraction.js": "^4.2.0", "nanoid": "^4.0.0", + "nanostores": "^0.7.4", "preact": "^10.7.3", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/website/public/fonts/3270/3270-Regular.ttf b/website/public/fonts/3270/3270-Regular.ttf new file mode 100644 index 00000000..d6b55a6a Binary files /dev/null and b/website/public/fonts/3270/3270-Regular.ttf differ diff --git a/website/public/fonts/3270/LICENSE.txt b/website/public/fonts/3270/LICENSE.txt new file mode 100644 index 00000000..b8f248ab --- /dev/null +++ b/website/public/fonts/3270/LICENSE.txt @@ -0,0 +1,51 @@ +Copyright 2022 The 3270font Authors (https://github.com/rbanffy/3270font) + +Copyright (c) 2011-2022, Ricardo Banffy. +Copyright (c) 1993-2011, Paul Mattes. +Copyright (c) 2004-2005, Don Russell. +Copyright (c) 2004, Dick Altenbern. +Copyright (c) 1990, Jeff Sparkes. +Copyright (c) 1989, Georgia Tech Research Corporation (GTRC), Atlanta, GA 30332. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Ricardo Banffy, Paul Mattes, Don Russell, + Dick Altenbern, Jeff Sparkes, GTRC nor the names of their contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL RICARDO BANFFY, PAUL MATTES, DON RUSSELL, DICK ALTENBERN, JEFF +SPARKES OR GTRC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The Debian Logo glyph is based on the Debian Open Use Logo and is +Copyright (c) 1999 Software in the Public Interest, Inc., and it is +incorporated here under the terms of the Creative Commons +Attribution-ShareAlike 3.0 Unported License. The logo is released +under the terms of the GNU Lesser General Public License, version 3 or +any later version, or, at your option, of the Creative Commons +Attribution-ShareAlike 3.0 Unported License. + +Ubuntu, the Ubuntu logo and the Circle of Friends symbol are +registered trademarks of Canonical Ltd. + +The Fontforge SFD font description file is optionally licensed under +the SIL Open Font License v1.1 with no Reserved Font Name. This +license is available with a FAQ at http://scripts.sil.org/OFL. diff --git a/website/public/fonts/BigBlueTerminal/BigBlue_TerminalPlus.TTF b/website/public/fonts/BigBlueTerminal/BigBlue_TerminalPlus.TTF new file mode 100644 index 00000000..ddcdc328 Binary files /dev/null and b/website/public/fonts/BigBlueTerminal/BigBlue_TerminalPlus.TTF differ diff --git a/website/public/fonts/BigBlueTerminal/LICENSE.txt b/website/public/fonts/BigBlueTerminal/LICENSE.txt new file mode 100644 index 00000000..fd662a7e --- /dev/null +++ b/website/public/fonts/BigBlueTerminal/LICENSE.txt @@ -0,0 +1,428 @@ +Attribution-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-ShareAlike 4.0 International Public +License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-ShareAlike 4.0 International Public License ("Public +License"). To the extent this Public License may be interpreted as a +contract, You are granted the Licensed Rights in consideration of Your +acceptance of these terms and conditions, and the Licensor grants You +such rights in consideration of benefits the Licensor receives from +making the Licensed Material available under these terms and +conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + + including for purposes of Section 3(b); and + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the β€œLicensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/website/public/fonts/PressStart2P/OFL.txt b/website/public/fonts/PressStart2P/OFL.txt new file mode 100644 index 00000000..2a6f4a8d --- /dev/null +++ b/website/public/fonts/PressStart2P/OFL.txt @@ -0,0 +1,92 @@ +Copyright (c) 2012, Cody "CodeMan38" Boisclair (cody@zone38.net), with Reserved Font Name "Press Start 2P" +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/website/public/fonts/PressStart2P/PressStart2P-Regular.ttf b/website/public/fonts/PressStart2P/PressStart2P-Regular.ttf new file mode 100644 index 00000000..1098ed23 Binary files /dev/null and b/website/public/fonts/PressStart2P/PressStart2P-Regular.ttf differ diff --git a/website/src/components/Footer/AvatarList.astro b/website/src/components/Footer/AvatarList.astro index b75589f5..86bbcc87 100644 --- a/website/src/components/Footer/AvatarList.astro +++ b/website/src/components/Footer/AvatarList.astro @@ -1,66 +1,64 @@ --- // fetch all commits for just this page's path type Props = { - path: string; + path: string; }; const { path } = Astro.props as Props; -const resolvedPath = `examples/docs/${path}`; -const url = `https://api.github.com/repos/withastro/astro/commits?path=${resolvedPath}`; -const commitsURL = `https://github.com/withastro/astro/commits/main/${resolvedPath}`; +const resolvedPath = `website/src/pages${path}.mdx`; +const url = `https://api.github.com/repos/tidalcycles/strudel/commits?path=${resolvedPath}`; +const commitsURL = `https://github.com/tidalcycles/strudel/commits/main/${resolvedPath}`; type Commit = { - author: { - id: string; - login: string; - }; + author: { + id: string; + login: string; + }; }; async function getCommits(url: string) { - try { - const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN ?? 'hello'; - if (!token) { - throw new Error( - 'Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.' - ); - } + try { + const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN ?? 'hello'; + if (!token) { + throw new Error('Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.'); + } - const auth = `Basic ${Buffer.from(token, 'binary').toString('base64')}`; + const auth = `Basic ${Buffer.from(token, 'binary').toString('base64')}`; - const res = await fetch(url, { - method: 'GET', - headers: { - Authorization: auth, - 'User-Agent': 'astro-docs/1.0', - }, - }); + const res = await fetch(url, { + method: 'GET', + headers: { + Authorization: auth, + 'User-Agent': 'astro-docs/1.0', + }, + }); - const data = await res.json(); + const data = await res.json(); - if (!res.ok) { - throw new Error( - `Request to fetch commits failed. Reason: ${res.statusText} - Message: ${data.message}` - ); - } + if (!res.ok) { + throw new Error( + `Request to fetch commits failed. Reason: ${res.statusText} + Message: ${data.message}`, + ); + } - return data as Commit[]; - } catch (e) { - console.warn(`[error] /src/components/AvatarList.astro + return data as Commit[]; + } catch (e) { + console.warn(`[error] /src/components/AvatarList.astro ${(e as any)?.message ?? e}`); - return [] as Commit[]; - } + return [] as Commit[]; + } } function removeDups(arr: Commit[]) { - const map = new Map(); + const map = new Map(); + for (let item of arr) { + const author = item.author; + // Deduplicate based on author.id + //map.set(author.id, { login: author.login, id: author.id }); + author && map.set(author.id, { login: author.login, id: author.id }); + } - for (let item of arr) { - const author = item.author; - // Deduplicate based on author.id - map.set(author.id, { login: author.login, id: author.id }); - } - - return [...map.values()]; + return [...map.values()]; } const data = await getCommits(url); @@ -70,102 +68,102 @@ const additionalContributors = unique.length - recentContributors.length; // lis --- -
-
    - { - recentContributors.map((item) => ( -
  • - - {`Contributor - -
  • - )) - } -
- { - additionalContributors > 0 && ( - - {`and ${additionalContributors} additional contributor${ - additionalContributors > 1 ? 's' : '' - }.`} - - ) - } - {unique.length === 0 && Contributors} +
+
    + { + recentContributors.map((item) => ( +
  • + + {`Contributor + +
  • + )) + } +
+ { + additionalContributors > 0 && ( + + {`and ${additionalContributors} additional contributor${ + additionalContributors > 1 ? 's' : '' + }.`} + + ) + } + {unique.length === 0 && Contributors}
diff --git a/website/src/components/Footer/Footer.astro b/website/src/components/Footer/Footer.astro deleted file mode 100644 index 1ec756b8..00000000 --- a/website/src/components/Footer/Footer.astro +++ /dev/null @@ -1,19 +0,0 @@ ---- -import AvatarList from './AvatarList.astro'; -type Props = { - path: string; -}; -const { path } = Astro.props as Props; ---- - -
- -
- - diff --git a/website/src/components/HeadCommon.astro b/website/src/components/HeadCommon.astro index 796f96db..24388a20 100644 --- a/website/src/components/HeadCommon.astro +++ b/website/src/components/HeadCommon.astro @@ -1,12 +1,9 @@ --- import { pwaInfo } from 'virtual:pwa-info'; import '../styles/index.css'; -import { settings } from '../repl/themes.mjs'; const { BASE_URL } = import.meta.env; const base = BASE_URL; - -const { strudelTheme } = settings; --- @@ -48,37 +45,43 @@ const { strudelTheme } = settings; {pwaInfo && } - diff --git a/website/src/components/RightSidebar/RightSidebar.astro b/website/src/components/RightSidebar/RightSidebar.astro index e6031e4d..ba193d24 100644 --- a/website/src/components/RightSidebar/RightSidebar.astro +++ b/website/src/components/RightSidebar/RightSidebar.astro @@ -2,6 +2,7 @@ import TableOfContents from './TableOfContents'; import MoreMenu from './MoreMenu.astro'; import type { MarkdownHeading } from 'astro'; +import AvatarList from '../Footer/AvatarList.astro'; type Props = { headings: MarkdownHeading[]; @@ -17,4 +18,5 @@ currentPage = currentPage.endsWith('/') ? currentPage.slice(0, -1) : currentPage diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index f3e83d99..83106a53 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -4,8 +4,7 @@ import { useEffect, useState } from 'react'; import { prebake } from '../repl/prebake'; import { themes, settings } from '../repl/themes.mjs'; import './MiniRepl.css'; - -const theme = localStorage.getItem('strudel-theme') || 'strudelTheme'; +import { useSettings } from '../settings.mjs'; let modules; if (typeof window !== 'undefined') { @@ -29,6 +28,7 @@ if (typeof window !== 'undefined') { export function MiniRepl({ tune, drawTime, punchcard, canvasHeight = 100 }) { const [Repl, setRepl] = useState(); + const { theme } = useSettings(); useEffect(() => { // we have to load this package on the client // because codemirror throws an error on the server @@ -36,7 +36,6 @@ export function MiniRepl({ tune, drawTime, punchcard, canvasHeight = 100 }) { .then(([res]) => setRepl(() => res.MiniRepl)) .catch((err) => console.error(err)); }, []); - // const { settings } = useTheme(); return Repl ? (
) : ( diff --git a/website/src/layouts/MainLayout.astro b/website/src/layouts/MainLayout.astro index f4cf091a..49952a7e 100644 --- a/website/src/layouts/MainLayout.astro +++ b/website/src/layouts/MainLayout.astro @@ -7,7 +7,6 @@ import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro'; import RightSidebar from '../components/RightSidebar/RightSidebar.astro'; import * as CONFIG from '../config'; import type { MarkdownHeading } from 'astro'; -import Footer from '../components/Footer/Footer.astro'; import '../docs/docs.css'; type Props = { @@ -31,7 +30,7 @@ const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`; - +
@@ -49,7 +48,6 @@ const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`;
-
diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro index 8d673c37..40a1a03f 100644 --- a/website/src/pages/index.astro +++ b/website/src/pages/index.astro @@ -8,7 +8,7 @@ import { Repl } from '../repl/Repl.jsx'; Strudel REPL - + diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx index 28939c03..07bdd386 100644 --- a/website/src/repl/Footer.jsx +++ b/website/src/repl/Footer.jsx @@ -6,14 +6,13 @@ import { nanoid } from 'nanoid'; import React, { useCallback, useLayoutEffect, useRef, useState } from 'react'; import { loadedSamples } from './Repl'; import { Reference } from './Reference'; -import { themes, themeColors } from './themes.mjs'; +import { themes } from './themes.mjs'; +import { useSettings, settingsMap, setActiveFooter, defaultSettings } from '../settings.mjs'; export function Footer({ context }) { - // const [activeFooter, setActiveFooter] = useState('console'); - // const { activeFooter, setActiveFooter, isZen } = useContext?.(ReplContext); - const { activeFooter, setActiveFooter, isZen, theme, setTheme } = context; const footerContent = useRef(); const [log, setLog] = useState([]); + const { activeFooter, isZen } = useSettings(); useLayoutEffect(() => { if (footerContent.current && activeFooter === 'console') { @@ -56,8 +55,8 @@ export function Footer({ context }) {
setActiveFooter(name)} className={cx( - 'h-8 px-2 text-foreground cursor-pointer hover:text-tertiary flex items-center space-x-1 border-b', - activeFooter === name ? 'border-foreground hover:border-tertiary' : 'border-transparent', + 'h-8 px-2 text-foreground cursor-pointer hover:opacity-50 flex items-center space-x-1 border-b', + activeFooter === name ? 'border-foreground' : 'border-transparent', )} > {label || name} @@ -76,7 +75,7 @@ export function Footer({ context }) { - +
{activeFooter !== '' && ( + ))} + + ); +} + +function SelectInput({ value, options, onChange }) { + return ( + + ); +} + +function NumberSlider({ value, onChange, step = 1, ...rest }) { + return ( +
+ onChange(Number(e.target.value))} + {...rest} + /> + onChange(Number(e.target.value))} + /> +
+ ); +} + +function FormItem({ label, children }) { + return ( +
+ + {children} +
+ ); +} + +const themeOptions = Object.fromEntries(Object.keys(themes).map((k) => [k, k])); +const fontFamilyOptions = { + monospace: 'monospace', + BigBlueTerminal: 'BigBlueTerminal', + x3270: 'x3270', + PressStart: 'PressStart2P', +}; + +function SettingsTab() { + const { theme, keybindings, fontSize, fontFamily } = useSettings(); + return ( +
+ + settingsMap.setKey('theme', theme)} /> + +
+ + settingsMap.setKey('fontFamily', fontFamily)} + /> + + + settingsMap.setKey('fontSize', fontSize)} + min={10} + max={40} + step={2} + /> + +
+ + settingsMap.setKey('keybindings', keybindings)} + items={{ codemirror: 'Codemirror', vim: 'Vim', emacs: 'Emacs' }} + > + + + + +
+ ); +} diff --git a/website/src/repl/Header.jsx b/website/src/repl/Header.jsx index c58efe11..213e336e 100644 --- a/website/src/repl/Header.jsx +++ b/website/src/repl/Header.jsx @@ -6,6 +6,7 @@ import SparklesIcon from '@heroicons/react/20/solid/SparklesIcon'; import StopCircleIcon from '@heroicons/react/20/solid/StopCircleIcon'; import { cx } from '@strudel.cycles/react'; import React, { useContext } from 'react'; +import { useSettings, setIsZen } from '../settings.mjs'; // import { ReplContext } from './Repl'; import './Repl.css'; @@ -21,11 +22,9 @@ export function Header({ context }) { handleUpdate, handleShuffle, handleShare, - isZen, - setIsZen, } = context; const isEmbedded = embedded || window.location !== window.parent.location; - // useContext(ReplContext) + const { isZen } = useSettings(); return (
!isEmbedded && setIsZen((z) => !z)} + onClick={() => { + if (!isEmbedded) { + setIsZen(!isZen); + } + }} > πŸŒ€
@@ -69,7 +72,7 @@ export function Header({ context }) { )} {isEmbedded && ( -