diff --git a/packages/codemirror/themes/strudel-theme.mjs b/packages/codemirror/themes/strudel-theme.mjs index 658a682f..58c67563 100644 --- a/packages/codemirror/themes/strudel-theme.mjs +++ b/packages/codemirror/themes/strudel-theme.mjs @@ -5,7 +5,7 @@ export const settings = { background: '#222', lineBackground: '#22222299', foreground: '#fff', - muted: '#ffffff50', + muted: '#8a919966', caret: '#ffcc00', selection: 'rgba(128, 203, 196, 0.5)', selectionMatch: '#036dd626', diff --git a/website/src/repl/components/Code.jsx b/website/src/repl/components/Code.jsx index 8481cc27..e8cccb86 100644 --- a/website/src/repl/components/Code.jsx +++ b/website/src/repl/components/Code.jsx @@ -8,7 +8,7 @@ export function Code(Props) { return (
{ containerRef.current = el; diff --git a/website/src/repl/components/EmbeddedReplEditor.jsx b/website/src/repl/components/EmbeddedReplEditor.jsx index 74db2c65..100d5ad9 100644 --- a/website/src/repl/components/EmbeddedReplEditor.jsx +++ b/website/src/repl/components/EmbeddedReplEditor.jsx @@ -2,7 +2,7 @@ import Loader from '@src/repl/components/Loader'; import { Code } from '@src/repl/components/Code'; import BigPlayButton from '@src/repl/components/BigPlayButton'; import UserFacingErrorMessage from '@src/repl/components/UserFacingErrorMessage'; -import { Header } from './Header'; +import { MainPanel } from './panel/Panel'; // type Props = { // context: replcontext, @@ -14,7 +14,7 @@ export default function EmbeddedReplEditor(Props) { return (
-
+
diff --git a/website/src/repl/components/Header.jsx b/website/src/repl/components/Header.jsx deleted file mode 100644 index 19e7b8fa..00000000 --- a/website/src/repl/components/Header.jsx +++ /dev/null @@ -1,116 +0,0 @@ -import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; -import StopCircleIcon from '@heroicons/react/20/solid/StopCircleIcon'; -import cx from '@src/cx.mjs'; -import { useSettings, setIsZen } from '../../settings.mjs'; -import { StrudelIcon } from '@src/repl/components/icons/StrudelIcon'; -import '../Repl.css'; - -const { BASE_URL } = import.meta.env; -const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL; - -export function Header({ context, isEmbedded = false }) { - const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShare } = context; - const { isZen, isButtonRowHidden, isCSSAnimationDisabled, fontFamily } = useSettings(); - - return ( - - ); -} diff --git a/website/src/repl/components/ReplEditor.jsx b/website/src/repl/components/ReplEditor.jsx index 03cf89f1..fe2e00ac 100644 --- a/website/src/repl/components/ReplEditor.jsx +++ b/website/src/repl/components/ReplEditor.jsx @@ -1,8 +1,7 @@ -import Loader from '@src/repl/components/Loader'; -import { HorizontalPanel, VerticalPanel, PanelToggle } from '@src/repl/components/panel/Panel'; import { Code } from '@src/repl/components/Code'; +import Loader from '@src/repl/components/Loader'; +import { HorizontalPanel, MainPanel, VerticalPanel } from '@src/repl/components/panel/Panel'; import UserFacingErrorMessage from '@src/repl/components/UserFacingErrorMessage'; -import { Header } from './Header'; import { useSettings } from '@src/settings.mjs'; // type Props = { @@ -19,15 +18,17 @@ export default function ReplEditor(Props) { return (
-
- -
- - {!isZen && panelPosition === 'right' && } - +
+ {/* */} + +
+ + {!isZen && panelPosition === 'right' && } +
{!isZen && panelPosition === 'bottom' && } + {/* */}
); } diff --git a/website/src/repl/components/button/action-button.jsx b/website/src/repl/components/button/action-button.jsx index f413a1e9..245cf961 100644 --- a/website/src/repl/components/button/action-button.jsx +++ b/website/src/repl/components/button/action-button.jsx @@ -2,7 +2,7 @@ import cx from '@src/cx.mjs'; export function ActionButton({ children, label, labelIsHidden, className, ...buttonProps }) { return ( - diff --git a/website/src/repl/components/icons/SidebarIcon.jsx b/website/src/repl/components/icons/SidebarIcon.jsx new file mode 100644 index 00000000..07966a2a --- /dev/null +++ b/website/src/repl/components/icons/SidebarIcon.jsx @@ -0,0 +1,19 @@ +export function SidebarIcon() { + return ( + + + + + ); +} diff --git a/website/src/repl/components/panel/ConsoleTab.jsx b/website/src/repl/components/panel/ConsoleTab.jsx index a8044254..64981937 100644 --- a/website/src/repl/components/panel/ConsoleTab.jsx +++ b/website/src/repl/components/panel/ConsoleTab.jsx @@ -7,8 +7,10 @@ export function ConsoleTab() { const log = useStore($strudel_log_history); const { fontFamily } = useSettings(); return ( -
-
+
+
+ {' '} + {/* bg-background */} {log.map((l, i) => { const message = linkify(l.message); const color = l.data?.hap?.value?.color; diff --git a/website/src/repl/components/panel/ExportTab.jsx b/website/src/repl/components/panel/ExportTab.jsx index 071d8d69..1e953def 100644 --- a/website/src/repl/components/panel/ExportTab.jsx +++ b/website/src/repl/components/panel/ExportTab.jsx @@ -45,7 +45,7 @@ export default function ExportTab(Props) { return ( <> -
+
{ @@ -56,7 +56,7 @@ export default function ExportTab(Props) { }} disabled={exporting} placeholder="Leave empty to use current date" - className={cx('placeholder:opacity-50', exporting && 'opacity-50 border-opacity-50')} + className={cx('placeholder-muted', exporting && 'opacity-50 border-opacity-50')} value={downloadName ?? ''} /> diff --git a/website/src/repl/components/panel/Forms.jsx b/website/src/repl/components/panel/Forms.jsx index 11c89335..8b4e8c0f 100644 --- a/website/src/repl/components/panel/Forms.jsx +++ b/website/src/repl/components/panel/Forms.jsx @@ -1,15 +1,15 @@ import cx from '@src/cx.mjs'; -export function ButtonGroup({ value, onChange, items }) { +export function ButtonGroup({ value, onChange, items, wrap = false }) { return ( -
+
{Object.entries(items).map(([key, label], i, arr) => ( + + {!isEmbedded && ( + + )} + {!isEmbedded && ( + + learn + + )} +
+ ); +} + function PanelCloseButton() { const { isPanelOpen } = useSettings(); return ( isPanelOpen && ( ) diff --git a/website/src/repl/components/panel/PatternsTab.jsx b/website/src/repl/components/panel/PatternsTab.jsx index 4fadd9df..44b280fb 100644 --- a/website/src/repl/components/panel/PatternsTab.jsx +++ b/website/src/repl/components/panel/PatternsTab.jsx @@ -8,7 +8,7 @@ import { useViewingPatternData, userPattern, } from '../../../user_pattern_utils.mjs'; -import { useMemo } from 'react'; +import { useMemo, useRef } from 'react'; import { getMetadata } from '../../../metadata_parser.js'; import { useExamplePatterns } from '../../useExamplePatterns.jsx'; import { parseJSON, isUdels } from '../../util.mjs'; @@ -43,7 +43,7 @@ function PatternButton({ showOutline, onClick, pattern, showHiglight }) { className={cx( 'mr-4 hover:opacity-50 cursor-pointer block', showOutline && 'outline outline-1', - showHiglight && 'bg-selection', + showHiglight && 'ring-selection', )} onClick={onClick} > @@ -53,11 +53,10 @@ function PatternButton({ showOutline, onClick, pattern, showHiglight }) { } function PatternButtons({ patterns, activePattern, onClick, started }) { - const viewingPatternStore = useViewingPatternData(); - const viewingPatternData = parseJSON(viewingPatternStore); + const viewingPatternData = useViewingPatternData(); const viewingPatternID = viewingPatternData.id; return ( -
+
{Object.values(patterns) .reverse() .map((pattern) => { @@ -83,8 +82,8 @@ const updateCodeWindow = (context, patternData, reset = false) => { export function PatternsTab({ context }) { const [search, setSearch] = useState(''); const activePattern = useActivePattern(); - const viewingPatternStore = useViewingPatternData(); - const viewingPatternData = parseJSON(viewingPatternStore); + const viewingPatternData = useViewingPatternData(); + const { userPatterns, patternAutoStart } = useSettings(); const viewingPatternID = viewingPatternData?.id; @@ -121,74 +120,71 @@ export function PatternsTab({ context }) { ); }), ); - }, [search, viewingPatternStore]); + }, [search, userPatterns]); + const importRef = useRef(); return ( -
-
- +
+ +
+ { + const { data } = userPattern.createAndAddToDB(); + updateCodeWindow(context, data); + }} + /> + { + const { data } = userPattern.duplicate(viewingPatternData); + updateCodeWindow(context, data); + }} + /> + { + const { data } = userPattern.delete(viewingPatternID); + updateCodeWindow(context, { ...data, collection: userPattern.collection }); + }} + /> + importPatterns(e.target.files)} + /> + importRef.current.click()} /> + + + { + const { data } = userPattern.clearAll(); + updateCodeWindow(context, data); + }} + />
-
-
- { - const { data } = userPattern.createAndAddToDB(); - updateCodeWindow(context, data); - }} - /> - { - const { data } = userPattern.duplicate(viewingPatternData); - updateCodeWindow(context, data); - }} - /> - { - const { data } = userPattern.delete(viewingPatternID); - updateCodeWindow(context, { ...data, collection: userPattern.collection }); - }} - /> - - - { - const { data } = userPattern.clearAll(); - updateCodeWindow(context, data); - }} - /> -
+
+ {/* bg-background */} + {/* {patternFilter === patternFilterName.user && ( */} + { + updateCodeWindow(context, { ...userPatterns[id], collection: userPattern.collection }, patternAutoStart); -
- {/* {patternFilter === patternFilterName.user && ( */} - { - updateCodeWindow(context, { ...userPatterns[id], collection: userPattern.collection }, patternAutoStart); - - if (context.started && activePattern === id) { - context.handleEvaluate(); - } - }} - patterns={visiblePatterns} - started={context.started} - activePattern={activePattern} - viewingPatternID={viewingPatternID} - /> - {/* )} */} -
+ if (context.started && activePattern === id) { + context.handleEvaluate(); + } + }} + patterns={visiblePatterns} + started={context.started} + activePattern={activePattern} + viewingPatternID={viewingPatternID} + /> + {/* )} */}
); diff --git a/website/src/repl/components/panel/Reference.jsx b/website/src/repl/components/panel/Reference.jsx index 9c98cbad..fcd6151b 100644 --- a/website/src/repl/components/panel/Reference.jsx +++ b/website/src/repl/components/panel/Reference.jsx @@ -2,6 +2,7 @@ import { memo, useEffect, useMemo, useState, Fragment } from 'react'; import jsdocJson from '../../../../../doc.json'; import { Textbox } from '@src/repl/components/panel/SettingsTab'; +import { settingsMap, useSettings } from '@src/settings.mjs'; const isValid = ({ name, description }) => name && !name.startsWith('_') && !!description; @@ -37,6 +38,19 @@ const availableFunctions = (() => { return functions.sort((a, b) => /* a.meta.filename.localeCompare(b.meta.filename) + */ a.name.localeCompare(b.name)); })(); +const tagCounts = {}; +// const tagOptions = { all: `all (${availableFunctions.length})` }; +const tagOptions = { all: `all` }; +for (const doc of availableFunctions) { + (doc.tags || ['untagged']).forEach((t) => { + if (typeof t === 'string' && t) { + tagCounts[t] = (tagCounts[t] || 0) + 1; + //tagOptions[t] = `${t} (${tagCounts[t]})`; + tagOptions[t] = t; + } + }); +} + const getInnerText = (html) => { var div = document.createElement('div'); div.innerHTML = html; @@ -45,40 +59,38 @@ const getInnerText = (html) => { export const Reference = memo(function Reference() { const [search, setSearch] = useState(''); - const [selectedTag, setSelectedTag] = useState(null); const [selectedFunction, setSelectedFunction] = useState(null); + const { referenceTag } = useSettings(); const toggleTag = (tag) => { - if (selectedTag === tag) { - setSelectedTag(null); + if (referenceTag === tag) { + setReferenceTag('all'); } else { - setSelectedTag(tag); + setReferenceTag(tag); } }; const searchVisibleFunctions = useMemo(() => { return availableFunctions.filter((entry) => { - if (selectedTag) { - if (!(entry.tags || ['untagged']).includes(selectedTag)) { + if (referenceTag && referenceTag !== 'all') { + if (!(entry.tags || ['untagged']).includes(referenceTag)) { return false; } } - if (!search) { return true; } - const lowerCaseSearch = search.toLowerCase(); return ( entry.name.toLowerCase().includes(lowerCaseSearch) || (entry.synonyms?.some((s) => s.toLowerCase().includes(lowerCaseSearch)) ?? false) ); }); - }, [search, selectedTag]); + }, [search, referenceTag]); const detailVisibleFunctions = useMemo(() => { return searchVisibleFunctions.filter((x) => { - if (selectedTag === null) { + if (referenceTag === null || referenceTag === 'all') { if (search) { return true; } @@ -87,19 +99,10 @@ export const Reference = memo(function Reference() { return true; } }); - }, [searchVisibleFunctions, selectedFunction, selectedTag]); - - const tagCounts = {}; - for (const doc of availableFunctions) { - (doc.tags || ['untagged']).forEach((t) => { - if (typeof t === 'string' && t) { - tagCounts[t] = (tagCounts[t] || 0) + 1; - } - }); - } + }, [searchVisibleFunctions, selectedFunction, referenceTag]); const onSearchTagFilterClick = () => { - setSelectedTag(null); + setReferenceTag('all'); setSelectedFunction(null); }; @@ -111,36 +114,44 @@ export const Reference = memo(function Reference() { } }, [selectedFunction]); + let setReferenceTag = (value) => settingsMap.setKey('referenceTag', value); + return ( -
-
+
+
+ {/* bg-background */}
{ setSelectedFunction(null); + setReferenceTag('all'); setSearch(e); }} />
- {selectedTag && ( + + {/*
+ +
*/} + {referenceTag && referenceTag !== 'all' && (
- {selectedTag} + {referenceTag}
)} -
-
+

API Reference

This is the long list of functions you can use. Remember that you don't need to remember all of those and that you can already make music with a small set of functions!

+ {/* */} {Object.entries(tagCounts) .sort(([a], [b]) => a.localeCompare(b)) .map(([t, count]) => ( @@ -175,7 +187,7 @@ export const Reference = memo(function Reference() { toggleTag(t)} > @@ -187,7 +199,7 @@ export const Reference = memo(function Reference() { {detailVisibleFunctions.map((entry, i) => (
-

+

{entry.name}

{entry.tags && ( @@ -201,7 +213,7 @@ export const Reference = memo(function Reference() { Synonyms: {entry.synonyms_text}

)} - {/* {entry.meta.filename} */} +

    {entry.params?.map(({ name, type, description }, i) => ( @@ -211,12 +223,12 @@ export const Reference = memo(function Reference() { ))}
{entry.examples?.map((example, j) => ( -
+                
                   {example}
                 
))}
- )) ||

Searcb or select a tag to get started.

} + )) ||

Search or select a tag to get started.

} {detailVisibleFunctions.length > 0 &&
}
diff --git a/website/src/repl/components/panel/SettingsTab.jsx b/website/src/repl/components/panel/SettingsTab.jsx index 7999f44f..d2953446 100644 --- a/website/src/repl/components/panel/SettingsTab.jsx +++ b/website/src/repl/components/panel/SettingsTab.jsx @@ -15,17 +15,17 @@ function cx(...classes) { } const inputClass = - 'bg-background text-sm border rounded-0 text-foreground border-muted placeholder-foreground focus:outline-none focus:ring-0 focus:border-foreground'; + 'bg-background text-xs h-8 max-h-8 border border-box rounded-0 text-foreground border-muted placeholder-muted focus:outline-none focus:ring-0 focus:border-foreground'; export function Textbox({ onChange, className, ...inputProps }) { return ( - onChange(e.target.value)} {...inputProps} /> + onChange(e.target.value)} {...inputProps} /> ); } function Checkbox({ label, value, onChange, disabled = false }) { return ( -