generated from tpl/obsidian-sample-plugin
Switch to vite for building and add rating modal
This commit is contained in:
parent
db676f93f2
commit
1ecf93e5da
14
package.json
14
package.json
|
@ -4,23 +4,26 @@
|
||||||
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
|
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node esbuild.config.mjs",
|
"dev": "vite build --watch --mode=development",
|
||||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
"build": "vite build",
|
||||||
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
||||||
"svelte-check": "svelte-check --tsconfig tsconfig.json"
|
"svelte-check": "svelte-check --tsconfig tsconfig.json"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@types/node": "^16.11.6",
|
"@sveltejs/vite-plugin-svelte": "^5.1.0",
|
||||||
|
"@types/node": "^24.0.6",
|
||||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||||
"@typescript-eslint/parser": "5.29.0",
|
"@typescript-eslint/parser": "5.29.0",
|
||||||
|
"bits-ui": "^2.8.10",
|
||||||
"builtin-modules": "3.3.0",
|
"builtin-modules": "3.3.0",
|
||||||
"esbuild": "0.17.3",
|
"esbuild": "0.17.3",
|
||||||
"esbuild-svelte": "^0.9.3",
|
"esbuild-svelte": "^0.9.3",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.8",
|
||||||
|
"lucide-svelte": "^0.525.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"obsidian": "latest",
|
"obsidian": "latest",
|
||||||
"sass": "^1.89.2",
|
"sass": "^1.89.2",
|
||||||
|
@ -28,6 +31,7 @@
|
||||||
"svelte-check": "^4.2.2",
|
"svelte-check": "^4.2.2",
|
||||||
"svelte-preprocess": "^6.0.3",
|
"svelte-preprocess": "^6.0.3",
|
||||||
"tslib": "2.4.0",
|
"tslib": "2.4.0",
|
||||||
"typescript": "5.0.4"
|
"typescript": "5.0.4",
|
||||||
|
"vite": "^6.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
753
pnpm-lock.yaml
753
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -1,2 +0,0 @@
|
||||||
onlyBuiltDependencies:
|
|
||||||
- esbuild
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import RatingInput from "./RatingInput.svelte";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onSubmit: (value: number) => void;
|
||||||
|
}
|
||||||
|
let { onSubmit }: Props = $props();
|
||||||
|
|
||||||
|
let value = $state(0);
|
||||||
|
|
||||||
|
function onsubmit(ev: SubmitEvent) {
|
||||||
|
ev.preventDefault();
|
||||||
|
|
||||||
|
onSubmit(value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="obt-rating">
|
||||||
|
<h2>Rating</h2>
|
||||||
|
<form {onsubmit}>
|
||||||
|
<div class="value-field">
|
||||||
|
<label for="value">Rating</label>
|
||||||
|
<RatingInput bind:value />
|
||||||
|
</div>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.obt-rating {
|
||||||
|
padding-bottom: var(--size-4-4);
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--size-4-4);
|
||||||
|
|
||||||
|
.value-field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,62 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { unstable_RatingGroup as RatingGroup } from "bits-ui";
|
||||||
|
import { Star, StarHalf } from "lucide-svelte";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value?: number;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { value = $bindable(), name }: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="rating-input">
|
||||||
|
<RatingGroup.Root
|
||||||
|
{name}
|
||||||
|
bind:value
|
||||||
|
min={0}
|
||||||
|
max={5}
|
||||||
|
allowHalf
|
||||||
|
class="rating-group"
|
||||||
|
>
|
||||||
|
{#snippet children({ items })}
|
||||||
|
{#each items as item (item.index)}
|
||||||
|
<RatingGroup.Item index={item.index} class="rating-item">
|
||||||
|
{#if item.state === "inactive"}
|
||||||
|
<Star fill="var(--interactive-normal)" />
|
||||||
|
{:else if item.state === "active"}
|
||||||
|
<Star fill="var(--interactive-accent)" />
|
||||||
|
{:else if item.state === "partial"}
|
||||||
|
<Star fill="var(--interactive-normal)" />
|
||||||
|
<StarHalf fill="var(--interactive-accent)" />
|
||||||
|
{/if}
|
||||||
|
</RatingGroup.Item>
|
||||||
|
{/each}
|
||||||
|
{/snippet}
|
||||||
|
</RatingGroup.Root>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.rating-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
:global(svg) {
|
||||||
|
position: absolute;
|
||||||
|
width: var(--size-4-16);
|
||||||
|
height: var(--size-4-16);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.rating-group) {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.rating-item) {
|
||||||
|
position: relative;
|
||||||
|
width: var(--size-4-16);
|
||||||
|
height: var(--size-4-16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,5 +1,9 @@
|
||||||
import { requestUrl } from "obsidian";
|
import { requestUrl } from "obsidian";
|
||||||
import { Author, Book as OutputBook, Series as OutputSeries } from "../types";
|
import type {
|
||||||
|
Author,
|
||||||
|
Book as OutputBook,
|
||||||
|
Series as OutputSeries,
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
interface Ref {
|
interface Ref {
|
||||||
__ref: string;
|
__ref: string;
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
} from "./const";
|
} from "./const";
|
||||||
import { ReadingLog, Storage } from "@utils/storage";
|
import { ReadingLog, Storage } from "@utils/storage";
|
||||||
import { ReadingProgressModal } from "@views/reading-progress-modal";
|
import { ReadingProgressModal } from "@views/reading-progress-modal";
|
||||||
|
import { RatingModal } from "@views/rating-modal";
|
||||||
|
|
||||||
export default class BookTrackerPlugin extends Plugin {
|
export default class BookTrackerPlugin extends Plugin {
|
||||||
settings: BookTrackerPluginSettings;
|
settings: BookTrackerPluginSettings;
|
||||||
|
@ -279,6 +280,11 @@ export default class BookTrackerPlugin extends Plugin {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.settings.ratingProperty) {
|
||||||
|
new Notice("Rating property is not set in settings.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const pageLength =
|
const pageLength =
|
||||||
(this.app.metadataCache.getFileCache(activeFile)?.frontmatter?.[
|
(this.app.metadataCache.getFileCache(activeFile)?.frontmatter?.[
|
||||||
this.settings.pageLengthProperty
|
this.settings.pageLengthProperty
|
||||||
|
@ -291,6 +297,8 @@ export default class BookTrackerPlugin extends Plugin {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const rating = await RatingModal.createAndOpen(this.app);
|
||||||
|
|
||||||
await this.readingLog.addEntry(activeFile.basename, pageLength);
|
await this.readingLog.addEntry(activeFile.basename, pageLength);
|
||||||
|
|
||||||
// @ts-expect-error Moment is provided by Obsidian
|
// @ts-expect-error Moment is provided by Obsidian
|
||||||
|
@ -299,6 +307,7 @@ export default class BookTrackerPlugin extends Plugin {
|
||||||
this.app.fileManager.processFrontMatter(activeFile, (frontMatter) => {
|
this.app.fileManager.processFrontMatter(activeFile, (frontMatter) => {
|
||||||
frontMatter[this.settings.statusProperty] = READ_STATE;
|
frontMatter[this.settings.statusProperty] = READ_STATE;
|
||||||
frontMatter[this.settings.endDateProperty] = endDate;
|
frontMatter[this.settings.endDateProperty] = endDate;
|
||||||
|
frontMatter[this.settings.ratingProperty] = rating;
|
||||||
});
|
});
|
||||||
|
|
||||||
new Notice("Reading finished for " + activeFile.name);
|
new Notice("Reading finished for " + activeFile.name);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
|
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
|
||||||
|
|
||||||
import { App, ISuggestOwner, Scope } from "obsidian";
|
import { App, type ISuggestOwner, Scope } from "obsidian";
|
||||||
import { createPopper, Instance as PopperInstance } from "@popperjs/core";
|
import { createPopper, type Instance as PopperInstance } from "@popperjs/core";
|
||||||
|
|
||||||
const wrapAround = (value: number, size: number): number => {
|
const wrapAround = (value: number, size: number): number => {
|
||||||
return ((value % size) + size) % size;
|
return ((value % size) + size) % size;
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import Rating from "@components/Rating.svelte";
|
||||||
|
import { App, Modal } from "obsidian";
|
||||||
|
import { mount, unmount } from "svelte";
|
||||||
|
|
||||||
|
export class RatingModal extends Modal {
|
||||||
|
private component: ReturnType<typeof Rating> | undefined;
|
||||||
|
|
||||||
|
constructor(app: App, private readonly onSubmit: (rating: number) => void) {
|
||||||
|
super(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpen(): void {
|
||||||
|
this.component = mount(Rating, {
|
||||||
|
target: this.contentEl,
|
||||||
|
props: {
|
||||||
|
onSubmit: (rating) => {
|
||||||
|
this.onSubmit(rating);
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose(): void {
|
||||||
|
if (this.component) {
|
||||||
|
unmount(this.component);
|
||||||
|
this.component = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static createAndOpen(app: App): Promise<number> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const modal = new RatingModal(app, (rating) => {
|
||||||
|
resolve(rating);
|
||||||
|
});
|
||||||
|
modal.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1 @@
|
||||||
.obt-settings .search-input-container {
|
.obt-goodreads-search.svelte-11kqgr4{padding-bottom:var(--size-4-4)}.obt-goodreads-search.svelte-11kqgr4 input:where(.svelte-11kqgr4){width:100%}.obt-goodreads-search-suggestion.svelte-1kq4sbn{display:flex;align-items:center}.obt-goodreads-search-suggestion.svelte-1kq4sbn img.cover:where(.svelte-1kq4sbn){max-width:100px;max-height:100px;margin-right:var(--size-4-2);object-fit:cover;border-radius:var(--radius-s)}.obt-goodreads-search-suggestion.svelte-1kq4sbn .details:where(.svelte-1kq4sbn){flex-grow:1}.obt-goodreads-search-suggestion.svelte-1kq4sbn .details:where(.svelte-1kq4sbn) .title:where(.svelte-1kq4sbn){color:var(--text-normal);font-size:var(--font-ui-medium)}.obt-goodreads-search-suggestion.svelte-1kq4sbn .details:where(.svelte-1kq4sbn) .extra-details:where(.svelte-1kq4sbn){color:var(--text-muted);font-size:var(--font-ui-small);display:flex;gap:var(--size-4-1)}.obt-reading-progress.svelte-paogvq{padding-bottom:var(--size-4-4)}.obt-reading-progress.svelte-paogvq h2:where(.svelte-paogvq){margin-bottom:var(--size-4-6)}.obt-reading-progress.svelte-paogvq form:where(.svelte-paogvq){display:flex;flex-direction:column;gap:var(--size-4-4)}.obt-reading-progress.svelte-paogvq form:where(.svelte-paogvq) .value-field:where(.svelte-paogvq){display:flex;flex-direction:column;align-items:stretch;gap:var(--size-4-2);width:100%}.obt-reading-progress.svelte-paogvq form:where(.svelte-paogvq) .mode-field:where(.svelte-paogvq){width:100%;display:grid;grid-template-columns:1fr 1fr}.obt-reading-progress.svelte-paogvq form:where(.svelte-paogvq) .mode-field:where(.svelte-paogvq) .mode-field-option:where(.svelte-paogvq){text-align:center;padding:var(--size-4-2);background-color:var(--interactive-normal);border:var(--border-width) solid var(--background-modifier-border);border-radius:var(--radius-m)}.obt-reading-progress.svelte-paogvq form:where(.svelte-paogvq) .mode-field:where(.svelte-paogvq) .mode-field-option:where(.svelte-paogvq):has(input:where(.svelte-paogvq):checked){background-color:var(--interactive-accent)}.obt-reading-progress.svelte-paogvq form:where(.svelte-paogvq) .mode-field:where(.svelte-paogvq) .mode-field-option:where(.svelte-paogvq):hover{background-color:var(--interactive-hover)}.obt-reading-progress.svelte-paogvq form:where(.svelte-paogvq) .mode-field:where(.svelte-paogvq) .mode-field-option:where(.svelte-paogvq) input:where(.svelte-paogvq){display:none}.obt-reading-progress.svelte-paogvq form:where(.svelte-paogvq) .mode-field:where(.svelte-paogvq) .mode-field-option:where(.svelte-paogvq).page-number{border-top-right-radius:0;border-bottom-right-radius:0}.obt-reading-progress.svelte-paogvq form:where(.svelte-paogvq) .mode-field:where(.svelte-paogvq) .mode-field-option:where(.svelte-paogvq).percentage{border-top-left-radius:0;border-bottom-left-radius:0}.rating-input.svelte-19sa8ca{display:flex;align-items:center;gap:.5rem}.rating-input.svelte-19sa8ca svg{position:absolute;width:var(--size-4-16);height:var(--size-4-16)}.rating-input.svelte-19sa8ca .rating-group{display:flex;gap:.25rem}.rating-input.svelte-19sa8ca .rating-item{position:relative;width:var(--size-4-16);height:var(--size-4-16)}.obt-rating.svelte-badw3i{padding-bottom:var(--size-4-4)}.obt-rating.svelte-badw3i h2:where(.svelte-badw3i){text-align:center}.obt-rating.svelte-badw3i form:where(.svelte-badw3i){display:flex;flex-direction:column;gap:var(--size-4-4)}.obt-rating.svelte-badw3i form:where(.svelte-badw3i) .value-field:where(.svelte-badw3i){display:flex;flex-direction:column;align-items:center}.obt-rating.svelte-badw3i form:where(.svelte-badw3i) .value-field:where(.svelte-badw3i) label:where(.svelte-badw3i){display:none}.obt-rating.svelte-badw3i form:where(.svelte-badw3i) button:where(.svelte-badw3i){align-self:stretch}
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { UserConfig, defineConfig } from "vite";
|
||||||
|
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||||
|
import path from "path";
|
||||||
|
import builtins from "builtin-modules";
|
||||||
|
|
||||||
|
export default defineConfig(async ({ mode }) => {
|
||||||
|
const { resolve } = path;
|
||||||
|
const prod = mode === "production";
|
||||||
|
|
||||||
|
return {
|
||||||
|
plugins: [svelte()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@components": path.resolve(__dirname, "./src/components"),
|
||||||
|
"@data-sources": path.resolve(__dirname, "./src/data-sources"),
|
||||||
|
"@settings": path.resolve(__dirname, "./src/settings"),
|
||||||
|
"@utils": path.resolve(__dirname, "./src/utils"),
|
||||||
|
"@views": path.resolve(__dirname, "./src/views"),
|
||||||
|
"@src": path.resolve(__dirname, "./src"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: resolve(__dirname, "src/main.ts"),
|
||||||
|
name: "main",
|
||||||
|
fileName: () => "main.js",
|
||||||
|
formats: ["cjs"],
|
||||||
|
},
|
||||||
|
minify: prod,
|
||||||
|
sourcemap: prod ? false : "inline",
|
||||||
|
cssCodeSplit: false,
|
||||||
|
emptyOutDir: false,
|
||||||
|
outDir: "",
|
||||||
|
rollupOptions: {
|
||||||
|
input: {
|
||||||
|
main: resolve(__dirname, "src/main.ts"),
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
entryFileNames: "main.js",
|
||||||
|
assetFileNames: "styles.css",
|
||||||
|
},
|
||||||
|
external: [
|
||||||
|
"obsidian",
|
||||||
|
"electron",
|
||||||
|
"@codemirror/autocomplete",
|
||||||
|
"@codemirror/collab",
|
||||||
|
"@codemirror/commands",
|
||||||
|
"@codemirror/language",
|
||||||
|
"@codemirror/lint",
|
||||||
|
"@codemirror/search",
|
||||||
|
"@codemirror/state",
|
||||||
|
"@codemirror/view",
|
||||||
|
"@lezer/common",
|
||||||
|
"@lezer/highlight",
|
||||||
|
"@lezer/lr",
|
||||||
|
...builtins,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as UserConfig;
|
||||||
|
});
|
Loading…
Reference in New Issue