Add random colors and designs to bookshelf

This commit is contained in:
Evan Fiordeliso 2025-07-05 00:05:50 -04:00
parent b5b9a3fd31
commit cfcde1dc5c
16 changed files with 270 additions and 112 deletions

View File

@ -1,3 +1,5 @@
import type { IN_PROGRESS_STATE, READ_STATE, TO_BE_READ_STATE } from "./const";
export interface Author {
name: string;
description: string;
@ -21,3 +23,9 @@ export interface Book {
isbn: string;
isbn13: string;
}
export type ToBeReadState = typeof TO_BE_READ_STATE;
export type InProgressState = typeof IN_PROGRESS_STATE;
export type ReadState = typeof READ_STATE;
export type ReadingState = ToBeReadState | InProgressState | ReadState;

View File

@ -1,131 +1,194 @@
<script lang="ts">
import { READ_STATE } from "@src/const";
import type BookTrackerPlugin from "@src/main";
import type { ReadingState } from "@src/types";
import Book from "@ui/components/bookshelf/Book.svelte";
import Bookshelf from "@ui/components/bookshelf/Bookshelf.svelte";
import BookStack from "@ui/components/bookshelf/BookStack.svelte";
import BookStackElement from "@ui/components/bookshelf/BookStackElement.svelte";
import {
createMetadata,
setMetadataContext,
} from "@ui/stores/metadata.svelte";
import {
createSettings,
setSettingsContext,
} from "@ui/stores/settings.svelte";
import { COLOR_NAMES } from "@utils/color";
import { randomElement } from "@utils/rand";
import { onDestroy } from "svelte";
interface Props {
plugin: BookTrackerPlugin;
source: string;
}
const { plugin }: Props = $props();
const settingsStore = createSettings(plugin);
setSettingsContext(settingsStore);
let stateFilter: ReadingState = $state(READ_STATE);
const metadataStore = createMetadata(plugin, stateFilter);
setMetadataContext(metadataStore);
const designs = [
"default",
"colored-spine",
"dual-top-bands",
"split-bands",
] as const;
function randomDesign() {
return randomElement(designs);
}
function randomColor() {
return randomElement(COLOR_NAMES);
}
onDestroy(() => metadataStore.destroy());
</script>
<Bookshelf>
<Book
title="Hello World"
color="purple"
width={1120}
design="colored-spine"
color={randomColor()}
design={randomDesign()}
/>
<Book
title="White Space"
width={700}
color={randomColor()}
design={randomDesign()}
/>
<Book title="White Space" width={700} design="split-bands" color="pink" />
<Book
title="The Art of Computer Programming Vol 1"
width={1156}
design="dual-top-bands"
color="cyan"
color={randomColor()}
design={randomDesign()}
/>
<Book
title="Cascading Style Sheets"
subtitle="Guide to Design"
width={560}
color={randomColor()}
design={randomDesign()}
orientation="tilted"
/>
<Book
title="HTML5"
subtitle="Welcome to the Web"
width={1350}
design="colored-spine"
color={randomColor()}
design={randomDesign()}
/>
<BookStack totalChildren={2}>
<BookStackElement
title="Coding for Dummies"
subtitle="JS tutorial"
color="blue"
design="colored-spine"
color={randomColor()}
design={randomDesign()}
/>
<BookStackElement
title="Coding for Dummies"
subtitle="C# tutorial"
color="pink"
design="dual-top-bands"
color={randomColor()}
design={randomDesign()}
/>
</BookStack>
<Book
title="CoffeeScript"
subtitle="The JS Alternative"
author="The Dev Guy"
design="split-bands"
color="green"
color={randomColor()}
design={randomDesign()}
orientation="on-display"
/>
<Book
title="Cheat Sheet"
subtitle="Guide to Design"
color="blue"
design="split-bands"
width={870}
color={randomColor()}
design={randomDesign()}
/>
<Book
title="Psychology of Colors"
color="pink"
design="dual-top-bands"
width={540}
color={randomColor()}
design={randomDesign()}
/>
<Book
title="TypeScript"
subtitle="Intro JS to type checking"
color="cyan"
design="colored-spine"
width={1130}
color={randomColor()}
design={randomDesign()}
/>
<Book
title="Testing"
width={10}
color={randomColor()}
design={randomDesign()}
/>
<Book title="Testing" width={10} />
<Book
title="JavaScript"
subtitle="The Definitive Guide"
author="David Flanagan"
design="split-bands"
color="purple"
color={randomColor()}
design={randomDesign()}
orientation="on-display"
/>
<Book title="Pragmatic Programmer" color="red" />
<Book title="White Space" color="yellow" design="split-bands" />
<Book
title="Pragmatic Programmer"
color={randomColor()}
design={randomDesign()}
/>
<Book title="White Space" color={randomColor()} design={randomDesign()} />
<Book
title="W3 Schools"
subtitle="The best around"
color="blue"
design="split-bands"
color={randomColor()}
design={randomDesign()}
orientation="tilted"
/>
<Book
title="UI/UX"
subtitle="Guide to Mobile Development"
author="John Doe"
color="purple"
color={randomColor()}
design={randomDesign()}
orientation="on-display"
design="dual-top-bands"
/>
<Book
title="Clean Code"
color="orange"
color={randomColor()}
design={randomDesign()}
orientation="tilted"
design="dual-top-bands"
/>
<Book title="Docs for Devs" />
<Book title="Docs for Devs" color={randomColor()} design={randomDesign()} />
<BookStack totalChildren={4}>
<BookStackElement
title="The Art of Computer Programming Vol 1"
color="green"
design="dual-top-bands"
color={randomColor()}
design={randomDesign()}
/>
<BookStackElement
title="The Art of Computer Programming Vol 2"
color="red"
design="dual-top-bands"
color={randomColor()}
design={randomDesign()}
/>
<BookStackElement
title="The Art of Computer Programming Vol 3"
color="blue"
design="dual-top-bands"
color={randomColor()}
design={randomDesign()}
/>
<BookStackElement
title="The Art of Computer Programming Vol 4a"
color="pink"
design="dual-top-bands"
color={randomColor()}
design={randomDesign()}
/>
</BookStack>
</Bookshelf>

View File

@ -56,7 +56,6 @@
);
const verifiedWidth = $derived(widthCheck(width));
const textColor = $derived(color.contrastColor.hex);
</script>
{#if orientation}
@ -85,19 +84,19 @@
</BookOnDisplay>
{/if}
{:else if design === "split-bands"}
<BookSplitBands color={color.hex} width={verifiedWidth} {textColor}>
<BookSplitBands color={color.hex} width={verifiedWidth}>
<BookText {title} {subtitle} />
</BookSplitBands>
{:else if design === "dual-top-bands"}
<BookDualTopBands color={color.hex} width={verifiedWidth} {textColor}>
<BookDualTopBands color={color.hex} width={verifiedWidth}>
<BookText {title} {subtitle} />
</BookDualTopBands>
{:else if design === "colored-spine"}
<BookColoredSpine color={color.hex} width={verifiedWidth} {textColor}>
<BookColoredSpine color={color.hex} width={verifiedWidth}>
<BookText {title} {subtitle} />
</BookColoredSpine>
{:else}
<BookDefault color={color.hex} width={verifiedWidth} {textColor}>
<BookDefault color={color.hex} width={verifiedWidth}>
<BookText {title} {subtitle} />
</BookDefault>
{/if}

View File

@ -25,24 +25,23 @@
? Color.fromName(colorRaw).darken()
: Color.fromCSSColor(colorRaw),
);
const textColor = $derived(color.contrastColor.hex);
</script>
<li class="bookshelf__bookstack-elem">
{#if design === "split-bands"}
<BookStackSplitBands color={color.hex} {textColor}>
<BookStackSplitBands color={color.hex}>
<BookText {title} {subtitle} />
</BookStackSplitBands>
{:else if design === "dual-top-bands"}
<BookStackDualTopBands color={color.hex} {textColor}>
<BookStackDualTopBands color={color.hex}>
<BookText {title} {subtitle} />
</BookStackDualTopBands>
{:else if design === "colored-spine"}
<BookStackColoredSpine color={color.hex} {textColor}>
<BookStackColoredSpine color={color.hex}>
<BookText {title} {subtitle} />
</BookStackColoredSpine>
{:else}
<BookStackDefault color={color.hex} {textColor}>
<BookStackDefault color={color.hex}>
<BookText {title} {subtitle} />
</BookStackDefault>
{/if}

View File

@ -19,6 +19,7 @@ $bookEdge: 2px;
display: inline-flex;
flex-flow: column nowrap;
list-style: none;
margin: 0;
padding: 0;
.bookshelf__bookStack-outOfStock {
@ -40,6 +41,8 @@ $bookEdge: 2px;
.bookshelf__bookstack-elem {
margin-inline-start: 0;
margin: 0;
padding: 0;
.bookshelf__book-wrapper {
width: 100%;

View File

@ -1,19 +1,28 @@
<script lang="ts">
import type { Snippet } from "svelte";
import chroma from "chroma-js";
import { Color } from "@utils/color";
interface Props {
children?: Snippet;
color?: string;
width?: number;
textColor?: string;
}
let { children, color = "green", width = 40, textColor }: Props = $props();
let { children, color = "green", width = 40 }: Props = $props();
const borderLeftColor = $derived(chroma(color).mix("white", 0.04));
const borderRightColor = $derived(chroma(color).mix("black", 0.04));
const backgroundColor = $derived(chroma(color).mix("black", 0.14));
const textColor = $derived(new Color(backgroundColor).contrastColor.hex);
</script>
<div
class="bookshelf__book-wrapper"
style:--book-color={color}
style:--book-border-left-color={borderLeftColor.css()}
style:--book-border-right-color={borderRightColor.css()}
style:--book-background-color={backgroundColor.css()}
style:--book-width={width + "px"}
style:width={width + "px"}
style:color={textColor}
@ -24,13 +33,13 @@
<style lang="scss">
div {
background: var(--book-color);
border-left: 2px solid color-mix(in srgb, var(--book-color), white 4%);
border-right: 2px solid color-mix(in srgb, var(--book-color), black 4%);
border-left: 2px solid var(--book-border-left-color);
border-right: 2px solid var(--book-border-right-color);
&:before {
content: " ";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-background-color);
height: 100%;
width: calc(var(--book-width));
border-radius: 4px;

View File

@ -1,19 +1,27 @@
<script lang="ts">
import type { Snippet } from "svelte";
import chroma from "chroma-js";
import { Color } from "@utils/color";
interface Props {
children?: Snippet;
color?: ColorName | string;
color?: string;
width?: number;
textColor?: string;
}
let { children, color = "green", width = 40, textColor }: Props = $props();
let { children, color = "green", width = 40 }: Props = $props();
const backgroundColor = $derived(chroma(color));
const borderLeftColor = $derived(chroma(color).mix("white", 0.04));
const borderRightColor = $derived(chroma(color).mix("black", 0.04));
const textColor = $derived(new Color(backgroundColor).contrastColor.hex);
</script>
<div
class="bookshelf__book-wrapper"
style:--book-color={color}
style:--book-color={backgroundColor.css()}
style:--book-border-left-color={borderLeftColor.css()}
style:--book-border-right-color={borderRightColor.css()}
style:--book-width={width + "px"}
style:width={width + "px"}
style:color={textColor}
@ -24,8 +32,8 @@
<style lang="scss">
div {
background: var(--book-color);
border-left: 2px solid color-mix(in srgb, var(--book-color), white 4%);
border-right: 2px solid color-mix(in srgb, var(--book-color), black 4%);
border-left: 2px solid var(--book-border-left-color);
border-right: 2px solid var(--book-border-right-color);
:global(.bookshelf__book-content) {
height: calc(var(--book-width));

View File

@ -1,19 +1,29 @@
<script lang="ts">
import type { Snippet } from "svelte";
import chroma from "chroma-js";
import { Color } from "@utils/color";
interface Props {
children?: Snippet;
color?: string;
width?: number;
textColor?: string;
}
let { children, color = "green", width = 40, textColor }: Props = $props();
let { children, color = "green", width = 40 }: Props = $props();
const backgroundColor = $derived(chroma(color));
const borderLeftColor = $derived(chroma(color).mix("white", 0.04));
const borderRightColor = $derived(chroma(color).mix("black", 0.04));
const bandColor = $derived(chroma(color).mix("black", 0.14));
const textColor = $derived(new Color(backgroundColor).contrastColor.hex);
</script>
<div
class="bookshelf__book-wrapper"
style:--book-color={color}
style:--book-color={backgroundColor.css()}
style:--book-border-left-color={borderLeftColor.css()}
style:--book-border-right-color={borderRightColor.css()}
style:--book-band-color={bandColor.css()}
style:--book-width={width + "px"}
style:width={width + "px"}
style:color={textColor}
@ -24,13 +34,13 @@
<style lang="scss">
div {
background: var(--book-color);
border-left: 2px solid color-mix(in srgb, var(--book-color), white 4%);
border-right: 2px solid color-mix(in srgb, var(--book-color), black 4%);
border-left: 2px solid var(--book-border-left-color);
border-right: 2px solid var(--book-border-right-color);
&:after {
content: "";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-band-color);
height: 20px;
width: calc(100% + 4px);
@ -42,7 +52,7 @@
&:before {
content: "";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-band-color);
height: 20px;
width: calc(100% + 4px);

View File

@ -1,19 +1,29 @@
<script lang="ts">
import type { Snippet } from "svelte";
import chroma from "chroma-js";
import { Color } from "@utils/color";
interface Props {
children?: Snippet;
color?: string;
width?: number;
textColor?: string;
}
let { children, color = "green", width = 40, textColor }: Props = $props();
let { children, color = "green", width = 40 }: Props = $props();
const backgroundColor = $derived(chroma(color));
const borderLeftColor = $derived(chroma(color).mix("white", 0.04));
const borderRightColor = $derived(chroma(color).mix("black", 0.04));
const bandColor = $derived(chroma(color).mix("black", 0.14));
const textColor = $derived(new Color(backgroundColor).contrastColor.hex);
</script>
<div
class="bookshelf__book-wrapper"
style:--book-color={color}
style:--book-color={backgroundColor.css()}
style:--book-border-left-color={borderLeftColor.css()}
style:--book-border-right-color={borderRightColor.css()}
style:--book-band-color={bandColor.css()}
style:--book-width={width + "px"}
style:width={width + "px"}
style:color={textColor}
@ -24,13 +34,13 @@
<style lang="scss">
div {
background: var(--book-color);
border-left: 2px solid color-mix(in srgb, var(--book-color), white 4%);
border-right: 2px solid color-mix(in srgb, var(--book-color), black 4%);
border-left: 2px solid var(--book-border-left-color);
border-right: 2px solid var(--book-border-right-color);
&:after {
content: "";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-band-color);
height: 20px;
width: calc(100% + 4px);
@ -42,7 +52,7 @@
&:before {
content: "";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-band-color);
height: 20px;
width: calc(100% + 4px);

View File

@ -1,18 +1,26 @@
<script lang="ts">
import type { Snippet } from "svelte";
import chroma from "chroma-js";
import { Color } from "@utils/color";
interface Props {
children?: Snippet;
color?: string;
textColor?: string;
}
let { children, color = "green", textColor }: Props = $props();
let { children, color = "green" }: Props = $props();
const borderLeftColor = $derived(chroma(color).mix("white", 0.04));
const borderRightColor = $derived(chroma(color).mix("black", 0.04));
const backgroundColor = $derived(chroma(color).mix("black", 0.14));
const textColor = $derived(new Color(backgroundColor).contrastColor.hex);
</script>
<div
class="bookshelf__book-wrapper"
style:--book-color={color}
style:--book-border-left-color={borderLeftColor.css()}
style:--book-border-right-color={borderRightColor.css()}
style:--book-background-color={backgroundColor.css()}
style:color={textColor}
>
{@render children?.()}
@ -21,13 +29,13 @@
<style lang="scss">
div {
background: var(--book-color);
border-left: 2px solid color-mix(in srgb, var(--book-color), white 4%);
border-right: 2px solid color-mix(in srgb, var(--book-color), black 4%);
border-left: 2px solid var(--book-border-left-color);
border-right: 2px solid var(--book-border-right-color);
&:before {
content: " ";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-background-color);
height: 40px;
width: calc(100% + 4px);
border-radius: 4px;

View File

@ -1,18 +1,26 @@
<script lang="ts">
import type { Snippet } from "svelte";
import chroma from "chroma-js";
import { Color } from "@utils/color";
interface Props {
children?: Snippet;
color?: string;
textColor?: string;
}
let { children, color = "green", textColor }: Props = $props();
let { children, color = "green" }: Props = $props();
const backgroundColor = $derived(chroma(color));
const borderLeftColor = $derived(chroma(color).mix("white", 0.04));
const borderRightColor = $derived(chroma(color).mix("black", 0.04));
const textColor = $derived(new Color(backgroundColor).contrastColor.hex);
</script>
<div
class="bookshelf__book-wrapper"
style:--book-color={color}
style:--book-color={backgroundColor.css()}
style:--book-border-left-color={borderLeftColor.css()}
style:--book-border-right-color={borderRightColor.css()}
style:color={textColor}
>
{@render children?.()}
@ -21,7 +29,7 @@
<style lang="scss">
div {
background: var(--book-color);
border-left: 2px solid color-mix(in srgb, var(--book-color), white 4%);
border-right: 2px solid color-mix(in srgb, var(--book-color), black 4%);
border-left: 2px solid var(--book-border-left-color);
border-right: 2px solid var(--book-border-right-color);
}
</style>

View File

@ -1,18 +1,28 @@
<script lang="ts">
import type { Snippet } from "svelte";
import chroma from "chroma-js";
import { Color } from "@utils/color";
interface Props {
children?: Snippet;
color?: string;
textColor?: string;
}
let { children, color = "green", textColor }: Props = $props();
let { children, color = "green" }: Props = $props();
const backgroundColor = $derived(chroma(color));
const borderLeftColor = $derived(chroma(color).mix("white", 0.04));
const borderRightColor = $derived(chroma(color).mix("black", 0.04));
const bandColor = $derived(chroma(color).mix("black", 0.14));
const textColor = $derived(new Color(backgroundColor).contrastColor.hex);
</script>
<div
class="bookshelf__book-wrapper"
style:--book-color={color}
style:--book-color={backgroundColor.css()}
style:--book-border-left-color={borderLeftColor.css()}
style:--book-border-right-color={borderRightColor.css()}
style:--book-band-color={bandColor.css()}
style:color={textColor}
>
{@render children?.()}
@ -21,13 +31,13 @@
<style lang="scss">
div {
background: var(--book-color);
border-left: 2px solid color-mix(in srgb, var(--book-color), white 4%);
border-right: 2px solid color-mix(in srgb, var(--book-color), black 4%);
border-left: 2px solid var(--book-border-left-color);
border-right: 2px solid var(--book-border-right-color);
&:after {
content: " ";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-band-color);
height: 40px;
width: 10px;
@ -39,7 +49,7 @@
&:before {
content: " ";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-band-color);
height: 40px;
width: 15px;

View File

@ -1,18 +1,28 @@
<script lang="ts">
import type { Snippet } from "svelte";
import chroma from "chroma-js";
import { Color } from "@utils/color";
interface Props {
children?: Snippet;
color?: string;
textColor?: string;
}
let { children, color = "green", textColor }: Props = $props();
let { children, color = "green" }: Props = $props();
const backgroundColor = $derived(chroma(color));
const borderLeftColor = $derived(chroma(color).mix("white", 0.04));
const borderRightColor = $derived(chroma(color).mix("black", 0.04));
const bandColor = $derived(chroma(color).mix("black", 0.14));
const textColor = $derived(new Color(backgroundColor).contrastColor.hex);
</script>
<div
class="bookshelf__book-wrapper"
style:--book-color={color}
style:--book-color={backgroundColor.css()}
style:--book-border-left-color={borderLeftColor.css()}
style:--book-border-right-color={borderRightColor.css()}
style:--book-band-color={bandColor.css()}
style:color={textColor}
>
{@render children?.()}
@ -21,13 +31,13 @@
<style lang="scss">
div {
background: var(--book-color);
border-left: 2px solid color-mix(in srgb, var(--book-color), white 4%);
border-right: 2px solid color-mix(in srgb, var(--book-color), black 4%);
border-left: 2px solid var(--book-border-left-color);
border-right: 2px solid var(--book-border-right-color);
&:after {
content: " ";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-band-color);
height: 40px;
width: 20px;
@ -39,7 +49,7 @@
&:before {
content: " ";
display: block;
background: color-mix(in srgb, var(--book-color), black 14%);
background: var(--book-band-color);
height: 40px;
width: 20px;

View File

@ -51,7 +51,6 @@
books.set(key, bookCount + 1);
}
console.log(pages);
if (isMonthly && typeof store.filterMonth === "number") {
// @ts-expect-error Moment is provided by Obsidian
const daysInMonth = moment()
@ -65,7 +64,6 @@
}
}
}
console.log(pages);
const labels = Array.from(books.keys())
.sort((a, b) => a - b)

View File

@ -4,6 +4,7 @@ import { getContext, setContext } from "svelte";
import { getSettingsContext } from "./settings.svelte";
import type BookTrackerPlugin from "@src/main";
import { createDateFilter, type DateFilterStore } from "./date-filter.svelte";
import type { ReadingState } from "@src/types";
export type FileMetadata = {
file: TFile;
@ -20,23 +21,30 @@ interface MetadataStore extends DateFilterStore {
destroy(): void;
}
export function createMetadata(plugin: BookTrackerPlugin): MetadataStore {
const settings = getSettingsContext().settings;
export function createMetadata(
plugin: BookTrackerPlugin,
state: ReadingState = READ_STATE
): MetadataStore {
const settingsStore = getSettingsContext();
const initialMetadata: FileMetadata[] = [];
let metadata: FileMetadata[] = $state([]);
$effect(() => {
const newMetadata: FileMetadata[] = [];
for (const file of plugin.app.vault.getMarkdownFiles()) {
const frontmatter =
plugin.app.metadataCache.getFileCache(file)?.frontmatter ?? {};
if (frontmatter[settings.statusProperty] !== READ_STATE) {
if (frontmatter[settingsStore.settings.statusProperty] !== state) {
continue;
}
initialMetadata.push({ file, frontmatter });
newMetadata.push({ file, frontmatter });
}
let metadata = $state(initialMetadata);
metadata = newMetadata;
});
function onChanged(file: TFile, _data: string, cache: CachedMetadata) {
metadata = metadata.map((f) => {

7
src/utils/rand.ts Normal file
View File

@ -0,0 +1,7 @@
export function randomInt(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export function randomElement<T>(arr: T[] | ReadonlyArray<T>): T {
return arr[randomInt(0, arr.length - 1)];
}