mirror of
https://github.com/eliasstepanik/strudel.git
synced 2026-01-11 13:48:40 +00:00
commit
a253c26bee
@ -15,4 +15,6 @@ vite.config.js
|
||||
!**/*.mjs
|
||||
**/*.tsx
|
||||
**/*.ts
|
||||
**/*.json
|
||||
**/*.json
|
||||
**/dev-dist
|
||||
**/dist
|
||||
@ -8,4 +8,5 @@ packages/mini/krill-parser.js
|
||||
packages/xen/tunejs.js
|
||||
paper
|
||||
pnpm-lock.yaml
|
||||
pnpm-workspace.yaml
|
||||
pnpm-workspace.yaml
|
||||
**/dev-dist
|
||||
@ -49,11 +49,12 @@ const highlightField = StateField.define({
|
||||
try {
|
||||
for (let e of tr.effects) {
|
||||
if (e.is(setHighlights)) {
|
||||
const { haps } = e.value;
|
||||
const marks =
|
||||
e.value
|
||||
haps
|
||||
.map((hap) =>
|
||||
(hap.context.locations || []).map(({ start, end }) => {
|
||||
const color = hap.context.color || '#FFCA28';
|
||||
const color = hap.context.color || e.value.color || '#FFCA28';
|
||||
let from = tr.newDoc.line(start.line).from + start.column;
|
||||
let to = tr.newDoc.line(end.line).from + end.column;
|
||||
const l = tr.newDoc.length;
|
||||
@ -79,9 +80,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 +115,7 @@ export default function CodeMirror({ value, onChange, onViewChanged, onSelection
|
||||
<>
|
||||
<_CodeMirror
|
||||
value={value}
|
||||
theme={theme || strudelTheme}
|
||||
onChange={handleOnChange}
|
||||
onCreateEditor={handleOnCreateEditor}
|
||||
onUpdate={handleOnUpdate}
|
||||
|
||||
@ -10,10 +10,21 @@ import { Icon } from './Icon';
|
||||
import styles from './MiniRepl.module.css';
|
||||
import './style.css';
|
||||
import { logger } from '@strudel.cycles/core';
|
||||
import useEvent from '../hooks/useEvent.mjs';
|
||||
import useKeydown from '../hooks/useKeydown.mjs';
|
||||
|
||||
const getTime = () => getAudioContext().currentTime;
|
||||
|
||||
export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTime, punchcard, canvasHeight = 200 }) {
|
||||
export function MiniRepl({
|
||||
tune,
|
||||
hideOutsideView = false,
|
||||
enableKeyboard,
|
||||
drawTime,
|
||||
punchcard,
|
||||
canvasHeight = 200,
|
||||
theme,
|
||||
highlightColor,
|
||||
}) {
|
||||
drawTime = drawTime || (punchcard ? [0, 4] : undefined);
|
||||
const evalOnMount = !!drawTime;
|
||||
const drawContext = useCallback(
|
||||
@ -61,6 +72,7 @@ export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTi
|
||||
pattern,
|
||||
active: started && !activeCode?.includes('strudel disable-highlighting'),
|
||||
getTime: () => scheduler.now(),
|
||||
color: highlightColor,
|
||||
});
|
||||
|
||||
// keyboard shortcuts
|
||||
@ -132,7 +144,7 @@ export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTi
|
||||
{error && <div className={styles.error}>{error.message}</div>}
|
||||
</div>
|
||||
<div className={styles.body}>
|
||||
{show && <CodeMirror6 value={code} onChange={setCode} onViewChanged={setView} />}
|
||||
{show && <CodeMirror6 value={code} onChange={setCode} onViewChanged={setView} theme={theme} />}
|
||||
</div>
|
||||
{drawTime && (
|
||||
<canvas
|
||||
@ -161,18 +173,3 @@ export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTi
|
||||
function useLogger(onTrigger) {
|
||||
useEvent(logger.key, onTrigger);
|
||||
}
|
||||
|
||||
// TODO: dedupe
|
||||
function useEvent(name, onTrigger, useCapture = false) {
|
||||
useEffect(() => {
|
||||
document.addEventListener(name, onTrigger, useCapture);
|
||||
return () => {
|
||||
document.removeEventListener(name, onTrigger, useCapture);
|
||||
};
|
||||
}, [onTrigger]);
|
||||
}
|
||||
|
||||
// TODO: dedupe
|
||||
function useKeydown(onTrigger) {
|
||||
useEvent('keydown', onTrigger, true);
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
.container {
|
||||
@apply rounded-md overflow-hidden bg-[#222222];
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply flex justify-between bg-slate-700 border-t border-slate-500;
|
||||
@apply flex justify-between bg-lineHighlight border-t border-l border-r border-lineHighlight rounded-t-md overflow-hidden;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
@ -11,11 +11,11 @@
|
||||
}
|
||||
|
||||
.button {
|
||||
@apply cursor-pointer w-16 flex items-center justify-center p-1 bg-slate-700 border-r border-slate-500 text-white hover:bg-slate-600;
|
||||
@apply cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground hover:bg-background;
|
||||
}
|
||||
|
||||
.buttonDisabled {
|
||||
@apply w-16 flex items-center justify-center p-1 bg-slate-600 text-slate-400 cursor-not-allowed;
|
||||
@apply w-16 flex items-center justify-center p-1 opacity-50 cursor-not-allowed border-r border-lineHighlight;
|
||||
}
|
||||
|
||||
.error {
|
||||
|
||||
@ -5,10 +5,10 @@
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.cm-theme-light {
|
||||
.cm-theme {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cm-line > * {
|
||||
background: #00000095;
|
||||
.cm-theme-light {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
12
packages/react/src/hooks/useEvent.mjs
Normal file
12
packages/react/src/hooks/useEvent.mjs
Normal file
@ -0,0 +1,12 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
function useEvent(name, onTrigger, useCapture = false) {
|
||||
useEffect(() => {
|
||||
document.addEventListener(name, onTrigger, useCapture);
|
||||
return () => {
|
||||
document.removeEventListener(name, onTrigger, useCapture);
|
||||
};
|
||||
}, [onTrigger]);
|
||||
}
|
||||
|
||||
export default useEvent;
|
||||
@ -1,7 +1,7 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { setHighlights } from '../components/CodeMirror6';
|
||||
|
||||
function useHighlighting({ view, pattern, active, getTime }) {
|
||||
function useHighlighting({ view, pattern, active, getTime, color }) {
|
||||
const highlights = useRef([]);
|
||||
const lastEnd = useRef(0);
|
||||
useEffect(() => {
|
||||
@ -19,9 +19,9 @@ function useHighlighting({ view, pattern, active, getTime }) {
|
||||
highlights.current = highlights.current.filter((hap) => hap.whole.end > audioTime); // keep only highlights that are still active
|
||||
const haps = pattern.queryArc(...span).filter((hap) => hap.hasOnset());
|
||||
highlights.current = highlights.current.concat(haps); // add potential new onsets
|
||||
view.dispatch({ effects: setHighlights.of(highlights.current) }); // highlight all still active + new active haps
|
||||
view.dispatch({ effects: setHighlights.of({ haps: highlights.current, color }) }); // highlight all still active + new active haps
|
||||
} catch (err) {
|
||||
view.dispatch({ effects: setHighlights.of([]) });
|
||||
view.dispatch({ effects: setHighlights.of({ haps: [] }) });
|
||||
}
|
||||
frame = requestAnimationFrame(updateHighlights);
|
||||
});
|
||||
@ -30,10 +30,10 @@ function useHighlighting({ view, pattern, active, getTime }) {
|
||||
};
|
||||
} else {
|
||||
highlights.current = [];
|
||||
view.dispatch({ effects: setHighlights.of([]) });
|
||||
view.dispatch({ effects: setHighlights.of({ haps: [] }) });
|
||||
}
|
||||
}
|
||||
}, [pattern, active, view]);
|
||||
}, [pattern, active, view, color]);
|
||||
}
|
||||
|
||||
export default useHighlighting;
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
// import 'tailwindcss/tailwind.css';
|
||||
|
||||
export { default as CodeMirror, flash } from './components/CodeMirror6';
|
||||
export * from './components/MiniRepl';
|
||||
export { default as useHighlighting } from './hooks/useHighlighting';
|
||||
export { default as CodeMirror, flash } from './components/CodeMirror6'; // !SSR
|
||||
export * from './components/MiniRepl'; // !SSR
|
||||
export { default as useHighlighting } from './hooks/useHighlighting'; // !SSR
|
||||
export { default as useStrudel } from './hooks/useStrudel'; // !SSR
|
||||
export { default as usePostMessage } from './hooks/usePostMessage';
|
||||
export { default as useStrudel } from './hooks/useStrudel';
|
||||
export { default as useKeydown } from './hooks/useKeydown';
|
||||
export { default as useEvent } from './hooks/useEvent';
|
||||
export { default as strudelTheme } from './themes/strudel-theme';
|
||||
export { default as cx } from './cx';
|
||||
|
||||
235
pnpm-lock.yaml
generated
235
pnpm-lock.yaml
generated
@ -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.8
|
||||
'@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.8
|
||||
astro: 1.9.2_@types+node@18.11.18
|
||||
canvas: 2.11.0
|
||||
fraction.js: 4.2.0
|
||||
@ -3994,6 +3996,173 @@ packages:
|
||||
'@codemirror/view': 6.7.3
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-abcdef/4.19.8:
|
||||
resolution: {integrity: sha512-sR7srfMJRGTsAFQYEs+8IogUxUHDsMqNqZ4waIA6rNIvOH9Q1NYFEqTpqf4AeivkNeXm3N1LI+1nQAKhWzWpOA==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-androidstudio/4.19.8:
|
||||
resolution: {integrity: sha512-xhvEPZ1NvihIJVx7MA1Z8A8NwaTbM6mtBsfwM3mKAmzW6K6JcIJftcKe5z5wSPZk4J3S66vq8RYEMOBygSOdEQ==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-atomone/4.19.8:
|
||||
resolution: {integrity: sha512-enZR8RPiKohyuEU4DOWA7A/xLs/+NsuvZAuGmg5PU43CQITzK1Wqri43/WxkGGsEIztejX439s1QuYxUwCCeUg==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-aura/4.19.8:
|
||||
resolution: {integrity: sha512-DLoi2XEPNBD6Cxsp3v/nYw7jJ7sDEXET9+C43KZnk1dQ9H5e0HSpZhOkw1xmaCGzoXn9q7HInPa7GgUEMv8NPA==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-bbedit/4.19.8:
|
||||
resolution: {integrity: sha512-1vaVaVhMP2IB7H77W9yvPRhVr+8HGBWPDfFEVWAc7tfeU0xC2MFby05gO/7T6K2JWyj2lXnVw/i+oFNeDdcekQ==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-bespin/4.19.8:
|
||||
resolution: {integrity: sha512-JyzmgCloEWhduH5GVYzHQ3vPc3zC0YVRiu7lOjgdOVRhr49M6KmwTytmbmqXbaqmSZKFUJqiHjz8VswqcNC4dw==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-darcula/4.19.8:
|
||||
resolution: {integrity: sha512-fPKyzMqCtBfez2ubC/77AP0BfE+XOio+sy8oRYfX3HqRQEivnnEddQJnTZVz0kKSLYSryQHbOMw/qwgInPvBCA==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-dracula/4.19.8:
|
||||
resolution: {integrity: sha512-YHQJUDnYKrew/YkEPQG3SQFcnKr6MzVbIXxmdKuxlCTrySNFNMK19dKrzY3fwc+Lgpp5r26QLLocTZyCvu1xeA==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-duotone/4.19.8:
|
||||
resolution: {integrity: sha512-SJkjyKxU2Nazv6uEctvRdz62/ZQ8rBP4xtXrjF/zcjOdWmx2ecUAGn/j5Euw5V55Dr74yIQFs0L+GB5UTHCHDA==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-eclipse/4.19.8:
|
||||
resolution: {integrity: sha512-6XXzYFC809e5MWT/NNTqoZ0N9H6P8mXwIEGDfigh33VU1TJPPpO1LCWdf59VcXx/xIY0ctDp7rU7hTy3f3tHkw==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-github/4.19.8:
|
||||
resolution: {integrity: sha512-RUAzHGkG2G2PXTxsH4KbKVCKqPs/+H6xvhCT3Q4YiPj1W2aGSfPwZZ8cLLCm9dYaIh/+H6L+AcoiUtvADjyKsQ==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-gruvbox-dark/4.19.8:
|
||||
resolution: {integrity: sha512-EQepnqhfcu7HY2uutigzflZ9OFzDcF9eq4xF53UylD+WZBdwq2qarZMQgBfOXZZKYI3XcTny064fa7Xxklhs1g==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-material/4.19.8:
|
||||
resolution: {integrity: sha512-dm7FtZkJSZ4AV+9vXxKUDnXLTHaqWnsmn9HOb6AmLiHmHcLFLDgeosSBnA80fwXBhd6QswJI0cEnKHAvcC/vFg==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-noctis-lilac/4.19.8:
|
||||
resolution: {integrity: sha512-vPH8KOiRgcBK1V7/BN04n8K03cfR4CEmOGZUMKpcLlSZwWRe0+JPk6S2qtjbJ072Fsn1ZrcLRYrqtaAJQNOVnw==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-nord/4.19.8:
|
||||
resolution: {integrity: sha512-qBqKJI9fa35rFefXqaiw3FCXWSpD+65+Weji3g/AgB0m0+MHG+3rkC+rLZ4PE2QpkcMz6wHj89EMwOW9W1i3cA==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-okaidia/4.19.8:
|
||||
resolution: {integrity: sha512-gxEThgbbfIxKjk7UzD0D8gw5bVpgxDct3e6r9/WegZw7tTvTHMnz9wutGbJp2cYSwdgLHoQJZzZBi6jKhExZSg==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-solarized/4.19.8:
|
||||
resolution: {integrity: sha512-xHp2i6zWBMw2+kZX0GUYi7pCL3ZL1qWSO8OaleHCkpY3jn+lfLSJOAYYkajvNyu3tPsiKQuAgpCQ6AYFWOr6BQ==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-sublime/4.19.8:
|
||||
resolution: {integrity: sha512-tapkCty8lwpRw2CAY5bPiK8S2ptdTL4d1X/IkCVyHqbC0B8728iQJu3E4Rrka7yggFx4QGUpyZB9UTIFYURtsw==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-tokyo-night-day/4.19.8:
|
||||
resolution: {integrity: sha512-HDKp2KDjluubpe+7M31SohWUFCW7wGQIvoD60xr86OkPZDdqsCVUFmna6rqfttV6S2OsgVNJPBzZvOF398Eapg==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-tokyo-night-storm/4.19.8:
|
||||
resolution: {integrity: sha512-Kp8HIf1H+pgbRx/ZhRsqqN5qfyx3SVVfjnUPGltsdBymqh8QGdr7LC8Tp0P5+Yjb6CqF6Dgx7RnQDj1XZ94rbA==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-tokyo-night/4.19.8:
|
||||
resolution: {integrity: sha512-LrfB+EgZqBNlMF6Zqk8RrlsfVzKe6Ple7ckvREV6kSuwxncF5FlhzVL3cWgxNfNQ7TJ5ySVSvw4fWOcxIcc1LQ==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-vscode/4.19.8:
|
||||
resolution: {integrity: sha512-UdUuJfNjG2y88taP5gsEA9AQlhRTURnl+9kl+LOJkQtXavrqp3J8gUAHRhEWxN7k8q8YimsSVcQ4yw0FKAgXQQ==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-theme-xcode/4.19.8:
|
||||
resolution: {integrity: sha512-VYCRhStYujUNGIkiaZZ1o5OO2Z2edsKkYCCYSy0rwb4G17vT6sd4YDnmJQuF0gzqQkTIdDxSb6aCM9ISkPABlg==}
|
||||
dependencies:
|
||||
'@uiw/codemirror-themes': 4.19.8
|
||||
dev: false
|
||||
|
||||
/@uiw/codemirror-themes-all/4.19.8:
|
||||
resolution: {integrity: sha512-0kAWabe46Vkz+gwNfaXvn/0adeUSCTAuZC0d7Nu8ebcr1TjT1fDLFNZIXlwidn40suiXq8FDfZ9euArx3RPg0Q==}
|
||||
dependencies:
|
||||
'@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:
|
||||
resolution: {integrity: sha512-M/42RkPI60ItlssmNuEoZO2MQvlY6fRmdX7XRUAhKjxczZoaq8xS6HIvv1whGf2zGsTrwdVTPCm6ls0l17dvPA==}
|
||||
peerDependencies:
|
||||
@ -4005,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:
|
||||
@ -10221,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'}
|
||||
@ -10231,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==}
|
||||
@ -10240,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==}
|
||||
@ -10257,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'}
|
||||
@ -10265,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==}
|
||||
@ -11873,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
|
||||
@ -11889,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
|
||||
|
||||
@ -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.8",
|
||||
"astro": "^1.7.2",
|
||||
"canvas": "^2.11.0",
|
||||
"fraction.js": "^4.2.0",
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
---
|
||||
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;
|
||||
---
|
||||
|
||||
<!-- Global Metadata -->
|
||||
@ -27,4 +30,55 @@ const base = BASE_URL;
|
||||
<script src="./make-scrollable-code-focusable.js" is:inline></script>
|
||||
|
||||
<script src="/src/pwa.ts"></script>
|
||||
<!-- this does not work for some reason: -->
|
||||
<!-- <style is:global define:vars={strudelTheme}></style> -->
|
||||
<!-- the following variables are just a fallback to make sure everything is readable without JS -->
|
||||
<style is:global>
|
||||
:root {
|
||||
--background: #222;
|
||||
--lineBackground: #22222250;
|
||||
--foreground: #fff;
|
||||
--caret: #ffcc00;
|
||||
--selection: rgba(128, 203, 196, 0.5);
|
||||
--selectionMatch: #036dd626;
|
||||
--lineHighlight: #00000050;
|
||||
--gutterBackground: transparent;
|
||||
--gutterForeground: #8a919966;
|
||||
}
|
||||
</style>
|
||||
{pwaInfo && <Fragment set:html={pwaInfo.webManifest.linkTag} />}
|
||||
|
||||
<script define:vars={{ settings, strudelTheme }} is:inline>
|
||||
const themeStyle = document.createElement('style');
|
||||
themeStyle.id = 'strudel-theme';
|
||||
document.head.append(themeStyle);
|
||||
function getTheme(name) {
|
||||
if (!settings[name]) {
|
||||
console.warn('theme', name, 'has no settings');
|
||||
}
|
||||
return {
|
||||
name,
|
||||
settings: settings[name] || settings.strudelTheme,
|
||||
};
|
||||
}
|
||||
function setTheme(name) {
|
||||
const { settings } = getTheme(name);
|
||||
// set css variables
|
||||
themeStyle.innerHTML = `:root {
|
||||
${Object.entries(settings)
|
||||
// important to override fallback
|
||||
.map(([key, value]) => `--${key}: ${value} !important;`)
|
||||
.join('\n')}
|
||||
}`;
|
||||
// tailwind dark mode
|
||||
if (settings.light) {
|
||||
document.documentElement.classList.remove('dark');
|
||||
} else {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
// persist theme name
|
||||
localStorage.setItem('strudel-theme', name || 'strudelTheme');
|
||||
}
|
||||
setTheme(localStorage.getItem('strudel-theme'));
|
||||
document.addEventListener('strudel-theme', (e) => setTheme(e.detail));
|
||||
</script>
|
||||
|
||||
@ -19,13 +19,13 @@ const langCode = 'en'; // getLanguageFromURL(currentPage);
|
||||
const sidebar = SIDEBAR[langCode];
|
||||
---
|
||||
|
||||
<nav class="flex justify-between py-2 px-4 items-center h-14 max-h-14 bg-[#161616]" title="Top Navigation">
|
||||
<nav class="flex justify-between py-2 px-4 items-center h-14 max-h-14 bg-lineHighlight text-foreground" title="Top Navigation">
|
||||
<!-- <div class="menu-toggle">
|
||||
<SidebarToggle client:idle />
|
||||
</div> -->
|
||||
<div class="flex overflow-visible items-center grow" style="overflow:visible">
|
||||
<a href="/" class="flex items-center text-2xl space-x-2">
|
||||
<h1 class="text-white font-bold flex space-x-2 items-baseline text-xl">
|
||||
<h1 class="font-bold flex space-x-2 items-baseline text-xl">
|
||||
<span>🌀</span>
|
||||
<div class="flex space-x-1 items-baseline">
|
||||
<span class="">strudel</span>
|
||||
|
||||
@ -14,7 +14,7 @@ const langCode = 'en'; // getLanguageFromURL(currentPage);
|
||||
const sidebar = SIDEBAR[langCode];
|
||||
---
|
||||
|
||||
<nav aria-labelledby="grid-left" class="max-h-full overflow-auto pb-20">
|
||||
<nav aria-labelledby="grid-left" class="max-h-full overflow-auto pb-20 text-foreground">
|
||||
<ul>
|
||||
{
|
||||
Object.entries(sidebar).map(([header, children]) => (
|
||||
@ -27,8 +27,8 @@ const sidebar = SIDEBAR[langCode];
|
||||
return (
|
||||
<li class="">
|
||||
<a
|
||||
class={`pl-4 py-0.5 w-full hover:bg-header block${
|
||||
currentPageMatch === child.link ? ' bg-header' : ''
|
||||
class={`pl-4 py-0.5 w-full hover:bg-lineHighlight block${
|
||||
currentPageMatch === child.link ? ' bg-lineHighlight' : ''
|
||||
}`}
|
||||
href={url}
|
||||
aria-current={currentPageMatch === child.link ? 'page' : false}
|
||||
|
||||
@ -22,7 +22,7 @@ const currentPage = Astro.url.pathname;
|
||||
<span>On this Page:</span>
|
||||
<TableOfContents client:media="(max-width: 50em)" headings={headings} currentPage={currentPage} />
|
||||
</nav> -->
|
||||
<div class="prose prose-invert max-w-full pb-8">
|
||||
<div class="prose dark:prose-invert max-w-full pb-8">
|
||||
<slot />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -12,7 +12,7 @@ const { headings, githubEditUrl } = Astro.props as Props;
|
||||
const currentPage = Astro.url.pathname;
|
||||
---
|
||||
|
||||
<nav aria-labelledby="grid-right" class="w-64">
|
||||
<nav aria-labelledby="grid-right" class="w-64 text-foreground">
|
||||
<TableOfContents client:media="(min-width: 50em)" headings={headings} currentPage={currentPage} />
|
||||
<MoreMenu editHref={githubEditUrl} />
|
||||
</nav>
|
||||
|
||||
@ -78,9 +78,9 @@ const TableOfContents: FunctionalComponent<{ headings: MarkdownHeading[]; curren
|
||||
<a
|
||||
href={`${currentPage}#${heading.slug}`}
|
||||
onClick={onLinkClick}
|
||||
className={`py-0.5 block cursor-pointer w-full border-l-4 border-header hover:bg-header ${
|
||||
className={`py-0.5 block cursor-pointer w-full border-l-4 border-lineHighlight hover:bg-lineHighlight ${
|
||||
['pl-4', 'pl-9', 'pl-12'][heading.depth - minDepth]
|
||||
} ${currentID === heading.slug ? 'bg-header' : ''}`.trim()}
|
||||
} ${currentID === heading.slug ? 'bg-lineHighlight' : ''}`.trim()}
|
||||
>
|
||||
{unescape(heading.text)}
|
||||
</a>
|
||||
|
||||
9
website/src/docs/MiniRepl.css
Normal file
9
website/src/docs/MiniRepl.css
Normal file
@ -0,0 +1,9 @@
|
||||
.cm-activeLine {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.cm-theme {
|
||||
background-color: var(--background);
|
||||
border: 1px solid var(--lineHighlight);
|
||||
padding: 2px;
|
||||
}
|
||||
@ -2,6 +2,10 @@ import { evalScope, controls } from '@strudel.cycles/core';
|
||||
import { initAudioOnFirstClick } from '@strudel.cycles/webaudio';
|
||||
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';
|
||||
|
||||
let modules;
|
||||
if (typeof window !== 'undefined') {
|
||||
@ -32,9 +36,18 @@ export function MiniRepl({ tune, drawTime, punchcard, canvasHeight = 100 }) {
|
||||
.then(([res]) => setRepl(() => res.MiniRepl))
|
||||
.catch((err) => console.error(err));
|
||||
}, []);
|
||||
// const { settings } = useTheme();
|
||||
return Repl ? (
|
||||
<div className="mb-4">
|
||||
<Repl tune={tune} hideOutsideView={true} drawTime={drawTime} punchcard={punchcard} canvasHeight={canvasHeight} />
|
||||
<Repl
|
||||
tune={tune}
|
||||
hideOutsideView={true}
|
||||
drawTime={drawTime}
|
||||
punchcard={punchcard}
|
||||
canvasHeight={canvasHeight}
|
||||
theme={themes[theme]}
|
||||
highlightColor={settings[theme]?.foreground}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<pre>{tune}</pre>
|
||||
|
||||
@ -23,7 +23,7 @@ export default function MobileNav({ sidebar }) {
|
||||
<div className="space-y-1 px-4 py-4 bg-[#161616]">
|
||||
<a
|
||||
href=".."
|
||||
className="py-2 flex cursor-pointer items-center space-x-1 hover:bg-bg hover:px-2 rounded-md"
|
||||
className="py-2 flex cursor-pointer items-center space-x-1 hover:bg-background hover:px-2 rounded-md"
|
||||
>
|
||||
<span>go to REPL</span>
|
||||
</a>
|
||||
@ -36,7 +36,9 @@ export default function MobileNav({ sidebar }) {
|
||||
as="a"
|
||||
href={`/${item.link}`}
|
||||
className={classNames(
|
||||
item.current ? 'bg-bg text-white' : 'text-gray-300 hover:bg-bg hover:text-white',
|
||||
item.current
|
||||
? 'bg-background text-white'
|
||||
: 'text-gray-300 hover:bg-lineHighlight hover:text-white',
|
||||
'block px-3 py-2 rounded-md text-base font-medium',
|
||||
)}
|
||||
aria-current={item.current ? 'page' : undefined}
|
||||
|
||||
@ -22,7 +22,7 @@ const currentFile = `src/pages${currentPage.replace(/\/$/, '')}.mdx`;
|
||||
const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`;
|
||||
---
|
||||
|
||||
<html dir={frontmatter.dir ?? 'ltr'} lang={frontmatter.lang ?? 'en'} class="initial">
|
||||
<html dir={frontmatter.dir ?? 'ltr'} lang={frontmatter.lang ?? 'en'} class="initial dark">
|
||||
<head>
|
||||
<HeadCommon />
|
||||
<HeadSEO frontmatter={frontmatter} canonicalUrl={canonicalURL} />
|
||||
@ -31,7 +31,7 @@ const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`;
|
||||
</title>
|
||||
</head>
|
||||
|
||||
<body class="h-screen text-gray-50">
|
||||
<body class="h-screen text-gray-50 bg-background">
|
||||
<div class="w-full h-full space-y-4 flex flex-col">
|
||||
<header class="max-w-full fixed top-0 w-full z-[100]">
|
||||
<Header currentPage={currentPage} />
|
||||
|
||||
@ -3,12 +3,12 @@ import HeadCommon from '../components/HeadCommon.astro';
|
||||
import { Repl } from '../repl/Repl.jsx';
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<HeadCommon />
|
||||
<title>Strudel REPL</title>
|
||||
</head>
|
||||
<body>
|
||||
<body class="bg-background">
|
||||
<Repl client:only="react" />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
import XMarkIcon from '@heroicons/react/20/solid/XMarkIcon';
|
||||
import { logger } from '@strudel.cycles/core';
|
||||
import { cx } from '@strudel.cycles/react';
|
||||
import { useEvent, cx } from '@strudel.cycles/react';
|
||||
// import { cx } from '@strudel.cycles/react';
|
||||
import { nanoid } from 'nanoid';
|
||||
import React, { useContext, useCallback, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { useEvent, loadedSamples, ReplContext } from './Repl';
|
||||
import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { loadedSamples } from './Repl';
|
||||
import { Reference } from './Reference';
|
||||
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 } = context;
|
||||
const { activeFooter, setActiveFooter, isZen, theme, setTheme } = context;
|
||||
const footerContent = useRef();
|
||||
const [log, setLog] = useState([]);
|
||||
|
||||
@ -54,8 +56,8 @@ export function Footer({ context }) {
|
||||
<div
|
||||
onClick={() => 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}
|
||||
@ -67,16 +69,17 @@ export function Footer({ context }) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<footer className="bg-footer z-[20]">
|
||||
<footer className="bg-lineHighlight z-[20]">
|
||||
<div className="flex justify-between px-2">
|
||||
<div className={cx('flex select-none', activeFooter && 'pb-2')}>
|
||||
<div className={cx('flex select-none max-w-full overflow-auto', activeFooter && 'pb-2')}>
|
||||
<FooterTab name="intro" label="welcome" />
|
||||
<FooterTab name="samples" />
|
||||
<FooterTab name="console" />
|
||||
<FooterTab name="reference" />
|
||||
<FooterTab name="theme" />
|
||||
</div>
|
||||
{activeFooter !== '' && (
|
||||
<button onClick={() => setActiveFooter('')} className="text-white" aria-label="Close Panel">
|
||||
<button onClick={() => setActiveFooter('')} className="text-foreground" aria-label="Close Panel">
|
||||
<XMarkIcon className="w-5 h-5" />
|
||||
</button>
|
||||
)}
|
||||
@ -87,7 +90,7 @@ export function Footer({ context }) {
|
||||
ref={footerContent}
|
||||
>
|
||||
{activeFooter === 'intro' && (
|
||||
<div className="prose prose-invert max-w-[600px] pt-2 font-sans pb-8 px-4">
|
||||
<div className="prose dark:prose-invert max-w-[600px] pt-2 font-sans pb-8 px-4">
|
||||
<h3>
|
||||
<span className={cx('animate-spin inline-block select-none')}>🌀</span> welcome
|
||||
</h3>
|
||||
@ -132,7 +135,7 @@ export function Footer({ context }) {
|
||||
</div>
|
||||
)}
|
||||
{activeFooter === 'console' && (
|
||||
<div className="break-all px-4">
|
||||
<div className="break-all px-4 dark:text-white text-stone-900">
|
||||
{log.map((l, i) => {
|
||||
const message = linkify(l.message);
|
||||
return (
|
||||
@ -148,8 +151,8 @@ export function Footer({ context }) {
|
||||
</div>
|
||||
)}
|
||||
{activeFooter === 'samples' && (
|
||||
<div className="break-normal w-full px-4">
|
||||
<span className="text-white">{loadedSamples.length} banks loaded:</span>
|
||||
<div className="break-normal w-full px-4 dark:text-white text-stone-900">
|
||||
<span>{loadedSamples.length} banks loaded:</span>
|
||||
{loadedSamples.map(([name, samples]) => (
|
||||
<span key={name} className="cursor-pointer hover:text-tertiary" onClick={() => {}}>
|
||||
{' '}
|
||||
@ -165,6 +168,34 @@ export function Footer({ context }) {
|
||||
</div>
|
||||
)}
|
||||
{activeFooter === 'reference' && <Reference />}
|
||||
{activeFooter === 'theme' && (
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-2 p-2">
|
||||
{Object.entries(themes).map(([k, t]) => (
|
||||
<div
|
||||
key={k}
|
||||
className={cx(
|
||||
'border-2 border-transparent cursor-pointer p-4 bg-background bg-opacity-25 rounded-md',
|
||||
theme === k ? '!border-foreground' : '',
|
||||
)}
|
||||
onClick={() => {
|
||||
setTheme(k);
|
||||
document.dispatchEvent(
|
||||
new CustomEvent('strudel-theme', {
|
||||
detail: k,
|
||||
}),
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className="mb-2 w-full text-center text-foreground">{k}</div>
|
||||
<div className="flex justify-stretch overflow-hidden rounded-md">
|
||||
{themeColors(t).map((c, i) => (
|
||||
<div key={i} className="grow h-6" style={{ background: c }} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</footer>
|
||||
|
||||
@ -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',
|
||||
)}
|
||||
>
|
||||
@ -48,8 +48,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',
|
||||
)}
|
||||
>
|
||||
<div
|
||||
@ -66,7 +65,7 @@ export function Header({ context }) {
|
||||
</h1>
|
||||
</div>
|
||||
{!isZen && (
|
||||
<div className="flex max-w-full overflow-auto text-white ">
|
||||
<div className="flex max-w-full overflow-auto text-foreground">
|
||||
<button
|
||||
onClick={handleTogglePlay}
|
||||
title={started ? 'stop' : 'play'}
|
||||
|
||||
@ -5,16 +5,16 @@ const visibleFunctions = jsdocJson.docs
|
||||
|
||||
export function Reference() {
|
||||
return (
|
||||
<div className="flex h-full w-full pt-2">
|
||||
<div className="flex h-full w-full pt-2 text-foreground">
|
||||
<div className="w-64 flex-none h-full overflow-y-auto overflow-x-hidden pr-4">
|
||||
{visibleFunctions.map((entry, i) => (
|
||||
<a key={i} className="cursor-pointer block hover:bg-linegray py-1 px-4" href={`#doc-${i}`}>
|
||||
<a key={i} className="cursor-pointer block hover:bg-lineHighlight py-1 px-4" href={`#doc-${i}`}>
|
||||
{entry.name} {/* <span className="text-gray-600">{entry.meta.filename}</span> */}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
<div className="break-normal w-full h-full overflow-auto pl-4 flex relative">
|
||||
<div className="prose prose-invert">
|
||||
<div className="prose dark:prose-invert">
|
||||
<h2>API Reference</h2>
|
||||
<p>
|
||||
This is the long list functions you can use! Remember that you don't need to remember all of those and that
|
||||
|
||||
@ -10,11 +10,11 @@
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.cm-gutters {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.cm-content {
|
||||
padding-top: 12px !important;
|
||||
padding-left: 8px !important;
|
||||
}
|
||||
|
||||
.cm-line > * {
|
||||
background: var(--lineBackground);
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
||||
*/
|
||||
|
||||
import { cleanupDraw, cleanupUi, controls, evalScope, getDrawContext, logger } from '@strudel.cycles/core';
|
||||
import { CodeMirror, cx, flash, useHighlighting, useStrudel } from '@strudel.cycles/react';
|
||||
import { CodeMirror, cx, flash, useHighlighting, useStrudel, useKeydown } from '@strudel.cycles/react';
|
||||
import {
|
||||
getAudioContext,
|
||||
getLoadedSamples,
|
||||
@ -22,6 +22,10 @@ import { Header } from './Header';
|
||||
import { prebake } from './prebake.mjs';
|
||||
import * as tunes from './tunes.mjs';
|
||||
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
||||
import { themes } from './themes.mjs';
|
||||
import useTheme from '../useTheme';
|
||||
|
||||
const initialTheme = localStorage.getItem('strudel-theme') || 'strudelTheme';
|
||||
|
||||
initAudioOnFirstClick();
|
||||
|
||||
@ -109,6 +113,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(initialTheme);
|
||||
const [lastShared, setLastShared] = useState();
|
||||
const [activeFooter, setActiveFooter] = useState('');
|
||||
const [isZen, setIsZen] = useState(false);
|
||||
@ -167,12 +172,15 @@ 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,
|
||||
});
|
||||
|
||||
//
|
||||
@ -255,6 +263,8 @@ export function Repl({ embedded = false }) {
|
||||
handleShare,
|
||||
isZen,
|
||||
setIsZen,
|
||||
theme,
|
||||
setTheme,
|
||||
};
|
||||
return (
|
||||
// bg-gradient-to-t from-blue-900 to-slate-900
|
||||
@ -269,6 +279,7 @@ export function Repl({ embedded = false }) {
|
||||
<Header context={context} />
|
||||
<section className="grow flex text-gray-100 relative overflow-auto cursor-text pb-0" id="code">
|
||||
<CodeMirror
|
||||
theme={themes[theme] || themes.strudelTheme}
|
||||
value={code}
|
||||
onChange={handleChangeCode}
|
||||
onViewChanged={setView}
|
||||
@ -276,7 +287,7 @@ export function Repl({ embedded = false }) {
|
||||
/>
|
||||
</section>
|
||||
{error && (
|
||||
<div className="text-red-500 p-4 bg-lineblack animate-pulse">{error.message || 'Unknown Error :-/'}</div>
|
||||
<div className="text-red-500 p-4 bg-lineHighlight animate-pulse">{error.message || 'Unknown Error :-/'}</div>
|
||||
)}
|
||||
{isEmbedded && !started && (
|
||||
<button
|
||||
@ -292,15 +303,3 @@ export function Repl({ embedded = false }) {
|
||||
</ReplContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useEvent(name, onTrigger, useCapture = false) {
|
||||
useEffect(() => {
|
||||
document.addEventListener(name, onTrigger, useCapture);
|
||||
return () => {
|
||||
document.removeEventListener(name, onTrigger, useCapture);
|
||||
};
|
||||
}, [onTrigger]);
|
||||
}
|
||||
function useKeydown(onTrigger) {
|
||||
useEvent('keydown', onTrigger, true);
|
||||
}
|
||||
|
||||
457
website/src/repl/themes.mjs
Normal file
457
website/src/repl/themes.mjs
Normal file
@ -0,0 +1,457 @@
|
||||
import {
|
||||
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,
|
||||
} from '@uiw/codemirror-themes-all';
|
||||
|
||||
import strudelTheme from '@strudel.cycles/react/src/themes/strudel-theme';
|
||||
|
||||
export const themes = {
|
||||
strudelTheme,
|
||||
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,
|
||||
};
|
||||
|
||||
// lineBackground is background with 50% opacity, to make sure the selection below is visible
|
||||
|
||||
export const settings = {
|
||||
strudelTheme: {
|
||||
background: '#222',
|
||||
lineBackground: '#22222250',
|
||||
foreground: '#fff',
|
||||
// foreground: '#75baff',
|
||||
caret: '#ffcc00',
|
||||
selection: 'rgba(128, 203, 196, 0.5)',
|
||||
selectionMatch: '#036dd626',
|
||||
// lineHighlight: '#8a91991a', // original
|
||||
lineHighlight: '#00000050',
|
||||
gutterBackground: 'transparent',
|
||||
// gutterForeground: '#8a919966',
|
||||
gutterForeground: '#8a919966',
|
||||
},
|
||||
abcdef: {
|
||||
background: '#0f0f0f',
|
||||
lineBackground: '#0f0f0f50',
|
||||
foreground: '#defdef',
|
||||
caret: '#00FF00',
|
||||
selection: '#515151',
|
||||
selectionMatch: '#515151',
|
||||
gutterBackground: '#555',
|
||||
gutterForeground: '#FFFFFF',
|
||||
lineHighlight: '#314151',
|
||||
},
|
||||
androidstudio: {
|
||||
background: '#282b2e',
|
||||
lineBackground: '#282b2e50',
|
||||
foreground: '#a9b7c6',
|
||||
caret: '#00FF00',
|
||||
selection: '#343739',
|
||||
selectionMatch: '#343739',
|
||||
lineHighlight: '#343739',
|
||||
},
|
||||
atomone: {
|
||||
background: '#272C35',
|
||||
lineBackground: '#272C3550',
|
||||
foreground: '#9d9b97',
|
||||
caret: '#797977',
|
||||
selection: '#ffffff30',
|
||||
selectionMatch: '#2B323D',
|
||||
gutterBackground: '#272C35',
|
||||
gutterForeground: '#465063',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: '#2B323D',
|
||||
},
|
||||
aura: {
|
||||
background: '#21202e',
|
||||
lineBackground: '#21202e50',
|
||||
foreground: '#edecee',
|
||||
caret: '#a277ff',
|
||||
selection: '#3d375e7f',
|
||||
selectionMatch: '#3d375e7f',
|
||||
gutterBackground: '#21202e',
|
||||
gutterForeground: '#edecee',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: '#a394f033',
|
||||
},
|
||||
bbedit: {
|
||||
light: true,
|
||||
background: '#FFFFFF',
|
||||
lineBackground: '#FFFFFF50',
|
||||
foreground: '#000000',
|
||||
caret: '#FBAC52',
|
||||
selection: '#FFD420',
|
||||
selectionMatch: '#FFD420',
|
||||
gutterBackground: '#f5f5f5',
|
||||
gutterForeground: '#4D4D4C',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: '#00000012',
|
||||
},
|
||||
bespin: {
|
||||
background: '#28211c',
|
||||
lineBackground: '#28211c50',
|
||||
foreground: '#9d9b97',
|
||||
caret: '#797977',
|
||||
selection: '#36312e',
|
||||
selectionMatch: '#4f382b',
|
||||
gutterBackground: '#28211c',
|
||||
gutterForeground: '#666666',
|
||||
lineHighlight: 'rgba(255, 255, 255, 0.1)',
|
||||
},
|
||||
darcula: {
|
||||
background: '#2B2B2B',
|
||||
lineBackground: '#2B2B2B50',
|
||||
foreground: '#f8f8f2',
|
||||
caret: '#FFFFFF',
|
||||
selection: 'rgba(255, 255, 255, 0.1)',
|
||||
selectionMatch: 'rgba(255, 255, 255, 0.2)',
|
||||
gutterBackground: 'rgba(255, 255, 255, 0.1)',
|
||||
gutterForeground: '#999',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: 'rgba(255, 255, 255, 0.1)',
|
||||
},
|
||||
dracula: {
|
||||
background: '#282a36',
|
||||
lineBackground: '#282a3650',
|
||||
foreground: '#f8f8f2',
|
||||
caret: '#f8f8f0',
|
||||
selection: 'rgba(255, 255, 255, 0.1)',
|
||||
selectionMatch: 'rgba(255, 255, 255, 0.2)',
|
||||
gutterBackground: '#282a36',
|
||||
gutterForeground: '#6D8A88',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: 'rgba(255, 255, 255, 0.1)',
|
||||
},
|
||||
duotoneLight: {
|
||||
light: true,
|
||||
background: '#faf8f5',
|
||||
lineBackground: '#faf8f550',
|
||||
foreground: '#b29762',
|
||||
caret: '#93abdc',
|
||||
selection: '#e3dcce',
|
||||
selectionMatch: '#e3dcce',
|
||||
gutterBackground: '#faf8f5',
|
||||
gutterForeground: '#cdc4b1',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: '#EFEFEF',
|
||||
},
|
||||
duotoneDark: {
|
||||
background: '#2a2734',
|
||||
lineBackground: '#2a273450',
|
||||
foreground: '#6c6783',
|
||||
caret: '#ffad5c',
|
||||
selection: 'rgba(255, 255, 255, 0.1)',
|
||||
gutterBackground: '#2a2734',
|
||||
gutterForeground: '#545167',
|
||||
lineHighlight: '#36334280',
|
||||
},
|
||||
eclipse: {
|
||||
light: true,
|
||||
background: '#fff',
|
||||
lineBackground: '#ffffff50',
|
||||
foreground: '#000',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#d7d4f0',
|
||||
selectionMatch: '#d7d4f0',
|
||||
gutterBackground: '#f7f7f7',
|
||||
gutterForeground: '#999',
|
||||
lineHighlight: '#e8f2ff',
|
||||
gutterBorder: 'transparent',
|
||||
},
|
||||
githubLight: {
|
||||
light: true,
|
||||
background: '#fff',
|
||||
lineBackground: '#ffffff50',
|
||||
foreground: '#24292e',
|
||||
selection: '#BBDFFF',
|
||||
selectionMatch: '#BBDFFF',
|
||||
gutterBackground: '#fff',
|
||||
gutterForeground: '#6e7781',
|
||||
},
|
||||
githubDark: {
|
||||
background: '#0d1117',
|
||||
lineBackground: '#0d111750',
|
||||
foreground: '#c9d1d9',
|
||||
caret: '#c9d1d9',
|
||||
selection: '#003d73',
|
||||
selectionMatch: '#003d73',
|
||||
lineHighlight: '#36334280',
|
||||
},
|
||||
gruvboxDark: {
|
||||
background: '#282828',
|
||||
lineBackground: '#28282850',
|
||||
foreground: '#ebdbb2',
|
||||
caret: '#ebdbb2',
|
||||
selection: '#bdae93',
|
||||
selectionMatch: '#bdae93',
|
||||
lineHighlight: '#3c3836',
|
||||
gutterBackground: '#282828',
|
||||
gutterForeground: '#7c6f64',
|
||||
},
|
||||
gruvboxLight: {
|
||||
light: true,
|
||||
background: '#fbf1c7',
|
||||
lineBackground: '#fbf1c750',
|
||||
foreground: '#3c3836',
|
||||
caret: '#af3a03',
|
||||
selection: '#ebdbb2',
|
||||
selectionMatch: '#bdae93',
|
||||
lineHighlight: '#ebdbb2',
|
||||
gutterBackground: '#ebdbb2',
|
||||
gutterForeground: '#665c54',
|
||||
gutterBorder: 'transparent',
|
||||
},
|
||||
materialDark: {
|
||||
background: '#2e3235',
|
||||
lineBackground: '#2e323550',
|
||||
foreground: '#bdbdbd',
|
||||
caret: '#a0a4ae',
|
||||
selection: '#d7d4f0',
|
||||
selectionMatch: '#d7d4f0',
|
||||
gutterBackground: '#2e3235',
|
||||
gutterForeground: '#999',
|
||||
gutterActiveForeground: '#4f5b66',
|
||||
lineHighlight: '#545b61',
|
||||
},
|
||||
materialLight: {
|
||||
light: true,
|
||||
background: '#FAFAFA',
|
||||
lineBackground: '#FAFAFA50',
|
||||
foreground: '#90A4AE',
|
||||
caret: '#272727',
|
||||
selection: '#80CBC440',
|
||||
selectionMatch: '#FAFAFA',
|
||||
gutterBackground: '#FAFAFA',
|
||||
gutterForeground: '#90A4AE',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: '#CCD7DA50',
|
||||
},
|
||||
noctisLilac: {
|
||||
light: true,
|
||||
background: '#f2f1f8',
|
||||
lineBackground: '#f2f1f850',
|
||||
foreground: '#0c006b',
|
||||
caret: '#5c49e9',
|
||||
selection: '#d5d1f2',
|
||||
selectionMatch: '#d5d1f2',
|
||||
gutterBackground: '#f2f1f8',
|
||||
gutterForeground: '#0c006b70',
|
||||
lineHighlight: '#e1def3',
|
||||
},
|
||||
nord: {
|
||||
background: '#2e3440',
|
||||
lineBackground: '#2e344050',
|
||||
foreground: '#FFFFFF',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#3b4252',
|
||||
selectionMatch: '#e5e9f0',
|
||||
gutterBackground: '#2e3440',
|
||||
gutterForeground: '#4c566a',
|
||||
gutterActiveForeground: '#d8dee9',
|
||||
lineHighlight: '#4c566a',
|
||||
},
|
||||
okaidia: {
|
||||
background: '#272822',
|
||||
lineBackground: '#27282250',
|
||||
foreground: '#FFFFFF',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#49483E',
|
||||
selectionMatch: '#49483E',
|
||||
gutterBackground: '#272822',
|
||||
gutterForeground: '#FFFFFF70',
|
||||
lineHighlight: '#00000059',
|
||||
},
|
||||
solarizedLight: {
|
||||
light: true,
|
||||
background: '#fdf6e3',
|
||||
lineBackground: '#fdf6e350',
|
||||
foreground: '#657b83',
|
||||
caret: '#586e75',
|
||||
selection: '#dfd9c8',
|
||||
selectionMatch: '#dfd9c8',
|
||||
gutterBackground: '#00000010',
|
||||
gutterForeground: '#657b83',
|
||||
lineHighlight: '#dfd9c8',
|
||||
},
|
||||
solarizedDark: {
|
||||
background: '#002b36',
|
||||
lineBackground: '#002b3650',
|
||||
foreground: '#93a1a1',
|
||||
caret: '#839496',
|
||||
selection: '#173541',
|
||||
selectionMatch: '#aafe661a',
|
||||
gutterBackground: '#00252f',
|
||||
gutterForeground: '#839496',
|
||||
lineHighlight: '#173541',
|
||||
},
|
||||
sublime: {
|
||||
background: '#303841',
|
||||
lineBackground: '#30384150',
|
||||
foreground: '#FFFFFF',
|
||||
caret: '#FBAC52',
|
||||
selection: '#4C5964',
|
||||
selectionMatch: '#3A546E',
|
||||
gutterBackground: '#303841',
|
||||
gutterForeground: '#FFFFFF70',
|
||||
lineHighlight: '#00000059',
|
||||
},
|
||||
tokyoNightDay: {
|
||||
light: true,
|
||||
background: '#e1e2e7',
|
||||
lineBackground: '#e1e2e750',
|
||||
foreground: '#3760bf',
|
||||
caret: '#3760bf',
|
||||
selection: '#99a7df',
|
||||
selectionMatch: '#99a7df',
|
||||
gutterBackground: '#e1e2e7',
|
||||
gutterForeground: '#3760bf',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: '#5f5faf11',
|
||||
},
|
||||
tokyoNightStorm: {
|
||||
background: '#24283b',
|
||||
lineBackground: '#24283b50',
|
||||
foreground: '#7982a9',
|
||||
caret: '#c0caf5',
|
||||
selection: '#6f7bb630',
|
||||
selectionMatch: '#1f2335',
|
||||
gutterBackground: '#24283b',
|
||||
gutterForeground: '#7982a9',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: '#292e42',
|
||||
},
|
||||
tokyoNight: {
|
||||
background: '#1a1b26',
|
||||
lineBackground: '#1a1b2650',
|
||||
foreground: '#787c99',
|
||||
caret: '#c0caf5',
|
||||
selection: '#515c7e40',
|
||||
selectionMatch: '#16161e',
|
||||
gutterBackground: '#1a1b26',
|
||||
gutterForeground: '#787c99',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: '#1e202e',
|
||||
},
|
||||
vscodeDark: {
|
||||
background: '#1e1e1e',
|
||||
lineBackground: '#1e1e1e50',
|
||||
foreground: '#9cdcfe',
|
||||
caret: '#c6c6c6',
|
||||
selection: '#6199ff2f',
|
||||
selectionMatch: '#72a1ff59',
|
||||
lineHighlight: '#ffffff0f',
|
||||
gutterBackground: '#1e1e1e',
|
||||
gutterForeground: '#838383',
|
||||
gutterActiveForeground: '#fff',
|
||||
fontFamily: 'Menlo, Monaco, Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace',
|
||||
},
|
||||
xcodeLight: {
|
||||
light: true,
|
||||
background: '#fff',
|
||||
lineBackground: '#ffffff50',
|
||||
foreground: '#3D3D3D',
|
||||
selection: '#BBDFFF',
|
||||
selectionMatch: '#BBDFFF',
|
||||
gutterBackground: '#fff',
|
||||
gutterForeground: '#AFAFAF',
|
||||
lineHighlight: '#EDF4FF',
|
||||
},
|
||||
xcodeDark: {
|
||||
background: '#292A30',
|
||||
lineBackground: '#292A3050',
|
||||
foreground: '#CECFD0',
|
||||
caret: '#fff',
|
||||
selection: '#727377',
|
||||
selectionMatch: '#727377',
|
||||
lineHighlight: '#2F3239',
|
||||
},
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: remove
|
||||
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());
|
||||
}
|
||||
@ -1,7 +1,3 @@
|
||||
body {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.cm-gutters {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
27
website/src/useTheme.jsx
Normal file
27
website/src/useTheme.jsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { useState } from 'react';
|
||||
import { settings } from './repl/themes.mjs';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
function useTheme() {
|
||||
const [theme, setTheme] = useState(localStorage.getItem('strudel-theme'));
|
||||
useEvent('strudel-theme', (e) => setTheme(e.detail));
|
||||
const themeSettings = settings[theme || 'strudelTheme'];
|
||||
return {
|
||||
theme,
|
||||
setTheme,
|
||||
settings: themeSettings,
|
||||
isDark: !themeSettings.light,
|
||||
isLight: !!themeSettings.light,
|
||||
};
|
||||
}
|
||||
// TODO: dedupe
|
||||
function useEvent(name, onTrigger, useCapture = false) {
|
||||
useEffect(() => {
|
||||
document.addEventListener(name, onTrigger, useCapture);
|
||||
return () => {
|
||||
document.removeEventListener(name, onTrigger, useCapture);
|
||||
};
|
||||
}, [onTrigger]);
|
||||
}
|
||||
|
||||
export default useTheme;
|
||||
@ -3,6 +3,7 @@
|
||||
const defaultTheme = require('tailwindcss/defaultTheme');
|
||||
|
||||
module.exports = {
|
||||
darkMode: 'class',
|
||||
content: [
|
||||
'./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}',
|
||||
'../packages/react/src/**/*.{html,js,jsx,md,mdx,ts,tsx}',
|
||||
@ -10,18 +11,19 @@ module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: '#c792ea',
|
||||
secondary: '#c3e88d',
|
||||
tertiary: '#82aaff',
|
||||
highlight: '#ffcc00',
|
||||
linegray: '#8a91991a',
|
||||
lineblack: '#00000095',
|
||||
bg: '#222222',
|
||||
// header: '#8a91991a',
|
||||
// footer: '#8a91991a',
|
||||
header: '#00000050',
|
||||
// header: 'transparent',
|
||||
footer: '#00000050',
|
||||
highlight: '#bb8800',
|
||||
// codemirror-theme settings
|
||||
background: 'var(--background)',
|
||||
lineBackground: 'var(--lineBackground)',
|
||||
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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user