mirror of
https://github.com/dudaanton/obsidian-strudel-plugin.git
synced 2026-07-22 06:43:01 +00:00
Cleanup and build script update
This commit is contained in:
parent
0ef71cd431
commit
28652c6b31
9 changed files with 40 additions and 173 deletions
|
|
@ -5,6 +5,19 @@ source ./.env
|
|||
# Exit immediately if a command exits with a non-zero status.
|
||||
set -e
|
||||
|
||||
if [ "$1" = "prod" ]; then
|
||||
TARGET_DIR="$TARGET_VAULT_DIR"
|
||||
echo ">>> Building for PROD vault"
|
||||
else
|
||||
TARGET_DIR="$TARGET_TEST_VAULT_DIR"
|
||||
echo ">>> Building for TEST vault"
|
||||
fi
|
||||
|
||||
if [ -z "$TARGET_DIR" ]; then
|
||||
echo "Error: Target directory is not defined. Check your .env file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Define plugin source and build directories
|
||||
PLUGIN_DIR="."
|
||||
BUILD_DIR="$PLUGIN_DIR/build"
|
||||
|
|
@ -24,18 +37,19 @@ npm run build
|
|||
echo "--- Copying Plugin Files to Test Vault ---"
|
||||
|
||||
# Create target directory in test vault if it doesn't exist
|
||||
mkdir -p "$TARGET_TEST_VAULT_DIR"
|
||||
echo "Ensured target directory exists: $TARGET_TEST_VAULT_DIR"
|
||||
mkdir -p "$TARGET_DIR"
|
||||
echo "Ensured target directory exists: $TARGET_DIR"
|
||||
|
||||
# Copy built files
|
||||
cp "$BUILD_DIR/main.js" "$TARGET_TEST_VAULT_DIR/main.js"
|
||||
cp -X "$BUILD_DIR/main.js" "$TARGET_DIR/main.js"
|
||||
echo "Copied main.js"
|
||||
|
||||
cp "$BUILD_DIR/main.css" "$TARGET_TEST_VAULT_DIR/styles.css"
|
||||
cp -X "$BUILD_DIR/main.css" "$TARGET_DIR/styles.css"
|
||||
echo "Copied styles.css"
|
||||
|
||||
cp "$PLUGIN_DIR/manifest.json" "$TARGET_TEST_VAULT_DIR/manifest.json"
|
||||
cp -X "$PLUGIN_DIR/manifest.json" "$TARGET_DIR/manifest.json"
|
||||
echo "Copied manifest.json"
|
||||
|
||||
echo "--- Plugin Build and Copy Complete ---"
|
||||
echo "Plugin files are ready in: $TARGET_TEST_VAULT_DIR"
|
||||
echo "Plugin files are ready in: $TARGET_DIR"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Exit immediately if a command exits with a non-zero status.
|
||||
set -e
|
||||
|
||||
# Define plugin source and build directories
|
||||
PLUGIN_DIR="."
|
||||
BUILD_DIR="$PLUGIN_DIR/build"
|
||||
|
||||
echo "--- Building Strudel Obsidian Plugin ---"
|
||||
|
||||
# Install dependencies if node_modules doesn't exist
|
||||
if [ ! -d "node_modules" ]; then
|
||||
echo "Node modules not found. Installing dependencies..."
|
||||
npm install
|
||||
fi
|
||||
|
||||
# Run the build script
|
||||
echo "Running build..."
|
||||
npm run build
|
||||
|
||||
echo "--- Copying Plugin Files to Test Vault ---"
|
||||
|
||||
# Copy built files
|
||||
cp -X "$BUILD_DIR/main.js" "$TARGET_VAULT_DIR/main.js"
|
||||
echo "Copied main.js"
|
||||
|
||||
cp -X "$BUILD_DIR/main.css" "$TARGET_VAULT_DIR/styles.css"
|
||||
echo "Copied styles.css"
|
||||
|
||||
cp -X "$PLUGIN_DIR/manifest.json" "$TARGET_VAULT_DIR/manifest.json"
|
||||
echo "Copied manifest.json"
|
||||
|
||||
echo "--- Plugin Build and Copy Complete ---"
|
||||
echo "Plugin files are ready in: $TARGET_VAULT_DIR"
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Strudel REPL",
|
||||
"version": "0.0.1",
|
||||
"minAppVersion": "1.9.14",
|
||||
"description": "",
|
||||
"description": "Live-coding music environment — Strudel REPL integrated into your vault.",
|
||||
"author": "Anton Duda",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
"scripts": {
|
||||
"dev": "vite preview",
|
||||
"build": "tsc -noEmit -skipLibCheck && vite build",
|
||||
"deploy:test": "bash ./build_and_copy_plugin.sh",
|
||||
"deploy:prod": "bash ./build_and_copy_plugin.sh prod",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"keywords": [],
|
||||
|
|
|
|||
|
|
@ -8,85 +8,27 @@
|
|||
<ObsidianIcon v-if="isCurrentBlockPlaying" icon="refresh-ccw" @click="play()" />
|
||||
</div>
|
||||
<canvas v-show="isCurrentBlockPlaying" ref="canvas"></canvas>
|
||||
<!-- <div ref="editorRef"></div> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ObsidianIcon from './obsidian/Icon.vue'
|
||||
import { Strudel } from '@/entities/Strudel'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { initStrudel } from '@/strudel/init.js'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { GlobalStore } from '@/stores/GlobalStore'
|
||||
import { updateMiniLocations } from '@/editor/StrudelHighlight'
|
||||
import { MarkdownView, WorkspaceLeaf } from 'obsidian'
|
||||
import { EditorView } from '@codemirror/view'
|
||||
|
||||
const props = defineProps<{
|
||||
strudelBlock: Strudel
|
||||
}>()
|
||||
|
||||
const editorRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const { isPlaying, currentBlock } = GlobalStore.getInstance()
|
||||
|
||||
const isCurrentBlockPlaying = computed(() => {
|
||||
return isPlaying.value && currentBlock.value?.id === props.strudelBlock.id
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.strudelBlock,
|
||||
(newBlock) => {
|
||||
if (isCurrentBlockPlaying.value) {
|
||||
// GlobalStore.getInstance().repl.setCode(newBlock.code)
|
||||
// GlobalStore.getInstance().resetMiniLocations()
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
const canvas = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
//
|
||||
// const editor = new StrudelMirror({
|
||||
// defaultOutput: webaudioOutput,
|
||||
// getTime: () => getAudioContext().currentTime,
|
||||
// transpiler,
|
||||
// root: document.getElementById('editor'),
|
||||
// initialCode: funk42,
|
||||
// drawTime,
|
||||
// onDraw: (haps, time) => drawPianoroll({ haps, time, ctx: drawContext, drawTime, fold: 0 }),
|
||||
// prebake: async () => {
|
||||
// initAudioOnFirstClick(); // needed to make the browser happy (don't await this here..)
|
||||
// const loadModules = evalScope(
|
||||
// import('@strudel/core'),
|
||||
// import('@strudel/draw'),
|
||||
// import('@strudel/mini'),
|
||||
// import('@strudel/tonal'),
|
||||
// import('@strudel/webaudio'),
|
||||
// );
|
||||
// await Promise.all([loadModules, registerSynthSounds(), registerSoundfonts()]);
|
||||
// },
|
||||
// });
|
||||
//
|
||||
// document.getElementById('play').addEventListener('click', () => editor.evaluate());
|
||||
// document.getElementById('stop').addEventListener('click', () => editor.stop());
|
||||
|
||||
const test = () => {
|
||||
const activeLeaf = GlobalStore.getInstance()
|
||||
.app.workspace.getLeavesOfType('markdown')
|
||||
.find(
|
||||
(leaf: WorkspaceLeaf) =>
|
||||
(leaf.view as MarkdownView).file?.path === props.strudelBlock.filePath
|
||||
)
|
||||
|
||||
const view = activeLeaf?.view as MarkdownView
|
||||
|
||||
if (activeLeaf && view.editor) {
|
||||
// updateMiniLocations((view.editor as any).cm as EditorView, [])
|
||||
}
|
||||
}
|
||||
|
||||
const play = () => {
|
||||
GlobalStore.getInstance().play(props.strudelBlock)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ const miniLocations = StateField.define<DecorationSet>({
|
|||
locations = locations.map(tr.changes)
|
||||
}
|
||||
|
||||
// console.log('miniLocations update', tr.effects)
|
||||
|
||||
for (const e of tr.effects) {
|
||||
if (e.is(setMiniLocations)) {
|
||||
// this is called on eval, with the mini locations obtained from the transpiler
|
||||
|
|
@ -71,14 +69,11 @@ const visibleMiniLocations = StateField.define<{
|
|||
// we can NOT create new marks because the context.locations haven't changed since eval time
|
||||
// this is why we need to find a way to update the existing decorations, showing the ones that have an active range
|
||||
const haps = new Map()
|
||||
// console.log(e.value, e.value.haps)
|
||||
for (const hap of e.value.haps) {
|
||||
if (!hap.context?.locations || !hap.whole) {
|
||||
continue
|
||||
}
|
||||
for (const { start, end } of hap.context.locations) {
|
||||
// start += e.value.shift
|
||||
// end += e.value.shift
|
||||
const id = `${start}:${end}`
|
||||
if (!haps.has(id) || haps.get(id).whole.begin.lt(hap.whole.begin)) {
|
||||
haps.set(id, hap)
|
||||
|
|
@ -101,8 +96,6 @@ const miniLocationHighlights = EditorView.decorations.compute(
|
|||
const { haps } = state.field(visibleMiniLocations)
|
||||
const builder = new RangeSetBuilder<Decoration>()
|
||||
|
||||
// console.log('highlighting mini locations', haps, shift)
|
||||
|
||||
while (iterator.value) {
|
||||
const {
|
||||
from,
|
||||
|
|
@ -112,12 +105,9 @@ const miniLocationHighlights = EditorView.decorations.compute(
|
|||
},
|
||||
} = iterator
|
||||
|
||||
// console.log(haps, id)
|
||||
|
||||
if (haps.has(id)) {
|
||||
const hap = haps.get(id)
|
||||
const colorMod = hap.value?.color ? ` strudel-mark_${hap.value.color}` : ''
|
||||
// const style = hap.value?.markcss || `outline: solid 2px ${color}`
|
||||
const classStr = `strudel-mark${colorMod}`
|
||||
// Get explicit channels for color values
|
||||
/*
|
||||
|
|
@ -139,7 +129,6 @@ const miniLocationHighlights = EditorView.decorations.compute(
|
|||
from,
|
||||
to,
|
||||
Decoration.mark({
|
||||
// attributes: { style: `outline: solid 2px rgba(${channels.join(', ')})` },
|
||||
attributes: { class: classStr },
|
||||
})
|
||||
)
|
||||
|
|
@ -154,11 +143,3 @@ const miniLocationHighlights = EditorView.decorations.compute(
|
|||
|
||||
export const highlightExtension = [miniLocations, visibleMiniLocations, miniLocationHighlights]
|
||||
|
||||
// export const isPatternHighlightingEnabled = (on, config) => {
|
||||
// on &&
|
||||
// config &&
|
||||
// setTimeout(() => {
|
||||
// updateMiniLocations(config.editor, config.miniLocations)
|
||||
// }, 100)
|
||||
// return on ? Prec.highest(highlightExtension) : []
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ export class Strudel {
|
|||
public lineFrom: number
|
||||
public drawContext: CanvasRenderingContext2D | null = null
|
||||
|
||||
public lineFromWhenPlaybackStarts: number | null = null
|
||||
|
||||
constructor(data: { id: string; code: string; filePath: string; lineFrom: number }) {
|
||||
this.id = data.id
|
||||
this.code = data.code
|
||||
|
|
@ -24,12 +22,4 @@ export class Strudel {
|
|||
setDrawContext(ctx: CanvasRenderingContext2D) {
|
||||
this.drawContext = ctx
|
||||
}
|
||||
|
||||
playbackStarted() {
|
||||
this.lineFromWhenPlaybackStarts = this.lineFrom
|
||||
}
|
||||
|
||||
playbackStopped() {
|
||||
this.lineFromWhenPlaybackStarts = null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,19 +6,21 @@ interface StrudelConfigData {
|
|||
samplesToPreload: string[]
|
||||
}
|
||||
|
||||
const defaultSamples: string[] = [
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/tidal-drum-machines.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/piano.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/Dirt-Samples.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/EmuSP12.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/vcsl.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/mridangam.json',
|
||||
]
|
||||
|
||||
export class StrudelConfig {
|
||||
private static instance: StrudelConfig
|
||||
|
||||
public cacheDir: string | null = null
|
||||
public saveToCache = true
|
||||
public samplesToPreload: string[] = [
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/tidal-drum-machines.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/piano.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/Dirt-Samples.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/EmuSP12.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/vcsl.json',
|
||||
'https://raw.githubusercontent.com/felixroos/dough-samples/main/mridangam.json',
|
||||
]
|
||||
public samplesToPreload: string[] = [...defaultSamples]
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
private constructor() {}
|
||||
|
|
@ -30,12 +32,14 @@ export class StrudelConfig {
|
|||
return StrudelConfig.instance
|
||||
}
|
||||
|
||||
public applySettings(data: StrudelConfigData): void {
|
||||
this.cacheDir = data.cacheDir || null
|
||||
if (data.saveToCache !== undefined) {
|
||||
public applySettings(data?: StrudelConfigData): void {
|
||||
this.cacheDir = data?.cacheDir || null
|
||||
if (data?.saveToCache !== undefined) {
|
||||
this.saveToCache = data.saveToCache
|
||||
}
|
||||
this.samplesToPreload = data.samplesToPreload ? [...data.samplesToPreload] : []
|
||||
this.samplesToPreload = data?.samplesToPreload
|
||||
? [...data.samplesToPreload]
|
||||
: [...defaultSamples]
|
||||
}
|
||||
|
||||
public getCacheDir(): string | null {
|
||||
|
|
|
|||
|
|
@ -62,33 +62,13 @@ export class GlobalStore {
|
|||
|
||||
public drawer: any | null = null
|
||||
|
||||
// public resetMiniLocations() {
|
||||
// const editor = this.getActiveEditor()
|
||||
// if (this.currentBlock.value && editor) {
|
||||
// updateMiniLocations(this.getActiveEditor(), [])
|
||||
// }
|
||||
// }
|
||||
|
||||
// public recalculateMiniLocations() {
|
||||
// if (this.currentBlock.value) {
|
||||
// const locations = recalculateMiniLocations(this.currentBlock.value.code)
|
||||
// updateMiniLocations(this.getActiveEditor(), locations || [])
|
||||
// }
|
||||
// }
|
||||
|
||||
public async initStrudel() {
|
||||
this.repl = await init({
|
||||
afterEval: (options: any) => {
|
||||
// console.log('afterEval', options.meta?.miniLocations)
|
||||
if (options.meta?.miniLocations) {
|
||||
const locations = options.meta.miniLocations
|
||||
// for (const loc of locations) {
|
||||
// loc[0] = loc[0] + this.currentBlock.lineFrom
|
||||
// loc[1] = loc[1] + this.currentBlock.lineFrom
|
||||
// }
|
||||
const editor = this.getActiveEditor()
|
||||
if (this.currentBlock.value && editor) {
|
||||
this.currentBlock.value.playbackStarted()
|
||||
updateMiniLocations(editor, locations || [], this.currentBlock.value.lineFrom)
|
||||
}
|
||||
}
|
||||
|
|
@ -100,22 +80,12 @@ export class GlobalStore {
|
|||
},
|
||||
onToggle: (started: boolean) => {
|
||||
if (started) {
|
||||
this.currentBlock.value.playbackStarted()
|
||||
this.drawer.start(this.repl.scheduler)
|
||||
// if (this.solo) {
|
||||
// // stop other repls when this one is started
|
||||
// document.dispatchEvent(
|
||||
// new CustomEvent('start-repl', {
|
||||
// detail: this.id,
|
||||
// })
|
||||
// )
|
||||
// }
|
||||
} else {
|
||||
this.drawer.stop()
|
||||
|
||||
const editor = this.getActiveEditor()
|
||||
if (editor) {
|
||||
this.currentBlock.value?.playbackStopped()
|
||||
updateMiniLocations(editor, [], 0)
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +103,6 @@ export class GlobalStore {
|
|||
return
|
||||
}
|
||||
|
||||
// console.log(this.currentBlock.value.lineFrom)
|
||||
const currentFrame = haps.filter((hap: any) => hap.isActive(time))
|
||||
highlightMiniLocations(editor, time, currentFrame)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue