all should work now

This commit is contained in:
2025-09-26 21:59:20 -04:00
parent e7dd34d323
commit 8b9e092329
4 changed files with 367 additions and 168 deletions

219
README.md
View File

@@ -1,10 +1,20 @@
# Menu Plugin for Obsidian # Obsidian Menus
Create custom navigation menus in Obsidian using simple code blocks. Supports internal links, external URLs, and local file links with built-in themes and full customization. Create simple, stylable menus from code blocks. You write links inside a `menu` code block, and the plugin renders:
- a single div with class `menu-container`
- a set of anchor tags inside it
You can:
- Pick a built-in template (default, minimal, slate, horizon, aether)
- Use your own CSS class (no plugin CSS applied)
- Override styles using a small, safe set of YAML-like variables
- Mix template + extra classes (e.g., `layout: horizon wide`)
CSS stays clean and predictable.
## Basic Usage ## Basic Usage
Create a menu using a `menu` code block with one of the built-in layouts: Create a menu using a `menu` code block with one of the built-in templates:
````markdown ````markdown
```menu ```menu
@@ -16,32 +26,21 @@ layout: default
``` ```
```` ````
## Built-in Layouts - `[[Note]]` or `[[Note|Alias]]` creates internal links.
- `[Text](https://example.com)` creates web links.
- `[Text](file:///C:/path/to/file)` opens local files/folders.
### `default` ## Built-in Templates
Standard buttons with borders and backgrounds
````markdown
```menu
layout: default
[[Dashboard]]
[GitHub](https://github.com)
[Files](file:///C:/Users/Documents)
```
````
### `minimal` Available out of the box:
Clean text links with subtle colors - default
````markdown - minimal
```menu - slate
layout: minimal - horizon
[[Notes]] - aether
[Web](https://example.com)
[Folder](file:///C:/Projects) Example:
```
````
### `slate`
Solid background buttons
````markdown ````markdown
```menu ```menu
layout: slate layout: slate
@@ -50,37 +49,95 @@ layout: slate
``` ```
```` ````
### `horizon` You can also add extra classes like `wide` next to the layout:
Modern outlined style
````markdown ````markdown
```menu ```menu
layout: horizon layout: horizon wide
[[Dashboard]] [[Dashboard]]
[Resources](https://example.com) [Resources](https://example.com)
``` ```
```` ````
### `aether` Note: Built-in template CSS only applies when a built-in layout is selected. Internally, the container gets a `data-layout="..."` attribute which gates the plugin CSS. If you dont select a built-in layout, none of the plugin CSS will affect your menu.
Grid layout with equal-width items
## Custom CSS Class Mode (No Plugin CSS)
Use your own CSS by providing a custom class via `class:` or `layout:` with a non-built-in value. In this mode, the plugin does not apply any of its CSS. It only renders the HTML and exposes inline CSS variables from the YAML-like overrides.
````markdown ````markdown
```menu ```menu
layout: aether class: my-menu wide
[[Projects]] bg: #111
[GitHub](https://github.com) text: #eee
[Documents](file:///C:/Users/Documents) hover-text: #0af
internal-hover-text: orange
[[Home]]
[Web](https://example.com)
[Folder](file:///C:/Projects)
``` ```
```` ````
## Link Types Then, in a CSS snippet:
- **Internal**: `[[Note Name]]` or `[[Note Name|Display Text]]` ```css
- **External**: `[Display Text](https://example.com)` /* Example custom styling */
- **Files**: `[Display Text](file:///C:/path/to/file)` .menu-container.my-menu {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
## Color Customization .menu-container.my-menu a {
text-decoration: none;
padding: 0.5rem 0.8rem;
border-radius: 6px;
color: var(--text, var(--text-normal));
background: var(--bg, transparent);
border: 1px solid var(--border, var(--background-modifier-border));
}
Add color properties using YAML syntax: .menu-container.my-menu a:hover {
color: var(--hover-text, var(--text-accent));
background: var(--hover-bg, transparent);
border-color: var(--hover-border, var(--text-accent));
}
```
## YAML-like Overrides (Safe Whitelist)
The code block supports a small set of variables. No raw CSS properties are accepted in the code block. If you need full CSS power, use a CSS snippet in your IDE.
Global variables:
- bg
- text
- border
- font
- hover-text
- hover-bg
- hover-border
- hover-font
Per link type variants (prefix with internal-, external-, file-):
- internal-bg, internal-text, internal-border, internal-font
- internal-hover-text, internal-hover-bg, internal-hover-border, internal-hover-font
- external-... (same set)
- file-... (same set)
Naming aliases supported:
- text-hover -> hover-text
- bg-hover -> hover-bg
- border-hover -> hover-border
- font-hover -> hover-font
- accent -> hover-text (and internal-accent/external-accent/file-accent -> corresponding -hover-text)
Behavior of keys:
- bg applies to the buttons (anchors), not the container
- hover-* applies to the hover state of the buttons
- type-specific keys (e.g., internal-text) override the global ones for that link type
Examples (template mode):
````markdown ````markdown
```menu ```menu
layout: default layout: default
@@ -88,49 +145,51 @@ bg: #1a1a1a
text: #ffffff text: #ffffff
hover-text: #ff6b6b hover-text: #ff6b6b
border: #333333 border: #333333
[[Home]] [[Home]]
[GitHub](https://github.com) [GitHub](https://github.com)
``` ```
```` ````
### Global Color Variables Per-link-type overrides:
- `bg`: Background color
- `text`: Text color
- `border`: Border color
- `hover-text`: Hover text color
- `hover-bg`: Hover background
- `hover-border`: Hover border color
- `font`: Font family
### Link-Type Specific Colors
Customize each link type individually:
````markdown ````markdown
```menu ```menu
layout: minimal layout: minimal
internal-text: #00ff00 internal-text: #00ff00
external-text: #ff6600 external-text: #ff6600
file-text: #0066ff file-text: #0066ff
internal-font: "Arial" internal-font: "Fira Code"
external-font: "Georgia" external-font: "Georgia"
file-font: "Arial"
[[Internal Link]] [[Internal Link]]
[External Link](https://example.com) [External Link](https://example.com)
[File Link](file:///C:/Documents) [File Link](file:///C:/Documents)
``` ```
```` ````
**Available for each type** (`internal`, `external`, `file`): ## Link Types
- `{type}-text`: Text color
- `{type}-bg`: Background color
- `{type}-border`: Border color
- `{type}-font`: Font family
- `{type}-hover-text`: Hover text color
- `{type}-hover-bg`: Hover background
- `{type}-hover-border`: Hover border color
## Advanced Examples - Internal: `[[Note Name]]` or `[[Note Name|Display Text]]`
- External: `[Display Text](https://example.com)`
- Files: `[Display Text](file:///C:/path/to/file)`
### Gradient Background Behavior:
- Internal links open within Obsidian.
- External links open in your browser.
- File links open via the OS.
## Notes
- Use either `layout:` or `class:`. If the value contains a built-in template, the template is applied. Otherwise, its treated as a pure CSS class (no plugin CSS).
- If no `layout:` or `class:` is provided, `layout: default` is assumed.
- Colors support hex, rgb, hsl, CSS variables, and gradients.
- Font names with spaces need quotes: `font: "Work Sans"`.
- You can append additional classes after the layout or class: `layout: horizon wide my-extra`.
## Examples
Built-in template with overrides:
````markdown ````markdown
```menu ```menu
layout: horizon layout: horizon
@@ -142,23 +201,25 @@ hover-text: #ffd700
``` ```
```` ````
### Different Fonts Per Link Type Custom class with overrides:
````markdown ````markdown
```menu ```menu
layout: default class: my-toolbar
font: "Inter" text: var(--text-normal)
internal-font: "Fira Code" hover-text: var(--text-accent)
external-font: "Georgia" [[Inbox]]
file-font: "Arial" [Wiki](https://example.com)
[[Code Notes]]
[Articles](https://medium.com)
[Local Files](file:///C:/Documents)
``` ```
```` ````
## Notes Minimal template focusing on text colors:
````markdown
- Use either `layout:` or `class:` (both work the same) ```menu
- File paths use `file://` protocol layout: minimal
- Colors support hex, rgb, hsl, CSS variables, and gradients internal-text: var(--text-accent)
- Font names with spaces need quotes: `font: "Work Sans"` external-text: var(--text-faint)
file-text: var(--text-muted)
[[Notes]]
[Web](https://example.com)
[Folder](file:///C:/Projects)
```

94
main.js

File diff suppressed because one or more lines are too long

131
main.ts
View File

@@ -1,30 +1,13 @@
import { Plugin } from 'obsidian'; import { Plugin } from 'obsidian';
import { fileURLToPath } from 'url';
const { shell } = require('electron'); const { shell } = require('electron');
// Simple YAML parser for color properties
function parseYAML(text: string) {
const result: Record<string, string> = {};
const lines = text.split('\n');
for (const line of lines) {
const trimmed = line.trim();
if (trimmed && trimmed.includes(':')) {
const [key, ...valueParts] = trimmed.split(':');
const value = valueParts.join(':').trim();
if (key && value) {
result[key.trim()] = value;
}
}
}
return result;
}
export default class MenuPlugin extends Plugin { export default class MenuPlugin extends Plugin {
async onload() { async onload() {
this.registerMarkdownCodeBlockProcessor('menu', (source, el, ctx) => { this.registerMarkdownCodeBlockProcessor('menu', (source, el, ctx) => {
const lines = source.trim().split('\n'); const lines = source.trim().split('\n');
let layout = ''; let layoutOrClass = '';
let colors: Record<string, string> = {}; let colors: Record<string, string> = {};
const links: string[] = []; const links: string[] = [];
@@ -33,7 +16,7 @@ export default class MenuPlugin extends Plugin {
const trimmed = line.trim(); const trimmed = line.trim();
if (trimmed.startsWith('layout:') || trimmed.startsWith('class:')) { if (trimmed.startsWith('layout:') || trimmed.startsWith('class:')) {
const colonIndex = trimmed.indexOf(':'); const colonIndex = trimmed.indexOf(':');
layout = trimmed.substring(colonIndex + 1).trim(); layoutOrClass = trimmed.substring(colonIndex + 1).trim();
} else if (trimmed.includes(':') && !trimmed.startsWith('[') && !trimmed.startsWith('[[')) { } else if (trimmed.includes(':') && !trimmed.startsWith('[') && !trimmed.startsWith('[[')) {
// Parse color properties // Parse color properties
const [key, ...valueParts] = trimmed.split(':'); const [key, ...valueParts] = trimmed.split(':');
@@ -48,23 +31,102 @@ export default class MenuPlugin extends Plugin {
} }
} }
const finalLayout = layout || 'default'; // Determine layout and classes
const container = el.createEl('div', { cls: `menu-container ${finalLayout}` }); const builtInLayouts = new Set(['default', 'minimal', 'slate', 'horizon', 'aether']);
const container = el.createEl('div', { cls: 'menu-container' });
// Apply custom colors as CSS variables
if (Object.keys(colors).length > 0) { let selectedLayout = '';
for (const [key, value] of Object.entries(colors)) { let extraClasses: string[] = [];
// Replace 'accent' with 'hover-text' for consistency
let cssKey = key.replace(/accent/g, 'hover-text'); if (layoutOrClass) {
container.style.setProperty(`--${cssKey}`, value); const tokens = layoutOrClass.split(/\s+/).filter(Boolean);
if (tokens.length) {
// Allow built-in layout to appear anywhere in the list (e.g., "class: my-class horizon wide")
const builtInIndex = tokens.findIndex(t => builtInLayouts.has(t));
if (builtInIndex !== -1) {
selectedLayout = tokens[builtInIndex];
extraClasses = tokens.filter((_, i) => i !== builtInIndex);
} else {
// Custom class mode: do not apply plugin CSS (no data-layout)
extraClasses = tokens;
}
} }
// Example: ensure hover-text is set and add a comment for usage } else {
if (colors['hover-text']) { // No layout/class provided: use default built-in template
container.style.setProperty('--hover-text', colors['hover-text']); selectedLayout = 'default';
// To use in CSS: a:hover { color: var(--hover-text); } }
// Apply selected built-in template via data attribute (gates plugin CSS)
if (selectedLayout) {
container.setAttr('data-layout', selectedLayout);
}
// Apply any extra classes (e.g., "wide" or user-provided classes)
for (const cls of extraClasses) {
container.addClass(cls);
}
// Apply custom properties (whitelist only: bg, text, border, font and their -hover variants,
// plus internal-, external-, file- prefixed versions). No raw CSS props allowed.
if (Object.keys(colors).length > 0) {
const baseKeys = new Set([
'bg','text','border','font',
'hover-text','hover-bg','hover-border','hover-font',
]);
const normalizeKey = (raw: string) => {
let s = raw.trim().toLowerCase();
// Normalize synonyms/order for hover variants
s = s
// Prefer "hover-*" (matches CSS)
.replace(/\btext-hover\b/g, 'hover-text')
.replace(/\bbg-hover\b/g, 'hover-bg')
.replace(/\bborder-hover\b/g, 'hover-border')
// Old naming from earlier versions -> new "hover-*" order
.replace(/\binternal-text-hover\b/g, 'internal-hover-text')
.replace(/\binternal-bg-hover\b/g, 'internal-hover-bg')
.replace(/\binternal-border-hover\b/g, 'internal-hover-border')
.replace(/\bexternal-text-hover\b/g, 'external-hover-text')
.replace(/\bexternal-bg-hover\b/g, 'external-hover-bg')
.replace(/\bexternal-border-hover\b/g, 'external-hover-border')
.replace(/\bfile-text-hover\b/g, 'file-hover-text')
.replace(/\bfile-bg-hover\b/g, 'file-hover-bg')
.replace(/\bfile-border-hover\b/g, 'file-hover-border')
// Back-compat for "accent" -> "hover-text"
.replace(/\baccent\b/g, 'hover-text')
.replace(/\binternal-accent\b/g, 'internal-hover-text')
.replace(/\bexternal-accent\b/g, 'external-hover-text')
.replace(/\bfile-accent\b/g, 'file-hover-text')
.replace(/\bbackground\b/g, 'bg');
return s;
};
const isAllowed = (key: string) => {
if (baseKeys.has(key)) return true;
const m = key.match(/^(internal|external|file)-(.*)$/);
return !!(m && baseKeys.has(m[2]));
};
for (const [rawKey, value] of Object.entries(colors)) {
const key = normalizeKey(rawKey);
if (!isAllowed(key)) continue;
container.style.setProperty(`--${key}`, value);
} }
} }
// In custom class mode (no built-in layout), apply base inline styles to anchors so whitelist vars work without CSS.
const applyInlineBaseStyles = (a: HTMLElement, variant: 'internal' | 'external' | 'file' | 'generic') => {
const prefix = variant === 'generic' ? '' : `${variant}-`;
const get = (k: string) => (colors[`${prefix}${k}`] ?? colors[k]);
const bgVal = get('bg'); if (bgVal) a.style.background = bgVal as string;
const textVal = get('text'); if (textVal) a.style.color = textVal as string;
const borderVal = get('border'); if (borderVal) a.style.borderColor = borderVal as string;
const fontVal = get('font'); if (fontVal) a.style.fontFamily = fontVal as string;
// Expose hover values as CSS variables on the anchor for user CSS to consume if desired
const hoverKeys = ['hover-bg','hover-text','hover-border','hover-font'];
for (const hk of hoverKeys) {
const v = get(hk);
if (v) a.style.setProperty(`--${hk}`, v as string);
}
};
// Process each link // Process each link
for (const link of links) { for (const link of links) {
if (link.startsWith('[[') && link.endsWith(']]')) { if (link.startsWith('[[') && link.endsWith(']]')) {
@@ -80,6 +142,7 @@ export default class MenuPlugin extends Plugin {
attr: { 'data-href': href } attr: { 'data-href': href }
}); });
a.addClass('menu-internal-link'); a.addClass('menu-internal-link');
if (!selectedLayout) applyInlineBaseStyles(a, 'internal');
a.style.cursor = 'pointer'; a.style.cursor = 'pointer';
a.addEventListener('click', (e) => { a.addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();
@@ -103,8 +166,10 @@ export default class MenuPlugin extends Plugin {
// Add appropriate class based on link type // Add appropriate class based on link type
if (url.startsWith('file://')) { if (url.startsWith('file://')) {
a.addClass('menu-file-link'); a.addClass('menu-file-link');
if (!selectedLayout) applyInlineBaseStyles(a, 'file');
} else { } else {
a.addClass('menu-external-link'); a.addClass('menu-external-link');
if (!selectedLayout) applyInlineBaseStyles(a, 'external');
} }
a.addEventListener('click', (e) => { a.addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();

View File

@@ -1,6 +1,6 @@
/* Special styles to hide the border and </> icon on hover */ /* Special styles to hide the border and </> icon on hover */
.markdown-source-view.mod-cm6 .cm-embed-block:not(.cm-table-widget, .cm-lang-base):has(.menu-container):hover { .markdown-source-view.mod-cm6 .cm-embed-block:not(.cm-table-widget, .cm-lang-base):has(.menu-container[data-layout]):hover {
border-width: 0; border-width: 0;
outline: 0; outline: 0;
box-shadow: var(--background-primary) 0 0 0 1px inset !important; box-shadow: var(--background-primary) 0 0 0 1px inset !important;
@@ -22,8 +22,8 @@
} }
} }
.menu-container, .menu-container[data-layout],
.menu-container a { .menu-container[data-layout] a {
transition: 125ms; transition: 125ms;
} }
@@ -35,12 +35,11 @@
/* Default style variant */ /* Default style variant */
.menu-container.default { .menu-container[data-layout='default'] {
display: flex; display: flex;
gap: 1em; gap: 0.7em;
flex-wrap: wrap; flex-wrap: wrap;
border-radius: 6px; border-radius: 6px;
background-color: var(--bg, var(--background-primary));
font-family: var(--font, inherit); font-family: var(--font, inherit);
a { a {
@@ -51,49 +50,51 @@
font-weight: 500; font-weight: 500;
border: 1px solid var(--border, var(--background-modifier-border)); border: 1px solid var(--border, var(--background-modifier-border));
color: var(--text, var(--text-normal)); color: var(--text, var(--text-normal));
background: var(--bg, var(--background-primary));
font-family: var(--font, inherit); font-family: var(--font, inherit);
&:hover { &:hover {
color: var(--hover-text, var(--accent, var(--text-accent))); color: var(--hover-text, var(--accent, var(--text-accent)));
border-color: var(--hover-border, var(--accent, var(--text-accent))); border-color: var(--hover-border, var(--accent, var(--text-accent)));
background: var(--hover-bg, transparent);
} }
&.menu-internal-link { &.menu-internal-link {
color: var(--internal-text, var(--text, var(--text-normal))); color: var(--internal-text, var(--text, var(--text-normal)));
border-color: var(--internal-border, var(--border, var(--background-modifier-border))); border-color: var(--internal-border, var(--border, var(--background-modifier-border)));
background-color: var(--internal-bg, transparent); background: var(--internal-bg, var(--bg, var(--background-primary)));
font-family: var(--internal-font, var(--font, inherit)); font-family: var(--internal-font, var(--font, inherit));
&:hover { &:hover {
color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--accent, var(--text-accent))))); color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--accent, var(--text-accent)))));
border-color: var(--internal-hover-border, var(--hover-border, var(--accent, var(--text-accent)))); border-color: var(--internal-hover-border, var(--hover-border, var(--accent, var(--text-accent))));
background-color: var(--internal-hover-bg, var(--hover-bg, transparent)); background: var(--internal-hover-bg, var(--hover-bg, transparent));
} }
} }
&.menu-external-link { &.menu-external-link {
color: var(--external-text, var(--text, var(--text-normal))); color: var(--external-text, var(--text, var(--text-normal)));
border-color: var(--external-border, var(--border, var(--background-modifier-border))); border-color: var(--external-border, var(--border, var(--background-modifier-border)));
background-color: var(--external-bg, transparent); background: var(--external-bg, var(--bg, var(--background-primary)));
font-family: var(--external-font, var(--font, inherit)); font-family: var(--external-font, var(--font, inherit));
&:hover { &:hover {
color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--accent, var(--text-accent))))); color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--accent, var(--text-accent)))));
border-color: var(--external-hover-border, var(--hover-border, var(--accent, var(--text-accent)))); border-color: var(--external-hover-border, var(--hover-border, var(--accent, var(--text-accent))));
background-color: var(--external-hover-bg, var(--hover-bg, transparent)); background: var(--external-hover-bg, var(--hover-bg, transparent));
} }
} }
&.menu-file-link { &.menu-file-link {
color: var(--file-text, var(--text, var(--text-normal))); color: var(--file-text, var(--text, var(--text-normal)));
border-color: var(--file-border, var(--border, var(--background-modifier-border))); border-color: var(--file-border, var(--border, var(--background-modifier-border)));
background-color: var(--file-bg, transparent); background: var(--file-bg, var(--bg, var(--background-primary)));
font-family: var(--file-font, var(--font, inherit)); font-family: var(--file-font, var(--font, inherit));
&:hover { &:hover {
color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--accent, var(--text-accent))))); color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--accent, var(--text-accent)))));
border-color: var(--file-hover-border, var(--hover-border, var(--accent, var(--text-accent)))); border-color: var(--file-hover-border, var(--hover-border, var(--accent, var(--text-accent))));
background-color: var(--file-hover-bg, var(--hover-bg, transparent)); background: var(--file-hover-bg, var(--hover-bg, transparent));
} }
} }
} }
@@ -112,12 +113,11 @@
/* Minimal style variant */ /* Minimal style variant */
.menu-container.minimal { .menu-container[data-layout='minimal'] {
display: flex; display: flex;
gap: 0.2em; gap: 0.2em;
flex-wrap: wrap; flex-wrap: wrap;
transition: 125ms; transition: 125ms;
background-color: var(--bg, transparent);
font-family: var(--font, inherit); font-family: var(--font, inherit);
a { a {
@@ -128,10 +128,11 @@
font-size: 0.9em; font-size: 0.9em;
font-weight: normal; font-weight: normal;
color: var(--text, var(--text-normal)); color: var(--text, var(--text-normal));
background: var(--bg, transparent);
font-family: var(--font, inherit); font-family: var(--font, inherit);
&:hover { &:hover {
background-color: var(--hover-bg, var(--background-secondary)); background: var(--hover-bg, var(--background-secondary));
color: var(--hover-text, var(--accent, var(--text-accent))); color: var(--hover-text, var(--accent, var(--text-accent)));
} }
@@ -141,7 +142,7 @@
&:hover { &:hover {
color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--internal-hover, var(--text-accent-hover))))); color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--internal-hover, var(--text-accent-hover)))));
background-color: var(--internal-hover-bg, var(--hover-bg, var(--background-secondary))); background: var(--internal-hover-bg, var(--hover-bg, var(--background-secondary)));
} }
} }
@@ -151,7 +152,7 @@
&:hover { &:hover {
color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--external-hover, var(--text-normal))))); color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--external-hover, var(--text-normal)))));
background-color: var(--external-hover-bg, var(--hover-bg, var(--background-secondary))); background: var(--external-hover-bg, var(--hover-bg, var(--background-secondary)));
} }
} }
@@ -161,18 +162,17 @@
&:hover { &:hover {
color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--file-hover, var(--text-normal))))); color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--file-hover, var(--text-normal)))));
background-color: var(--file-hover-bg, var(--hover-bg, var(--background-secondary))); background: var(--file-hover-bg, var(--hover-bg, var(--background-secondary)));
} }
} }
} }
} }
/* Minimal style variant */ /* Minimal style variant */
.menu-container.slate { .menu-container[data-layout='slate'] {
display: flex; display: flex;
gap: 0.2em; gap: 0.2em;
flex-wrap: wrap; flex-wrap: wrap;
background-color: var(--bg, transparent);
font-family: var(--font, inherit); font-family: var(--font, inherit);
a { a {
@@ -182,13 +182,13 @@
transition: color 0.15s ease; transition: color 0.15s ease;
font-size: 0.9em; font-size: 0.9em;
font-weight: normal; font-weight: normal;
background-color: var(--item-bg, var(--background-secondary)); background: var(--bg, var(--background-secondary));
border: 1px solid var(--border, var(--background-secondary)); border: 1px solid var(--border, var(--background-secondary));
color: var(--text, var(--text-faint)); color: var(--text, var(--text-faint));
font-family: var(--font, inherit); font-family: var(--font, inherit);
&:hover { &:hover {
background-color: var(--hover-bg, var(--background-secondary)); background: var(--hover-bg, var(--background-secondary));
color: var(--hover-text, var(--accent, var(--text-accent))); color: var(--hover-text, var(--accent, var(--text-accent)));
border: 1px solid var(--hover-border, var(--accent, var(--text-accent))); border: 1px solid var(--hover-border, var(--accent, var(--text-accent)));
} }
@@ -196,51 +196,50 @@
&.menu-internal-link { &.menu-internal-link {
color: var(--internal-text, var(--text, var(--text-faint))); color: var(--internal-text, var(--text, var(--text-faint)));
border-color: var(--internal-border, var(--border, var(--background-secondary))); border-color: var(--internal-border, var(--border, var(--background-secondary)));
background-color: var(--internal-bg, var(--item-bg, var(--background-secondary))); background: var(--internal-bg, var(--bg, var(--background-secondary)));
font-family: var(--internal-font, var(--font, inherit)); font-family: var(--internal-font, var(--font, inherit));
&:hover { &:hover {
color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--accent, var(--text-accent))))); color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--accent, var(--text-accent)))));
border-color: var(--internal-hover-border, var(--hover-border, var(--accent, var(--text-accent)))); border-color: var(--internal-hover-border, var(--hover-border, var(--accent, var(--text-accent))));
background-color: var(--internal-hover-bg, var(--hover-bg, var(--background-secondary))); background: var(--internal-hover-bg, var(--hover-bg, var(--background-secondary)));
} }
} }
&.menu-external-link { &.menu-external-link {
color: var(--external-text, var(--text, var(--text-faint))); color: var(--external-text, var(--text, var(--text-faint)));
border-color: var(--external-border, var(--border, var(--background-secondary))); border-color: var(--external-border, var(--border, var(--background-secondary)));
background-color: var(--external-bg, var(--item-bg, var(--background-secondary))); background: var(--external-bg, var(--bg, var(--background-secondary)));
font-family: var(--external-font, var(--font, inherit)); font-family: var(--external-font, var(--font, inherit));
&:hover { &:hover {
color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--accent, var(--text-accent))))); color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--accent, var(--text-accent)))));
border-color: var(--external-hover-border, var(--hover-border, var(--accent, var(--text-accent)))); border-color: var(--external-hover-border, var(--hover-border, var(--accent, var(--text-accent))));
background-color: var(--external-hover-bg, var(--hover-bg, var(--background-secondary))); background: var(--external-hover-bg, var(--hover-bg, var(--background-secondary)));
} }
} }
&.menu-file-link { &.menu-file-link {
color: var(--file-text, var(--text, var(--text-faint))); color: var(--file-text, var(--text, var(--text-faint)));
border-color: var(--file-border, var(--border, var(--background-secondary))); border-color: var(--file-border, var(--border, var(--background-secondary)));
background-color: var(--file-bg, var(--item-bg, var(--background-secondary))); background: var(--file-bg, var(--bg, var(--background-secondary)));
font-family: var(--file-font, var(--font, inherit)); font-family: var(--file-font, var(--font, inherit));
&:hover { &:hover {
color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--accent, var(--text-accent))))); color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--accent, var(--text-accent)))));
border-color: var(--file-hover-border, var(--hover-border, var(--accent, var(--text-accent)))); border-color: var(--file-hover-border, var(--hover-border, var(--accent, var(--text-accent))));
background-color: var(--file-hover-bg, var(--hover-bg, var(--background-secondary))); background: var(--file-hover-bg, var(--hover-bg, var(--background-secondary)));
} }
} }
} }
} }
.menu-container.horizon { .menu-container[data-layout='horizon'] {
display: flex; display: flex;
gap: 0.5em; gap: 0.5em;
flex-wrap: wrap; flex-wrap: wrap;
border-radius: 8px; border-radius: 8px;
background-color: var(--bg, var(--background-primary));
font-family: var(--font, 'Space Grotesk', Inter, sans-serif); font-family: var(--font, 'Space Grotesk', Inter, sans-serif);
a { a {
@@ -254,49 +253,51 @@
border-radius: 3px; border-radius: 3px;
padding-block: var(--size-2, 0.5em); padding-block: var(--size-2, 0.5em);
padding-inline: var(--size-3, 2em); padding-inline: var(--size-3, 2em);
background: var(--bg, transparent);
transition: 250ms; transition: 250ms;
&:hover { &:hover {
color: var(--hover-text, var(--accent, var(--orange-500, darkorange))); color: var(--hover-text, var(--accent, var(--orange-500, darkorange)));
border: 1px solid var(--hover-border, var(--accent, var(--orange-500, darkorange))); border: 1px solid var(--hover-border, var(--accent, var(--orange-500, darkorange)));
background: var(--hover-bg, transparent);
} }
&.menu-internal-link { &.menu-internal-link {
color: var(--internal-text, var(--text, var(--cyan-500, darkcyan))); color: var(--internal-text, var(--text, var(--cyan-500, darkcyan)));
border-color: var(--internal-border, var(--border, var(--cyan-500, darkcyan))); border-color: var(--internal-border, var(--border, var(--cyan-500, darkcyan)));
background-color: var(--internal-bg, transparent); background: var(--internal-bg, var(--bg, transparent));
font-family: var(--internal-font, var(--font, 'Space Grotesk', Inter, sans-serif)); font-family: var(--internal-font, var(--font, 'Space Grotesk', Inter, sans-serif));
&:hover { &:hover {
color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--accent, var(--orange-500, darkorange))))); color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--accent, var(--orange-500, darkorange)))));
border-color: var(--internal-hover-border, var(--hover-border, var(--accent, var(--orange-500, darkorange)))); border-color: var(--internal-hover-border, var(--hover-border, var(--accent, var(--orange-500, darkorange))));
background-color: var(--internal-hover-bg, var(--hover-bg, transparent)); background: var(--internal-hover-bg, var(--hover-bg, transparent));
} }
} }
&.menu-external-link { &.menu-external-link {
color: var(--external-text, var(--text, var(--cyan-500, darkcyan))); color: var(--external-text, var(--text, var(--cyan-500, darkcyan)));
border-color: var(--external-border, var(--border, var(--cyan-500, darkcyan))); border-color: var(--external-border, var(--border, var(--cyan-500, darkcyan)));
background-color: var(--external-bg, transparent); background: var(--external-bg, var(--bg, transparent));
font-family: var(--external-font, var(--font, 'Space Grotesk', Inter, sans-serif)); font-family: var(--external-font, var(--font, 'Space Grotesk', Inter, sans-serif));
&:hover { &:hover {
color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--accent, var(--orange-500, darkorange))))); color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--accent, var(--orange-500, darkorange)))));
border-color: var(--external-hover-border, var(--hover-border, var(--accent, var(--orange-500, darkorange)))); border-color: var(--external-hover-border, var(--hover-border, var(--accent, var(--orange-500, darkorange))));
background-color: var(--external-hover-bg, var(--hover-bg, transparent)); background: var(--external-hover-bg, var(--hover-bg, transparent));
} }
} }
&.menu-file-link { &.menu-file-link {
color: var(--file-text, var(--text, var(--cyan-500, darkcyan))); color: var(--file-text, var(--text, var(--cyan-500, darkcyan)));
border-color: var(--file-border, var(--border, var(--cyan-500, darkcyan))); border-color: var(--file-border, var(--border, var(--cyan-500, darkcyan)));
background-color: var(--file-bg, transparent); background: var(--file-bg, var(--bg, transparent));
font-family: var(--file-font, var(--font, 'Space Grotesk', Inter, sans-serif)); font-family: var(--file-font, var(--font, 'Space Grotesk', Inter, sans-serif));
&:hover { &:hover {
color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--accent, var(--orange-500, darkorange))))); color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--accent, var(--orange-500, darkorange)))));
border-color: var(--file-hover-border, var(--hover-border, var(--accent, var(--orange-500, darkorange)))); border-color: var(--file-hover-border, var(--hover-border, var(--accent, var(--orange-500, darkorange))));
background-color: var(--file-hover-bg, var(--hover-bg, transparent)); background: var(--file-hover-bg, var(--hover-bg, transparent));
} }
} }
} }
@@ -308,11 +309,10 @@
} }
} }
.menu-container.aether { .menu-container[data-layout='aether'] {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 0.5em; gap: 0.5em;
background-color: var(--bg, transparent);
font-family: var(--font, inherit); font-family: var(--font, inherit);
a { a {
@@ -323,50 +323,51 @@
border-radius: 8px; border-radius: 8px;
color: var(--text, var(--text-normal)); color: var(--text, var(--text-normal));
border: 1px solid var(--border, var(--background-modifier-border)); border: 1px solid var(--border, var(--background-modifier-border));
background: var(--bg, transparent);
font-family: var(--font, inherit); font-family: var(--font, inherit);
&:hover { &:hover {
color: var(--hover-text, var(--accent, var(--text-accent))); color: var(--hover-text, var(--accent, var(--text-accent)));
border-color: var(--hover-border, var(--accent, var(--text-accent))); border-color: var(--hover-border, var(--accent, var(--text-accent)));
background-color: var(--hover-bg, var(--background-modifier-hover)); background: var(--hover-bg, var(--background-modifier-hover));
} }
&.menu-internal-link { &.menu-internal-link {
color: var(--internal-text, var(--text, var(--text-normal))); color: var(--internal-text, var(--text, var(--text-normal)));
border-color: var(--internal-border, var(--border, var(--background-modifier-border))); border-color: var(--internal-border, var(--border, var(--background-modifier-border)));
background-color: var(--internal-bg, transparent); background: var(--internal-bg, var(--bg, transparent));
font-family: var(--internal-font, var(--font, inherit)); font-family: var(--internal-font, var(--font, inherit));
&:hover { &:hover {
color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--accent, var(--text-accent))))); color: var(--internal-hover-text, var(--internal-accent, var(--hover-text, var(--accent, var(--text-accent)))));
border-color: var(--internal-hover-border, var(--hover-border, var(--accent, var(--text-accent)))); border-color: var(--internal-hover-border, var(--hover-border, var(--accent, var(--text-accent))));
background-color: var(--internal-hover-bg, var(--hover-bg, var(--background-modifier-hover))); background: var(--internal-hover-bg, var(--hover-bg, var(--background-modifier-hover)));
} }
} }
&.menu-external-link { &.menu-external-link {
color: var(--external-text, var(--text, var(--text-normal))); color: var(--external-text, var(--text, var(--text-normal)));
border-color: var(--external-border, var(--border, var(--background-modifier-border))); border-color: var(--external-border, var(--border, var(--background-modifier-border)));
background-color: var(--external-bg, transparent); background: var(--external-bg, var(--bg, transparent));
font-family: var(--external-font, var(--font, inherit)); font-family: var(--external-font, var(--font, inherit));
&:hover { &:hover {
color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--accent, var(--text-accent))))); color: var(--external-hover-text, var(--external-accent, var(--hover-text, var(--accent, var(--text-accent)))));
border-color: var(--external-hover-border, var(--hover-border, var(--accent, var(--text-accent)))); border-color: var(--external-hover-border, var(--hover-border, var(--accent, var(--text-accent))));
background-color: var(--external-hover-bg, var(--hover-bg, var(--background-modifier-hover))); background: var(--external-hover-bg, var(--hover-bg, var(--background-modifier-hover)));
} }
} }
&.menu-file-link { &.menu-file-link {
color: var(--file-text, var(--text, var(--text-normal))); color: var(--file-text, var(--text, var(--text-normal)));
border-color: var(--file-border, var(--border, var(--background-modifier-border))); border-color: var(--file-border, var(--border, var(--background-modifier-border)));
background-color: var(--file-bg, transparent); background: var(--file-bg, var(--bg, transparent));
font-family: var(--file-font, var(--font, inherit)); font-family: var(--file-font, var(--font, inherit));
&:hover { &:hover {
color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--accent, var(--text-accent))))); color: var(--file-hover-text, var(--file-accent, var(--hover-text, var(--accent, var(--text-accent)))));
border-color: var(--file-hover-border, var(--hover-border, var(--accent, var(--text-accent)))); border-color: var(--file-hover-border, var(--hover-border, var(--accent, var(--text-accent))));
background-color: var(--file-hover-bg, var(--hover-bg, var(--background-modifier-hover))); background: var(--file-hover-bg, var(--hover-bg, var(--background-modifier-hover)));
} }
} }
} }