Skip to content

Commit

Permalink
feat: Adds ability to specify a callback to obtain the displayed day …
Browse files Browse the repository at this point in the history
…number in the calendar UI
  • Loading branch information
valentine195 committed Sep 5, 2024
1 parent 17638df commit 524796c
Show file tree
Hide file tree
Showing 11 changed files with 1,540 additions and 398 deletions.
1,411 changes: 1,017 additions & 394 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
"author": "",
"license": "MIT",
"devDependencies": {
"@codemirror/commands": "^6.6.1",
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/search": "^6.5.6",
"@javalent/utilities": "^1.1.5",
"@lezer/highlight": "^1.2.1",
"@sniptt/monads": "^0.5.10",
"@testing-library/jest-dom": "^6.1.3",
"@testing-library/svelte": "^4.0.3",
Expand Down Expand Up @@ -47,7 +51,7 @@
"ts-jest": "^29.1.1",
"tslib": "^2.6.2",
"typescript": "^5.2.2",
"vitest": "^0.34.5",
"vitest": "^2.0.4",
"xmldom": "^0.6.0"
},
"dependencies": {
Expand Down
27 changes: 26 additions & 1 deletion src/calendar/ui/Day/Day.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
const ephemeral = getTypedContext("ephemeralStore");
const full = getTypedContext("full");
$: calendar = $store;
$: config = calendar.staticStore.staticConfiguration;
$: index = month.index;
$: year = month.year;
$: current = $store.current;
Expand Down Expand Up @@ -57,6 +58,30 @@
$viewing.month == $index &&
$viewing.year == year.year;
$: number = `${day.number}`;
$: {
if ($config.dayDisplayCallback) {
try {
const frame = document.body.createEl("iframe");
const funct = (frame.contentWindow as any).Function;
const func = new funct(
"day",
"calendar",
$config.dayDisplayCallback,
);
number = func.call(undefined, day, $calendar) ?? number;
document.body.removeChild(frame);
} catch (e) {
console.error(e);
}
if (
number == null ||
(typeof number != "number" && typeof number != "string")
)
number = `${day.number}`;
}
}
const openMenu = (evt: MouseEvent) => {
const menu = new CalendariumMenu(plugin);
Expand Down Expand Up @@ -142,7 +167,7 @@
{/if}
{#if day.type === TimeSpanType.Day || day.numbered}
<span class="day-number">
{day.number}
{number}
</span>
{/if}
{#key $events}
Expand Down
1 change: 1 addition & 0 deletions src/schemas/calendar/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export type StaticCalendarData = {
years?: Year[];
padMonths?: number;
padDays?: number;
dayDisplayCallback?: string;
};

/**
Expand Down
6 changes: 4 additions & 2 deletions src/settings/creator/Containers/dates/Dates.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import CurrentDate from "./current/CurrentDate.svelte";
import LeapDayContainer from "./leapdays/LeapDayContainer.svelte";
import YearContainer from "./years/YearContainer.svelte";
import DayCallback from "./day-callback/DayCallback.svelte";
</script>

<CurrentDate />
<WeekdayContainer />
<MonthContainer />
<LeapDayContainer />
<YearContainer />
<LeapDayContainer />
<YearContainer />
<DayCallback />
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script lang="ts">
import { getContext, onDestroy } from "svelte";
import { TextAreaComponent } from "obsidian";
import { EditorView } from "@codemirror/view";
import Details from "../../../Utilities/Details.svelte";
import { editorFromTextArea } from "src/utils/editor/editor";
const calendar = getContext("store");
$: cal = $calendar;
let editor: EditorView;
const textarea = (node: HTMLDivElement) => {
const component = new TextAreaComponent(node).setValue(
cal.static.dayDisplayCallback ?? "",
);
editor = editorFromTextArea(
component.inputEl,
EditorView.updateListener.of((update) => {
if (update.docChanged) {
cal.static.dayDisplayCallback = update.state.doc.toString();
}
}),
);
};
onDestroy(() => {
editor.destroy();
});
</script>

<Details name={"Day Callback"}>
<p>Use this to override what is displayed for a given day.</p>
<p>
Your callback will receive the <code>day</code> and
<code>calendar</code>
parameters and <b>must</b> return a <code>string</code> or
<code>number</code>
</p>
<div use:textarea />
</Details>

<style scoped>
div :global(.cm-editor) {
height: 200px;
}
</style>
1 change: 1 addition & 0 deletions src/stores/calendar.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ function createStaticStore(store: Writable<Calendar>) {
offset: data.offset,
incrementDay: data.incrementDay,
useCustomYears: data.useCustomYears,
dayDisplayCallback: data.dayDisplayCallback,
};
});
return {
Expand Down
32 changes: 32 additions & 0 deletions src/utils/editor/editor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { EditorState, type Extension } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import { basicSetup } from "./extensions";
import { materialPalenight } from "./theme-dark";
import { basicLightTheme } from "./theme-light";

export function editorFromTextArea(
textarea: HTMLTextAreaElement,
facet?: Extension
) {
let setup = basicSetup();
if (document.body.hasClass("theme-dark")) {
setup.push(materialPalenight);
} else {
setup.push(basicLightTheme);
}
const extensions = [...setup];
if (facet) extensions.push(facet);
let view = new EditorView({
state: EditorState.create({
doc: textarea.value,
extensions,
}),
});
textarea.parentNode!.appendChild(view.dom);
textarea.style.display = "none";
if (textarea.form)
textarea.form.addEventListener("submit", () => {
textarea.value = view.state.doc.toString();
});
return view;
}
60 changes: 60 additions & 0 deletions src/utils/editor/extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {
defaultKeymap,
history,
historyKeymap,
indentWithTab
} from "@codemirror/commands";
import { javascriptLanguage } from "@codemirror/lang-javascript";
import {
bracketMatching,
defaultHighlightStyle,
foldGutter,
foldKeymap,
indentOnInput,
syntaxHighlighting
} from "@codemirror/language";
import type { Extension } from "@codemirror/state";
import {
drawSelection,
dropCursor,
EditorView,
keymap,
rectangularSelection
} from "@codemirror/view";

import {
autocompletion,
closeBrackets,
closeBracketsKeymap,
completionKeymap
} from "@codemirror/autocomplete";
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";

import { lintKeymap } from "@codemirror/lint";

export const basicSetup = (): Extension[] =>
[
javascriptLanguage,

foldGutter(),
drawSelection(),
dropCursor(),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
EditorView.lineWrapping,
bracketMatching(),
closeBrackets(),
autocompletion(),
rectangularSelection(),
highlightSelectionMatches(),
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...searchKeymap,
...historyKeymap,
indentWithTab,
...foldKeymap,
...completionKeymap,
...lintKeymap
])
].filter((ext) => ext);
133 changes: 133 additions & 0 deletions src/utils/editor/theme-dark.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { EditorView } from "@codemirror/view";
import type { Extension } from "@codemirror/state";
import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
import { tags as t } from "@lezer/highlight";

/*
Credits for color palette:
Author: Mattia Astorino (http://github.com/equinusocio)
Website: https://material-theme.site/
*/

const ivory = "#abb2bf",
stone = "#7d8799", // Brightened compared to original to increase contrast
invalid = "#ffffff",
darkBackground = "#21252b",
highlightBackground = "rgba(0, 0, 0, 0.5)",
background = "#292d3e",
tooltipBackground = "#353a42",
selection = "rgba(128, 203, 196, 0.2)",
cursor = "#ffcc00";

/// The editor theme styles for Material Palenight.
export const materialPalenightTheme = EditorView.theme(
{
// done
"&": {
color: "#ffffff",
backgroundColor: background,
},

// done
".cm-content": {
caretColor: cursor,
},

// done
"&.cm-focused .cm-cursor": {
borderLeftColor: cursor,
},

"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": {
backgroundColor: selection,
},

".cm-panels": { backgroundColor: darkBackground, color: "#ffffff" },
".cm-panels.cm-panels-top": { borderBottom: "2px solid black" },
".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" },

// done, use onedarktheme
".cm-searchMatch": {
backgroundColor: "#72a1ff59",
outline: "1px solid #457dff",
},
".cm-searchMatch.cm-searchMatch-selected": {
backgroundColor: "#6199ff2f",
},

".cm-activeLine": { backgroundColor: highlightBackground },
".cm-selectionMatch": { backgroundColor: "#aafe661a" },

"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": {
backgroundColor: "#bad0f847",
outline: "1px solid #515a6b",
},

// done
".cm-gutters": {
background: "#292d3e",
color: "#676e95",
border: "none",
},

".cm-activeLineGutter": {
backgroundColor: highlightBackground,
},

".cm-foldPlaceholder": {
backgroundColor: "transparent",
border: "none",
color: "#ddd",
},

".cm-tooltip": {
border: "none",
backgroundColor: tooltipBackground,
},
".cm-tooltip .cm-tooltip-arrow:before": {
borderTopColor: "transparent",
borderBottomColor: "transparent",
},
".cm-tooltip .cm-tooltip-arrow:after": {
borderTopColor: tooltipBackground,
borderBottomColor: tooltipBackground,
},
".cm-tooltip-autocomplete": {
"& > ul > li[aria-selected]": {
backgroundColor: highlightBackground,
color: ivory,
},
},
},
{ dark: true }
);

/// The highlighting style for code in the Material Palenight theme.
export const materialPalenightHighlightStyle = HighlightStyle.define([
{ tag: t.keyword, color: "#c792ea" },
{ tag: t.operator, color: "#89ddff" },
{ tag: t.special(t.variableName), color: "#eeffff" },
{ tag: t.typeName, color: "#f07178" },
{ tag: t.atom, color: "#f78c6c" },
{ tag: t.number, color: "#ff5370" },
{ tag: t.definition(t.variableName), color: "#82aaff" },
{ tag: t.string, color: "#c3e88d" },
{ tag: t.special(t.string), color: "#f07178" },
{ tag: t.comment, color: stone },
{ tag: t.variableName, color: "#f07178" },
{ tag: t.tagName, color: "#ff5370" },
{ tag: t.bracket, color: "#a2a1a4" },
{ tag: t.meta, color: "#ffcb6b" },
{ tag: t.attributeName, color: "#c792ea" },
{ tag: t.propertyName, color: "#c792ea" },
{ tag: t.className, color: "#decb6b" },
{ tag: t.invalid, color: invalid },
]);

/// Extension to enable the Material Palenight theme (both the editor theme and
/// the highlight style).
export const materialPalenight: Extension = [
materialPalenightTheme,
syntaxHighlighting(materialPalenightHighlightStyle),
];
Loading

0 comments on commit 524796c

Please sign in to comment.