refactor(core): migrate UI framework from Svelte to SolidJS

- Replace App.svelte with App.tsx SolidJS component
- Update view layer to use SolidJS render/dispose API
- Switch plugin imports from @inkweave/plugins/svelte to solidjs
- Adapt test stubs for framework-agnostic plugin loading
- Update build config (vite, tsconfig) for SolidJS JSX
- Replace svelte deps with solid-js/vite-plugin-solid
This commit is contained in:
Uglyboy 2026-05-08 16:25:18 +08:00
parent b34f1e9826
commit ba3e5d84e0
8 changed files with 83 additions and 48 deletions

View file

@ -13,18 +13,17 @@
"author": "Uglyboy",
"license": "MIT",
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^7.0.0",
"@tsconfig/bun": "^1.0.0",
"@tsconfig/svelte": "^5.0.0",
"@types/mustache": "^4.2.0",
"esbuild": "^0.28.0",
"svelte": "^5.0.0",
"vite": "^8.0.0"
"solid-js": "^1.9.12",
"vite": "^8.0.0",
"vite-plugin-solid": "^2.11.12"
},
"dependencies": {
"@inkweave/core": "^2.0.4",
"@inkweave/plugins": "^2.0.4",
"@inkweave/svelte": "^2.0.4",
"@inkweave/core": "^2.3.1",
"@inkweave/plugins": "^2.3.1",
"@inkweave/solidjs": "^2.3.1",
"zustand": "^5.0.0",
"mustache": "^4.2.0"
},

View file

@ -1,24 +0,0 @@
<script lang="ts">
import type { InkStory } from "@inkweave/core";
import { Image } from "@inkweave/plugins/svelte";
import { CommandBar, Story } from "@inkweave/svelte";
import { t } from "./locales/i18n";
let { ink }: { ink: InkStory } = $props();
</script>
<div id="inkweave-player" class="container">
<nav class="view-header">
<div class="view-header-title-container mod-at-start mod-fade"></div>
<CommandBar
{ink}
class="view-actions"
buttonClass="clickable-icon nav-action-button"
modalClass="modal"
t={t}
/>
</nav>
<Story {ink} class="markdown-preview-view">
<Image class="inkweave-image" />
</Story>
</div>

26
src/App.tsx Normal file
View file

@ -0,0 +1,26 @@
import type { InkStory } from "@inkweave/core";
import { Image } from "@inkweave/plugins/solidjs";
import { CommandBar, Story } from "@inkweave/solidjs";
import { t } from "./locales/i18n";
const App = (props: { ink: InkStory }) => {
return (
<div id="inkweave-player" class="container">
<nav class="view-header">
<div class="view-header-title-container mod-at-start mod-fade" />
<CommandBar
ink={props.ink}
class="view-actions"
buttonClass="clickable-icon nav-action-button"
modalClass="modal"
t={t}
/>
</nav>
<Story ink={props.ink} class="markdown-preview-view">
<Image class="inkweave-image" />
</Story>
</div>
);
};
export default App;

View file

@ -1,6 +1,38 @@
import { afterAll, describe, expect, it } from "bun:test";
import type { Plugin } from "@inkweave/core";
import { PluginRegistry } from "@inkweave/core";
import { plugins } from "../plugins";
// Stub plugins matching the obsidian plugin list (no SolidJS imports needed)
const plugins: Plugin[] = [
{ id: "audio", name: "Audio", enabledByDefault: true, onLoad: () => {} },
{ id: "auto-button", name: "Auto Button", enabledByDefault: true, onLoad: () => {} },
{
id: "auto-restore",
name: "Auto Restore",
enabledByDefault: true,
onLoad: () => {},
dependencies: ["memory"],
},
{
id: "auto-save",
name: "Auto Save",
enabledByDefault: true,
onLoad: () => {},
dependencies: ["memory"],
},
{ id: "cd-button", name: "CD Button", enabledByDefault: true, onLoad: () => {} },
{ id: "class-tag", name: "Class Tag", enabledByDefault: true, onLoad: () => {} },
{ id: "fade-effect", name: "Fade Effect", enabledByDefault: true, onLoad: () => {} },
{ id: "image", name: "Image", enabledByDefault: true, onLoad: () => {} },
{ id: "link-open", name: "Link Open", enabledByDefault: true, onLoad: () => {} },
{ id: "memory", name: "Memory", enabledByDefault: true, onLoad: () => {} },
{
id: "scroll-after-choice",
name: "Scroll After Choice",
enabledByDefault: true,
onLoad: () => {},
},
];
for (const p of plugins) {
PluginRegistry.register(p);

View file

@ -11,7 +11,7 @@ import {
linkOpenPlugin,
memoryPlugin,
scrollAfterChoicePlugin,
} from "@inkweave/plugins/svelte";
} from "@inkweave/plugins/solidjs";
export const plugins: Plugin[] = [
audioPlugin,

View file

@ -1,18 +1,18 @@
import "@inkweave/svelte/svelte.css";
import "@inkweave/plugins/plugins.css";
import "@inkweave/solidjs/solidjs.css";
import "@inkweave/plugins/solidjs.css";
import "./styles/styles.custom.css";
import type { InkStory } from "@inkweave/core";
import { type EventRef, ItemView, type MarkdownView, TFile, type ViewStateResult } from "obsidian";
import { mount, unmount } from "svelte";
import App from "./App.svelte";
import { render } from "solid-js/web";
import App from "./App";
import { compile } from "./utils/compile";
import { default as useFile } from "./utils/file";
export const VIEW_TYPE = "InkWeave Story View";
export class StoryView extends ItemView {
appInstance: Record<string, unknown> | null = null;
appInstance: (() => void) | null = null;
ink: InkStory | null = null;
private watcher: EventRef | null = null;
@ -54,14 +54,13 @@ export class StoryView extends ItemView {
if (!container) return;
if (this.appInstance) {
unmount(this.appInstance);
this.appInstance();
this.appInstance = null;
}
if (this.ink) {
this.appInstance = mount(App, {
target: container as HTMLElement,
props: { ink: this.ink },
});
const ink = this.ink;
this.appInstance = render(() => App({ ink }), container as HTMLElement);
}
}
@ -117,7 +116,7 @@ export class StoryView extends ItemView {
}
this.ink?.dispose();
if (this.appInstance) {
unmount(this.appInstance);
this.appInstance();
this.appInstance = null;
}
}

View file

@ -1,8 +1,11 @@
{
"$schema": "https://www.schemastore.org/tsconfig",
"extends": ["@tsconfig/bun/tsconfig.json", "@tsconfig/svelte/tsconfig.json"],
"extends": ["@tsconfig/bun/tsconfig.json"],
"compilerOptions": {
"types": ["bun-types"]
"jsx": "preserve",
"jsxImportSource": "solid-js",
"lib": ["ESNext", "DOM"],
"types": ["bun-types", "vite/client"]
},
"include": ["src", "package.json"],
"exclude": ["dist"]

View file

@ -1,7 +1,7 @@
import { builtinModules } from "node:module";
import { resolve } from "node:path";
import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import solid from "vite-plugin-solid";
export default defineConfig(({ mode }) => ({
define: {
@ -32,5 +32,5 @@ export default defineConfig(({ mode }) => ({
cssMinify: "esbuild",
emptyOutDir: true,
},
plugins: [svelte()],
plugins: [solid()],
}));