Skip to content

Commit ea74167

Browse files
committed
Fixed:
- Adapted to the new Obsidian style. Improved: - Smoothness dramatically improved thanks to Svelte 5
1 parent dab545a commit ea74167

17 files changed

+2935
-3572
lines changed

.eslintrc

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
11
{
2-
"root": true,
3-
"parser": "@typescript-eslint/parser",
4-
"plugins": [
5-
"@typescript-eslint"
6-
],
7-
"extends": [
8-
"eslint:recommended",
9-
"plugin:@typescript-eslint/eslint-recommended",
10-
"plugin:@typescript-eslint/recommended"
11-
],
12-
"parserOptions": {
13-
"sourceType": "module"
14-
},
15-
"rules": {
16-
"no-unused-vars": "off",
17-
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
18-
"@typescript-eslint/ban-ts-comment": "off",
19-
"no-prototype-builtins": "off",
20-
"@typescript-eslint/no-empty-function": "off"
21-
}
22-
}
2+
"root": true,
3+
"parser": "@typescript-eslint/parser",
4+
"plugins": ["@typescript-eslint"],
5+
"extends": [
6+
"eslint:recommended",
7+
"plugin:@typescript-eslint/eslint-recommended",
8+
"plugin:@typescript-eslint/recommended"
9+
],
10+
"parserOptions": {
11+
"sourceType": "module",
12+
"project": ["tsconfig.json"]
13+
},
14+
"ignorePatterns": [
15+
"**/node_modules/*",
16+
"**/jest.config.js",
17+
"src/lib/coverage",
18+
"src/lib/browsertest",
19+
"**/test.ts",
20+
"**/tests.ts",
21+
"**/**test.ts",
22+
"**/**.test.ts",
23+
"esbuild.*.mjs",
24+
"terser.*.mjs",
25+
"svelte.config.js"
26+
],
27+
"rules": {
28+
"no-unused-vars": "off",
29+
"no-unused-labels": "off",
30+
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
31+
"@typescript-eslint/ban-ts-comment": "off",
32+
"no-prototype-builtins": "off",
33+
"@typescript-eslint/no-empty-function": "off",
34+
"require-await": "warn",
35+
"@typescript-eslint/require-await": "warn",
36+
"@typescript-eslint/no-misused-promises": "warn",
37+
"@typescript-eslint/no-floating-promises": "warn",
38+
"no-async-promise-executor": "warn",
39+
"@typescript-eslint/no-explicit-any": "off",
40+
"@typescript-eslint/no-unnecessary-type-assertion": "error",
41+
"no-constant-condition": [
42+
"error",
43+
{
44+
"checkLoops": false
45+
}
46+
]
47+
}
48+
}

OnDemandRender.svelte

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,58 @@
11
<script lang="ts">
2-
import { performHide } from "store";
3-
import { getContext, onDestroy, onMount } from "svelte";
4-
export let cssClass = "";
5-
export let isVisible = false;
6-
let hidingScheduled = false;
2+
import { performHide } from "store";
3+
import { getContext, onDestroy, onMount } from "svelte";
4+
interface Props {
5+
cssClass?: string;
6+
isVisible?: boolean;
7+
children?: import('svelte').Snippet<[any]>;
8+
}
79
8-
const { observe, unobserve } = getContext("observer") as {
9-
observe: (el: Element, callback: (visibility: boolean) => void) => void;
10-
unobserve: (el: Element) => void;
11-
};
12-
function setIsVisible(visibility: boolean) {
13-
if (isVisible != visibility) {
14-
if (visibility) {
15-
isVisible = visibility;
16-
}
17-
}
18-
hidingScheduled = !visibility;
19-
}
10+
let { cssClass = "", isVisible = $bindable(false), children }: Props = $props();
11+
let hidingScheduled = $state(false);
2012
21-
onMount(() => {
22-
performHide.subscribe(() => {
23-
if (hidingScheduled) {
24-
isVisible = false;
25-
hidingScheduled = false;
26-
}
27-
});
28-
});
29-
onDestroy(() => {
30-
if (_el) {
31-
unobserve(_el);
32-
}
33-
});
13+
const { observe, unobserve } = getContext("observer") as {
14+
observe: (el: Element, callback: (visibility: boolean) => void) => void;
15+
unobserve: (el: Element) => void;
16+
};
17+
function setIsVisible(visibility: boolean) {
18+
if (isVisible != visibility) {
19+
if (visibility) {
20+
isVisible = visibility;
21+
}
22+
}
23+
hidingScheduled = !visibility;
24+
}
3425
35-
let _el: HTMLDivElement;
36-
let el: HTMLDivElement;
26+
onMount(() => {
27+
performHide.subscribe(() => {
28+
if (hidingScheduled) {
29+
isVisible = false;
30+
hidingScheduled = false;
31+
}
32+
});
33+
});
34+
onDestroy(() => {
35+
if (_el) {
36+
unobserve(_el);
37+
}
38+
});
3739
38-
$: {
39-
if (_el != el) {
40-
if (_el) {
41-
unobserve(_el);
42-
}
43-
_el = el;
44-
if (el) {
45-
observe(el, setIsVisible);
46-
}
47-
}
48-
}
40+
let _el = $state<HTMLDivElement>();
41+
let el = $state<HTMLDivElement>();
42+
43+
$effect(() => {
44+
if (_el != el) {
45+
if (_el) {
46+
unobserve(_el);
47+
}
48+
_el = el;
49+
if (el) {
50+
observe(el, setIsVisible);
51+
}
52+
}
53+
});
4954
</script>
5055

5156
<div class={cssClass} bind:this={el}>
52-
<slot {isVisible} />
57+
{@render children?.({ isVisible, })}
5358
</div>

ScrollView.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ import {
1212
import { writable, type Writable } from "svelte/store";
1313
import TagFolderPlugin from "./main";
1414
import { doEvents } from "./util";
15+
import { mount, unmount } from "svelte";
1516

1617
// Show notes as like scroll.
1718
export class ScrollView extends ItemView {
1819

19-
component?: ScrollViewComponent;
20+
component?: ReturnType<typeof mount>;
2021
plugin: TagFolderPlugin;
2122
icon = "sheets-in-box";
2223
store: Writable<ScrollViewState>;
@@ -97,17 +98,24 @@ export class ScrollView extends ItemView {
9798
}
9899

99100
async onOpen() {
100-
this.component = new ScrollViewComponent({
101-
target: this.contentEl,
102-
props: {
103-
store: this.store,
104-
openfile: this.plugin.focusFile,
105-
plugin: this.plugin
106-
},
107-
});
101+
const app = mount(ScrollViewComponent,
102+
{
103+
target: this.contentEl,
104+
props: {
105+
store: this.store,
106+
openfile: this.plugin.focusFile,
107+
plugin: this.plugin
108+
},
109+
});
110+
this.component = app;
111+
return await Promise.resolve();
108112
}
109113

110114
async onClose() {
111-
this.component?.$destroy();
115+
if (this.component) {
116+
unmount(this.component);
117+
this.component = undefined;
118+
}
119+
return await Promise.resolve();
112120
}
113121
}

ScrollViewComponent.svelte

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,47 +5,51 @@
55
import { renderSpecialTag, trimTrailingSlash } from "./util";
66
77
import ScrollViewMarkdown from "ScrollViewMarkdownComponent.svelte";
8-
import { onDestroy, onMount } from "svelte";
8+
import { onDestroy } from "svelte";
99
import type TagFolderPlugin from "main";
1010
11-
export let store: Writable<ScrollViewState> = writable<ScrollViewState>({
12-
files: [],
13-
title: "",
14-
tagPath: "",
15-
});
16-
export let openfile: (path: string, specialKey: boolean) => void;
17-
export let plugin: TagFolderPlugin;
18-
19-
let state: ScrollViewState = { files: [], title: "", tagPath: "" };
20-
$: {
21-
store.subscribe((_state) => {
22-
state = { ..._state };
23-
return () => {};
24-
});
11+
interface Props {
12+
store?: Writable<ScrollViewState>;
13+
openfile: (path: string, specialKey: boolean) => void;
14+
plugin: TagFolderPlugin;
2515
}
26-
$: files = state.files;
27-
$: tagPath = state.tagPath
28-
.split(", ")
29-
.map(
30-
(e) =>
31-
"#" +
32-
trimTrailingSlash(e)
33-
.split("/")
34-
.map((e) => renderSpecialTag(e.trim()))
35-
.join("/"),
36-
)
37-
.join(", ");
16+
17+
let {
18+
store = writable<ScrollViewState>({
19+
files: [],
20+
title: "",
21+
tagPath: "",
22+
}),
23+
openfile,
24+
plugin,
25+
}: Props = $props();
26+
27+
const _state: ScrollViewState = $derived($store);
28+
let files = $derived(_state.files);
29+
const tagPath = $derived(
30+
_state.tagPath
31+
.split(", ")
32+
.map(
33+
(e) =>
34+
"#" +
35+
trimTrailingSlash(e)
36+
.split("/")
37+
.map((e) => renderSpecialTag(e.trim()))
38+
.join("/"),
39+
)
40+
.join(", "),
41+
);
3842
function handleOpenFile(e: MouseEvent, file: ScrollViewFile) {
3943
openfile(file.path, false);
4044
e.preventDefault();
4145
}
4246
// Observe appearing and notify the component that you should render the content.
43-
let scrollEl: HTMLElement;
44-
let observer: IntersectionObserver;
47+
let scrollEl = $state<HTMLElement>();
48+
let observer = $state<IntersectionObserver>();
4549
const onAppearing = new CustomEvent("appearing", {
4650
detail: {},
4751
});
48-
onMount(() => {
52+
$effect(() => {
4953
const options = {
5054
root: scrollEl,
5155
rootMargin: "10px",
@@ -63,7 +67,7 @@
6367
);
6468
});
6569
onDestroy(() => {
66-
observer.disconnect();
70+
observer?.disconnect();
6771
});
6872
</script>
6973

@@ -73,11 +77,11 @@
7377
</div>
7478
<hr />
7579
{#each files as file}
76-
<!-- svelte-ignore a11y-click-events-have-key-events -->
77-
<!-- svelte-ignore a11y-no-static-element-interactions -->
80+
<!-- svelte-ignore a11y_click_events_have_key_events -->
81+
<!-- svelte-ignore a11y_no_static_element_interactions -->
7882
<div
7983
class="file"
80-
on:click={(evt) => handleOpenFile(evt, file)}
84+
onclick={(evt) => handleOpenFile(evt, file)}
8185
bind:this={scrollEl}
8286
>
8387
<div class="header">

ScrollViewMarkdownComponent.svelte

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
import { onDestroy, onMount } from "svelte";
66
import { type ScrollViewFile } from "types";
77
8-
export let file: ScrollViewFile = { path: "" };
9-
export let observer: IntersectionObserver;
10-
export let plugin: TagFolderPlugin;
8+
interface Props {
9+
file?: ScrollViewFile;
10+
observer?: IntersectionObserver;
11+
plugin: TagFolderPlugin;
12+
}
13+
14+
let { file = { path: "" }, observer, plugin }: Props = $props();
1115
12-
let el: HTMLElement;
13-
let renderedContent = "";
16+
let el = $state<HTMLElement>();
17+
let renderedContent = $state("");
1418
1519
function onAppearing(this: HTMLElement, _: Event) {
1620
if (file.content && el && renderedContent != file.content) {
@@ -26,15 +30,19 @@
2630
}
2731
2832
onMount(() => {
29-
observer.observe(el);
30-
el.addEventListener("appearing", onAppearing);
33+
if (el && observer) {
34+
observer.observe(el);
35+
el.addEventListener("appearing", onAppearing);
36+
}
3137
});
3238
onDestroy(() => {
33-
observer.unobserve(el);
34-
el.removeEventListener("appearing", onAppearing);
39+
if (el && observer) {
40+
observer.unobserve(el);
41+
el.removeEventListener("appearing", onAppearing);
42+
}
3543
});
3644
37-
$: {
45+
$effect(() => {
3846
if (
3947
renderedContent &&
4048
file &&
@@ -54,10 +62,10 @@
5462
renderedContent = file.content;
5563
el.style.minHeight = "20px";
5664
}
57-
}
65+
});
5866
</script>
5967

60-
<div class="markdownBody" bind:this={el} style="min-height: 1em;" />
68+
<div class="markdownBody" bind:this={el} style="min-height: 1em;"></div>
6169

6270
<style>
6371
.markdownBody {

0 commit comments

Comments
 (0)