mac csc link

This commit is contained in:
nicwands
2026-02-25 21:37:51 -05:00
parent d21076a785
commit 949f14f0e1
14 changed files with 3035 additions and 1171 deletions

View File

@@ -1,9 +1,9 @@
"use strict";
const utils = require("@electron-toolkit/utils");
const electron = require("electron");
const path = require("path");
const filesystemPlugin = require("takerofnotes-plugin-filesystem");
const fs = require("fs/promises");
const matter = require("gray-matter");
const path = require("path");
const flexsearch = require("flexsearch");
const crypto = require("crypto");
class PluginRegistry {
@@ -23,96 +23,28 @@ class PluginRegistry {
return Array.from(this.plugins.values());
}
}
class BaseNotesAdapter {
constructor(config = {}) {
this.config = config;
}
async init() {
throw new Error("init() not implemented");
}
async getAll() {
throw new Error("getAll() not implemented");
}
async create(note) {
throw new Error("create() not implemented");
}
async update(note) {
throw new Error("update() not implemented");
}
async delete(id) {
throw new Error("delete() not implemented");
}
}
class FileSystemNotesAdapter extends BaseNotesAdapter {
constructor(config) {
super();
for (const field in config) {
this[field] = config[field];
}
}
async init() {
await fs.mkdir(this.notesDir, { recursive: true });
}
async getAll() {
const files = await fs.readdir(this.notesDir);
const notes = [];
for (const file of files) {
if (!file.endsWith(".md")) continue;
const fullPath = path.join(this.notesDir, file);
const raw = await fs.readFile(fullPath, "utf8");
const parsed = matter(raw);
notes.push({
...parsed.data,
content: parsed.content
});
}
return notes;
}
async create(note) {
await this._write(note);
}
async update(note) {
await this._write(note);
}
async delete(id) {
const filePath = path.join(this.notesDir, `${id}.md`);
await fs.unlink(filePath);
}
async _write(note) {
const filePath = path.join(this.notesDir, `${note.id}.md`);
const fileContent = matter.stringify(note.content, {
id: note.id,
title: note.title,
category: note.category ?? null,
createdAt: note.createdAt,
updatedAt: note.updatedAt
});
await fs.writeFile(filePath, fileContent, "utf8");
}
}
const filesystemPlugin = {
id: "filesystem",
name: "Local Filesystem",
description: "Stores notes as markdown files locally.",
version: "1.0.0",
configSchema: [
{
key: "notesDir",
label: "Notes Directory",
type: "directory",
default: path.join(electron.app.getPath("userData"), "notes"),
required: true
}
],
createAdapter(config) {
return new FileSystemNotesAdapter(config);
}
};
const USER_DATA_STRING = "__DEFAULT_USER_DATA__";
class PluginConfig {
constructor(defaultPlugin) {
this.defaultPlugin = defaultPlugin;
this.configPath = path.join(electron.app.getPath("userData"), "config.json");
}
// Helper to replace placeholders with dynamic values, recursively
_resolveDefaults(config) {
if (Array.isArray(config)) {
return config.map((item) => this._resolveDefaults(item));
} else if (config && typeof config === "object") {
const resolved = {};
for (const [key, value] of Object.entries(config)) {
resolved[key] = this._resolveDefaults(value);
}
return resolved;
} else if (typeof config === "string" && config.includes(USER_DATA_STRING)) {
return config.replace(USER_DATA_STRING, electron.app.getPath("userData"));
} else {
return config;
}
}
async load() {
let parsed;
try {
@@ -131,15 +63,21 @@ class PluginConfig {
adapterConfig: defaultConfig
};
await this.write(parsed);
} else {
parsed.adapterConfig = this._resolveDefaults(parsed.adapterConfig);
}
return parsed;
}
async write(configObject) {
const dir = path.dirname(this.configPath);
await fs.mkdir(dir, { recursive: true });
const resolvedConfig = {
...configObject,
adapterConfig: this._resolveDefaults(configObject.adapterConfig)
};
await fs.writeFile(
this.configPath,
JSON.stringify(configObject, null, 2),
JSON.stringify(resolvedConfig, null, 2),
"utf8"
);
}
@@ -297,7 +235,7 @@ electron.app.whenReady().then(async () => {
createNoteWindow(noteId);
});
const registry = new PluginRegistry();
registry.register(filesystemPlugin);
registry.register(filesystemPlugin.default);
const config = await new PluginConfig(filesystemPlugin).load();
const plugin = registry.get(config.activeAdapter);
const adapter = plugin.createAdapter(config.adapterConfig);

View File

@@ -264,8 +264,8 @@ html.has-scroll-smooth .hide-on-smooth-scroll {
:root {
--layout-column-count: 5;
--layout-column-gap: 4.5454545455vw;
--layout-margin: 6.8181818182vw;
--layout-column-gap: 5.6497175141vw;
--layout-margin: 8.4745762712vw;
--layout-width: calc(100vw - (2 * var(--layout-margin)));
--layout-column-width: calc(
(
@@ -278,13 +278,6 @@ html.has-scroll-smooth .hide-on-smooth-scroll {
var(--layout-column-count)
);
}
@media (min-width: 800px) {
:root {
--layout-column-count: 18;
--layout-column-gap: 1.1574074074vw;
--layout-margin: 3.4722222222vw;
}
}
.layout-block, .layout-grid {
max-width: var(--layout-width);
@@ -394,8 +387,7 @@ html.lenis {
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
background: var(--theme-bg);
color: var(--theme-fg);
background: var(--black);
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
@@ -417,9 +409,21 @@ h6 {
font-family: var(--font-display);
font-weight: 400;
letter-spacing: -0.02em;
line-height: 1;
line-height: 1.3;
font-size: 8.4745762712vw;
}
.h1.mono,
h1.mono,
h2.mono,
h3.mono,
h4.mono,
h5.mono,
h6.mono {
font-family: var(--font-mono);
font-weight: 400;
line-height: 1;
font-size: 6.2146892655vw;
}
.p,
p,
@@ -433,145 +437,22 @@ pre {
font-size: 3.3898305085vw;
}
#app {
min-height: 100vh;
}/* Breakpoints */
@keyframes flip-r {
50% {
transform: translateX(100%);
opacity: 0;
}
51% {
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes flip-l {
50% {
transform: translateX(-100%);
opacity: 0;
}
51% {
transform: translateX(100%);
opacity: 0;
}
}
@keyframes flip-d {
50% {
transform: translateY(100%);
opacity: 0;
}
51% {
transform: translateY(-100%);
opacity: 0;
}
}
@keyframes flip-u {
50% {
transform: translateY(-100%);
opacity: 0;
}
51% {
transform: translateY(100%);
opacity: 0;
}
}
.editor {
padding-top: 2.2598870056vw;
}
.editor h1 {
font-weight: 700 !important;
font-family: var(--font-mono);
font-weight: 400;
line-height: 1;
font-size: 3.3898305085vw;
}
.editor h1:first-child {
font-family: var(--font-mono);
font-size: 3.3898305085vw;
font-weight: 400 !important;
}
.editor h1:first-child:first-child::first-letter {
font-family: var(--font-display);
font-size: 11.8644067797vw;
}
.editor h1.is-editor-empty:first-child::before {
color: var(--grey-100);
content: attr(data-placeholder);
pointer-events: none;
font-family: var(--font-mono);
font-size: 3.3898305085vw;
font-weight: 400 !important;
}
.editor h1.is-editor-empty:first-child::before:first-child::first-letter {
font-family: var(--font-display);
font-size: 11.8644067797vw;
}
.editor p strong {
.bold {
font-weight: 700;
}
.editor p em {
font-style: italic;
#app {
min-height: 100vh;
}
.editor hr::before {
content: "-----------------------------------------";
}
.editor ul {
list-style-type: disc;
}
.editor ul li {
display: list-item;
margin-left: 1em;
}
.editor ol {
list-style-type: decimal;
}
.editor ol li {
display: list-item;
margin-left: 1.5em;
}
.editor ol li::marker {
font-family: var(--font-mono);
font-weight: 400;
line-height: 1;
font-size: 3.3898305085vw;
}
.editor a {
color: var(--theme-link);
cursor: pointer;
}
.editor .editor-wrap > div {
display: flex;
flex-direction: column;
gap: 5.6497175141vw;
}
.editor .editor-wrap > div:focus {
outline: none;
}
.editor .floating-menu,
.editor .bubble-menu {
display: flex;
gap: 1.4124293785vw;
border: 1px solid var(--grey-100);
color: var(--grey-100);
border-radius: 0.2em;
background: var(--theme-bg);
}
.editor .floating-menu button,
.editor .bubble-menu button {
cursor: pointer;
padding: 0.2em;
border-radius: 0.2em;
}
.editor .floating-menu button:hover,
.editor .bubble-menu button:hover {
background: var(--grey-100);
::selection {
color: var(--theme-bg);
background: var(--theme-accent);
}
.editor .floating-menu button.active,
.editor .bubble-menu button.active {
background: var(--theme-fg);
::-moz-selection {
color: var(--theme-bg);
background: var(--theme-accent);
}/* Breakpoints */
@keyframes flip-r {
50% {
@@ -623,4 +504,394 @@ pre {
}
.container:not(.fonts-ready) {
opacity: 0;
}/* Breakpoints */
@keyframes flip-r {
50% {
transform: translateX(100%);
opacity: 0;
}
51% {
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes flip-l {
50% {
transform: translateX(-100%);
opacity: 0;
}
51% {
transform: translateX(100%);
opacity: 0;
}
}
@keyframes flip-d {
50% {
transform: translateY(100%);
opacity: 0;
}
51% {
transform: translateY(-100%);
opacity: 0;
}
}
@keyframes flip-u {
50% {
transform: translateY(-100%);
opacity: 0;
}
51% {
transform: translateY(100%);
opacity: 0;
}
}
.category-row {
display: grid;
grid-template-columns: 7.3446327684vw 1fr;
width: 100%;
position: relative;
padding: 1.4124293785vw 0 4.2372881356vw;
cursor: pointer;
}
.category-row .index {
margin-top: 5.3672316384vw;
}
.category-row .title {
display: block;
width: 100%;
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
@media (max-width: 799px) {
.category-row .title {
-webkit-line-clamp: 2;
}
}
.category-row::after {
content: "----------------------------------------";
position: absolute;
bottom: 0;
left: 0;
}
.category-row.router-link-exact-active {
cursor: default;
}
.category-row:hover:not(.router-link-exact-active) {
color: var(--theme-accent);
}/* Breakpoints */
@keyframes flip-r {
50% {
transform: translateX(100%);
opacity: 0;
}
51% {
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes flip-l {
50% {
transform: translateX(-100%);
opacity: 0;
}
51% {
transform: translateX(100%);
opacity: 0;
}
}
@keyframes flip-d {
50% {
transform: translateY(100%);
opacity: 0;
}
51% {
transform: translateY(-100%);
opacity: 0;
}
}
@keyframes flip-u {
50% {
transform: translateY(-100%);
opacity: 0;
}
51% {
transform: translateY(100%);
opacity: 0;
}
}
.note-row {
grid-template-columns: auto 1fr;
display: grid;
gap: 5.6497175141vw;
cursor: pointer;
}
.note-row .title {
width: 44.9152542373vw;
position: relative;
}
.note-row .title::after {
content: "(open)";
position: absolute;
bottom: 0;
right: 0;
transform: translateX(100%);
font-weight: 700;
opacity: 0;
}
.note-row:hover {
color: var(--theme-accent);
}
.note-row:hover .title::after {
opacity: 1;
}/* Breakpoints */
@keyframes flip-r {
50% {
transform: translateX(100%);
opacity: 0;
}
51% {
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes flip-l {
50% {
transform: translateX(-100%);
opacity: 0;
}
51% {
transform: translateX(100%);
opacity: 0;
}
}
@keyframes flip-d {
50% {
transform: translateY(100%);
opacity: 0;
}
51% {
transform: translateY(-100%);
opacity: 0;
}
}
@keyframes flip-u {
50% {
transform: translateY(-100%);
opacity: 0;
}
51% {
transform: translateY(100%);
opacity: 0;
}
}
.directory {
padding-top: 5.0847457627vw;
}
.directory .label {
text-transform: uppercase;
margin: 4.802259887vw 0 6.7796610169vw;
font-family: var(--font-mono);
font-weight: 400;
line-height: 1;
font-size: 3.3898305085vw;
}
.directory .notes {
display: flex;
flex-direction: column;
gap: 3.9548022599vw;
}/* Breakpoints */
@keyframes flip-r {
50% {
transform: translateX(100%);
opacity: 0;
}
51% {
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes flip-l {
50% {
transform: translateX(-100%);
opacity: 0;
}
51% {
transform: translateX(100%);
opacity: 0;
}
}
@keyframes flip-d {
50% {
transform: translateY(100%);
opacity: 0;
}
51% {
transform: translateY(-100%);
opacity: 0;
}
}
@keyframes flip-u {
50% {
transform: translateY(-100%);
opacity: 0;
}
51% {
transform: translateY(100%);
opacity: 0;
}
}
.editor {
padding-top: 2.2598870056vw;
padding-bottom: 5.6497175141vw;
}
.editor h1 {
font-weight: 700 !important;
font-family: var(--font-mono);
font-weight: 400;
line-height: 1;
font-size: 3.3898305085vw;
}
.editor h1:first-child {
font-family: var(--font-mono);
font-size: 3.3898305085vw;
font-weight: 400 !important;
}
.editor h1:first-child:first-child::first-letter {
font-family: var(--font-display);
font-size: 11.8644067797vw;
}
.editor h1.is-editor-empty:first-child::before {
color: var(--grey-100);
content: attr(data-placeholder);
pointer-events: none;
font-family: var(--font-mono);
font-size: 3.3898305085vw;
font-weight: 400 !important;
}
.editor h1.is-editor-empty:first-child::before:first-child::first-letter {
font-family: var(--font-display);
font-size: 11.8644067797vw;
}
.editor p strong {
font-weight: 700;
}
.editor p em {
font-style: italic;
}
.editor hr::before {
content: "----------------------------------------";
font-family: var(--font-mono);
font-weight: 400;
line-height: 1;
font-size: 3.3898305085vw;
}
.editor ul {
list-style-type: disc;
}
.editor ul li {
display: list-item;
margin-left: 1em;
}
.editor ol {
list-style-type: decimal;
}
.editor ol li {
display: list-item;
margin-left: 1.5em;
}
.editor ol li::marker {
font-family: var(--font-mono);
font-weight: 400;
line-height: 1;
font-size: 3.3898305085vw;
}
.editor a {
color: var(--theme-link);
cursor: pointer;
}
.editor .editor-wrap > div {
display: flex;
flex-direction: column;
gap: 5.6497175141vw;
}
.editor .editor-wrap > div:focus {
outline: none;
}
.editor .bubble-menu {
display: flex;
gap: 1.4124293785vw;
border: 1px solid var(--grey-100);
color: var(--grey-100);
border-radius: 0.2em;
background: var(--theme-bg);
}
.editor .bubble-menu button {
cursor: pointer;
padding: 0.2em;
border-radius: 0.2em;
}
.editor .bubble-menu button:hover {
background: var(--grey-100);
color: var(--theme-bg);
}
.editor .bubble-menu button.active {
background: var(--theme-fg);
color: var(--theme-bg);
}/* Breakpoints */
@keyframes flip-r {
50% {
transform: translateX(100%);
opacity: 0;
}
51% {
transform: translateX(-100%);
opacity: 0;
}
}
@keyframes flip-l {
50% {
transform: translateX(-100%);
opacity: 0;
}
51% {
transform: translateX(100%);
opacity: 0;
}
}
@keyframes flip-d {
50% {
transform: translateY(100%);
opacity: 0;
}
51% {
transform: translateY(-100%);
opacity: 0;
}
}
@keyframes flip-u {
50% {
transform: translateY(-100%);
opacity: 0;
}
51% {
transform: translateY(100%);
opacity: 0;
}
}
.category .back {
display: block;
opacity: 0.25;
margin-top: 2.5423728814vw;
}
.category .category-row {
margin-top: 1.1299435028vw;
}
.category .notes {
display: flex;
flex-direction: column;
gap: 3.9548022599vw;
margin-top: 2.5423728814vw;
}

View File

@@ -8,8 +8,8 @@
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
/>
<script type="module" crossorigin src="./assets/index-CnVkU_B_.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-rzd5KlBx.css">
<script type="module" crossorigin src="./assets/index-Dv1qfmwr.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-CZWw79gc.css">
</head>
<body>