From cdd40df9d33f3789c696b57d8c680d8e1d869273 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 8 Feb 2023 18:54:19 +0100 Subject: [PATCH 001/112] disable sw in dev --- website/astro.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 646a3b3ca..f1b8395d5 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -53,7 +53,7 @@ export default defineConfig({ ], }, devOptions: { - enabled: true, + enabled: false, }, manifest: { includeAssets: ['favicon.ico', 'icons/apple-icon-180.png', 'favicon.svg'], From 30b149053ceaf7fb5d041fa3e4c6fffb436b7ce0 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 8 Feb 2023 18:54:34 +0100 Subject: [PATCH 002/112] basic theme switcher --- packages/react/src/components/CodeMirror6.jsx | 13 +- packages/react/src/components/style.css | 8 +- pnpm-lock.yaml | 177 ++++++++++++++++++ website/package.json | 1 + website/src/repl/Footer.jsx | 21 ++- website/src/repl/Repl.jsx | 5 + website/src/repl/themes.mjs | 31 +++ 7 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 website/src/repl/themes.mjs diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx index 8b05a7278..1dbc10668 100644 --- a/packages/react/src/components/CodeMirror6.jsx +++ b/packages/react/src/components/CodeMirror6.jsx @@ -79,9 +79,17 @@ const highlightField = StateField.define({ provide: (f) => EditorView.decorations.from(f), }); -const extensions = [javascript(), strudelTheme, highlightField, flashField]; +const extensions = [javascript(), highlightField, flashField]; -export default function CodeMirror({ value, onChange, onViewChanged, onSelectionChange, options, editorDidMount }) { +export default function CodeMirror({ + value, + onChange, + onViewChanged, + onSelectionChange, + theme, + options, + editorDidMount, +}) { const handleOnChange = useCallback( (value) => { onChange?.(value); @@ -106,6 +114,7 @@ export default function CodeMirror({ value, onChange, onViewChanged, onSelection <> <_CodeMirror value={value} + theme={theme || strudelTheme} onChange={handleOnChange} onCreateEditor={handleOnCreateEditor} onUpdate={handleOnUpdate} diff --git a/packages/react/src/components/style.css b/packages/react/src/components/style.css index d3aed9d77..cb6bd3ffa 100644 --- a/packages/react/src/components/style.css +++ b/packages/react/src/components/style.css @@ -1,14 +1,18 @@ .cm-editor { - background-color: transparent !important; + /* background-color: transparent !important; */ height: 100%; z-index: 11; font-size: 18px; } +.cm-theme { + width: 100%; +} + .cm-theme-light { width: 100%; } .cm-line > * { - background: #00000095; + /* background: #00000095; */ } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 477cb7231..3c0ea11f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -373,6 +373,7 @@ importers: '@types/node': ^18.0.0 '@types/react': ^18.0.26 '@types/react-dom': ^18.0.9 + '@uiw/codemirror-themes-all': ^4.19.7 '@vite-pwa/astro': ^0.0.1 astro: ^1.7.2 canvas: ^2.11.0 @@ -415,6 +416,7 @@ importers: '@types/node': 18.11.18 '@types/react': 18.0.27 '@types/react-dom': 18.0.10 + '@uiw/codemirror-themes-all': 4.19.7 astro: 1.9.2_@types+node@18.11.18 canvas: 2.11.0 fraction.js: 4.2.0 @@ -3994,6 +3996,181 @@ packages: '@codemirror/view': 6.7.3 dev: false + /@uiw/codemirror-theme-abcdef/4.19.7: + resolution: {integrity: sha512-mkZrkcq0AfRXNfUQ9sZWe6is8VKfbFWvtbFLGtMqTctdzUbZS/SJj4+W5D1fHMdRBegWn3T5u3fDshtJq/Ky5Q==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-androidstudio/4.19.7: + resolution: {integrity: sha512-emZ9xWH/kOF3TZcCghQWBz5XUG2sM0/okVkXKIbt28uMp5EgPiSKxCR8tUNOXU2WvyFhkgfoNFl5kH+YfjCaNA==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-atomone/4.19.7: + resolution: {integrity: sha512-YBljhvQz2VynKt0bk6jOdPRblK/JtIRst6JDCfXg0TZGkxsNng9uJgYeIT7uNRDvXPtmg47hSqpjL7X0XeSFKg==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-aura/4.19.7: + resolution: {integrity: sha512-n1P3nD0f3RucFeqWZ4tGpKTz/G352XNN7JCCx0pTTSrcC6gXVwrTazAGjjmq60R5za2lufEP3u/PYGgz8joVlg==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-bbedit/4.19.7: + resolution: {integrity: sha512-WjrkNhwHNU+KiwJLbrdTin9YVq5UmveLuH3VFtswLxw8hlFjjEziKgpErD4C8PsC125o6Dlcc7p1nbqVSmQjog==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-bespin/4.19.7: + resolution: {integrity: sha512-ta0o7eX0G3OmDKbQJci51+YM1XFEAR5+21pbcjAQMgD85ZRV23A+8iW+simHNRiRA31cv09pi+tdfXQGcx4drg==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-darcula/4.19.7: + resolution: {integrity: sha512-BNRoEOjTHfolU+VfwT2MZehVaokG3bJuq1we2PcHXSKZtGUT2fHmDNZQ3BSiLUDfC/1f6/Aqf63T8u7mAWB2zw==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-dracula/4.19.7: + resolution: {integrity: sha512-QnVjtq31vqjVcq5GItbfXuaB7c9DAwSvqiTtFLxLXqPO37lwwyYmrMdd5AbFsGlVv3Bxq4zvJ3LbyVlF6mexcA==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-duotone/4.19.7: + resolution: {integrity: sha512-SncdJtjQVBAReEtOPAYJoxitZqxHCbmkJCyZqOj81VB8HI8sdC9pOvdOVviT22/1nzosspmRYoPSHNbq0Jzx6Q==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-eclipse/4.19.7: + resolution: {integrity: sha512-msy5pkECeslpb9J8RT+Oj1XIV7GfOMIl400BG/A2beMXktdBTvomtsjBvn2i124pxevafK0iiuXDm8Rpk9x/9w==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-github/4.19.7: + resolution: {integrity: sha512-yeBKOS31bJWvxHWv/hO8CC5Hz657poyuCRX533B+7c2W3B5TX48i49GC9k91yX/BfCsTVqneONk4ZgRWGJkDww==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-gruvbox-dark/4.19.7: + resolution: {integrity: sha512-Qc1eTPv5KFJ96HIv4tyGFKZ4cWJeEQfwQ6PCHPCMEjEhQEXrT2jkveEUWL/JiUADrF3B32eB3k8f6D0kfZiDyw==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-material/4.19.7: + resolution: {integrity: sha512-uJmausR247K31mM3mjHAAFDQJSB+PB9Wux+aXksGU8QMVSCm7QGBUD6oKrtdQ0+KusdtpO3x+XprlNXhAXDcIw==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-noctis-lilac/4.19.7: + resolution: {integrity: sha512-7j7jA+s0skPKp7BRPI8AmWjgounCgf+1lYDnGjezPsZhM60v9GN9JQRZgI0zNub4kaRz9efXI65E5yN0chjR5w==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-nord/4.19.7: + resolution: {integrity: sha512-nAz4mBHMURyZ/o0b1W1VN9Qp5SvS8frOVEbJyDoCg6MFQ3NYOE8QNPzWIl7525Z8D+bpSHZz9leGuopT2vmXzA==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-okaidia/4.19.7: + resolution: {integrity: sha512-a2NONl4hGW9toluBfhr530BolSRoFGAhqFZMSq4RT/GeeKACE3hI7+uDeJID9B3D9Xh0d9C0VEksvGgEDuVD2g==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-solarized/4.19.7: + resolution: {integrity: sha512-do+SQtXzEVokfFcfIRr6MLceVfE3cHiTFaWQ0npWi5rzc/0i+BNe3J4ewGjUyU2Bofi/LYhAuTTiVoaKNdc5gQ==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-sublime/4.19.7: + resolution: {integrity: sha512-TakRTzdbiLJTfM1htEKVPcHFpnHzUYOFexE5UQQD9BLPfTABTAWLSjb+DeCfbP+m0gsTyzvHd8gH4t+WDIK4gQ==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-tokyo-night-day/4.19.7: + resolution: {integrity: sha512-0oyfyoNNfaKOW2TkJFHMUyI/kyoI6DXYd+Drkp4vHGd8zaLZWm/yyi05b0Nk/RKXnOfzrmLY0uU0FL4471rM1w==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-tokyo-night-storm/4.19.7: + resolution: {integrity: sha512-ObXQDcfECWd9EeawRXqkQQUxdwFF6RdqusEmRl5SJYorcGZA/6zsmxpIjtmXRKwBj0vv+pMk/RKoEmedglMMjw==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-tokyo-night/4.19.7: + resolution: {integrity: sha512-D/oLEsamQ7goFYnP46kyrt60vc2Tx8nC9FWyHqJvD3DL8+ugUsQvCL2oIadCadfMm7pQrFj1ILfokb8uC9W5eg==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-vscode/4.19.7: + resolution: {integrity: sha512-LaT9kSr7U6JTKxTYN0XkKZva5dtM63ltp7ae3JQsinL4ePoI1xNgn0Z4XapCK0VK1VyYbFKEWz3RN8s+pX+N1Q==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-theme-xcode/4.19.7: + resolution: {integrity: sha512-Le3qV3kJe2QgHjfxHHkEvpXF+XSQVUAdDPY2xnyDzijBooxd61ukFqgEPDPHVPT1Aqh+VHglafQRNOxChnlwdQ==} + dependencies: + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-themes-all/4.19.7: + resolution: {integrity: sha512-JCVwjZF9+omz+RaNEJXd0estiD7VliKZe1XvaPG3dy0MqQMJLzoUPxaagetPJlaCskrz1piXYL4V0Qp0J6ni8Q==} + dependencies: + '@uiw/codemirror-theme-abcdef': 4.19.7 + '@uiw/codemirror-theme-androidstudio': 4.19.7 + '@uiw/codemirror-theme-atomone': 4.19.7 + '@uiw/codemirror-theme-aura': 4.19.7 + '@uiw/codemirror-theme-bbedit': 4.19.7 + '@uiw/codemirror-theme-bespin': 4.19.7 + '@uiw/codemirror-theme-darcula': 4.19.7 + '@uiw/codemirror-theme-dracula': 4.19.7 + '@uiw/codemirror-theme-duotone': 4.19.7 + '@uiw/codemirror-theme-eclipse': 4.19.7 + '@uiw/codemirror-theme-github': 4.19.7 + '@uiw/codemirror-theme-gruvbox-dark': 4.19.7 + '@uiw/codemirror-theme-material': 4.19.7 + '@uiw/codemirror-theme-noctis-lilac': 4.19.7 + '@uiw/codemirror-theme-nord': 4.19.7 + '@uiw/codemirror-theme-okaidia': 4.19.7 + '@uiw/codemirror-theme-solarized': 4.19.7 + '@uiw/codemirror-theme-sublime': 4.19.7 + '@uiw/codemirror-theme-tokyo-night': 4.19.7 + '@uiw/codemirror-theme-tokyo-night-day': 4.19.7 + '@uiw/codemirror-theme-tokyo-night-storm': 4.19.7 + '@uiw/codemirror-theme-vscode': 4.19.7 + '@uiw/codemirror-theme-xcode': 4.19.7 + '@uiw/codemirror-themes': 4.19.7 + dev: false + + /@uiw/codemirror-themes/4.19.7: + resolution: {integrity: sha512-M/42RkPI60ItlssmNuEoZO2MQvlY6fRmdX7XRUAhKjxczZoaq8xS6HIvv1whGf2zGsTrwdVTPCm6ls0l17dvPA==} + dependencies: + '@codemirror/language': 6.4.0 + '@codemirror/state': 6.2.0 + '@codemirror/view': 6.7.3 + dev: false + /@uiw/codemirror-themes/4.19.7_a4vbhepr4qhxm5cldqd4jpyase: resolution: {integrity: sha512-M/42RkPI60ItlssmNuEoZO2MQvlY6fRmdX7XRUAhKjxczZoaq8xS6HIvv1whGf2zGsTrwdVTPCm6ls0l17dvPA==} peerDependencies: diff --git a/website/package.json b/website/package.json index b07c9f0f1..1ee37756b 100644 --- a/website/package.json +++ b/website/package.json @@ -38,6 +38,7 @@ "@types/node": "^18.0.0", "@types/react": "^18.0.26", "@types/react-dom": "^18.0.9", + "@uiw/codemirror-themes-all": "^4.19.7", "astro": "^1.7.2", "canvas": "^2.11.0", "fraction.js": "^4.2.0", diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx index 31468e819..c47f19a7e 100644 --- a/website/src/repl/Footer.jsx +++ b/website/src/repl/Footer.jsx @@ -5,11 +5,12 @@ import { nanoid } from 'nanoid'; import React, { useContext, useCallback, useLayoutEffect, useRef, useState } from 'react'; import { useEvent, loadedSamples, ReplContext } from './Repl'; import { Reference } from './Reference'; +import * as themes from './themes.mjs'; export function Footer({ context }) { // const [activeFooter, setActiveFooter] = useState('console'); // const { activeFooter, setActiveFooter, isZen } = useContext?.(ReplContext); - const { activeFooter, setActiveFooter, isZen } = context; + const { activeFooter, setActiveFooter, isZen, setTheme } = context; const footerContent = useRef(); const [log, setLog] = useState([]); @@ -69,11 +70,12 @@ export function Footer({ context }) { return (
-
+
+
{activeFooter !== '' && (
)} + {activeFooter === 'settings' && ( +
+ {Object.entries(themes).map(([k, t]) => ( +
  • + { + setTheme(t); + }} + > + {k} + +
  • + ))} +
    + )} {activeFooter === 'reference' && }
    )} diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index b26f2bbc6..d01c1ec07 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -22,6 +22,7 @@ import { Header } from './Header'; import { prebake } from './prebake.mjs'; import * as tunes from './tunes.mjs'; import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; +import strudelTheme from '@strudel.cycles/react/src/themes/strudel-theme'; initAudioOnFirstClick(); @@ -109,6 +110,7 @@ export const ReplContext = createContext(null); export function Repl({ embedded = false }) { const isEmbedded = embedded || window.location !== window.parent.location; const [view, setView] = useState(); // codemirror view + const [theme, setTheme] = useState(strudelTheme); const [lastShared, setLastShared] = useState(); const [activeFooter, setActiveFooter] = useState(''); const [isZen, setIsZen] = useState(false); @@ -255,6 +257,8 @@ export function Repl({ embedded = false }) { handleShare, isZen, setIsZen, + theme, + setTheme, }; return ( // bg-gradient-to-t from-blue-900 to-slate-900 @@ -269,6 +273,7 @@ export function Repl({ embedded = false }) {
    Date: Wed, 8 Feb 2023 20:26:44 +0100 Subject: [PATCH 003/112] add freesound + shabda to offline cache rule --- website/astro.config.mjs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 646a3b3ca..46bfd0335 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -37,12 +37,18 @@ export default defineConfig({ globPatterns: ['**/*.{js,css,html,ico,png,svg,json,wav,mp3,ogg}'], runtimeCaching: [ { - urlPattern: /^https:\/\/raw\.githubusercontent\.com\/.*/i, + urlPattern: ({ url }) => { + [ + /^https:\/\/raw\.githubusercontent\.com\/.*/i, + /^https:\/\/freesound\.org\/.*/i, + /^https:\/\/shabda\.ndre\.gr\/.*/i, + ].some((regex) => regex.test(url)); + }, handler: 'CacheFirst', options: { cacheName: 'github-files', expiration: { - maxEntries: 200, + maxEntries: 5000, maxAgeSeconds: 60 * 60 * 24 * 30, // <== 14 days }, cacheableResponse: { @@ -53,7 +59,7 @@ export default defineConfig({ ], }, devOptions: { - enabled: true, + enabled: false, }, manifest: { includeAssets: ['favicon.ico', 'icons/apple-icon-180.png', 'favicon.svg'], From b6e42876ad94262445b6c3f810462247caa6a4bb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 8 Feb 2023 20:32:03 +0100 Subject: [PATCH 004/112] fix cache rule + disable service worker in dev --- website/astro.config.mjs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 46bfd0335..d4ef27354 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -37,16 +37,15 @@ export default defineConfig({ globPatterns: ['**/*.{js,css,html,ico,png,svg,json,wav,mp3,ogg}'], runtimeCaching: [ { - urlPattern: ({ url }) => { + urlPattern: ({ url }) => [ /^https:\/\/raw\.githubusercontent\.com\/.*/i, /^https:\/\/freesound\.org\/.*/i, /^https:\/\/shabda\.ndre\.gr\/.*/i, - ].some((regex) => regex.test(url)); - }, + ].some((regex) => regex.test(url)), handler: 'CacheFirst', options: { - cacheName: 'github-files', + cacheName: 'external-samples', expiration: { maxEntries: 5000, maxAgeSeconds: 60 * 60 * 24 * 30, // <== 14 days From 2a2c7437e48ca1bf53a661055135f17ea407f129 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 8 Feb 2023 21:18:03 +0100 Subject: [PATCH 005/112] add cdn.freesound to cache list --- website/astro.config.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/website/astro.config.mjs b/website/astro.config.mjs index d4ef27354..f8f345b83 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -41,6 +41,7 @@ export default defineConfig({ [ /^https:\/\/raw\.githubusercontent\.com\/.*/i, /^https:\/\/freesound\.org\/.*/i, + /^https:\/\/cdn\.freesound\.org\/.*/i, /^https:\/\/shabda\.ndre\.gr\/.*/i, ].some((regex) => regex.test(url)), handler: 'CacheFirst', From 3e727893bfb3574c9e8ec0ce2c032dc8e7efa41e Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 8 Feb 2023 23:43:02 +0100 Subject: [PATCH 006/112] basic theme picker --- website/src/repl/Footer.jsx | 39 ++++++++++++------- website/src/repl/themes.mjs | 77 ++++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 14 deletions(-) diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx index c47f19a7e..3ddf1dc4e 100644 --- a/website/src/repl/Footer.jsx +++ b/website/src/repl/Footer.jsx @@ -5,12 +5,12 @@ import { nanoid } from 'nanoid'; import React, { useContext, useCallback, useLayoutEffect, useRef, useState } from 'react'; import { useEvent, loadedSamples, ReplContext } from './Repl'; import { Reference } from './Reference'; -import * as themes from './themes.mjs'; +import { themes, themeColors } from './themes.mjs'; export function Footer({ context }) { // const [activeFooter, setActiveFooter] = useState('console'); // const { activeFooter, setActiveFooter, isZen } = useContext?.(ReplContext); - const { activeFooter, setActiveFooter, isZen, setTheme } = context; + const { activeFooter, setActiveFooter, isZen, theme, setTheme } = context; const footerContent = useRef(); const [log, setLog] = useState([]); @@ -166,22 +166,31 @@ export function Footer({ context }) { ))} )} + {activeFooter === 'reference' && } {activeFooter === 'settings' && ( -
    +
    {Object.entries(themes).map(([k, t]) => ( -
  • - { - setTheme(t); - }} - > - {k} - -
  • +
    { + console.log(k, themeColors(t)); + setTheme(t); + }} + > +
    {k}
    +
    + {themeColors(t).map((c, i) => ( +
    + ))} +
    +
    ))}
    )} - {activeFooter === 'reference' && }
    )}
    @@ -212,3 +221,7 @@ function linkify(inputText) { return replacedText; } + +function classNames(...classes) { + return classes.filter(Boolean).join(' '); +} diff --git a/website/src/repl/themes.mjs b/website/src/repl/themes.mjs index f956a8758..9303ca006 100644 --- a/website/src/repl/themes.mjs +++ b/website/src/repl/themes.mjs @@ -1,4 +1,4 @@ -export { +import { abcdef, androidstudio, atomone, @@ -29,3 +29,78 @@ export { tokyoNightDay, xcodeLight, } from '@uiw/codemirror-themes-all'; + +export const themes = { + abcdef, + androidstudio, + atomone, + aura, + bespin, + darcula, + dracula, + duotoneDark, + eclipse, + githubDark, + gruvboxDark, + materialDark, + nord, + okaidia, + solarizedDark, + sublime, + tokyoNight, + tokyoNightStorm, + vscodeDark, + xcodeDark, + bbedit, + duotoneLight, + githubLight, + gruvboxLight, + materialLight, + noctisLilac, + solarizedLight, + tokyoNightDay, + xcodeLight, +}; + +export const vars = { + abcdef: { + bg: '#0f0f0f', + activeLine: '#314151', + }, +}; + +function getColors(str) { + const colorRegex = /#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})/g; + const colors = []; + + let match; + while ((match = colorRegex.exec(str)) !== null) { + const color = match[0]; + if (!colors.includes(color)) { + colors.push(color); + } + } + + return colors; +} + +export function themeColors(theme) { + return getColors(stringifySafe(theme)); +} + +function getCircularReplacer() { + const seen = new WeakSet(); + return (key, value) => { + if (typeof value === 'object' && value !== null) { + if (seen.has(value)) { + return; + } + seen.add(value); + } + return value; + }; +} + +function stringifySafe(json) { + return JSON.stringify(json, getCircularReplacer()); +} From 97cbdc6b0fb35da4ca543ed271d41bd799508871 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Feb 2023 12:19:38 +0100 Subject: [PATCH 007/112] use jsdoc in autocomplete, still not context aware + add noAutocomplete flags + add superdirtOnly flags --- packages/core/controls.mjs | 32 ++++---- packages/core/pattern.mjs | 36 ++++++++- packages/core/util.mjs | 2 + packages/osc/osc.mjs | 1 + packages/react/package.json | 1 + packages/react/src/components/CodeMirror6.jsx | 79 ++++++++++++++++++- packages/tonal/tonal.mjs | 11 +-- packages/webaudio/sampler.mjs | 4 +- packages/webdirt/webdirt.mjs | 1 + pnpm-lock.yaml | 13 ++- 10 files changed, 149 insertions(+), 31 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index ad521112c..82e6e382f 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -11,15 +11,6 @@ const generic_params = [ /** * Select a sound / sample by name. * - *
    - * show all sounds - * - * 808 (6) 808bd (25) 808cy (25) 808hc (5) 808ht (5) 808lc (5) 808lt (5) 808mc (5) 808mt (5) 808oh (5) 808sd (25) 909 (1) ab (12) ade (10) ades2 (9) ades3 (7) ades4 (6) alex (2) alphabet (26) amencutup (32) armora (7) arp (2) arpy (11) auto (11) baa (7) baa2 (7) bass (4) bass0 (3) bass1 (30) bass2 (5) bass3 (11) bassdm (24) bassfoo (3) battles (2) bd (24) bend (4) bev (2) bin (2) birds (10) birds3 (19) bleep (13) blip (2) blue (2) bottle (13) breaks125 (2) breaks152 (1) breaks157 (1) breaks165 (1) breath (1) bubble (8) can (14) casio (3) cb (1) cc (6) chin (4) circus (3) clak (2) click (4) clubkick (5) co (4) coins (1) control (2) cosmicg (15) cp (2) cr (6) crow (4) d (4) db (13) diphone (38) diphone2 (12) dist (16) dork2 (4) dorkbot (2) dr (42) dr2 (6) dr55 (4) dr_few (8) drum (6) drumtraks (13) e (8) east (9) electro1 (13) em2 (6) erk (1) f (1) feel (7) feelfx (8) fest (1) fire (1) flick (17) fm (17) foo (27) future (17) gab (10) gabba (4) gabbaloud (4) gabbalouder (4) glasstap (3) glitch (8) glitch2 (8) gretsch (24) gtr (3) h (7) hand (17) hardcore (12) hardkick (6) haw (6) hc (6) hh (13) hh27 (13) hit (6) hmm (1) ho (6) hoover (6) house (8) ht (16) if (5) ifdrums (3) incoming (8) industrial (32) insect (3) invaders (18) jazz (8) jungbass (20) jungle (13) juno (12) jvbass (13) kicklinn (1) koy (2) kurt (7) latibro (8) led (1) less (4) lighter (33) linnhats (6) lt (16) made (7) made2 (1) mash (2) mash2 (4) metal (10) miniyeah (4) monsterb (6) moog (7) mouth (15) mp3 (4) msg (9) mt (16) mute (28) newnotes (15) noise (1) noise2 (8) notes (15) numbers (9) oc (4) odx (15) off (1) outdoor (6) pad (3) padlong (1) pebbles (1) perc (6) peri (15) pluck (17) popkick (10) print (11) proc (2) procshort (8) psr (30) rave (8) rave2 (4) ravemono (2) realclaps (4) reverbkick (1) rm (2) rs (1) sax (22) sd (2) seawolf (3) sequential (8) sf (18) sheffield (1) short (5) sid (12) sine (6) sitar (8) sn (52) space (18) speakspell (12) speech (7) speechless (10) speedupdown (9) stab (23) stomp (10) subroc3d (11) sugar (2) sundance (6) tabla (26) tabla2 (46) tablex (3) tacscan (22) tech (13) techno (7) tink (5) tok (4) toys (13) trump (11) ul (10) ulgab (5) uxay (3) v (6) voodoo (5) wind (10) wobble (1) world (3) xmas (1) yeah (31) - * - * more info - * - *
    - * * @name s * @param {string | Pattern} sound The sound / pattern of sounds to pick * @example @@ -28,20 +19,17 @@ const generic_params = [ */ ['s', 's', 'sound'], /** - * The note or sample number to choose for a synth or sampleset - * Note names currently not working yet, but will hopefully soon. Just stick to numbers for now + * Selects the given index from the sample map. + * Numbers too high will wrap around. + * `n` can also be used to play midi numbers, but it is recommended to use `note` instead. * * @name n - * @param {string | number | Pattern} value note name, note number or sample number + * @param {number | Pattern} value sample index starting from 0 * @example - * s('superpiano').n("<0 1 2 3>").osc() - * @example - * s('superpiano').n("").osc() - * @example - * n("0 1 2 3").s('east').osc() + * s("bd sd,hh*3").n("<0 1>") */ // also see https://github.com/tidalcycles/strudel/pull/63 - ['f', 'n', 'The note or sample number to choose for a synth or sampleset'], + ['f', 'n', 'The sample number to choose for a synth or sampleset'], ['f', 'note', 'The note or pitch to play a sound or synth with'], //['s', 'toArg', 'for internal sound routing'], // ["f", "from", "for internal sound routing"), @@ -386,6 +374,7 @@ const generic_params = [ * * @name detune * @param {number | Pattern} amount between 0 and 1 + * @superdirtOnly * @example * n("0 3 7").s('superzow').octave(3).detune("<0 .25 .5 1 2>").osc() * @@ -398,6 +387,7 @@ const generic_params = [ * @param {number | Pattern} dry 0 = wet, 1 = dry * @example * n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc() + * @superdirtOnly * */ [ @@ -456,6 +446,7 @@ const generic_params = [ * @param {number | Pattern} wet between 0 and 1 * @example * n("0,4,7").s("supersquare").leslie("<0 .4 .6 1>").osc() + * @superdirtOnly * */ ['f', 'leslie', ''], @@ -466,6 +457,7 @@ const generic_params = [ * @param {number | Pattern} rate 6.7 for fast, 0.7 for slow * @example * n("0,4,7").s("supersquare").leslie(1).lrate("<1 2 4 8>").osc() + * @superdirtOnly * */ // TODO: the rate seems to "lag" (in the example, 1 will be fast) @@ -477,6 +469,7 @@ const generic_params = [ * @param {number | Pattern} meters somewhere between 0 and 1 * @example * n("0,4,7").s("supersquare").leslie(1).lrate(2).lsize("<.1 .5 1>").osc() + * @superdirtOnly * */ ['f', 'lsize', ''], @@ -512,6 +505,7 @@ const generic_params = [ * @param {number | Pattern} octave octave number * @example * n("0,4,7").s('supersquare').octave("<3 4 5 6>").osc() + * @superDirtOnly */ ['i', 'octave', ''], ['f', 'offset', ''], // TODO: what is this? not found in tidal doc @@ -676,6 +670,7 @@ const generic_params = [ * @param {number | string | Pattern} unit see description above * @example * speed("1 2 .5 3").s("bd").unit("c").osc() + * @superdirtOnly * */ [ @@ -692,6 +687,7 @@ const generic_params = [ * @param {number | Pattern} squiz Try passing multiples of 2 to it - 2, 4, 8 etc. * @example * squiz("2 4/2 6 [8 16]").s("bd").osc() + * @superdirtOnly * */ ['f', 'squiz', ''], diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index dd02e5291..b9c9e24cc 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -27,6 +27,7 @@ export class Pattern { * Create a pattern. As an end user, you will most likely not create a Pattern directly. * * @param {function} query - The function that maps a {@link State} to an array of {@link Hap}. + * @noAutocomplete */ constructor(query) { this.query = query; @@ -51,6 +52,7 @@ export class Pattern { /** * see {@link Pattern#withValue} + * @noAutocomplete */ fmap(func) { return this.withValue(func); @@ -62,6 +64,7 @@ export class Pattern { * pattern of functions. * @param {Function} whole_func * @param {Function} func + * @noAutocomplete * @returns Pattern */ appWhole(whole_func, pat_val) { @@ -97,6 +100,7 @@ export class Pattern { * are not the same but do intersect, the resulting hap has a timespan of the * intersection. This applies to both the part and the whole timespan. * @param {Pattern} pat_val + * @noAutocomplete * @returns Pattern */ appBoth(pat_val) { @@ -117,6 +121,7 @@ export class Pattern { * are preserved from the pattern of functions (often referred to as the left * hand or inner pattern). * @param {Pattern} pat_val + * @noAutocomplete * @returns Pattern */ appLeft(pat_val) { @@ -147,6 +152,7 @@ export class Pattern { * pattern of values, i.e. structure is preserved from the right hand/outer * pattern. * @param {Pattern} pat_val + * @noAutocomplete * @returns Pattern */ appRight(pat_val) { @@ -332,6 +338,7 @@ export class Pattern { * const haps = pattern.queryArc(0, 1) * console.log(haps) * silence + * @noAutocomplete */ queryArc(begin, end) { try { @@ -347,6 +354,7 @@ export class Pattern { * some calculations easier to express, as all haps are then constrained to * happen within a cycle. * @returns Pattern + * @noAutocomplete */ splitQueries() { const pat = this; @@ -361,6 +369,7 @@ export class Pattern { * timespan before passing it to the original pattern. * @param {Function} func the function to apply * @returns Pattern + * @noAutocomplete */ withQuerySpan(func) { return new Pattern((state) => this.query(state.withSpan(func))); @@ -382,6 +391,7 @@ export class Pattern { * begin and end time of the query timespan. * @param {Function} func the function to apply * @returns Pattern + * @noAutocomplete */ withQueryTime(func) { return new Pattern((state) => this.query(state.withSpan((span) => span.withTime(func)))); @@ -393,6 +403,7 @@ export class Pattern { * present, `whole` timespans). * @param {Function} func * @returns Pattern + * @noAutocomplete */ withHapSpan(func) { return new Pattern((state) => this.query(state).map((hap) => hap.withSpan(func))); @@ -403,6 +414,7 @@ export class Pattern { * begin and end time of the hap timespans. * @param {Function} func the function to apply * @returns Pattern + * @noAutocomplete */ withHapTime(func) { return this.withHapSpan((span) => span.withTime(func)); @@ -412,6 +424,7 @@ export class Pattern { * Returns a new pattern with the given function applied to the list of haps returned by every query. * @param {Function} func * @returns Pattern + * @noAutocomplete */ withHaps(func) { return new Pattern((state) => func(this.query(state))); @@ -421,6 +434,7 @@ export class Pattern { * As with {@link Pattern#withHaps}, but applies the function to every hap, rather than every list of haps. * @param {Function} func * @returns Pattern + * @noAutocomplete */ withHap(func) { return this.withHaps((haps) => haps.map(func)); @@ -430,6 +444,7 @@ export class Pattern { * Returns a new pattern with the context field set to every hap set to the given value. * @param {*} context * @returns Pattern + * @noAutocomplete */ setContext(context) { return this.withHap((hap) => hap.setContext(context)); @@ -439,6 +454,7 @@ export class Pattern { * Returns a new pattern with the given function applied to the context field of every hap. * @param {Function} func * @returns Pattern + * @noAutocomplete */ withContext(func) { return this.withHap((hap) => hap.setContext(func(hap.context))); @@ -447,6 +463,7 @@ export class Pattern { /** * Returns a new pattern with the context field of every hap set to an empty object. * @returns Pattern + * @noAutocomplete */ stripContext() { return this.withHap((hap) => hap.setContext({})); @@ -458,6 +475,7 @@ export class Pattern { * @param {Number} start * @param {Number} end * @returns Pattern + * @noAutocomplete */ withLocation(start, end) { const location = { @@ -500,6 +518,7 @@ export class Pattern { * Returns a new Pattern, which only returns haps that meet the given test. * @param {Function} hap_test - a function which returns false for haps to be removed from the pattern * @returns Pattern + * @noAutocomplete */ filterHaps(hap_test) { return new Pattern((state) => this.query(state).filter(hap_test)); @@ -510,6 +529,7 @@ export class Pattern { * inside haps. * @param {Function} value_test * @returns Pattern + * @noAutocomplete */ filterValues(value_test) { return new Pattern((state) => this.query(state).filter((hap) => value_test(hap.value))); @@ -519,6 +539,7 @@ export class Pattern { * Returns a new pattern, with haps containing undefined values removed from * query results. * @returns Pattern + * @noAutocomplete */ removeUndefineds() { return this.filterValues((val) => val != undefined); @@ -529,6 +550,7 @@ export class Pattern { * with an onset is one with a `whole` timespan that begins at the same time * as its `part` timespan. * @returns Pattern + * @noAutocomplete */ onsetsOnly() { // Returns a new pattern that will only return haps where the start @@ -541,6 +563,7 @@ export class Pattern { * Returns a new pattern, with 'continuous' haps (those without 'whole' * timespans) removed from query results. * @returns Pattern + * @noAutocomplete */ discreteOnly() { // removes continuous haps that don't have a 'whole' timespan @@ -550,6 +573,7 @@ export class Pattern { /** * Combines adjacent haps with the same value and whole. Only * intended for use in tests. + * @noAutocomplete */ defragmentHaps() { // remove continuous haps @@ -604,6 +628,7 @@ export class Pattern { * @param {Boolean} with_context - set to true, otherwise the context field * will be stripped from the resulting haps. * @returns [Hap] + * @noAutocomplete */ firstCycle(with_context = false) { var self = this; @@ -615,6 +640,7 @@ export class Pattern { /** * Accessor for a list of values returned by querying the first cycle. + * @noAutocomplete */ get firstCycleValues() { return this.firstCycle().map((hap) => hap.value); @@ -622,6 +648,7 @@ export class Pattern { /** * More human-readable version of the {@link Pattern#firstCycleValues} accessor. + * @noAutocomplete */ get showFirstCycle() { return this.firstCycle().map( @@ -633,6 +660,7 @@ export class Pattern { * Returns a new pattern, which returns haps sorted in temporal order. Mainly * of use when comparing two patterns for equality, in tests. * @returns Pattern + * @noAutocomplete */ sortHapsByPart() { return this.withHaps((haps) => @@ -1103,6 +1131,7 @@ export const silence = new Pattern(() => []); * @returns {Pattern} * @example * pure('e4') // "e4" + * @noAutocomplete */ export function pure(value) { function query(state) { @@ -1343,6 +1372,7 @@ export const func = curry((a, b) => reify(b).func(a)); * * @param {string} name name of the function * @param {function} func function with 1 or more params, where last is the current pattern + * @noAutocomplete * */ export function register(name, func) { @@ -1448,15 +1478,17 @@ export const ceil = register('ceil', function (pat) { * Assumes a numerical pattern, containing unipolar values in the range 0 .. * 1. Returns a new pattern with values scaled to the bipolar range -1 .. 1 * @returns Pattern + * @noAutocomplete */ export const toBipolar = register('toBipolar', function (pat) { return pat.fmap((x) => x * 2 - 1); }); /** - * Assumes a numerical pattern, containing bipolar values in the range -1 .. - * 1. Returns a new pattern with values scaled to the unipolar range 0 .. 1 + * Assumes a numerical pattern, containing bipolar values in the range -1 .. 1 + * Returns a new pattern with values scaled to the unipolar range 0 .. 1 * @returns Pattern + * @noAutocomplete */ export const fromBipolar = register('fromBipolar', function (pat) { return pat.fmap((x) => (x + 1) / 2); diff --git a/packages/core/util.mjs b/packages/core/util.mjs index 19ff7c126..3127e0d1c 100644 --- a/packages/core/util.mjs +++ b/packages/core/util.mjs @@ -58,6 +58,7 @@ export const valueToMidi = (value, fallbackValue) => { /** * @deprecated does not appear to be referenced or invoked anywhere in the codebase + * @noAutocomplete */ export const getFreq = (noteOrMidi) => { if (typeof noteOrMidi === 'number') { @@ -68,6 +69,7 @@ export const getFreq = (noteOrMidi) => { /** * @deprecated does not appear to be referenced or invoked anywhere in the codebase + * @noAutocomplete */ export const midi2note = (n) => { const oct = Math.floor(n / 12) - 1; diff --git a/packages/osc/osc.mjs b/packages/osc/osc.mjs index 15909203e..234bdfce7 100644 --- a/packages/osc/osc.mjs +++ b/packages/osc/osc.mjs @@ -39,6 +39,7 @@ let startedAt = -1; /** * * Sends each hap as an OSC message, which can be picked up by SuperCollider or any other OSC-enabled software. + * For more info, read [MIDI & OSC in the docs](https://strudel.tidalcycles.org/learn/input-output) * * @name osc * @memberof Pattern diff --git a/packages/react/package.json b/packages/react/package.json index 886da0096..adfdc9bf5 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -32,6 +32,7 @@ }, "homepage": "https://github.com/tidalcycles/strudel#readme", "dependencies": { + "@codemirror/autocomplete": "^6.4.0", "@codemirror/lang-javascript": "^6.1.1", "@codemirror/state": "^6.2.0", "@codemirror/view": "^6.7.3", diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx index 8b05a7278..833f6de1e 100644 --- a/packages/react/src/components/CodeMirror6.jsx +++ b/packages/react/src/components/CodeMirror6.jsx @@ -6,6 +6,8 @@ import { javascript } from '@codemirror/lang-javascript'; import strudelTheme from '../themes/strudel-theme'; import './style.css'; import { useCallback } from 'react'; +import { autocompletion } from '@codemirror/autocomplete'; +import jsdoc from '../../../../doc.json'; export const setFlash = StateEffect.define(); const flashField = StateField.define({ @@ -79,7 +81,82 @@ const highlightField = StateField.define({ provide: (f) => EditorView.decorations.from(f), }); -const extensions = [javascript(), strudelTheme, highlightField, flashField]; +const getDocLabel = (doc) => doc.name || doc.longname; +console.log(jsdoc.docs.sort((a, b) => a.name.localeCompare(b.name))); +const jsdocCompletions = jsdoc.docs + .filter( + (doc) => + getDocLabel(doc) && + !getDocLabel(doc).startsWith('_') && + !['package'].includes(doc.kind) && + !['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag)), + ) + // https://codemirror.net/docs/ref/#autocomplete.Completion + .map((doc) /*: Completion */ => ({ + label: getDocLabel(doc), + // detail: 'xxx', // An optional short piece of information to show (with a different style) after the label. + info: () => { + const heading = document.createElement('h3'); + heading.innerText = getDocLabel(doc); + heading.style = 'padding-top:0;margin-top:0'; + const description = document.createElement('div'); + description.innerHTML = doc.description; + const params = document.createElement('ul'); + doc.params?.forEach(({ name, type, description }) => { + const li = document.createElement('li'); + const span = document.createElement('span'); + span.innerText = name + ': ' + type.names?.join(' | ') + (description ? ' - ' : ''); + const c = document.createElement('span'); + c.innerHTML = description || ''; + const comment = document.createElement('span'); + comment.innerHTML = c.innerText; + li.appendChild(span); + li.appendChild(comment); + params.appendChild(li); + }); + const examples = document.createElement('div'); + doc.examples?.forEach((ex) => { + const code = document.createElement('pre'); + code.style = 'font-size:14px'; + code.innerText = ex; + examples.appendChild(code); + }); + const node = document.createElement('div'); + node.classList.add('prose'); + node.classList.add('prose-invert'); + node.style = 'max-width:500px;max-height:400px;overflow:auto'; + node.appendChild(heading); + node.appendChild(description); + node.appendChild(params); + node.appendChild(examples); + return node; + }, // Additional info to show when the completion is selected + type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type + })); +console.log(jsdocCompletions); + +export const strudelAutocomplete = (context /* : CompletionContext */) => { + let word = context.matchBefore(/\w*/); + if (word.from == word.to && !context.explicit) return null; + return { + from: word.from, + options: jsdocCompletions, + /* options: [ + { label: 'match', type: 'keyword' }, + { label: 'hello', type: 'variable', info: '(World)' }, + { label: 'magic', type: 'text', apply: '⠁⭒*.✩.*⭒⠁', detail: 'macro' }, + ], */ + }; +}; + +const extensions = [ + javascript(), + strudelTheme, + highlightField, + flashField, + // javascriptLanguage.data.of({ autocomplete: strudelAutocomplete }), + autocompletion({ override: [strudelAutocomplete] }), +]; export default function CodeMirror({ value, onChange, onViewChanged, onSelectionChange, options, editorDidMount }) { const handleOnChange = useCallback( diff --git a/packages/tonal/tonal.mjs b/packages/tonal/tonal.mjs index 9e47d4a2f..206ea8409 100644 --- a/packages/tonal/tonal.mjs +++ b/packages/tonal/tonal.mjs @@ -123,17 +123,18 @@ export const scaleTranspose = register('scaleTranspose', function (offset /* : n /** * Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like {@link Pattern#scaleTranspose}. * - * The scale name has the form "TO? N" wher - * - * - T = Tonic - * - O = Octave (optional, defaults to 3) - * - N = Name of scale, available names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts). + * A scale consists of a root note (e.g. `c4`, `c`, `f#`, `bb4`) followed by a [scale type](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts). + * The root note defaults to octave 3, if no octave number is given. + * Note that you currently cannot pattern `scale` with the mini notation, because the scale name includes a space. + * This will be improved in the future. Until then, use a sequence function like `cat` or `seq`. * * @memberof Pattern * @name scale * @param {string} scale Name of scale * @returns Pattern * @example + * "0 2 4 6 4 2".scale('C2 major').note() + * @example * "0 2 4 6 4 2" * .scale(seq('C2 major', 'C2 minor').slow(2)) * .note() diff --git a/packages/webaudio/sampler.mjs b/packages/webaudio/sampler.mjs index f94b6b5a8..40a693766 100644 --- a/packages/webaudio/sampler.mjs +++ b/packages/webaudio/sampler.mjs @@ -111,7 +111,9 @@ let sampleCache = { current: undefined }; /** * Loads a collection of samples to use with `s` - * + * @example + * samples('github:tidalcycles/Dirt-Samples/master'); + * s("[bd ~]*2, [~ hh]*2, ~ sd") * @example * samples({ * bd: '808bd/BD0000.WAV', diff --git a/packages/webdirt/webdirt.mjs b/packages/webdirt/webdirt.mjs index 500d73739..6ae2ff9f3 100644 --- a/packages/webdirt/webdirt.mjs +++ b/packages/webdirt/webdirt.mjs @@ -59,6 +59,7 @@ export function loadWebDirt(config) { * @returns Pattern * @example * s("bd*2 hh sd hh").n("<0 1>").webdirt() + * @noAutocomplete */ Pattern.prototype.webdirt = function () { // create a WebDirt object and initialize Web Audio context diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 477cb7231..818edba19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -159,6 +159,7 @@ importers: packages/react: specifiers: + '@codemirror/autocomplete': ^6.4.0 '@codemirror/lang-javascript': ^6.1.1 '@codemirror/state': ^6.2.0 '@codemirror/view': ^6.7.3 @@ -179,6 +180,7 @@ importers: tailwindcss: ^3.0.24 vite: ^3.2.2 dependencies: + '@codemirror/autocomplete': 6.4.0_a4vbhepr4qhxm5cldqd4jpyase '@codemirror/lang-javascript': 6.1.2 '@codemirror/state': 6.2.0 '@codemirror/view': 6.7.3 @@ -187,7 +189,7 @@ importers: '@strudel.cycles/transpiler': link:../transpiler '@strudel.cycles/webaudio': link:../webaudio '@uiw/codemirror-themes': 4.19.7_a4vbhepr4qhxm5cldqd4jpyase - '@uiw/react-codemirror': 4.19.7_b6o5qp6ml4k7skggixohr5abde + '@uiw/react-codemirror': 4.19.7_r3x7zzmc35ug7i3c2vv4bf5iey react-hook-inview: 4.5.0_sfoxds7t5ydpegc3knd667wn6m devDependencies: '@types/react': 17.0.53 @@ -3979,9 +3981,10 @@ packages: eslint-visitor-keys: 3.3.0 dev: false - /@uiw/codemirror-extensions-basic-setup/4.19.7_a4vbhepr4qhxm5cldqd4jpyase: + /@uiw/codemirror-extensions-basic-setup/4.19.7_cgfc5aojxuwjajwhkrgidrzxoa: resolution: {integrity: sha512-pk0JTFJAZOGxouBB1pdBtb59qKibO9DW4hER4VSFGBGW3TBDeXUwL/gKujhRpySHG2MtG09cgt4a3XOFIWwXTw==} peerDependencies: + '@codemirror/autocomplete': '>=6.0.0' '@codemirror/state': '>=6.0.0' '@codemirror/view': '>=6.0.0' dependencies: @@ -4005,7 +4008,7 @@ packages: '@codemirror/view': 6.7.3 dev: false - /@uiw/react-codemirror/4.19.7_b6o5qp6ml4k7skggixohr5abde: + /@uiw/react-codemirror/4.19.7_r3x7zzmc35ug7i3c2vv4bf5iey: resolution: {integrity: sha512-IHvpYWVSdiaHX0Fk6oY6YyAJigDnyvSpWKNUTRzsMNxB+8/wqZ8lior4TprXH0zyLxW5F1+bTyifFFTeg+X3Sw==} peerDependencies: '@codemirror/state': '>=6.0.0' @@ -4018,10 +4021,12 @@ packages: '@codemirror/state': 6.2.0 '@codemirror/theme-one-dark': 6.1.0 '@codemirror/view': 6.7.3 - '@uiw/codemirror-extensions-basic-setup': 4.19.7_a4vbhepr4qhxm5cldqd4jpyase + '@uiw/codemirror-extensions-basic-setup': 4.19.7_cgfc5aojxuwjajwhkrgidrzxoa codemirror: 6.0.1 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 + transitivePeerDependencies: + - '@codemirror/autocomplete' dev: false /@vite-pwa/astro/0.0.1: From 8da81104aaf777b2d906110e2efe1d732cd8ea83 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Feb 2023 12:42:37 +0100 Subject: [PATCH 008/112] doc: note --- packages/core/controls.mjs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 82e6e382f..4e230240d 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -30,6 +30,25 @@ const generic_params = [ */ // also see https://github.com/tidalcycles/strudel/pull/63 ['f', 'n', 'The sample number to choose for a synth or sampleset'], + /** + * Plays the given note name or midi number. A note name consists of + * + * - a letter (a-g or A-G) + * - optional accidentals (b or #) + * - optional octave number (0-9). Defaults to 3 + * + * Examples of valid note names: `c`, `bb`, `Bb`, `f#`, `c3`, `A4`, `Eb2`, `c#5` + * + * You can also use midi numbers instead of note names, where 69 is mapped to A4 440Hz in 12EDO. + * + * @name note + * @example + * note("c a f e") + * @example + * note("c4 a4 f4 e4") + * @example + * note("60 69 65 64") + */ ['f', 'note', 'The note or pitch to play a sound or synth with'], //['s', 'toArg', 'for internal sound routing'], // ["f", "from", "for internal sound routing"), From 0f18f5eb8150eedbc575a2c646d40109bc2840d6 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Feb 2023 14:16:37 +0100 Subject: [PATCH 009/112] remove logs --- packages/react/src/components/CodeMirror6.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx index 833f6de1e..51573fee2 100644 --- a/packages/react/src/components/CodeMirror6.jsx +++ b/packages/react/src/components/CodeMirror6.jsx @@ -82,7 +82,6 @@ const highlightField = StateField.define({ }); const getDocLabel = (doc) => doc.name || doc.longname; -console.log(jsdoc.docs.sort((a, b) => a.name.localeCompare(b.name))); const jsdocCompletions = jsdoc.docs .filter( (doc) => @@ -133,7 +132,6 @@ const jsdocCompletions = jsdoc.docs }, // Additional info to show when the completion is selected type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type })); -console.log(jsdocCompletions); export const strudelAutocomplete = (context /* : CompletionContext */) => { let word = context.matchBefore(/\w*/); From f497d7b21207c54fe8a6e6e368a6ba9e52b514a3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Feb 2023 18:37:29 +0100 Subject: [PATCH 010/112] reactify autocomplete info --- .../react/src/components/Autocomplete.jsx | 72 +++++++++++++++++++ packages/react/src/components/CodeMirror6.jsx | 68 +----------------- website/src/repl/Repl.css | 4 ++ 3 files changed, 77 insertions(+), 67 deletions(-) create mode 100644 packages/react/src/components/Autocomplete.jsx diff --git a/packages/react/src/components/Autocomplete.jsx b/packages/react/src/components/Autocomplete.jsx new file mode 100644 index 000000000..54babd328 --- /dev/null +++ b/packages/react/src/components/Autocomplete.jsx @@ -0,0 +1,72 @@ +import { createRoot } from 'react-dom/client'; +import jsdoc from '../../../../doc.json'; + +const getDocLabel = (doc) => doc.name || doc.longname; + +export function Autocomplete({ doc }) { + return ( +
    +

    {getDocLabel(doc)}

    +
    +
      + {doc.params?.map(({ name, type, description }, i) => ( +
    • + {name} : {type.names?.join(' | ')} {description ? <> - {description} : ''} +
    • + ))} +
    +
    + {doc.examples?.map((example, i) => ( +
    +
     {
    +                console.log('ola!');
    +                navigator.clipboard.writeText(example);
    +                e.stopPropagation();
    +              }}
    +            >
    +              {example}
    +            
    +
    + ))} +
    +
    + ); +} + +const jsdocCompletions = jsdoc.docs + .filter( + (doc) => + getDocLabel(doc) && + !getDocLabel(doc).startsWith('_') && + !['package'].includes(doc.kind) && + !['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag)), + ) + // https://codemirror.net/docs/ref/#autocomplete.Completion + .map((doc) /*: Completion */ => ({ + label: getDocLabel(doc), + // detail: 'xxx', // An optional short piece of information to show (with a different style) after the label. + info: () => { + const node = document.createElement('div'); + // if Autocomplete is non-interactive, it could also be rendered at build time.. + // .. using renderToStaticMarkup + createRoot(node).render(); + return node; + }, + type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type + })); + +export const strudelAutocomplete = (context /* : CompletionContext */) => { + let word = context.matchBefore(/\w*/); + if (word.from == word.to && !context.explicit) return null; + return { + from: word.from, + options: jsdocCompletions, + /* options: [ + { label: 'match', type: 'keyword' }, + { label: 'hello', type: 'variable', info: '(World)' }, + { label: 'magic', type: 'text', apply: '⠁⭒*.✩.*⭒⠁', detail: 'macro' }, + ], */ + }; +}; diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx index 51573fee2..e198e8ab4 100644 --- a/packages/react/src/components/CodeMirror6.jsx +++ b/packages/react/src/components/CodeMirror6.jsx @@ -7,7 +7,7 @@ import strudelTheme from '../themes/strudel-theme'; import './style.css'; import { useCallback } from 'react'; import { autocompletion } from '@codemirror/autocomplete'; -import jsdoc from '../../../../doc.json'; +import { strudelAutocomplete } from './Autocomplete'; export const setFlash = StateEffect.define(); const flashField = StateField.define({ @@ -81,72 +81,6 @@ const highlightField = StateField.define({ provide: (f) => EditorView.decorations.from(f), }); -const getDocLabel = (doc) => doc.name || doc.longname; -const jsdocCompletions = jsdoc.docs - .filter( - (doc) => - getDocLabel(doc) && - !getDocLabel(doc).startsWith('_') && - !['package'].includes(doc.kind) && - !['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag)), - ) - // https://codemirror.net/docs/ref/#autocomplete.Completion - .map((doc) /*: Completion */ => ({ - label: getDocLabel(doc), - // detail: 'xxx', // An optional short piece of information to show (with a different style) after the label. - info: () => { - const heading = document.createElement('h3'); - heading.innerText = getDocLabel(doc); - heading.style = 'padding-top:0;margin-top:0'; - const description = document.createElement('div'); - description.innerHTML = doc.description; - const params = document.createElement('ul'); - doc.params?.forEach(({ name, type, description }) => { - const li = document.createElement('li'); - const span = document.createElement('span'); - span.innerText = name + ': ' + type.names?.join(' | ') + (description ? ' - ' : ''); - const c = document.createElement('span'); - c.innerHTML = description || ''; - const comment = document.createElement('span'); - comment.innerHTML = c.innerText; - li.appendChild(span); - li.appendChild(comment); - params.appendChild(li); - }); - const examples = document.createElement('div'); - doc.examples?.forEach((ex) => { - const code = document.createElement('pre'); - code.style = 'font-size:14px'; - code.innerText = ex; - examples.appendChild(code); - }); - const node = document.createElement('div'); - node.classList.add('prose'); - node.classList.add('prose-invert'); - node.style = 'max-width:500px;max-height:400px;overflow:auto'; - node.appendChild(heading); - node.appendChild(description); - node.appendChild(params); - node.appendChild(examples); - return node; - }, // Additional info to show when the completion is selected - type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type - })); - -export const strudelAutocomplete = (context /* : CompletionContext */) => { - let word = context.matchBefore(/\w*/); - if (word.from == word.to && !context.explicit) return null; - return { - from: word.from, - options: jsdocCompletions, - /* options: [ - { label: 'match', type: 'keyword' }, - { label: 'hello', type: 'variable', info: '(World)' }, - { label: 'magic', type: 'text', apply: '⠁⭒*.✩.*⭒⠁', detail: 'macro' }, - ], */ - }; -}; - const extensions = [ javascript(), strudelTheme, diff --git a/website/src/repl/Repl.css b/website/src/repl/Repl.css index 911324643..1ed44eaa5 100644 --- a/website/src/repl/Repl.css +++ b/website/src/repl/Repl.css @@ -18,3 +18,7 @@ padding-top: 12px !important; padding-left: 8px !important; } + +.cm-scroller { + padding-bottom: 50vh; +} From f02a41b675f1f6794739771c5da95f6a0eeeb64d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Feb 2023 18:44:41 +0100 Subject: [PATCH 011/112] fix param description --- packages/react/src/components/Autocomplete.jsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/react/src/components/Autocomplete.jsx b/packages/react/src/components/Autocomplete.jsx index 54babd328..64107fc69 100644 --- a/packages/react/src/components/Autocomplete.jsx +++ b/packages/react/src/components/Autocomplete.jsx @@ -2,6 +2,11 @@ import { createRoot } from 'react-dom/client'; import jsdoc from '../../../../doc.json'; const getDocLabel = (doc) => doc.name || doc.longname; +const getInnerText = (html) => { + var div = document.createElement('div'); + div.innerHTML = html; + return div.textContent || div.innerText || ''; +}; export function Autocomplete({ doc }) { return ( @@ -11,7 +16,7 @@ export function Autocomplete({ doc }) {
      {doc.params?.map(({ name, type, description }, i) => (
    • - {name} : {type.names?.join(' | ')} {description ? <> - {description} : ''} + {name} : {type.names?.join(' | ')} {description ? <> - {getInnerText(description)} : ''}
    • ))}
    From 33e2631e5df395973e28145216125adde38e7ce8 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Feb 2023 18:48:34 +0100 Subject: [PATCH 012/112] update snapshot --- test/__snapshots__/examples.test.mjs.snap | 171 +++++++++++++++++----- 1 file changed, 137 insertions(+), 34 deletions(-) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index e52a59323..e061d105a 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2506,40 +2506,26 @@ exports[`runs examples > example "mul" example index 0 1`] = ` exports[`runs examples > example "n" example index 0 1`] = ` [ - "[ 0/1 → 1/1 | s:superpiano n:0 ]", - "[ 1/1 → 2/1 | s:superpiano n:1 ]", - "[ 2/1 → 3/1 | s:superpiano n:2 ]", - "[ 3/1 → 4/1 | s:superpiano n:3 ]", -] -`; - -exports[`runs examples > example "n" example index 1 1`] = ` -[ - "[ 0/1 → 1/1 | s:superpiano n:c4 ]", - "[ 1/1 → 2/1 | s:superpiano n:d4 ]", - "[ 2/1 → 3/1 | s:superpiano n:e4 ]", - "[ 3/1 → 4/1 | s:superpiano n:g4 ]", -] -`; - -exports[`runs examples > example "n" example index 2 1`] = ` -[ - "[ 0/1 → 1/4 | n:0 s:east ]", - "[ 1/4 → 1/2 | n:1 s:east ]", - "[ 1/2 → 3/4 | n:2 s:east ]", - "[ 3/4 → 1/1 | n:3 s:east ]", - "[ 1/1 → 5/4 | n:0 s:east ]", - "[ 5/4 → 3/2 | n:1 s:east ]", - "[ 3/2 → 7/4 | n:2 s:east ]", - "[ 7/4 → 2/1 | n:3 s:east ]", - "[ 2/1 → 9/4 | n:0 s:east ]", - "[ 9/4 → 5/2 | n:1 s:east ]", - "[ 5/2 → 11/4 | n:2 s:east ]", - "[ 11/4 → 3/1 | n:3 s:east ]", - "[ 3/1 → 13/4 | n:0 s:east ]", - "[ 13/4 → 7/2 | n:1 s:east ]", - "[ 7/2 → 15/4 | n:2 s:east ]", - "[ 15/4 → 4/1 | n:3 s:east ]", + "[ 0/1 → 1/2 | s:bd n:0 ]", + "[ 1/2 → 1/1 | s:sd n:0 ]", + "[ 0/1 → 1/3 | s:hh n:0 ]", + "[ 1/3 → 2/3 | s:hh n:0 ]", + "[ 2/3 → 1/1 | s:hh n:0 ]", + "[ 1/1 → 3/2 | s:bd n:1 ]", + "[ 3/2 → 2/1 | s:sd n:1 ]", + "[ 1/1 → 4/3 | s:hh n:1 ]", + "[ 4/3 → 5/3 | s:hh n:1 ]", + "[ 5/3 → 2/1 | s:hh n:1 ]", + "[ 2/1 → 5/2 | s:bd n:0 ]", + "[ 5/2 → 3/1 | s:sd n:0 ]", + "[ 2/1 → 7/3 | s:hh n:0 ]", + "[ 7/3 → 8/3 | s:hh n:0 ]", + "[ 8/3 → 3/1 | s:hh n:0 ]", + "[ 3/1 → 7/2 | s:bd n:1 ]", + "[ 7/2 → 4/1 | s:sd n:1 ]", + "[ 3/1 → 10/3 | s:hh n:1 ]", + "[ 10/3 → 11/3 | s:hh n:1 ]", + "[ 11/3 → 4/1 | s:hh n:1 ]", ] `; @@ -2580,6 +2566,69 @@ exports[`runs examples > example "never" example index 0 1`] = ` ] `; +exports[`runs examples > example "note" example index 0 1`] = ` +[ + "[ 0/1 → 1/4 | note:c ]", + "[ 1/4 → 1/2 | note:a ]", + "[ 1/2 → 3/4 | note:f ]", + "[ 3/4 → 1/1 | note:e ]", + "[ 1/1 → 5/4 | note:c ]", + "[ 5/4 → 3/2 | note:a ]", + "[ 3/2 → 7/4 | note:f ]", + "[ 7/4 → 2/1 | note:e ]", + "[ 2/1 → 9/4 | note:c ]", + "[ 9/4 → 5/2 | note:a ]", + "[ 5/2 → 11/4 | note:f ]", + "[ 11/4 → 3/1 | note:e ]", + "[ 3/1 → 13/4 | note:c ]", + "[ 13/4 → 7/2 | note:a ]", + "[ 7/2 → 15/4 | note:f ]", + "[ 15/4 → 4/1 | note:e ]", +] +`; + +exports[`runs examples > example "note" example index 1 1`] = ` +[ + "[ 0/1 → 1/4 | note:c4 ]", + "[ 1/4 → 1/2 | note:a4 ]", + "[ 1/2 → 3/4 | note:f4 ]", + "[ 3/4 → 1/1 | note:e4 ]", + "[ 1/1 → 5/4 | note:c4 ]", + "[ 5/4 → 3/2 | note:a4 ]", + "[ 3/2 → 7/4 | note:f4 ]", + "[ 7/4 → 2/1 | note:e4 ]", + "[ 2/1 → 9/4 | note:c4 ]", + "[ 9/4 → 5/2 | note:a4 ]", + "[ 5/2 → 11/4 | note:f4 ]", + "[ 11/4 → 3/1 | note:e4 ]", + "[ 3/1 → 13/4 | note:c4 ]", + "[ 13/4 → 7/2 | note:a4 ]", + "[ 7/2 → 15/4 | note:f4 ]", + "[ 15/4 → 4/1 | note:e4 ]", +] +`; + +exports[`runs examples > example "note" example index 2 1`] = ` +[ + "[ 0/1 → 1/4 | note:60 ]", + "[ 1/4 → 1/2 | note:69 ]", + "[ 1/2 → 3/4 | note:65 ]", + "[ 3/4 → 1/1 | note:64 ]", + "[ 1/1 → 5/4 | note:60 ]", + "[ 5/4 → 3/2 | note:69 ]", + "[ 3/2 → 7/4 | note:65 ]", + "[ 7/4 → 2/1 | note:64 ]", + "[ 2/1 → 9/4 | note:60 ]", + "[ 9/4 → 5/2 | note:69 ]", + "[ 5/2 → 11/4 | note:65 ]", + "[ 11/4 → 3/1 | note:64 ]", + "[ 3/1 → 13/4 | note:60 ]", + "[ 13/4 → 7/2 | note:69 ]", + "[ 7/2 → 15/4 | note:65 ]", + "[ 15/4 → 4/1 | note:64 ]", +] +`; + exports[`runs examples > example "octave" example index 0 1`] = ` [ "[ 0/1 → 1/1 | n:0 s:supersquare octave:3 ]", @@ -3280,6 +3329,31 @@ exports[`runs examples > example "samples" example index 0 1`] = ` ] `; +exports[`runs examples > example "samples" example index 1 1`] = ` +[ + "[ 0/1 → 1/4 | s:bd ]", + "[ 1/2 → 3/4 | s:bd ]", + "[ 1/4 → 1/2 | s:hh ]", + "[ 3/4 → 1/1 | s:hh ]", + "[ 1/2 → 1/1 | s:sd ]", + "[ 1/1 → 5/4 | s:bd ]", + "[ 3/2 → 7/4 | s:bd ]", + "[ 5/4 → 3/2 | s:hh ]", + "[ 7/4 → 2/1 | s:hh ]", + "[ 3/2 → 2/1 | s:sd ]", + "[ 2/1 → 9/4 | s:bd ]", + "[ 5/2 → 11/4 | s:bd ]", + "[ 9/4 → 5/2 | s:hh ]", + "[ 11/4 → 3/1 | s:hh ]", + "[ 5/2 → 3/1 | s:sd ]", + "[ 3/1 → 13/4 | s:bd ]", + "[ 7/2 → 15/4 | s:bd ]", + "[ 13/4 → 7/2 | s:hh ]", + "[ 15/4 → 4/1 | s:hh ]", + "[ 7/2 → 4/1 | s:sd ]", +] +`; + exports[`runs examples > example "saw" example index 0 1`] = ` [ "[ 0/1 → 1/32 | note:c3 ]", @@ -3323,6 +3397,35 @@ exports[`runs examples > example "saw" example index 1 1`] = ` `; exports[`runs examples > example "scale" example index 0 1`] = ` +[ + "[ 0/1 → 1/6 | note:C2 ]", + "[ 1/6 → 1/3 | note:E2 ]", + "[ 1/3 → 1/2 | note:G2 ]", + "[ 1/2 → 2/3 | note:B2 ]", + "[ 2/3 → 5/6 | note:G2 ]", + "[ 5/6 → 1/1 | note:E2 ]", + "[ 1/1 → 7/6 | note:C2 ]", + "[ 7/6 → 4/3 | note:E2 ]", + "[ 4/3 → 3/2 | note:G2 ]", + "[ 3/2 → 5/3 | note:B2 ]", + "[ 5/3 → 11/6 | note:G2 ]", + "[ 11/6 → 2/1 | note:E2 ]", + "[ 2/1 → 13/6 | note:C2 ]", + "[ 13/6 → 7/3 | note:E2 ]", + "[ 7/3 → 5/2 | note:G2 ]", + "[ 5/2 → 8/3 | note:B2 ]", + "[ 8/3 → 17/6 | note:G2 ]", + "[ 17/6 → 3/1 | note:E2 ]", + "[ 3/1 → 19/6 | note:C2 ]", + "[ 19/6 → 10/3 | note:E2 ]", + "[ 10/3 → 7/2 | note:G2 ]", + "[ 7/2 → 11/3 | note:B2 ]", + "[ 11/3 → 23/6 | note:G2 ]", + "[ 23/6 → 4/1 | note:E2 ]", +] +`; + +exports[`runs examples > example "scale" example index 1 1`] = ` [ "[ 0/1 → 1/6 | note:C2 ]", "[ 1/6 → 1/3 | note:E2 ]", From 3209afa4ff8ddad3e1f226df531cdf1f3f19d6c2 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Feb 2023 19:20:44 +0100 Subject: [PATCH 013/112] minirepl: add keyboard shortcuts --- packages/react/src/components/MiniRepl.jsx | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/react/src/components/MiniRepl.jsx b/packages/react/src/components/MiniRepl.jsx index fd803ac13..b2c40d79c 100644 --- a/packages/react/src/components/MiniRepl.jsx +++ b/packages/react/src/components/MiniRepl.jsx @@ -63,6 +63,27 @@ export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTi getTime: () => scheduler.now(), }); + // keyboard shortcuts + useKeydown( + useCallback( + async (e) => { + if (view?.hasFocus) { + if (e.ctrlKey || e.altKey) { + if (e.code === 'Enter') { + e.preventDefault(); + flash(view); + await activateCode(); + } else if (e.code === 'Period') { + stop(); + e.preventDefault(); + } + } + } + }, + [activateCode, stop, view], + ), + ); + // set active pattern on ctrl+enter useLayoutEffect(() => { if (enableKeyboard) { @@ -150,3 +171,8 @@ function useEvent(name, onTrigger, useCapture = false) { }; }, [onTrigger]); } + +// TODO: dedupe +function useKeydown(onTrigger) { + useEvent('keydown', onTrigger, true); +} From ea1b2252fcdb28b3bdeecffead917b4fa4974c69 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Feb 2023 21:42:48 +0100 Subject: [PATCH 014/112] remove unused descriptions + fix some titles + comment out unfinished packages page + start offline page --- website/src/config.ts | 5 +++-- website/src/pages/functions/intro.mdx | 2 +- website/src/pages/learn/accumulation.mdx | 1 - website/src/pages/learn/code.mdx | 1 - website/src/pages/learn/effects.mdx | 1 - website/src/pages/learn/factories.mdx | 1 - website/src/pages/learn/getting-started.mdx | 1 - website/src/pages/learn/input-output.mdx | 3 +-- website/src/pages/learn/notes.mdx | 1 - website/src/pages/learn/pwa.mdx | 9 +++++++++ website/src/pages/learn/samples.mdx | 3 +-- website/src/pages/learn/signals.mdx | 3 +-- website/src/pages/learn/sounds.mdx | 1 - website/src/pages/learn/synths.mdx | 1 - 14 files changed, 16 insertions(+), 17 deletions(-) create mode 100644 website/src/pages/learn/pwa.mdx diff --git a/website/src/config.ts b/website/src/config.ts index 6fe760520..26273dbaa 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -65,16 +65,17 @@ export const SIDEBAR: Sidebar = { { text: 'Tonal Modifiers', link: 'learn/tonal' }, ], More: [ + { text: 'MIDI & OSC', link: 'learn/input-output' }, + { text: 'Offline', link: 'learn/pwa' }, { text: 'Patterns', link: 'technical-manual/patterns' }, { text: 'Pattern Alignment', link: 'technical-manual/alignment' }, - { text: 'MIDI & OSC', link: 'learn/input-output' }, { text: 'Strudel vs Tidal', link: 'learn/strudel-vs-tidal' }, ], Development: [ { text: 'REPL', link: 'technical-manual/repl' }, { text: 'Docs', link: 'technical-manual/docs' }, { text: 'Testing', link: 'technical-manual/testing' }, - { text: 'Packages', link: 'technical-manual/packages' }, + // { text: 'Packages', link: 'technical-manual/packages' }, // { text: 'Internals', link: 'technical-manual/internals' }, ], }, diff --git a/website/src/pages/functions/intro.mdx b/website/src/pages/functions/intro.mdx index bed3cb37a..6bbd26b91 100644 --- a/website/src/pages/functions/intro.mdx +++ b/website/src/pages/functions/intro.mdx @@ -1,5 +1,5 @@ --- -title: Introduction +title: JavaScript API layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/accumulation.mdx b/website/src/pages/learn/accumulation.mdx index 717613871..c442e87b1 100644 --- a/website/src/pages/learn/accumulation.mdx +++ b/website/src/pages/learn/accumulation.mdx @@ -1,6 +1,5 @@ --- title: Accumulation Modifiers -description: Strudel Tutorial - Coding syntax layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/code.mdx b/website/src/pages/learn/code.mdx index 7be95ed34..d10e1f64d 100644 --- a/website/src/pages/learn/code.mdx +++ b/website/src/pages/learn/code.mdx @@ -1,6 +1,5 @@ --- title: Coding syntax -description: Strudel Tutorial - Coding syntax layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index afe1c63cd..7fc0a77ca 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -1,6 +1,5 @@ --- title: Audio effects -description: Strudel Tutorial - Audio effects layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/factories.mdx b/website/src/pages/learn/factories.mdx index 7a7256ec1..86598cf24 100644 --- a/website/src/pages/learn/factories.mdx +++ b/website/src/pages/learn/factories.mdx @@ -1,6 +1,5 @@ --- title: Pattern Constructors -description: Strudel Tutorial layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/getting-started.mdx b/website/src/pages/learn/getting-started.mdx index 3f2868f1b..3f41c8591 100644 --- a/website/src/pages/learn/getting-started.mdx +++ b/website/src/pages/learn/getting-started.mdx @@ -1,6 +1,5 @@ --- title: Getting Started -description: Strudel Tutorial - Getting Started layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/input-output.mdx b/website/src/pages/learn/input-output.mdx index b77667193..68233159d 100644 --- a/website/src/pages/learn/input-output.mdx +++ b/website/src/pages/learn/input-output.mdx @@ -1,6 +1,5 @@ --- -title: Other Outptuts -description: Strudel Tutorial +title: MIDI & OSC layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/notes.mdx b/website/src/pages/learn/notes.mdx index e2d2c7bb8..42c54174a 100644 --- a/website/src/pages/learn/notes.mdx +++ b/website/src/pages/learn/notes.mdx @@ -1,6 +1,5 @@ --- title: Notes -description: Strudel Tutorial - Notes layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/pwa.mdx b/website/src/pages/learn/pwa.mdx new file mode 100644 index 000000000..ab2c68f32 --- /dev/null +++ b/website/src/pages/learn/pwa.mdx @@ -0,0 +1,9 @@ +--- +title: Offline +layout: ../../layouts/MainLayout.astro +--- + +# Using Strudel Offline + +You can use Strudel even without a network! When you first visit the [Strudel REPL](strudel.tidalcycles.org/), +your browser will download the whole web app including documentation. diff --git a/website/src/pages/learn/samples.mdx b/website/src/pages/learn/samples.mdx index 5ad0c0e01..4720e5fa7 100644 --- a/website/src/pages/learn/samples.mdx +++ b/website/src/pages/learn/samples.mdx @@ -1,6 +1,5 @@ --- -title: Notes -description: Strudel Tutorial - Notes +title: Samples layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/signals.mdx b/website/src/pages/learn/signals.mdx index 0cf0f58e8..79f255b0c 100644 --- a/website/src/pages/learn/signals.mdx +++ b/website/src/pages/learn/signals.mdx @@ -1,6 +1,5 @@ --- -title: What is Strudel? -description: Strudel Tutorial +title: Signals layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/sounds.mdx b/website/src/pages/learn/sounds.mdx index f80f51be8..a17c2d0cc 100644 --- a/website/src/pages/learn/sounds.mdx +++ b/website/src/pages/learn/sounds.mdx @@ -1,6 +1,5 @@ --- title: Sounds -description: Strudel Tutorial - Sounds layout: ../../layouts/MainLayout.astro --- diff --git a/website/src/pages/learn/synths.mdx b/website/src/pages/learn/synths.mdx index 69c453943..9b5b1c288 100644 --- a/website/src/pages/learn/synths.mdx +++ b/website/src/pages/learn/synths.mdx @@ -1,6 +1,5 @@ --- title: Synths -description: Strudel Tutorial - Synths layout: ../../layouts/MainLayout.astro --- From 0326244956b82da507f8fa47980ff0909dab5af1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 10 Feb 2023 09:25:58 +0100 Subject: [PATCH 015/112] update themes --- pnpm-lock.yaml | 268 +++++++++++++++++++++++++------------------ website/package.json | 2 +- 2 files changed, 160 insertions(+), 110 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3c0ea11f0..9c7090c2b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -373,7 +373,7 @@ importers: '@types/node': ^18.0.0 '@types/react': ^18.0.26 '@types/react-dom': ^18.0.9 - '@uiw/codemirror-themes-all': ^4.19.7 + '@uiw/codemirror-themes-all': ^4.19.8 '@vite-pwa/astro': ^0.0.1 astro: ^1.7.2 canvas: ^2.11.0 @@ -416,7 +416,7 @@ importers: '@types/node': 18.11.18 '@types/react': 18.0.27 '@types/react-dom': 18.0.10 - '@uiw/codemirror-themes-all': 4.19.7 + '@uiw/codemirror-themes-all': 4.19.8 astro: 1.9.2_@types+node@18.11.18 canvas: 2.11.0 fraction.js: 4.2.0 @@ -3996,179 +3996,171 @@ packages: '@codemirror/view': 6.7.3 dev: false - /@uiw/codemirror-theme-abcdef/4.19.7: - resolution: {integrity: sha512-mkZrkcq0AfRXNfUQ9sZWe6is8VKfbFWvtbFLGtMqTctdzUbZS/SJj4+W5D1fHMdRBegWn3T5u3fDshtJq/Ky5Q==} + /@uiw/codemirror-theme-abcdef/4.19.8: + resolution: {integrity: sha512-sR7srfMJRGTsAFQYEs+8IogUxUHDsMqNqZ4waIA6rNIvOH9Q1NYFEqTpqf4AeivkNeXm3N1LI+1nQAKhWzWpOA==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-androidstudio/4.19.7: - resolution: {integrity: sha512-emZ9xWH/kOF3TZcCghQWBz5XUG2sM0/okVkXKIbt28uMp5EgPiSKxCR8tUNOXU2WvyFhkgfoNFl5kH+YfjCaNA==} + /@uiw/codemirror-theme-androidstudio/4.19.8: + resolution: {integrity: sha512-xhvEPZ1NvihIJVx7MA1Z8A8NwaTbM6mtBsfwM3mKAmzW6K6JcIJftcKe5z5wSPZk4J3S66vq8RYEMOBygSOdEQ==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-atomone/4.19.7: - resolution: {integrity: sha512-YBljhvQz2VynKt0bk6jOdPRblK/JtIRst6JDCfXg0TZGkxsNng9uJgYeIT7uNRDvXPtmg47hSqpjL7X0XeSFKg==} + /@uiw/codemirror-theme-atomone/4.19.8: + resolution: {integrity: sha512-enZR8RPiKohyuEU4DOWA7A/xLs/+NsuvZAuGmg5PU43CQITzK1Wqri43/WxkGGsEIztejX439s1QuYxUwCCeUg==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-aura/4.19.7: - resolution: {integrity: sha512-n1P3nD0f3RucFeqWZ4tGpKTz/G352XNN7JCCx0pTTSrcC6gXVwrTazAGjjmq60R5za2lufEP3u/PYGgz8joVlg==} + /@uiw/codemirror-theme-aura/4.19.8: + resolution: {integrity: sha512-DLoi2XEPNBD6Cxsp3v/nYw7jJ7sDEXET9+C43KZnk1dQ9H5e0HSpZhOkw1xmaCGzoXn9q7HInPa7GgUEMv8NPA==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-bbedit/4.19.7: - resolution: {integrity: sha512-WjrkNhwHNU+KiwJLbrdTin9YVq5UmveLuH3VFtswLxw8hlFjjEziKgpErD4C8PsC125o6Dlcc7p1nbqVSmQjog==} + /@uiw/codemirror-theme-bbedit/4.19.8: + resolution: {integrity: sha512-1vaVaVhMP2IB7H77W9yvPRhVr+8HGBWPDfFEVWAc7tfeU0xC2MFby05gO/7T6K2JWyj2lXnVw/i+oFNeDdcekQ==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-bespin/4.19.7: - resolution: {integrity: sha512-ta0o7eX0G3OmDKbQJci51+YM1XFEAR5+21pbcjAQMgD85ZRV23A+8iW+simHNRiRA31cv09pi+tdfXQGcx4drg==} + /@uiw/codemirror-theme-bespin/4.19.8: + resolution: {integrity: sha512-JyzmgCloEWhduH5GVYzHQ3vPc3zC0YVRiu7lOjgdOVRhr49M6KmwTytmbmqXbaqmSZKFUJqiHjz8VswqcNC4dw==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-darcula/4.19.7: - resolution: {integrity: sha512-BNRoEOjTHfolU+VfwT2MZehVaokG3bJuq1we2PcHXSKZtGUT2fHmDNZQ3BSiLUDfC/1f6/Aqf63T8u7mAWB2zw==} + /@uiw/codemirror-theme-darcula/4.19.8: + resolution: {integrity: sha512-fPKyzMqCtBfez2ubC/77AP0BfE+XOio+sy8oRYfX3HqRQEivnnEddQJnTZVz0kKSLYSryQHbOMw/qwgInPvBCA==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-dracula/4.19.7: - resolution: {integrity: sha512-QnVjtq31vqjVcq5GItbfXuaB7c9DAwSvqiTtFLxLXqPO37lwwyYmrMdd5AbFsGlVv3Bxq4zvJ3LbyVlF6mexcA==} + /@uiw/codemirror-theme-dracula/4.19.8: + resolution: {integrity: sha512-YHQJUDnYKrew/YkEPQG3SQFcnKr6MzVbIXxmdKuxlCTrySNFNMK19dKrzY3fwc+Lgpp5r26QLLocTZyCvu1xeA==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-duotone/4.19.7: - resolution: {integrity: sha512-SncdJtjQVBAReEtOPAYJoxitZqxHCbmkJCyZqOj81VB8HI8sdC9pOvdOVviT22/1nzosspmRYoPSHNbq0Jzx6Q==} + /@uiw/codemirror-theme-duotone/4.19.8: + resolution: {integrity: sha512-SJkjyKxU2Nazv6uEctvRdz62/ZQ8rBP4xtXrjF/zcjOdWmx2ecUAGn/j5Euw5V55Dr74yIQFs0L+GB5UTHCHDA==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-eclipse/4.19.7: - resolution: {integrity: sha512-msy5pkECeslpb9J8RT+Oj1XIV7GfOMIl400BG/A2beMXktdBTvomtsjBvn2i124pxevafK0iiuXDm8Rpk9x/9w==} + /@uiw/codemirror-theme-eclipse/4.19.8: + resolution: {integrity: sha512-6XXzYFC809e5MWT/NNTqoZ0N9H6P8mXwIEGDfigh33VU1TJPPpO1LCWdf59VcXx/xIY0ctDp7rU7hTy3f3tHkw==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-github/4.19.7: - resolution: {integrity: sha512-yeBKOS31bJWvxHWv/hO8CC5Hz657poyuCRX533B+7c2W3B5TX48i49GC9k91yX/BfCsTVqneONk4ZgRWGJkDww==} + /@uiw/codemirror-theme-github/4.19.8: + resolution: {integrity: sha512-RUAzHGkG2G2PXTxsH4KbKVCKqPs/+H6xvhCT3Q4YiPj1W2aGSfPwZZ8cLLCm9dYaIh/+H6L+AcoiUtvADjyKsQ==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-gruvbox-dark/4.19.7: - resolution: {integrity: sha512-Qc1eTPv5KFJ96HIv4tyGFKZ4cWJeEQfwQ6PCHPCMEjEhQEXrT2jkveEUWL/JiUADrF3B32eB3k8f6D0kfZiDyw==} + /@uiw/codemirror-theme-gruvbox-dark/4.19.8: + resolution: {integrity: sha512-EQepnqhfcu7HY2uutigzflZ9OFzDcF9eq4xF53UylD+WZBdwq2qarZMQgBfOXZZKYI3XcTny064fa7Xxklhs1g==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-material/4.19.7: - resolution: {integrity: sha512-uJmausR247K31mM3mjHAAFDQJSB+PB9Wux+aXksGU8QMVSCm7QGBUD6oKrtdQ0+KusdtpO3x+XprlNXhAXDcIw==} + /@uiw/codemirror-theme-material/4.19.8: + resolution: {integrity: sha512-dm7FtZkJSZ4AV+9vXxKUDnXLTHaqWnsmn9HOb6AmLiHmHcLFLDgeosSBnA80fwXBhd6QswJI0cEnKHAvcC/vFg==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-noctis-lilac/4.19.7: - resolution: {integrity: sha512-7j7jA+s0skPKp7BRPI8AmWjgounCgf+1lYDnGjezPsZhM60v9GN9JQRZgI0zNub4kaRz9efXI65E5yN0chjR5w==} + /@uiw/codemirror-theme-noctis-lilac/4.19.8: + resolution: {integrity: sha512-vPH8KOiRgcBK1V7/BN04n8K03cfR4CEmOGZUMKpcLlSZwWRe0+JPk6S2qtjbJ072Fsn1ZrcLRYrqtaAJQNOVnw==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-nord/4.19.7: - resolution: {integrity: sha512-nAz4mBHMURyZ/o0b1W1VN9Qp5SvS8frOVEbJyDoCg6MFQ3NYOE8QNPzWIl7525Z8D+bpSHZz9leGuopT2vmXzA==} + /@uiw/codemirror-theme-nord/4.19.8: + resolution: {integrity: sha512-qBqKJI9fa35rFefXqaiw3FCXWSpD+65+Weji3g/AgB0m0+MHG+3rkC+rLZ4PE2QpkcMz6wHj89EMwOW9W1i3cA==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-okaidia/4.19.7: - resolution: {integrity: sha512-a2NONl4hGW9toluBfhr530BolSRoFGAhqFZMSq4RT/GeeKACE3hI7+uDeJID9B3D9Xh0d9C0VEksvGgEDuVD2g==} + /@uiw/codemirror-theme-okaidia/4.19.8: + resolution: {integrity: sha512-gxEThgbbfIxKjk7UzD0D8gw5bVpgxDct3e6r9/WegZw7tTvTHMnz9wutGbJp2cYSwdgLHoQJZzZBi6jKhExZSg==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-solarized/4.19.7: - resolution: {integrity: sha512-do+SQtXzEVokfFcfIRr6MLceVfE3cHiTFaWQ0npWi5rzc/0i+BNe3J4ewGjUyU2Bofi/LYhAuTTiVoaKNdc5gQ==} + /@uiw/codemirror-theme-solarized/4.19.8: + resolution: {integrity: sha512-xHp2i6zWBMw2+kZX0GUYi7pCL3ZL1qWSO8OaleHCkpY3jn+lfLSJOAYYkajvNyu3tPsiKQuAgpCQ6AYFWOr6BQ==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-sublime/4.19.7: - resolution: {integrity: sha512-TakRTzdbiLJTfM1htEKVPcHFpnHzUYOFexE5UQQD9BLPfTABTAWLSjb+DeCfbP+m0gsTyzvHd8gH4t+WDIK4gQ==} + /@uiw/codemirror-theme-sublime/4.19.8: + resolution: {integrity: sha512-tapkCty8lwpRw2CAY5bPiK8S2ptdTL4d1X/IkCVyHqbC0B8728iQJu3E4Rrka7yggFx4QGUpyZB9UTIFYURtsw==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-tokyo-night-day/4.19.7: - resolution: {integrity: sha512-0oyfyoNNfaKOW2TkJFHMUyI/kyoI6DXYd+Drkp4vHGd8zaLZWm/yyi05b0Nk/RKXnOfzrmLY0uU0FL4471rM1w==} + /@uiw/codemirror-theme-tokyo-night-day/4.19.8: + resolution: {integrity: sha512-HDKp2KDjluubpe+7M31SohWUFCW7wGQIvoD60xr86OkPZDdqsCVUFmna6rqfttV6S2OsgVNJPBzZvOF398Eapg==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-tokyo-night-storm/4.19.7: - resolution: {integrity: sha512-ObXQDcfECWd9EeawRXqkQQUxdwFF6RdqusEmRl5SJYorcGZA/6zsmxpIjtmXRKwBj0vv+pMk/RKoEmedglMMjw==} + /@uiw/codemirror-theme-tokyo-night-storm/4.19.8: + resolution: {integrity: sha512-Kp8HIf1H+pgbRx/ZhRsqqN5qfyx3SVVfjnUPGltsdBymqh8QGdr7LC8Tp0P5+Yjb6CqF6Dgx7RnQDj1XZ94rbA==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-tokyo-night/4.19.7: - resolution: {integrity: sha512-D/oLEsamQ7goFYnP46kyrt60vc2Tx8nC9FWyHqJvD3DL8+ugUsQvCL2oIadCadfMm7pQrFj1ILfokb8uC9W5eg==} + /@uiw/codemirror-theme-tokyo-night/4.19.8: + resolution: {integrity: sha512-LrfB+EgZqBNlMF6Zqk8RrlsfVzKe6Ple7ckvREV6kSuwxncF5FlhzVL3cWgxNfNQ7TJ5ySVSvw4fWOcxIcc1LQ==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-vscode/4.19.7: - resolution: {integrity: sha512-LaT9kSr7U6JTKxTYN0XkKZva5dtM63ltp7ae3JQsinL4ePoI1xNgn0Z4XapCK0VK1VyYbFKEWz3RN8s+pX+N1Q==} + /@uiw/codemirror-theme-vscode/4.19.8: + resolution: {integrity: sha512-UdUuJfNjG2y88taP5gsEA9AQlhRTURnl+9kl+LOJkQtXavrqp3J8gUAHRhEWxN7k8q8YimsSVcQ4yw0FKAgXQQ==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-theme-xcode/4.19.7: - resolution: {integrity: sha512-Le3qV3kJe2QgHjfxHHkEvpXF+XSQVUAdDPY2xnyDzijBooxd61ukFqgEPDPHVPT1Aqh+VHglafQRNOxChnlwdQ==} + /@uiw/codemirror-theme-xcode/4.19.8: + resolution: {integrity: sha512-VYCRhStYujUNGIkiaZZ1o5OO2Z2edsKkYCCYSy0rwb4G17vT6sd4YDnmJQuF0gzqQkTIdDxSb6aCM9ISkPABlg==} dependencies: - '@uiw/codemirror-themes': 4.19.7 + '@uiw/codemirror-themes': 4.19.8 dev: false - /@uiw/codemirror-themes-all/4.19.7: - resolution: {integrity: sha512-JCVwjZF9+omz+RaNEJXd0estiD7VliKZe1XvaPG3dy0MqQMJLzoUPxaagetPJlaCskrz1piXYL4V0Qp0J6ni8Q==} + /@uiw/codemirror-themes-all/4.19.8: + resolution: {integrity: sha512-0kAWabe46Vkz+gwNfaXvn/0adeUSCTAuZC0d7Nu8ebcr1TjT1fDLFNZIXlwidn40suiXq8FDfZ9euArx3RPg0Q==} dependencies: - '@uiw/codemirror-theme-abcdef': 4.19.7 - '@uiw/codemirror-theme-androidstudio': 4.19.7 - '@uiw/codemirror-theme-atomone': 4.19.7 - '@uiw/codemirror-theme-aura': 4.19.7 - '@uiw/codemirror-theme-bbedit': 4.19.7 - '@uiw/codemirror-theme-bespin': 4.19.7 - '@uiw/codemirror-theme-darcula': 4.19.7 - '@uiw/codemirror-theme-dracula': 4.19.7 - '@uiw/codemirror-theme-duotone': 4.19.7 - '@uiw/codemirror-theme-eclipse': 4.19.7 - '@uiw/codemirror-theme-github': 4.19.7 - '@uiw/codemirror-theme-gruvbox-dark': 4.19.7 - '@uiw/codemirror-theme-material': 4.19.7 - '@uiw/codemirror-theme-noctis-lilac': 4.19.7 - '@uiw/codemirror-theme-nord': 4.19.7 - '@uiw/codemirror-theme-okaidia': 4.19.7 - '@uiw/codemirror-theme-solarized': 4.19.7 - '@uiw/codemirror-theme-sublime': 4.19.7 - '@uiw/codemirror-theme-tokyo-night': 4.19.7 - '@uiw/codemirror-theme-tokyo-night-day': 4.19.7 - '@uiw/codemirror-theme-tokyo-night-storm': 4.19.7 - '@uiw/codemirror-theme-vscode': 4.19.7 - '@uiw/codemirror-theme-xcode': 4.19.7 - '@uiw/codemirror-themes': 4.19.7 - dev: false - - /@uiw/codemirror-themes/4.19.7: - resolution: {integrity: sha512-M/42RkPI60ItlssmNuEoZO2MQvlY6fRmdX7XRUAhKjxczZoaq8xS6HIvv1whGf2zGsTrwdVTPCm6ls0l17dvPA==} - dependencies: - '@codemirror/language': 6.4.0 - '@codemirror/state': 6.2.0 - '@codemirror/view': 6.7.3 + '@uiw/codemirror-theme-abcdef': 4.19.8 + '@uiw/codemirror-theme-androidstudio': 4.19.8 + '@uiw/codemirror-theme-atomone': 4.19.8 + '@uiw/codemirror-theme-aura': 4.19.8 + '@uiw/codemirror-theme-bbedit': 4.19.8 + '@uiw/codemirror-theme-bespin': 4.19.8 + '@uiw/codemirror-theme-darcula': 4.19.8 + '@uiw/codemirror-theme-dracula': 4.19.8 + '@uiw/codemirror-theme-duotone': 4.19.8 + '@uiw/codemirror-theme-eclipse': 4.19.8 + '@uiw/codemirror-theme-github': 4.19.8 + '@uiw/codemirror-theme-gruvbox-dark': 4.19.8 + '@uiw/codemirror-theme-material': 4.19.8 + '@uiw/codemirror-theme-noctis-lilac': 4.19.8 + '@uiw/codemirror-theme-nord': 4.19.8 + '@uiw/codemirror-theme-okaidia': 4.19.8 + '@uiw/codemirror-theme-solarized': 4.19.8 + '@uiw/codemirror-theme-sublime': 4.19.8 + '@uiw/codemirror-theme-tokyo-night': 4.19.8 + '@uiw/codemirror-theme-tokyo-night-day': 4.19.8 + '@uiw/codemirror-theme-tokyo-night-storm': 4.19.8 + '@uiw/codemirror-theme-vscode': 4.19.8 + '@uiw/codemirror-theme-xcode': 4.19.8 + '@uiw/codemirror-themes': 4.19.8 dev: false /@uiw/codemirror-themes/4.19.7_a4vbhepr4qhxm5cldqd4jpyase: @@ -4182,6 +4174,14 @@ packages: '@codemirror/view': 6.7.3 dev: false + /@uiw/codemirror-themes/4.19.8: + resolution: {integrity: sha512-k+0molX6YuQZ7vYymS5DEl3NcHxVE4VP4J0nB7RBnzLrhDwT2K8R5ie7J2eH+4bpppIK1ZZdZ6Mie7U48dH5dQ==} + dependencies: + '@codemirror/language': 6.4.0 + '@codemirror/state': 6.2.0 + '@codemirror/view': 6.7.3 + dev: false + /@uiw/react-codemirror/4.19.7_b6o5qp6ml4k7skggixohr5abde: resolution: {integrity: sha512-IHvpYWVSdiaHX0Fk6oY6YyAJigDnyvSpWKNUTRzsMNxB+8/wqZ8lior4TprXH0zyLxW5F1+bTyifFFTeg+X3Sw==} peerDependencies: @@ -10398,6 +10398,17 @@ 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'} @@ -10408,6 +10419,16 @@ 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==} @@ -10417,6 +10438,23 @@ 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==} @@ -10434,6 +10472,15 @@ 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'} @@ -10442,6 +10489,7 @@ 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==} @@ -12050,6 +12098,8 @@ 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 @@ -12066,10 +12116,10 @@ packages: object-hash: 3.0.0 picocolors: 1.0.0 postcss: 8.4.21 - 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-import: 14.1.0 + postcss-js: 4.0.0 + postcss-load-config: 3.1.4 + postcss-nested: 6.0.0 postcss-selector-parser: 6.0.11 postcss-value-parser: 4.2.0 quick-lru: 5.1.1 diff --git a/website/package.json b/website/package.json index 1ee37756b..5393d1b82 100644 --- a/website/package.json +++ b/website/package.json @@ -38,7 +38,7 @@ "@types/node": "^18.0.0", "@types/react": "^18.0.26", "@types/react-dom": "^18.0.9", - "@uiw/codemirror-themes-all": "^4.19.7", + "@uiw/codemirror-themes-all": "^4.19.8", "astro": "^1.7.2", "canvas": "^2.11.0", "fraction.js": "^4.2.0", From 0b994a1b0fde4736a049ce0ffdb3a94246b87937 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 10 Feb 2023 11:32:36 +0100 Subject: [PATCH 016/112] switchable css variables for theming --- packages/react/src/components/style.css | 4 ++-- website/src/components/HeadCommon.astro | 31 +++++++++++++++++++++++++ website/src/layouts/MainLayout.astro | 2 +- website/src/pages/index.astro | 2 +- website/src/repl/Footer.jsx | 18 +++++++++++++- website/src/repl/Header.jsx | 2 +- website/src/repl/Repl.css | 4 ---- website/src/repl/themes.mjs | 12 ++++++++++ website/src/styles/index.css | 4 ---- website/tailwind.config.cjs | 10 ++++++++ 10 files changed, 75 insertions(+), 14 deletions(-) diff --git a/packages/react/src/components/style.css b/packages/react/src/components/style.css index cb6bd3ffa..8f09e0f78 100644 --- a/packages/react/src/components/style.css +++ b/packages/react/src/components/style.css @@ -1,5 +1,5 @@ .cm-editor { - /* background-color: transparent !important; */ + background-color: transparent !important; height: 100%; z-index: 11; font-size: 18px; @@ -14,5 +14,5 @@ } .cm-line > * { - /* background: #00000095; */ + background: var(--background); } diff --git a/website/src/components/HeadCommon.astro b/website/src/components/HeadCommon.astro index ce00f97e2..b1f948d45 100644 --- a/website/src/components/HeadCommon.astro +++ b/website/src/components/HeadCommon.astro @@ -28,3 +28,34 @@ const base = BASE_URL; {pwaInfo && } + + diff --git a/website/src/layouts/MainLayout.astro b/website/src/layouts/MainLayout.astro index 84eb320b2..8fd78ccbf 100644 --- a/website/src/layouts/MainLayout.astro +++ b/website/src/layouts/MainLayout.astro @@ -31,7 +31,7 @@ const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`; - +
    diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro index fd6f96c16..243653215 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 3ddf1dc4e..898722f96 100644 --- a/website/src/repl/Footer.jsx +++ b/website/src/repl/Footer.jsx @@ -68,7 +68,7 @@ export function Footer({ context }) { return null; } return ( -
    +
    @@ -179,6 +179,22 @@ export function Footer({ context }) { onClick={() => { console.log(k, themeColors(t)); setTheme(t); + document.dispatchEvent( + new CustomEvent('strudel-theme', { + detail: { + // TODO: dynamic + background: '#21202e', + foreground: '#edecee', + caret: '#a277ff', + selection: '#3d375e7f', + selectionMatch: '#3d375e7f', + gutterBackground: '#21202e', + gutterForeground: '#edecee', + gutterBorder: 'transparent', + lineHighlight: '#a394f033', + }, + }), + ); }} >
    {k}
    diff --git a/website/src/repl/Header.jsx b/website/src/repl/Header.jsx index 1ea539fc8..0cf77dff4 100644 --- a/website/src/repl/Header.jsx +++ b/website/src/repl/Header.jsx @@ -32,7 +32,7 @@ export function Header({ context }) { id="header" className={cx( 'py-1 flex-none w-full text-black justify-between z-[100] text-lg select-none sticky top-0', - !isZen && !isEmbedded && 'bg-header', + !isZen && !isEmbedded && 'bg-lineHighlight', isEmbedded ? 'flex' : 'md:flex', )} > diff --git a/website/src/repl/Repl.css b/website/src/repl/Repl.css index 911324643..11d61f536 100644 --- a/website/src/repl/Repl.css +++ b/website/src/repl/Repl.css @@ -10,10 +10,6 @@ opacity: 0.5; } -.cm-gutters { - display: none !important; -} - .cm-content { padding-top: 12px !important; padding-left: 8px !important; diff --git a/website/src/repl/themes.mjs b/website/src/repl/themes.mjs index 9303ca006..44818b8a7 100644 --- a/website/src/repl/themes.mjs +++ b/website/src/repl/themes.mjs @@ -61,6 +61,18 @@ export const themes = { tokyoNightDay, xcodeLight, }; +// TODO: persist theme +export const defaultSettingsAura = { + background: '#21202e', + foreground: '#edecee', + caret: '#a277ff', + selection: '#3d375e7f', + selectionMatch: '#3d375e7f', + gutterBackground: '#21202e', + gutterForeground: '#edecee', + gutterBorder: 'transparent', + lineHighlight: '#a394f033', +}; export const vars = { abcdef: { diff --git a/website/src/styles/index.css b/website/src/styles/index.css index ef62234de..5c95a662f 100644 --- a/website/src/styles/index.css +++ b/website/src/styles/index.css @@ -1,7 +1,3 @@ -body { - background-color: #222; -} - .cm-gutters { display: none !important; } diff --git a/website/tailwind.config.cjs b/website/tailwind.config.cjs index f84b5c6e3..dcd550dfa 100644 --- a/website/tailwind.config.cjs +++ b/website/tailwind.config.cjs @@ -22,6 +22,16 @@ module.exports = { header: '#00000050', // header: 'transparent', footer: '#00000050', + // codemirror-theme settings + background: 'var(--background)', + foreground: 'var(--foreground)', + caret: 'var(--caret)', + selection: 'var(--selection)', + selectionMatch: 'var(--selectionMatch)', + gutterBackground: 'var(--gutterBackground)', + gutterForeground: 'var(--gutterForeground)', + gutterBorder: 'var(--gutterBorder)', + lineHighlight: 'var(--lineHighlight)', }, typography(theme) { return { From 46f70e6a5ea7d638203946ba0b20454d1494ca63 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 10 Feb 2023 12:54:15 +0100 Subject: [PATCH 017/112] persisted theme + add all settings --- website/src/components/HeadCommon.astro | 38 +-- website/src/repl/Footer.jsx | 28 +-- website/src/repl/Header.jsx | 4 +- website/src/repl/Repl.jsx | 8 +- website/src/repl/themes.mjs | 319 +++++++++++++++++++++++- 5 files changed, 342 insertions(+), 55 deletions(-) diff --git a/website/src/components/HeadCommon.astro b/website/src/components/HeadCommon.astro index b1f948d45..22828f26b 100644 --- a/website/src/components/HeadCommon.astro +++ b/website/src/components/HeadCommon.astro @@ -1,6 +1,7 @@ --- 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; @@ -29,33 +30,32 @@ const base = BASE_URL; {pwaInfo && } - diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx index 898722f96..f2f6f3048 100644 --- a/website/src/repl/Footer.jsx +++ b/website/src/repl/Footer.jsx @@ -55,8 +55,8 @@ export function Footer({ context }) {
    setActiveFooter(name)} className={cx( - 'h-8 px-2 text-white cursor-pointer hover:text-tertiary flex items-center space-x-1 border-b', - activeFooter === name ? 'border-white hover:border-tertiary' : 'border-transparent', + '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', )} > {label || name} @@ -78,7 +78,7 @@ export function Footer({ context }) {
    {activeFooter !== '' && ( - )} @@ -173,31 +173,19 @@ export function Footer({ context }) {
    { - console.log(k, themeColors(t)); - setTheme(t); + setTheme(k); document.dispatchEvent( new CustomEvent('strudel-theme', { - detail: { - // TODO: dynamic - background: '#21202e', - foreground: '#edecee', - caret: '#a277ff', - selection: '#3d375e7f', - selectionMatch: '#3d375e7f', - gutterBackground: '#21202e', - gutterForeground: '#edecee', - gutterBorder: 'transparent', - lineHighlight: '#a394f033', - }, + detail: k, }), ); }} > -
    {k}
    +
    {k}
    {themeColors(t).map((c, i) => (
    diff --git a/website/src/repl/Header.jsx b/website/src/repl/Header.jsx index 0cf77dff4..5d29d88f4 100644 --- a/website/src/repl/Header.jsx +++ b/website/src/repl/Header.jsx @@ -49,7 +49,7 @@ export function Header({ context }) { className={cx( isEmbedded ? 'text-l cursor-pointer' : 'text-xl', // 'bg-clip-text bg-gradient-to-r from-primary to-secondary text-transparent font-bold', - 'text-white font-bold flex space-x-2 items-center', + 'text-foreground font-bold flex space-x-2 items-center', )} >
    {!isZen && ( -
    +
    - {show && } + {show && }
    {drawTime && ( * { - background: var(--background); -} diff --git a/packages/react/src/index.js b/packages/react/src/index.js index e8a4c4478..40b9fa8d4 100644 --- a/packages/react/src/index.js +++ b/packages/react/src/index.js @@ -6,4 +6,5 @@ export { default as useHighlighting } from './hooks/useHighlighting'; export { default as usePostMessage } from './hooks/usePostMessage'; export { default as useStrudel } from './hooks/useStrudel'; export { default as useKeydown } from './hooks/useKeydown'; +export { default as strudelTheme } from './themes/strudel-theme'; export { default as cx } from './cx'; diff --git a/website/src/components/HeadCommon.astro b/website/src/components/HeadCommon.astro index 981433747..796f96db3 100644 --- a/website/src/components/HeadCommon.astro +++ b/website/src/components/HeadCommon.astro @@ -5,6 +5,8 @@ import { settings } from '../repl/themes.mjs'; const { BASE_URL } = import.meta.env; const base = BASE_URL; + +const { strudelTheme } = settings; --- @@ -28,14 +30,28 @@ const base = BASE_URL; + + + + {pwaInfo && } - diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index f3e83d992..51e489155 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -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 ? (
    } {activeFooter === 'samples' && } {activeFooter === 'reference' && } - {activeFooter === 'settings' && } + {activeFooter === 'settings' && }
    )}
    @@ -205,37 +206,34 @@ function SamplesTab() {
    ); } -function SettingsTab({ theme, setTheme }) { - /*{ - console.log('vim mode toggle', checked) - }}/>*/ - +function SettingsTab() { + const { state, update } = useStore(); + const { theme, vim } = state; return ( -
    - {Object.entries(themes).map(([k, t]) => ( -
    { - setTheme(k); - document.dispatchEvent( - new CustomEvent('strudel-theme', { - detail: k, - }), - ); - }} +
    + +
    ); } diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 818adea93..3b2f306c2 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -24,6 +24,7 @@ import * as tunes from './tunes.mjs'; import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; import { themes } from './themes.mjs'; import useTheme from '../useTheme'; +import useStore from '../useStore.mjs'; const initialTheme = localStorage.getItem('strudel-theme') || 'strudelTheme'; @@ -113,12 +114,16 @@ export const ReplContext = createContext(null); export function Repl({ embedded = false }) { const isEmbedded = embedded || window.location !== window.parent.location; const [view, setView] = useState(); // codemirror view - const [theme, setTheme] = useState(initialTheme); const [lastShared, setLastShared] = useState(); const [activeFooter, setActiveFooter] = useState(''); const [isZen, setIsZen] = useState(false); const [pending, setPending] = useState(false); + const { theme, themeSettings } = useTheme(); + const { + state: { vim }, + } = useStore(); + const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } = useStrudel({ initialCode: '// LOADING', @@ -172,15 +177,13 @@ export function Repl({ embedded = false }) { ), ); - const { settings } = useTheme(); - // highlighting useHighlighting({ view, pattern, active: started && !activeCode?.includes('strudel disable-highlighting'), getTime: () => scheduler.now(), - color: settings?.foreground, + color: themeSettings?.foreground, }); // @@ -263,8 +266,6 @@ export function Repl({ embedded = false }) { handleShare, isZen, setIsZen, - theme, - setTheme, }; return ( // bg-gradient-to-t from-blue-900 to-slate-900 @@ -281,6 +282,7 @@ export function Repl({ embedded = false }) { setState(e.detail.next)); + return { state, update: Store.updateState }; +} + +export default useStore; diff --git a/website/src/useTheme.jsx b/website/src/useTheme.jsx index 51c66cbf6..37c51100e 100644 --- a/website/src/useTheme.jsx +++ b/website/src/useTheme.jsx @@ -1,27 +1,14 @@ -import { useState } from 'react'; import { settings } from './repl/themes.mjs'; -import { useEffect } from 'react'; +import useStore from './useStore.mjs'; function useTheme() { - const [theme, setTheme] = useState(localStorage.getItem('strudel-theme')); - useEvent('strudel-theme', (e) => setTheme(e.detail)); - const themeSettings = settings[theme || 'strudelTheme']; + const { state } = useStore(); + const theme = state.theme || 'strudelTheme'; + const themeSettings = settings[theme]; return { - theme, - setTheme, - settings: themeSettings, - isDark: !themeSettings.light, - isLight: !!themeSettings.light, + theme: state.theme, + themeSettings, }; } -// TODO: dedupe -function useEvent(name, onTrigger, useCapture = false) { - useEffect(() => { - document.addEventListener(name, onTrigger, useCapture); - return () => { - document.removeEventListener(name, onTrigger, useCapture); - }; - }, [onTrigger]); -} export default useTheme; diff --git a/website/tailwind.config.cjs b/website/tailwind.config.cjs index 877a2acde..f24215984 100644 --- a/website/tailwind.config.cjs +++ b/website/tailwind.config.cjs @@ -41,5 +41,5 @@ module.exports = { }, }, }, - plugins: [require('@tailwindcss/typography')], + plugins: [require('@tailwindcss/typography'), require('@tailwindcss/forms')], }; From ceb3aa0627b78b6a7ac33eff8d6440a1e006eaff Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 19 Feb 2023 13:49:55 +0100 Subject: [PATCH 061/112] add emacs mode + fontSize slider --- packages/react/package.json | 1 + packages/react/src/components/CodeMirror6.jsx | 19 ++- packages/react/src/components/style.css | 1 - pnpm-lock.yaml | 16 +++ website/public/store.mjs | 10 +- website/src/repl/Footer.jsx | 125 ++++++++++++++---- website/src/repl/Repl.jsx | 5 +- 7 files changed, 143 insertions(+), 34 deletions(-) diff --git a/packages/react/package.json b/packages/react/package.json index dfc72b462..445910f8d 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -37,6 +37,7 @@ "@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:*", diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx index c04f422a0..5bc8cef5f 100644 --- a/packages/react/src/components/CodeMirror6.jsx +++ b/packages/react/src/components/CodeMirror6.jsx @@ -9,6 +9,7 @@ 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({ @@ -98,7 +99,8 @@ export default function CodeMirror({ onViewChanged, onSelectionChange, theme, - vimMode, + keybindings, + fontSize = 18, options, editorDidMount, }) { @@ -122,9 +124,18 @@ export default function CodeMirror({ }, [onSelectionChange], ); - const extensions = useMemo(() => [...staticExtensions, ...(vimMode ? [vim()] : [])], [vimMode]); + const extensions = useMemo(() => { + let bindings = { + vim, + emacs, + }; + if (bindings[keybindings]) { + return [...staticExtensions, bindings[keybindings]()]; + } + return staticExtensions; + }, [keybindings]); return ( - <> +
    <_CodeMirror value={value} theme={theme || strudelTheme} @@ -133,7 +144,7 @@ export default function CodeMirror({ onUpdate={handleOnUpdate} extensions={extensions} /> - +
    ); } diff --git a/packages/react/src/components/style.css b/packages/react/src/components/style.css index f2db01ccf..8983884e8 100644 --- a/packages/react/src/components/style.css +++ b/packages/react/src/components/style.css @@ -2,7 +2,6 @@ background-color: transparent !important; height: 100%; z-index: 11; - font-size: 18px; } .cm-theme { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b8e36d4d..d413286a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -164,6 +164,7 @@ 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:* @@ -186,6 +187,7 @@ 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 @@ -3404,6 +3406,20 @@ 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: diff --git a/website/public/store.mjs b/website/public/store.mjs index 1efcd91b6..191668108 100644 --- a/website/public/store.mjs +++ b/website/public/store.mjs @@ -1,7 +1,15 @@ export const storeKey = 'strudel-settings'; +const defaults = { + keybindings: 'codemirror', + theme: 'strudelTheme', + fontSize: 18, +}; export function get(prop) { - const state = JSON.parse(localStorage.getItem(storeKey)); + let state = { + ...defaults, + ...JSON.parse(localStorage.getItem(storeKey) || '{}'), + }; if (!prop) { return state; } diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx index 9b11b715c..bab35400e 100644 --- a/website/src/repl/Footer.jsx +++ b/website/src/repl/Footer.jsx @@ -206,34 +206,107 @@ function SamplesTab() {
    ); } -function SettingsTab() { - const { state, update } = useStore(); - const { theme, vim } = state; + +function ButtonGroup({ value, onChange, items }) { return ( -
    - - + {label} + + ))} +
    + ); +} + +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])); + +function SettingsTab() { + const { state, update } = useStore(); + const { theme, keybindings, fontSize } = state; + return ( +
    +
    + + update((current) => ({ ...current, theme }))} + /> + + + update((current) => ({ ...current, fontSize }))} + min={10} + max={40} + step={2} + /> + +
    + + update((current) => ({ ...current, keybindings }))} + items={{ codemirror: 'Codemirror', vim: 'Vim', emacs: 'Emacs' }} + > +
    ); } diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 3b2f306c2..f91310d6e 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -121,7 +121,7 @@ export function Repl({ embedded = false }) { const { theme, themeSettings } = useTheme(); const { - state: { vim }, + state: { keybindings, fontSize }, } = useStore(); const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } = @@ -282,7 +282,8 @@ export function Repl({ embedded = false }) { Date: Sun, 19 Feb 2023 13:50:08 +0100 Subject: [PATCH 062/112] fix app height for ios --- website/src/components/HeadCommon.astro | 9 +++++++++ website/src/layouts/MainLayout.astro | 2 +- website/tailwind.config.cjs | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/website/src/components/HeadCommon.astro b/website/src/components/HeadCommon.astro index dcf9af3b9..002a5a92a 100644 --- a/website/src/components/HeadCommon.astro +++ b/website/src/components/HeadCommon.astro @@ -80,4 +80,13 @@ const { strudelTheme } = settings; } setTheme(get().theme); watch(setTheme, 'theme'); + // https://medium.com/quick-code/100vh-problem-with-ios-safari-92ab23c852a8 + const appHeight = () => { + const doc = document.documentElement; + doc.style.setProperty('--app-height', `${window.innerHeight}px`); + }; + if (typeof window !== 'undefined') { + window.addEventListener('resize', appHeight); + appHeight(); + } diff --git a/website/src/layouts/MainLayout.astro b/website/src/layouts/MainLayout.astro index ac268cab1..49952a7ee 100644 --- a/website/src/layouts/MainLayout.astro +++ b/website/src/layouts/MainLayout.astro @@ -30,7 +30,7 @@ const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`; - +
    diff --git a/website/tailwind.config.cjs b/website/tailwind.config.cjs index f24215984..4b5fd0c05 100644 --- a/website/tailwind.config.cjs +++ b/website/tailwind.config.cjs @@ -25,6 +25,9 @@ module.exports = { gutterBorder: 'var(--gutterBorder)', lineHighlight: 'var(--lineHighlight)', }, + spacing: { + 'app-height': 'var(--app-height)', + }, typography(theme) { return { DEFAULT: { From 1e3f09f69b6a6856d06b9a724d3b6b814f210938 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 19 Feb 2023 18:53:35 +0100 Subject: [PATCH 063/112] add some custom themes --- packages/react/src/components/style.css | 1 + packages/react/src/themes/blackscreen.js | 36 ++++++++++++++++++++++ packages/react/src/themes/bluescreen.js | 39 ++++++++++++++++++++++++ packages/react/src/themes/gameboy.js | 38 +++++++++++++++++++++++ packages/react/src/themes/whitescreen.js | 38 +++++++++++++++++++++++ website/src/docs/MiniRepl.jsx | 6 ++-- website/src/repl/Footer.jsx | 6 ++-- website/src/repl/themes.mjs | 12 ++++++++ website/src/useStore.mjs | 15 +++++++-- 9 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 packages/react/src/themes/blackscreen.js create mode 100644 packages/react/src/themes/bluescreen.js create mode 100644 packages/react/src/themes/gameboy.js create mode 100644 packages/react/src/themes/whitescreen.js diff --git a/packages/react/src/components/style.css b/packages/react/src/components/style.css index 8983884e8..ae33a5d2f 100644 --- a/packages/react/src/components/style.css +++ b/packages/react/src/components/style.css @@ -6,6 +6,7 @@ .cm-theme { width: 100%; + height: 100%; } .cm-theme-light { diff --git a/packages/react/src/themes/blackscreen.js b/packages/react/src/themes/blackscreen.js new file mode 100644 index 000000000..8356942f5 --- /dev/null +++ b/packages/react/src/themes/blackscreen.js @@ -0,0 +1,36 @@ +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', + 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 000000000..c45120397 --- /dev/null +++ b/packages/react/src/themes/bluescreen.js @@ -0,0 +1,39 @@ +import { tags as t } from '@lezer/highlight'; +import { createTheme } from '@uiw/codemirror-themes'; +export const settings = { + background: '#051DB5', + 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/gameboy.js b/packages/react/src/themes/gameboy.js new file mode 100644 index 000000000..c9cf72cec --- /dev/null +++ b/packages/react/src/themes/gameboy.js @@ -0,0 +1,38 @@ +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', + 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/whitescreen.js b/packages/react/src/themes/whitescreen.js new file mode 100644 index 000000000..22abad9e9 --- /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/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index 51e489155..10065d89d 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 useStore from '../useStore.mjs'; let modules; if (typeof window !== 'undefined') { @@ -29,6 +28,9 @@ if (typeof window !== 'undefined') { export function MiniRepl({ tune, drawTime, punchcard, canvasHeight = 100 }) { const [Repl, setRepl] = useState(); + const { + state: { theme }, + } = useStore(); useEffect(() => { // we have to load this package on the client // because codemirror throws an error on the server diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx index bab35400e..f7a4fb130 100644 --- a/website/src/repl/Footer.jsx +++ b/website/src/repl/Footer.jsx @@ -6,7 +6,7 @@ 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 useStore from '../useStore.mjs'; export function Footer({ context }) { @@ -209,7 +209,7 @@ function SamplesTab() { function ButtonGroup({ value, onChange, items }) { return ( -
    +
    {Object.entries(items).map(([key, label], i, arr) => ( )} {isEmbedded && ( - +
    ); } diff --git a/website/src/useStore.mjs b/website/src/useStore.mjs index 065be3d1d..1b358c6b9 100644 --- a/website/src/useStore.mjs +++ b/website/src/useStore.mjs @@ -6,7 +6,7 @@ import {} from 'react'; function useStore() { const [state, setState] = useState(Store.get()); useEvent(Store.storeKey, (e) => setState(e.detail.next)); - return { state, update: Store.updateState }; + return { state, ...Store }; } // TODO: dedupe From 89cd0c769b8ae6cbaa931197cc0212161be056d1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 19 Feb 2023 23:27:56 +0100 Subject: [PATCH 070/112] fix bluescreen line bg --- packages/react/src/themes/bluescreen.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react/src/themes/bluescreen.js b/packages/react/src/themes/bluescreen.js index c57bd1208..661fcf68d 100644 --- a/packages/react/src/themes/bluescreen.js +++ b/packages/react/src/themes/bluescreen.js @@ -2,6 +2,7 @@ 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)', From 7716574076857532ea87b23fc3589eab15f56ef3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 19 Feb 2023 23:28:33 +0100 Subject: [PATCH 071/112] use terminal font for console + samples --- website/src/repl/Footer.jsx | 10 ++++++++-- website/src/styles/index.css | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx index f816df92f..384e95efd 100644 --- a/website/src/repl/Footer.jsx +++ b/website/src/repl/Footer.jsx @@ -175,7 +175,13 @@ function WelcomeTab() { function ConsoleTab({ log }) { return ( -
    +
    +
    {`███████╗████████╗██████╗ ██╗   ██╗██████╗ ███████╗██╗     
    +██╔════╝╚══██╔══╝██╔══██╗██║   ██║██╔══██╗██╔════╝██║     
    +███████╗   ██║   ██████╔╝██║   ██║██║  ██║█████╗  ██║     
    +╚════██║   ██║   ██╔══██╗██║   ██║██║  ██║██╔══╝  ██║     
    +███████║   ██║   ██║  ██║╚██████╔╝██████╔╝███████╗███████╗
    +╚══════╝   ╚═╝   ╚═╝  ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝`}
    {log.map((l, i) => { const message = linkify(l.message); return ( @@ -191,7 +197,7 @@ function ConsoleTab({ log }) { function SamplesTab() { return ( -
    +
    {loadedSamples.length} banks loaded: {loadedSamples.map(([name, samples]) => ( {}}> diff --git a/website/src/styles/index.css b/website/src/styles/index.css index c34a65faf..2657bab77 100644 --- a/website/src/styles/index.css +++ b/website/src/styles/index.css @@ -21,3 +21,8 @@ :root { --app-height: 100vh; } + +#console-tab, +#samples-tab { + font-family: BigBlueTerminal, monospace; +} From 20848aac093b8f1952f2559841d875be35d8277e Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 19 Feb 2023 23:28:46 +0100 Subject: [PATCH 072/112] fix store import --- website/src/components/HeadCommon.astro | 8 +++----- website/{public => src}/store.mjs | 0 website/src/useStore.mjs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) rename website/{public => src}/store.mjs (100%) diff --git a/website/src/components/HeadCommon.astro b/website/src/components/HeadCommon.astro index 002a5a92a..47929bc6a 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,8 +45,9 @@ const { strudelTheme } = settings; {pwaInfo && } -