generated from tpl/obsidian-sample-plugin
Add spice field handling
This commit is contained in:
parent
20ffc78e8e
commit
113ddefac7
|
@ -302,7 +302,10 @@ export default class BookTrackerPlugin extends Plugin {
|
|||
return;
|
||||
}
|
||||
|
||||
const rating = await RatingModal.createAndOpen(this.app);
|
||||
const rating = await RatingModal.createAndOpen(
|
||||
this.app,
|
||||
this.settings.spiceProperty !== ""
|
||||
);
|
||||
|
||||
await this.readingLog.addEntry(
|
||||
activeFile.basename,
|
||||
|
@ -317,6 +320,9 @@ export default class BookTrackerPlugin extends Plugin {
|
|||
frontMatter[this.settings.statusProperty] = READ_STATE;
|
||||
frontMatter[this.settings.endDateProperty] = endDate;
|
||||
frontMatter[this.settings.ratingProperty] = rating;
|
||||
if (this.settings.spiceProperty !== "") {
|
||||
frontMatter[this.settings.spiceProperty] = rating;
|
||||
}
|
||||
});
|
||||
|
||||
new Notice("Reading finished for " + activeFile.name);
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
<script lang="ts">
|
||||
import { Star, StarHalf } from "lucide-svelte";
|
||||
import type { Snippet } from "svelte";
|
||||
|
||||
interface Props {
|
||||
value?: number;
|
||||
name?: string;
|
||||
max?: number;
|
||||
half?: boolean;
|
||||
inactive?: Snippet;
|
||||
active?: Snippet;
|
||||
partial?: Snippet;
|
||||
}
|
||||
|
||||
const maxV = 5;
|
||||
|
||||
let { value = $bindable(), name }: Props = $props();
|
||||
let {
|
||||
value = $bindable(),
|
||||
name = "",
|
||||
max = 5,
|
||||
half = false,
|
||||
inactive,
|
||||
active,
|
||||
partial,
|
||||
}: Props = $props();
|
||||
|
||||
let ctrl: HTMLElement | null = $state(null);
|
||||
let w = $state(0);
|
||||
|
@ -27,7 +39,7 @@
|
|||
let displayVal = $derived(hovering ? valueHover : (value ?? 0));
|
||||
let items = $derived.by(() => {
|
||||
const full = Number.isInteger(displayVal);
|
||||
return Array.from({ length: maxV }, (_, i) => i + 1).map((index) => ({
|
||||
return Array.from({ length: max }, (_, i) => i + 1).map((index) => ({
|
||||
index,
|
||||
state:
|
||||
index <= Math.ceil(displayVal)
|
||||
|
@ -39,7 +51,7 @@
|
|||
});
|
||||
|
||||
function calcSliderPos(e: MouseEvent) {
|
||||
return (e.offsetX / (e.target as HTMLElement).clientWidth) * maxV;
|
||||
return (e.offsetX / (e.target as HTMLElement).clientWidth) * max;
|
||||
}
|
||||
|
||||
function onclick() {
|
||||
|
@ -53,7 +65,14 @@
|
|||
|
||||
function onmousemove(e: MouseEvent) {
|
||||
hovering = true;
|
||||
valueHover = Math.ceil(calcSliderPos(e) * 2) / 2;
|
||||
|
||||
const newValue = calcSliderPos(e);
|
||||
|
||||
if (half) {
|
||||
valueHover = Math.ceil(newValue * 2) / 2;
|
||||
} else {
|
||||
valueHover = Math.ceil(newValue);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -62,18 +81,37 @@
|
|||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
||||
<div class="rating-input" {onclick} {onmouseout}>
|
||||
<input type="number" {name} bind:value />
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div class="ctrl" {onmousemove} bind:this={ctrl}></div>
|
||||
<div class="cont m-1" bind:clientWidth={w} bind:clientHeight={h}>
|
||||
{#each items as item (item.index)}
|
||||
<div class="rating-item">
|
||||
{#if item.state === "inactive"}
|
||||
<Star fill="var(--interactive-normal)" />
|
||||
{#if inactive}
|
||||
{@render inactive()}
|
||||
{:else}
|
||||
<Star color="var(--background-modifier-border)" />
|
||||
{/if}
|
||||
{:else if item.state === "active"}
|
||||
<Star fill="var(--interactive-accent)" />
|
||||
{#if active}
|
||||
{@render active()}
|
||||
{:else}
|
||||
<Star
|
||||
color="var(--color-yellow)"
|
||||
fill="rgba(var(--color-yellow-rgb), 0.2)"
|
||||
/>
|
||||
{/if}
|
||||
{:else if item.state === "partial"}
|
||||
<Star fill="var(--interactive-normal)" />
|
||||
<StarHalf fill="var(--interactive-accent)" />
|
||||
{#if partial}
|
||||
{@render partial()}
|
||||
{:else}
|
||||
<Star color="var(--background-modifier-border)" />
|
||||
<StarHalf
|
||||
color="var(--color-yellow)"
|
||||
fill="rgba(var(--color-yellow-rgb), 0.2)"
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
@ -84,6 +122,10 @@
|
|||
.rating-input {
|
||||
cursor: pointer;
|
||||
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ctrl {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
|
|
@ -3,16 +3,27 @@ import { App } from "obsidian";
|
|||
import { SvelteModal } from "./SvelteModal";
|
||||
|
||||
export class RatingModal extends SvelteModal<typeof RatingModalView> {
|
||||
constructor(app: App, onSubmit: (rating: number) => void = () => {}) {
|
||||
super(app, RatingModalView, { props: { onSubmit } });
|
||||
constructor(
|
||||
app: App,
|
||||
spiceConfigured: boolean,
|
||||
onSubmit: (rating: number, spice: number) => void = () => {}
|
||||
) {
|
||||
super(app, RatingModalView, { props: { spiceConfigured, onSubmit } });
|
||||
}
|
||||
|
||||
static createAndOpen(app: App): Promise<number> {
|
||||
static createAndOpen(
|
||||
app: App,
|
||||
spiceConfigured: boolean
|
||||
): Promise<{ rating: number; spice: number }> {
|
||||
return new Promise((resolve) => {
|
||||
const modal = new RatingModal(app, (rating) => {
|
||||
const modal = new RatingModal(
|
||||
app,
|
||||
spiceConfigured,
|
||||
(rating, spice) => {
|
||||
modal.close();
|
||||
resolve(rating);
|
||||
});
|
||||
resolve({ rating, spice });
|
||||
}
|
||||
);
|
||||
modal.open();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,32 +1,53 @@
|
|||
<script lang="ts">
|
||||
import RatingInput from "@ui/components/RatingInput.svelte";
|
||||
import { Flame } from "lucide-svelte";
|
||||
|
||||
interface Props {
|
||||
onSubmit: (value: number) => void;
|
||||
spiceConfigured?: boolean;
|
||||
onSubmit: (rating: number, spice: number) => void;
|
||||
}
|
||||
let { onSubmit }: Props = $props();
|
||||
let { spiceConfigured = false, onSubmit }: Props = $props();
|
||||
|
||||
let value = $state(0);
|
||||
let rating = $state(0);
|
||||
let spice = $state(0);
|
||||
|
||||
function onsubmit(ev: SubmitEvent) {
|
||||
ev.preventDefault();
|
||||
|
||||
onSubmit(value);
|
||||
onSubmit(rating, spice);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="obt-rating">
|
||||
<h2>Rating</h2>
|
||||
<form {onsubmit}>
|
||||
<div class="value-field">
|
||||
<label for="value">Rating</label>
|
||||
<RatingInput bind:value />
|
||||
<div class="field">
|
||||
<label for="rating">Rating</label>
|
||||
<RatingInput name="rating" half bind:value={rating} />
|
||||
</div>
|
||||
{#if spiceConfigured}
|
||||
<div class="field">
|
||||
<label for="spice">Spice</label>
|
||||
<RatingInput name="spice" bind:value={spice}>
|
||||
{#snippet inactive()}
|
||||
<Flame color="var(--background-modifier-border)" />
|
||||
{/snippet}
|
||||
{#snippet active()}
|
||||
<Flame
|
||||
color="var(--color-red)"
|
||||
fill="rgba(var(--color-red-rgb), 0.2)"
|
||||
/>
|
||||
{/snippet}
|
||||
</RatingInput>
|
||||
</div>
|
||||
{/if}
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@use "../styles/utils";
|
||||
|
||||
.obt-rating {
|
||||
padding-bottom: var(--size-4-4);
|
||||
|
||||
|
@ -39,13 +60,13 @@
|
|||
flex-direction: column;
|
||||
gap: var(--size-4-4);
|
||||
|
||||
.value-field {
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
label {
|
||||
display: none;
|
||||
@include utils.visually-hidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import type BookTrackerPlugin from "@src/main";
|
||||
import { createSettingsStore } from "./store";
|
||||
import { onMount } from "svelte";
|
||||
import FieldSuggest from "@ui/components/suggesters/FieldSuggest.svelte";
|
||||
|
||||
type Props = {
|
||||
plugin: BookTrackerPlugin;
|
||||
|
@ -121,6 +122,15 @@
|
|||
bind:value={$settings.ratingProperty}
|
||||
accepts={["number"]}
|
||||
/>
|
||||
<FieldSuggestItem
|
||||
{app}
|
||||
id="spice-field"
|
||||
name="Spice Field"
|
||||
description={`Select the field to use for spice rating.
|
||||
Set to empty to disable.`}
|
||||
bind:value={$settings.spiceProperty}
|
||||
accepts={["number"]}
|
||||
/>
|
||||
<FieldSuggestItem
|
||||
{app}
|
||||
id="page-count-field"
|
||||
|
|
|
@ -12,6 +12,7 @@ export interface BookTrackerSettings {
|
|||
startDateProperty: string;
|
||||
endDateProperty: string;
|
||||
ratingProperty: string;
|
||||
spiceProperty: string;
|
||||
pageCountProperty: string;
|
||||
}
|
||||
|
||||
|
@ -29,5 +30,6 @@ export const DEFAULT_SETTINGS: BookTrackerSettings = {
|
|||
startDateProperty: "startDate",
|
||||
endDateProperty: "endDate",
|
||||
ratingProperty: "rating",
|
||||
spiceProperty: "",
|
||||
pageCountProperty: "pageCount",
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue