From 95ae5191ceedfdaae1f85b8e5ed34926129bb9fa Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 16 May 2024 03:36:35 +0200 Subject: [PATCH 001/164] begin "understanding voicings" --- website/src/config.ts | 1 + website/src/pages/understand/voicings.mdx | 196 ++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 website/src/pages/understand/voicings.mdx diff --git a/website/src/config.ts b/website/src/config.ts index 9dee2aac2..f85d60d81 100644 --- a/website/src/config.ts +++ b/website/src/config.ts @@ -99,6 +99,7 @@ export const SIDEBAR: Sidebar = { { text: 'Coding syntax', link: 'learn/code' }, { text: 'Pitch', link: 'understand/pitch' }, { text: 'Cycles', link: 'understand/cycles' }, + { text: 'Voicings', link: 'understand/voicings' }, { text: 'Pattern Alignment', link: 'technical-manual/alignment' }, { text: 'Strudel vs Tidal', link: 'learn/strudel-vs-tidal' }, ], diff --git a/website/src/pages/understand/voicings.mdx b/website/src/pages/understand/voicings.mdx new file mode 100644 index 000000000..a36ecd8a7 --- /dev/null +++ b/website/src/pages/understand/voicings.mdx @@ -0,0 +1,196 @@ +--- +title: Understanding Chod Voicings +layout: ../../layouts/MainLayout.astro +--- + +import { MiniRepl } from '../../docs/MiniRepl'; +import { PitchSlider } from '../../components/PitchSlider'; +import Box from '@components/Box.astro'; + +# Understanding Chords and Voicings + +Let's dig deeper into how chords and voicings work. +I'll try to keep theory jargon to a minimum, so hopefully this is approachable for anyone interested. + +## What is a chord + +Playing more than one note at a time is generally called a chord. Here's an example: + +").room(.5)`} /> + +Here's the same with midi numbers: + +").room(.5)`} /> + +Here, we have two 3-note chords played in a loop. +You could already stop here and write chords in this style, which is totally fine and gives you control over individual notes. +One downside is that it can be difficult to find good sounding chords and maybe you're yearning for a way to organize chords in some other way.. + +## Labeling Chords + +Chords are typically given different labels depending on the relationship of the notes within. +In the number example above, we have `48,51,55` and `53,57,60`. + +To analyze the relationship of those notes, they are typically compared to some `root`, which is often the lowest note. +In our case, the `roots` would be `48` (= `c3`) and `53` (= `f3`). +We can express the same chords relative to those `roots` like this: + +".add("<48 53>")).room(.5)`} /> + +Now within each chord, each number represents the distance from the root. +A distance between pitches is typically called `interval`, but let's stick to distance for now. + +Now we can see that our 2 chords are actually quite similar, as the only difference is the middle note (and the root of course). +They are part of a group of chords called `triads` which are chords with 3 notes. + +### Triads + +These 4 shapes are the most common types of `triads` you will encounter: + +| shape | label | +| ----- | ---------- | +| 0,3,6 | diminished | +| 0,3,7 | minor | +| 0,4,7 | major | +| 0,4,8 | augmented | + +Here they are in succession: + +".add("60")) +.room(.5)._pitchwheel()`} +/> + +Many types of music often only use minor and major chords, so we already have the knowledge to accompany songs. Here's one: + +\`.add(\`< +a c d f +a e a e +>\`)).room(.5)`} +/> + +These are the chords for "The house of the rising sun" by The Animals. +So far it doesn't sound too exiting but at least it's recognizable.. + +## Voicings + +A `voicing` is one of many ways a certain chord shape could be played. +The term comes from choral music, where chords can be sung in different ways by changing which voice sings which note. +For example we could add 12 to one or more notes in the chord: + +".add("48")) +.room(.5)`} +/> + +Notes that are 12 steps apart (= 1 `octave`) are considered to be equal in a harmonic sense, which is why they get the same note letter. +Here's the same example with note letterns: + +") +.room(.5)`} +/> + +This type of voicings are also called `inversions`. There are many other ways we could `voice` this minor chord: + +".add("48")) +.room(.5)`} +/> + +Here we are changing the flavour of the chord slightly by + +1. doubling notes 12 steps higher, +2. using very wide distances +3. omitting notes + +## Voice Leading + +Let's revisit "The House of the Rising Sun", this time using our newly acquired voicing techniques: + +\`.add(\`< +a c d f +a e a e +>\`)).room(.5)`} + punchcard +/> + +These voicings make the chords sound more connected and less jumpy, compared to the version without voicings. +The way chords interact is also called voice leading, reminiscent of how a choir voice would move through a sequence of chords. + +For example, try singing the top voice in the above example. Then try the same on the example without voice leading. Which one's easier? + +Naturally, there are many ways a progression of chords could be voiced and there is no clear right or wrong. + +## Chord Symbols + +Musicians playing chord-based music often rely on a so called lead sheet, which is a simplified notation of a music piece. +The chords in those lead sheets are notated with symbols that allow a piece to be notated in a very concise manner. +A common way to write the chords "The House of the Rising Sun" would be: + +``` +Am | C | D | F +Am | E | Am | E +``` + +Here, each symbol consists of the `root` of the chord and optionally an `m` to signal it's a minor chord (just the root note means it's major). +We could mirror that notation in strudel using the `pick` function: + +" + .pick({ + Am: "57,60,64", + C: "55,60,64", + D: "50,57,66", + F: "57,60,65", + E: "56,59,64", + }) + .note().room(.5)`} + punchcard +/> + +## The voicing function + +Coming up with good sounding voicings that connect well can be a difficult and time consuming process. +The `chord` and `voicing` functions can be used to automate that: + +").voicing().room(.5)`} punchcard /> + +Here we're also using chord symbols but the voicings will be automatically generated with smooth voice leading. + +## Voicing Dictionaries + +The voicing function internally uses so called `voicing dictionaries`, which can also be customized: + +") + .dict('house').anchor(66) + .voicing().room(.5)`} + punchcard +/> + +In a `voicing dictionary`, each chord symbol is assigned one or more voicings. +The `voicing` function then picks the voicing that is closest to the `anchor` (defaults to `c5`). + +The handy thing about this approach is that a `voicing dictionary` can be used to play any chord progression with automated voice leading! From 83e46037d2b0156e6270ab2f46d533e4bb61d091 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 16 May 2024 08:59:07 +0200 Subject: [PATCH 002/164] typo --- website/src/pages/understand/timbre.mdx | 12 ++++++++++++ website/src/pages/understand/voicings.mdx | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 website/src/pages/understand/timbre.mdx diff --git a/website/src/pages/understand/timbre.mdx b/website/src/pages/understand/timbre.mdx new file mode 100644 index 000000000..47a8e2994 --- /dev/null +++ b/website/src/pages/understand/timbre.mdx @@ -0,0 +1,12 @@ +--- +title: Understanding Timbre +layout: ../../layouts/MainLayout.astro +--- + +import { MiniRepl } from '../../docs/MiniRepl'; +import { PitchSlider } from '../../components/PitchSlider'; +import Box from '@components/Box.astro'; + +# Understanding Timbre + +Let's learn what timbre is! diff --git a/website/src/pages/understand/voicings.mdx b/website/src/pages/understand/voicings.mdx index a36ecd8a7..d66e075e0 100644 --- a/website/src/pages/understand/voicings.mdx +++ b/website/src/pages/understand/voicings.mdx @@ -1,5 +1,5 @@ --- -title: Understanding Chod Voicings +title: Understanding Chord Voicings layout: ../../layouts/MainLayout.astro --- From df2d28f0e596906b0b07dc863797073adb538522 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Sun, 20 Oct 2024 21:54:33 -0700 Subject: [PATCH 003/164] panel options --- website/.astro/astro/content.d.ts | 256 +++++++++++++++ website/.astro/settings.json | 3 + website/.astro/types.d.ts | 292 +----------------- website/src/repl/components/ReplEditor.jsx | 6 +- website/src/repl/components/panel/Forms.jsx | 1 + website/src/repl/components/panel/Panel.jsx | 122 +++++--- .../src/repl/components/panel/SettingsTab.jsx | 26 ++ .../src/repl/components/panel/SoundsTab.jsx | 4 +- website/src/settings.mjs | 11 +- 9 files changed, 385 insertions(+), 336 deletions(-) create mode 100644 website/.astro/astro/content.d.ts diff --git a/website/.astro/astro/content.d.ts b/website/.astro/astro/content.d.ts new file mode 100644 index 000000000..b4ac1c72d --- /dev/null +++ b/website/.astro/astro/content.d.ts @@ -0,0 +1,256 @@ +declare module 'astro:content' { + interface Render { + '.mdx': Promise<{ + Content: import('astro').MarkdownInstance<{}>['Content']; + headings: import('astro').MarkdownHeading[]; + remarkPluginFrontmatter: Record; + }>; + } +} + +declare module 'astro:content' { + interface RenderResult { + Content: import('astro/runtime/server/index.js').AstroComponentFactory; + headings: import('astro').MarkdownHeading[]; + remarkPluginFrontmatter: Record; + } + interface Render { + '.md': Promise; + } + + export interface RenderedContent { + html: string; + metadata?: { + imagePaths: Array; + [key: string]: unknown; + }; + } +} + +declare module 'astro:content' { + type Flatten = T extends { [K: string]: infer U } ? U : never; + + export type CollectionKey = keyof AnyEntryMap; + export type CollectionEntry = Flatten; + + export type ContentCollectionKey = keyof ContentEntryMap; + export type DataCollectionKey = keyof DataEntryMap; + + type AllValuesOf = T extends any ? T[keyof T] : never; + type ValidContentEntrySlug = AllValuesOf< + ContentEntryMap[C] + >['slug']; + + /** @deprecated Use `getEntry` instead. */ + export function getEntryBySlug< + C extends keyof ContentEntryMap, + E extends ValidContentEntrySlug | (string & {}), + >( + collection: C, + // Note that this has to accept a regular string too, for SSR + entrySlug: E, + ): E extends ValidContentEntrySlug + ? Promise> + : Promise | undefined>; + + /** @deprecated Use `getEntry` instead. */ + export function getDataEntryById( + collection: C, + entryId: E, + ): Promise>; + + export function getCollection>( + collection: C, + filter?: (entry: CollectionEntry) => entry is E, + ): Promise; + export function getCollection( + collection: C, + filter?: (entry: CollectionEntry) => unknown, + ): Promise[]>; + + export function getEntry< + C extends keyof ContentEntryMap, + E extends ValidContentEntrySlug | (string & {}), + >(entry: { + collection: C; + slug: E; + }): E extends ValidContentEntrySlug + ? Promise> + : Promise | undefined>; + export function getEntry< + C extends keyof DataEntryMap, + E extends keyof DataEntryMap[C] | (string & {}), + >(entry: { + collection: C; + id: E; + }): E extends keyof DataEntryMap[C] + ? Promise + : Promise | undefined>; + export function getEntry< + C extends keyof ContentEntryMap, + E extends ValidContentEntrySlug | (string & {}), + >( + collection: C, + slug: E, + ): E extends ValidContentEntrySlug + ? Promise> + : Promise | undefined>; + export function getEntry< + C extends keyof DataEntryMap, + E extends keyof DataEntryMap[C] | (string & {}), + >( + collection: C, + id: E, + ): E extends keyof DataEntryMap[C] + ? Promise + : Promise | undefined>; + + /** Resolve an array of entry references from the same collection */ + export function getEntries( + entries: { + collection: C; + slug: ValidContentEntrySlug; + }[], + ): Promise[]>; + export function getEntries( + entries: { + collection: C; + id: keyof DataEntryMap[C]; + }[], + ): Promise[]>; + + export function render( + entry: AnyEntryMap[C][string], + ): Promise; + + export function reference( + collection: C, + ): import('astro/zod').ZodEffects< + import('astro/zod').ZodString, + C extends keyof ContentEntryMap + ? { + collection: C; + slug: ValidContentEntrySlug; + } + : { + collection: C; + id: keyof DataEntryMap[C]; + } + >; + // Allow generic `string` to avoid excessive type errors in the config + // if `dev` is not running to update as you edit. + // Invalid collection names will be caught at build time. + export function reference( + collection: C, + ): import('astro/zod').ZodEffects; + + type ReturnTypeOrOriginal = T extends (...args: any[]) => infer R ? R : T; + type InferEntrySchema = import('astro/zod').infer< + ReturnTypeOrOriginal['schema']> + >; + + type ContentEntryMap = { + "blog": { +"release-0.0.2-schwindlig.mdx": { + id: "release-0.0.2-schwindlig.mdx"; + slug: "release-002-schwindlig"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.0.2.1-stuermisch.mdx": { + id: "release-0.0.2.1-stuermisch.mdx"; + slug: "release-0021-stuermisch"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.0.3-maelstrom.mdx": { + id: "release-0.0.3-maelstrom.mdx"; + slug: "release-003-maelstrom"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.0.4-gischt.mdx": { + id: "release-0.0.4-gischt.mdx"; + slug: "release-004-gischt"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.3.0-donauwelle.mdx": { + id: "release-0.3.0-donauwelle.mdx"; + slug: "release-030-donauwelle"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.4.0-brandung.mdx": { + id: "release-0.4.0-brandung.mdx"; + slug: "release-040-brandung"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.5.0-wirbel.mdx": { + id: "release-0.5.0-wirbel.mdx"; + slug: "release-050-wirbel"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.6.0-zimtschnecke.mdx": { + id: "release-0.6.0-zimtschnecke.mdx"; + slug: "release-060-zimtschnecke"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.7.0-zuckerguss.mdx": { + id: "release-0.7.0-zuckerguss.mdx"; + slug: "release-070-zuckerguss"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.8.0-himbeermuffin.mdx": { + id: "release-0.8.0-himbeermuffin.mdx"; + slug: "release-080-himbeermuffin"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-0.9.0-bananenbrot.mdx": { + id: "release-0.9.0-bananenbrot.mdx"; + slug: "release-090-bananenbrot"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"release-1.0.0-geburtstagskuchen.mdx": { + id: "release-1.0.0-geburtstagskuchen.mdx"; + slug: "release-100-geburtstagskuchen"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +"year-2.mdx": { + id: "year-2.mdx"; + slug: "year-2"; + body: string; + collection: "blog"; + data: InferEntrySchema<"blog"> +} & { render(): Render[".mdx"] }; +}; + + }; + + type DataEntryMap = { + + }; + + type AnyEntryMap = ContentEntryMap & DataEntryMap; + + export type ContentConfig = typeof import("../../src/content/config.js"); +} diff --git a/website/.astro/settings.json b/website/.astro/settings.json index bf82959bd..109959d70 100644 --- a/website/.astro/settings.json +++ b/website/.astro/settings.json @@ -1,5 +1,8 @@ { "devToolbar": { "enabled": false + }, + "_variables": { + "lastUpdateCheck": 1729351618095 } } \ No newline at end of file diff --git a/website/.astro/types.d.ts b/website/.astro/types.d.ts index f091daa1d..9a2a78c18 100644 --- a/website/.astro/types.d.ts +++ b/website/.astro/types.d.ts @@ -1,290 +1,2 @@ -declare module 'astro:content' { - interface Render { - '.mdx': Promise<{ - Content: import('astro').MarkdownInstance<{}>['Content']; - headings: import('astro').MarkdownHeading[]; - remarkPluginFrontmatter: Record; - }>; - } -} - -declare module 'astro:content' { - interface Render { - '.md': Promise<{ - Content: import('astro').MarkdownInstance<{}>['Content']; - headings: import('astro').MarkdownHeading[]; - remarkPluginFrontmatter: Record; - }>; - } -} - -declare module 'astro:content' { - export { z } from 'astro/zod'; - - type Flatten = T extends { [K: string]: infer U } ? U : never; - - export type CollectionKey = keyof AnyEntryMap; - export type CollectionEntry = Flatten; - - export type ContentCollectionKey = keyof ContentEntryMap; - export type DataCollectionKey = keyof DataEntryMap; - - // This needs to be in sync with ImageMetadata - export type ImageFunction = () => import('astro/zod').ZodObject<{ - src: import('astro/zod').ZodString; - width: import('astro/zod').ZodNumber; - height: import('astro/zod').ZodNumber; - format: import('astro/zod').ZodUnion< - [ - import('astro/zod').ZodLiteral<'png'>, - import('astro/zod').ZodLiteral<'jpg'>, - import('astro/zod').ZodLiteral<'jpeg'>, - import('astro/zod').ZodLiteral<'tiff'>, - import('astro/zod').ZodLiteral<'webp'>, - import('astro/zod').ZodLiteral<'gif'>, - import('astro/zod').ZodLiteral<'svg'>, - import('astro/zod').ZodLiteral<'avif'>, - ] - >; - }>; - - type BaseSchemaWithoutEffects = - | import('astro/zod').AnyZodObject - | import('astro/zod').ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]> - | import('astro/zod').ZodDiscriminatedUnion - | import('astro/zod').ZodIntersection; - - type BaseSchema = - | BaseSchemaWithoutEffects - | import('astro/zod').ZodEffects; - - export type SchemaContext = { image: ImageFunction }; - - type DataCollectionConfig = { - type: 'data'; - schema?: S | ((context: SchemaContext) => S); - }; - - type ContentCollectionConfig = { - type?: 'content'; - schema?: S | ((context: SchemaContext) => S); - }; - - type CollectionConfig = ContentCollectionConfig | DataCollectionConfig; - - export function defineCollection( - input: CollectionConfig - ): CollectionConfig; - - type AllValuesOf = T extends any ? T[keyof T] : never; - type ValidContentEntrySlug = AllValuesOf< - ContentEntryMap[C] - >['slug']; - - export function getEntryBySlug< - C extends keyof ContentEntryMap, - E extends ValidContentEntrySlug | (string & {}), - >( - collection: C, - // Note that this has to accept a regular string too, for SSR - entrySlug: E - ): E extends ValidContentEntrySlug - ? Promise> - : Promise | undefined>; - - export function getDataEntryById( - collection: C, - entryId: E - ): Promise>; - - export function getCollection>( - collection: C, - filter?: (entry: CollectionEntry) => entry is E - ): Promise; - export function getCollection( - collection: C, - filter?: (entry: CollectionEntry) => unknown - ): Promise[]>; - - export function getEntry< - C extends keyof ContentEntryMap, - E extends ValidContentEntrySlug | (string & {}), - >(entry: { - collection: C; - slug: E; - }): E extends ValidContentEntrySlug - ? Promise> - : Promise | undefined>; - export function getEntry< - C extends keyof DataEntryMap, - E extends keyof DataEntryMap[C] | (string & {}), - >(entry: { - collection: C; - id: E; - }): E extends keyof DataEntryMap[C] - ? Promise - : Promise | undefined>; - export function getEntry< - C extends keyof ContentEntryMap, - E extends ValidContentEntrySlug | (string & {}), - >( - collection: C, - slug: E - ): E extends ValidContentEntrySlug - ? Promise> - : Promise | undefined>; - export function getEntry< - C extends keyof DataEntryMap, - E extends keyof DataEntryMap[C] | (string & {}), - >( - collection: C, - id: E - ): E extends keyof DataEntryMap[C] - ? Promise - : Promise | undefined>; - - /** Resolve an array of entry references from the same collection */ - export function getEntries( - entries: { - collection: C; - slug: ValidContentEntrySlug; - }[] - ): Promise[]>; - export function getEntries( - entries: { - collection: C; - id: keyof DataEntryMap[C]; - }[] - ): Promise[]>; - - export function reference( - collection: C - ): import('astro/zod').ZodEffects< - import('astro/zod').ZodString, - C extends keyof ContentEntryMap - ? { - collection: C; - slug: ValidContentEntrySlug; - } - : { - collection: C; - id: keyof DataEntryMap[C]; - } - >; - // Allow generic `string` to avoid excessive type errors in the config - // if `dev` is not running to update as you edit. - // Invalid collection names will be caught at build time. - export function reference( - collection: C - ): import('astro/zod').ZodEffects; - - type ReturnTypeOrOriginal = T extends (...args: any[]) => infer R ? R : T; - type InferEntrySchema = import('astro/zod').infer< - ReturnTypeOrOriginal['schema']> - >; - - type ContentEntryMap = { - "blog": { -"release-0.0.2-schwindlig.mdx": { - id: "release-0.0.2-schwindlig.mdx"; - slug: "release-002-schwindlig"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.0.2.1-stuermisch.mdx": { - id: "release-0.0.2.1-stuermisch.mdx"; - slug: "release-0021-stuermisch"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.0.3-maelstrom.mdx": { - id: "release-0.0.3-maelstrom.mdx"; - slug: "release-003-maelstrom"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.0.4-gischt.mdx": { - id: "release-0.0.4-gischt.mdx"; - slug: "release-004-gischt"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.3.0-donauwelle.mdx": { - id: "release-0.3.0-donauwelle.mdx"; - slug: "release-030-donauwelle"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.4.0-brandung.mdx": { - id: "release-0.4.0-brandung.mdx"; - slug: "release-040-brandung"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.5.0-wirbel.mdx": { - id: "release-0.5.0-wirbel.mdx"; - slug: "release-050-wirbel"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.6.0-zimtschnecke.mdx": { - id: "release-0.6.0-zimtschnecke.mdx"; - slug: "release-060-zimtschnecke"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.7.0-zuckerguss.mdx": { - id: "release-0.7.0-zuckerguss.mdx"; - slug: "release-070-zuckerguss"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.8.0-himbeermuffin.mdx": { - id: "release-0.8.0-himbeermuffin.mdx"; - slug: "release-080-himbeermuffin"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-0.9.0-bananenbrot.mdx": { - id: "release-0.9.0-bananenbrot.mdx"; - slug: "release-090-bananenbrot"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"release-1.0.0-geburtstagskuchen.mdx": { - id: "release-1.0.0-geburtstagskuchen.mdx"; - slug: "release-100-geburtstagskuchen"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -"year-2.mdx": { - id: "year-2.mdx"; - slug: "year-2"; - body: string; - collection: "blog"; - data: InferEntrySchema<"blog"> -} & { render(): Render[".mdx"] }; -}; - - }; - - type DataEntryMap = { - - }; - - type AnyEntryMap = ContentEntryMap & DataEntryMap; - - type ContentConfig = typeof import("../src/content/config"); -} +/// +/// \ No newline at end of file diff --git a/website/src/repl/components/ReplEditor.jsx b/website/src/repl/components/ReplEditor.jsx index 5a1c2e676..c96fbbfdc 100644 --- a/website/src/repl/components/ReplEditor.jsx +++ b/website/src/repl/components/ReplEditor.jsx @@ -13,7 +13,7 @@ export default function ReplEditor(Props) { const { context } = Props; const { containerRef, editorRef, error, init, pending } = context; const settings = useSettings(); - const { panelPosition } = settings; + const { panelPosition, isZen } = settings; return (
@@ -21,10 +21,10 @@ export default function ReplEditor(Props) {
- {panelPosition === 'right' && } + {!isZen && panelPosition === 'right' && }
- {panelPosition === 'bottom' && } + {!isZen && panelPosition === 'bottom' && }
); } diff --git a/website/src/repl/components/panel/Forms.jsx b/website/src/repl/components/panel/Forms.jsx index c5b22002c..4cb73a469 100644 --- a/website/src/repl/components/panel/Forms.jsx +++ b/website/src/repl/components/panel/Forms.jsx @@ -6,6 +6,7 @@ export function ButtonGroup({ value, onChange, items }) { {Object.entries(items).map(([key, label], i, arr) => ( + )} ); } @@ -78,11 +82,27 @@ if (TAURI) { tabNames.files = 'files'; } -function PanelNav({ children, className, ...props }) { +function PanelNav({ children, className, settings, ...props }) { + const isHoverBehavior = settings.togglePanelTrigger === 'hover'; return (