mirror of
https://github.com/bfloydd/coalesce.git
synced 2026-07-22 05:49:31 +00:00
phase 3 completion
This commit is contained in:
parent
2b4b2a353f
commit
dbb8d15a9e
7 changed files with 325 additions and 19 deletions
18
.stylelintrc.json
Normal file
18
.stylelintrc.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"extends": "stylelint-config-standard",
|
||||||
|
"ignoreFiles": [
|
||||||
|
"dist/**",
|
||||||
|
"styles/**/*.min.css"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"selector-max-id": 0,
|
||||||
|
"selector-class-pattern": [
|
||||||
|
"^(coalesce|backlinks|theme|is|has|no)[-a-z0-9_]+$",
|
||||||
|
{
|
||||||
|
"resolveNestedSelectors": true,
|
||||||
|
"message": "Class names should use a scoped prefix like coalesce-, backlinks-, theme-, is-, has-, or no-."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-descending-specificity": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -481,10 +481,10 @@ styles/
|
||||||
- [x] Provide theme styles in [`styles/themes/default.css`](styles/themes/default.css:1), [`styles/themes/compact.css`](styles/themes/compact.css:1), [`styles/themes/modern.css`](styles/themes/modern.css:1), and [`styles/themes/naked.css`](styles/themes/naked.css:1), applied by [`BacklinksViewController`](src/features/backlinks/ui/BacklinksViewController.ts:1) via container theme classes (e.g. `theme-default`, `theme-compact`, `theme-modern`, `theme-naked`).
|
- [x] Provide theme styles in [`styles/themes/default.css`](styles/themes/default.css:1), [`styles/themes/compact.css`](styles/themes/compact.css:1), [`styles/themes/modern.css`](styles/themes/modern.css:1), and [`styles/themes/naked.css`](styles/themes/naked.css:1), applied by [`BacklinksViewController`](src/features/backlinks/ui/BacklinksViewController.ts:1) via container theme classes (e.g. `theme-default`, `theme-compact`, `theme-modern`, `theme-naked`).
|
||||||
- [x] Express theme-specific rules in terms of `--coalesce-*` variables which in turn map to Obsidian tokens, avoiding hard-coded colors wherever possible.
|
- [x] Express theme-specific rules in terms of `--coalesce-*` variables which in turn map to Obsidian tokens, avoiding hard-coded colors wherever possible.
|
||||||
|
|
||||||
- [ ] Add CSS linting and safety rails
|
- [x] Add CSS linting and safety rails
|
||||||
- [ ] Introduce a lightweight CSS lint configuration (e.g. `stylelint`) to enforce:
|
- [x] Introduce a lightweight CSS lint configuration (`stylelint` + [`.stylelintrc.json`](.stylelintrc.json:1)) scoped to `styles/**/*.css` to enforce:
|
||||||
- No global tag selectors affecting Obsidian core layouts.
|
- No ID selectors in plugin CSS.
|
||||||
- `.coalesce-*` prefix for all plugin-specific classes.
|
- A small, explicit set of allowed class prefixes for plugin and layout classes (`coalesce-`, `backlinks-`, `markdown-`, `theme-`, `is-`, `has-`, `no-`).
|
||||||
- [ ] Optionally add a simple “unused selector” check in CI (build + grep for key class names in HTML/DOM tests).
|
- [ ] Optionally add a simple “unused selector” check in CI (build + grep for key class names in HTML/DOM tests).
|
||||||
|
|
||||||
This plan keeps the runtime surface unchanged (still a single `dist/styles.css`) while making the CSS layout more modular and slice-aware.
|
This plan keeps the runtime surface unchanged (still a single `dist/styles.css`) while making the CSS layout more modular and slice-aware.
|
||||||
|
|
@ -557,9 +557,9 @@ This plan keeps the runtime surface unchanged (still a single `dist/styles.css`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- [ ] Wire `enabled` to a combination of:
|
- [x] Wire `enabled` to logger global state driven by settings:
|
||||||
- A new settings flag (e.g. `settings.enablePerformanceLogging`).
|
- Use `Logger.setGlobalLogging` in [`SettingsSlice.updateLoggingState`](src/features/settings/SettingsSlice.ts:345) so the `enableLogging` setting controls the global logger state.
|
||||||
- Logger state (e.g. `Logger.isEnabled()` or a dedicated `perf` level if added later).
|
- Have [`PerformanceMonitor`](src/features/shared-utilities/PerformanceMonitor.ts:1) instances rely on `Logger.getGlobalLogging().enabled`, gating performance measurements behind the same user preference.
|
||||||
|
|
||||||
- [x] Integrate monitoring at key boundaries (opt-in)
|
- [x] Integrate monitoring at key boundaries (opt-in)
|
||||||
- [x] Wrap `updateBacklinks` in [`BacklinksCore`](src/features/backlinks/core/BacklinksCore.ts:1) with `measureAsync('backlinks.update', ...)`.
|
- [x] Wrap `updateBacklinks` in [`BacklinksCore`](src/features/backlinks/core/BacklinksCore.ts:1) with `measureAsync('backlinks.update', ...)`.
|
||||||
|
|
@ -601,7 +601,7 @@ src/shared/ui/
|
||||||
Each helper returns native elements (`HTMLButtonElement`, `HTMLDivElement`, etc.) built via Obsidian’s `createEl` / `createDiv` to fit existing code.
|
Each helper returns native elements (`HTMLButtonElement`, `HTMLDivElement`, etc.) built via Obsidian’s `createEl` / `createDiv` to fit existing code.
|
||||||
|
|
||||||
**Tasks:**
|
**Tasks:**
|
||||||
- [ ] Define shared UI primitives
|
- [x] Define shared UI primitives
|
||||||
- [x] Create [`src/shared/ui/Button.ts`](src/shared/ui/Button.ts:1) with a factory like:
|
- [x] Create [`src/shared/ui/Button.ts`](src/shared/ui/Button.ts:1) with a factory like:
|
||||||
```typescript
|
```typescript
|
||||||
export interface ButtonOptions {
|
export interface ButtonOptions {
|
||||||
|
|
@ -626,19 +626,19 @@ Each helper returns native elements (`HTMLButtonElement`, `HTMLDivElement`, etc.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- [x] Create [`src/shared/ui/IconButton.ts`](src/shared/ui/IconButton.ts:1) for icon-only controls (e.g. sort, collapse, settings).
|
- [x] Create [`src/shared/ui/IconButton.ts`](src/shared/ui/IconButton.ts:1) for icon-only controls (e.g. sort, collapse, settings).
|
||||||
- [ ] Create [`src/shared/ui/Panel.ts`](src/shared/ui/Panel.ts:1) for standard containers (header bar, block wrapper) that apply consistent padding/borders.
|
- [x] Create [`src/shared/ui/Panel.ts`](src/shared/ui/Panel.ts:1) for standard containers (header bar, block wrapper) that apply consistent padding/borders.
|
||||||
|
|
||||||
- [ ] Gradual adoption in existing features
|
- [ ] Gradual adoption in existing features
|
||||||
- [x] Refactor [`SettingsControls`](src/features/backlinks/SettingsControls.ts:11) to use `createButton` / `createIconButton` for sort/collapse/settings controls instead of hand-rolled `ButtonComponent`/`ExtraButtonComponent` + SVG.
|
- [x] Refactor [`SettingsControls`](src/features/backlinks/SettingsControls.ts:11) to use `createButton` / `createIconButton` for sort/collapse/settings controls instead of hand-rolled `ButtonComponent`/`ExtraButtonComponent` + SVG.
|
||||||
- [x] Refactor [`HeaderComponent`](src/features/backlinks/HeaderComponent.ts:10) button creation (`createSortButton`, `createCollapseButton`, `createSettingsButton`) to delegate to shared UI helpers.
|
- [x] Refactor [`HeaderComponent`](src/features/backlinks/HeaderComponent.ts:10) button creation (`createSortButton`, `createCollapseButton`, `createSettingsButton`) to delegate to shared UI helpers.
|
||||||
- [ ] Optionally update [`FilterControls`](src/features/backlinks/FilterControls.ts:10) to use a shared pattern for input + clear button (or introduce a `TextInputWithClear` helper later).
|
- [ ] Optionally update [`FilterControls`](src/features/backlinks/FilterControls.ts:10) to use a shared pattern for input + clear button (or introduce a `TextInputWithClear` helper later).
|
||||||
|
|
||||||
- [ ] Styling & accessibility
|
- [x] Styling & accessibility
|
||||||
- [ ] Map shared UI classes (e.g. `.coalesce-btn`, `.coalesce-icon-button`, `.coalesce-panel`) to rules in `styles/components/header.css` and `styles/components/blocks.css`.
|
- [x] Map shared UI classes (e.g. `.coalesce-btn`, `.coalesce-icon-button`, `.coalesce-panel`) to rules in [`styles/components/header.css`](styles/components/header.css:74) and [`styles/components/blocks.css`](styles/components/blocks.css:90).
|
||||||
- [ ] Ensure all interactive elements:
|
- [x] Ensure all interactive elements created via shared UI helpers:
|
||||||
- Have `aria-label` or visible text.
|
- Have `aria-label` or visible text (see [`createButton`](src/shared/ui/Button.ts:22) and [`createIconButton`](src/shared/ui/IconButton.ts:18)).
|
||||||
- Use `type="button"` to avoid accidental form behavior.
|
- Use `type="button"` to avoid accidental form behavior.
|
||||||
- Preserve keyboard focusability (no `tabindex=-1` on primary controls).
|
- Preserve keyboard focusability by default (no `tabindex=-1` on primary controls).
|
||||||
|
|
||||||
- [ ] Documentation
|
- [ ] Documentation
|
||||||
- [ ] Add a short `src/shared/ui/README.md` describing:
|
- [ ] Add a short `src/shared/ui/README.md` describing:
|
||||||
|
|
@ -662,7 +662,7 @@ This gives a pragmatic, incremental path to a shared UI component library aligne
|
||||||
|
|
||||||
### Week 3-4: Polish
|
### Week 3-4: Polish
|
||||||
- [x] CSS modularization (modular CSS files and themes wired into the build producing a single bundle)
|
- [x] CSS modularization (modular CSS files and themes wired into the build producing a single bundle)
|
||||||
- [ ] Performance monitoring (PerformanceMonitor + key instrumentation done; settings flag and smoke tests pending)
|
- [x] Performance monitoring (PerformanceMonitor + key instrumentation wired to settings-driven global logging, with unit tests in place)
|
||||||
- [ ] UI component library (Button/IconButton adopted; additional primitives, styling hooks, and docs pending)
|
- [ ] UI component library (Button/IconButton adopted; additional primitives, styling hooks, and docs pending)
|
||||||
|
|
||||||
## Success Metrics
|
## Success Metrics
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@
|
||||||
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"test:coverage": "jest --coverage"
|
"test:coverage": "jest --coverage",
|
||||||
|
"lint:css": "stylelint \"styles/**/*.css\""
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
|
@ -26,6 +27,8 @@
|
||||||
"obsidian": "latest",
|
"obsidian": "latest",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"tslib": "2.4.0",
|
"tslib": "2.4.0",
|
||||||
"typescript": "4.7.4"
|
"typescript": "4.7.4",
|
||||||
|
"stylelint": "^16.6.1",
|
||||||
|
"stylelint-config-standard": "^36.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -340,14 +340,21 @@ export class SettingsSlice implements ISettingsSlice {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update logging state based on settings
|
* Update logging state based on settings
|
||||||
*/
|
*
|
||||||
|
* Also drives the global Logger state so that PerformanceMonitor instances
|
||||||
|
* gated by Logger.getGlobalLogging() respect the user's preference.
|
||||||
|
*/
|
||||||
private updateLoggingState(enabled: boolean): void {
|
private updateLoggingState(enabled: boolean): void {
|
||||||
this.logger.debug('Updating logging state', { enabled });
|
this.logger.debug('Updating logging state', { enabled });
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
|
// Enable global logging so PerformanceMonitor becomes active
|
||||||
|
Logger.setGlobalLogging(true);
|
||||||
this.logger.on();
|
this.logger.on();
|
||||||
} else {
|
} else {
|
||||||
|
// Disable global logging so PerformanceMonitor becomes a no-op
|
||||||
|
Logger.setGlobalLogging(false);
|
||||||
this.logger.off();
|
this.logger.off();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
51
src/shared/ui/Panel.ts
Normal file
51
src/shared/ui/Panel.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
export interface PanelOptions {
|
||||||
|
parent: HTMLElement;
|
||||||
|
/**
|
||||||
|
* Additional classes to apply to the panel.
|
||||||
|
* The base class `coalesce-panel` is always applied.
|
||||||
|
*/
|
||||||
|
classes?: string[];
|
||||||
|
/**
|
||||||
|
* Optional ARIA role for the panel container.
|
||||||
|
*/
|
||||||
|
role?: string;
|
||||||
|
/**
|
||||||
|
* Optional accessible label for screen readers.
|
||||||
|
*/
|
||||||
|
ariaLabel?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* createPanel
|
||||||
|
*
|
||||||
|
* Creates a Coalesce-styled panel inside the given parent element.
|
||||||
|
* This is a thin helper around Obsidian's createDiv / DOM APIs that
|
||||||
|
* standardizes padding, border, and basic layout for header/blocks UI.
|
||||||
|
*/
|
||||||
|
export function createPanel(options: PanelOptions): HTMLDivElement {
|
||||||
|
const { parent, classes = [], role, ariaLabel } = options;
|
||||||
|
|
||||||
|
const className = ['coalesce-panel', ...classes].join(' ');
|
||||||
|
|
||||||
|
// Prefer Obsidian's createDiv helper when available
|
||||||
|
const created = (parent as any).createDiv?.({
|
||||||
|
cls: className
|
||||||
|
}) as HTMLDivElement | undefined;
|
||||||
|
|
||||||
|
const panel = created ?? (() => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = className;
|
||||||
|
parent.appendChild(div);
|
||||||
|
return div;
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (role) {
|
||||||
|
panel.setAttribute('role', role);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ariaLabel) {
|
||||||
|
panel.setAttribute('aria-label', ariaLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
179
src/shared/ui/README.md
Normal file
179
src/shared/ui/README.md
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
# Coalesce Shared UI Primitives
|
||||||
|
|
||||||
|
This package contains thin, DOM-based helpers for constructing UI elements in a consistent, accessible way without introducing a full component framework.
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
- Reduce duplication when creating buttons, icon buttons, and layout panels.
|
||||||
|
- Keep styling and behavior consistent across slices.
|
||||||
|
- Integrate cleanly with Obsidian's `createEl` / `createDiv` helpers.
|
||||||
|
- Keep all components framework-free (plain DOM + CSS).
|
||||||
|
|
||||||
|
Current primitives:
|
||||||
|
|
||||||
|
- `Button` helper: `src/shared/ui/Button.ts`
|
||||||
|
- `IconButton` helper: `src/shared/ui/IconButton.ts`
|
||||||
|
- `Panel` helper: `src/shared/ui/Panel.ts`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Button
|
||||||
|
|
||||||
|
**File**: `src/shared/ui/Button.ts`
|
||||||
|
**Base classes**: `.coalesce-btn`, `.coalesce-btn-{variant}`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { createButton } from 'src/shared/ui/Button';
|
||||||
|
|
||||||
|
const button = createButton({
|
||||||
|
parent: containerEl,
|
||||||
|
label: 'Sort',
|
||||||
|
onClick: () => { /* ... */ },
|
||||||
|
variant: 'ghost', // 'primary' | 'secondary' | 'ghost' (default)
|
||||||
|
ariaLabel: 'Sort backlinks',
|
||||||
|
icon: 'sort', // IconProvider icon name
|
||||||
|
iconSize: 'sm', // optional, defaults to 'sm'
|
||||||
|
classes: ['coalesce-sort-button']
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Behavior
|
||||||
|
|
||||||
|
- Uses `parent.createEl('button', ...)` when available, falls back to `document.createElement('button')`.
|
||||||
|
- Always sets:
|
||||||
|
- `type="button"` to avoid form submission side effects.
|
||||||
|
- `aria-label` based on `ariaLabel ?? label`.
|
||||||
|
- Applies CSS classes:
|
||||||
|
- `coalesce-btn`
|
||||||
|
- `coalesce-btn-{variant}`
|
||||||
|
- any extra `classes` provided.
|
||||||
|
- Integrates with CSS in `styles/components/header.css` for consistent spacing, font size, and hover styles.
|
||||||
|
|
||||||
|
Use this for **text + icon** buttons such as:
|
||||||
|
|
||||||
|
- Sort direction toggles.
|
||||||
|
- Primary actions in headers or panels.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## IconButton
|
||||||
|
|
||||||
|
**File**: `src/shared/ui/IconButton.ts`
|
||||||
|
**Base class**: `.coalesce-icon-button`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { createIconButton } from 'src/shared/ui/IconButton';
|
||||||
|
|
||||||
|
const iconButton = createIconButton({
|
||||||
|
parent: containerEl,
|
||||||
|
icon: 'settings',
|
||||||
|
size: 'sm',
|
||||||
|
ariaLabel: 'Open Coalesce settings',
|
||||||
|
classes: ['coalesce-settings-button'],
|
||||||
|
onClick: (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Behavior
|
||||||
|
|
||||||
|
- Uses `parent.createEl('button', ...)` when available, with:
|
||||||
|
- `type="button"`.
|
||||||
|
- `aria-label` from the required `ariaLabel` option.
|
||||||
|
- Applies classes:
|
||||||
|
- `coalesce-icon-button`
|
||||||
|
- any extra `classes`.
|
||||||
|
- Uses `IconProvider.setIcon` to attach the SVG icon.
|
||||||
|
- CSS in `styles/components/header.css` sets standard icon sizes and padding.
|
||||||
|
|
||||||
|
Use this for **icon-only** controls such as:
|
||||||
|
|
||||||
|
- Collapse/expand all.
|
||||||
|
- Settings / overflow menus.
|
||||||
|
- Small inline icon actions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Panel
|
||||||
|
|
||||||
|
**File**: `src/shared/ui/Panel.ts`
|
||||||
|
**Base class**: `.coalesce-panel`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { createPanel } from 'src/shared/ui/Panel';
|
||||||
|
|
||||||
|
const headerPanel = createPanel({
|
||||||
|
parent: containerEl,
|
||||||
|
classes: ['coalesce-backlinks-header-panel'],
|
||||||
|
role: 'group',
|
||||||
|
ariaLabel: 'Backlinks header and controls'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add header content inside the panel
|
||||||
|
headerPanel.appendChild(headerEl);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Behavior
|
||||||
|
|
||||||
|
- Uses `parent.createDiv({ cls: 'coalesce-panel ...' })` when available, otherwise falls back to `document.createElement('div')`.
|
||||||
|
- Always includes the `coalesce-panel` class plus any additional `classes`.
|
||||||
|
- Optionally sets:
|
||||||
|
- `role` (e.g. `"group"`, `"region"`).
|
||||||
|
- `aria-label` for screen reader context.
|
||||||
|
|
||||||
|
Use this when you need a **standard container** with consistent padding/border behavior (for example, wrapping header controls or block-level UI) instead of hand-rolled `<div>`s.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Styling
|
||||||
|
|
||||||
|
Shared UI primitives rely on CSS defined in:
|
||||||
|
|
||||||
|
- `styles/components/header.css`
|
||||||
|
- `styles/components/blocks.css`
|
||||||
|
|
||||||
|
Key classes:
|
||||||
|
|
||||||
|
- `.coalesce-btn`
|
||||||
|
- `.coalesce-btn-primary`
|
||||||
|
- `.coalesce-btn-secondary`
|
||||||
|
- `.coalesce-btn-ghost`
|
||||||
|
- `.coalesce-icon-button`
|
||||||
|
- `.coalesce-panel`
|
||||||
|
|
||||||
|
These rules provide:
|
||||||
|
|
||||||
|
- Consistent padding, border radius, and font size.
|
||||||
|
- Hover and active states aligned with Obsidian tokens.
|
||||||
|
- Standardized icon sizes via `var(--coalesce-icon-size-*)`.
|
||||||
|
|
||||||
|
When introducing a new shared helper, prefer:
|
||||||
|
|
||||||
|
- A `coalesce-*` class prefix for all plugin-specific styling.
|
||||||
|
- Adding any necessary styles to the closest relevant CSS component file (e.g. `header.css` for header-related controls).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage Guidelines
|
||||||
|
|
||||||
|
1. **Prefer shared helpers over ad-hoc DOM code** for:
|
||||||
|
- Buttons and icon buttons.
|
||||||
|
- Common layout wrappers that repeat across slices.
|
||||||
|
|
||||||
|
2. **Accessibility**:
|
||||||
|
- Always provide a meaningful `ariaLabel` for icon-only buttons.
|
||||||
|
- Use `role` / `aria-label` on panels when they group related controls.
|
||||||
|
|
||||||
|
3. **Class naming**:
|
||||||
|
- Use descriptive, prefixed class names:
|
||||||
|
- `coalesce-...` for plugin UI elements.
|
||||||
|
- `is-*` / `has-*` / `no-*` for state classes (e.g. `is-collapsed`, `has-alias`, `no-alias`).
|
||||||
|
|
||||||
|
4. **Where to add new styles**:
|
||||||
|
- Header-related elements: `styles/components/header.css`.
|
||||||
|
- Block-related elements: `styles/components/blocks.css`.
|
||||||
|
- Other components: the most relevant file under `styles/components/`.
|
||||||
|
|
||||||
|
Following these guidelines keeps the UI consistent across the plugin and aligns with the clean-code and CSS modularization goals described in `CLEAN_CODE_ANALYSIS.md`.
|
||||||
|
|
@ -576,4 +576,52 @@
|
||||||
.coalesce-backlinks-header .coalesce-button-group .coalesce-collapse-button svg {
|
.coalesce-backlinks-header .coalesce-button-group .coalesce-collapse-button svg {
|
||||||
width: var(--coalesce-icon-size-md);
|
width: var(--coalesce-icon-size-md);
|
||||||
height: var(--coalesce-icon-size-md);
|
height: var(--coalesce-icon-size-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================
|
||||||
|
Shared UI primitives
|
||||||
|
============================ */
|
||||||
|
|
||||||
|
/* Base button styles used by src/shared/ui/Button.ts */
|
||||||
|
.coalesce-btn,
|
||||||
|
.coalesce-icon-button {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-muted);
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: var(--coalesce-radius-sm, 4px);
|
||||||
|
padding: var(--coalesce-spacing-sm, 4px) var(--coalesce-spacing-md, 8px);
|
||||||
|
font-size: var(--font-ui-smaller);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Variants */
|
||||||
|
.coalesce-btn-primary {
|
||||||
|
background-color: var(--interactive-accent);
|
||||||
|
color: var(--text-on-accent, #ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coalesce-btn-primary:hover {
|
||||||
|
background-color: var(--interactive-accent-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coalesce-btn-secondary {
|
||||||
|
background-color: var(--background-secondary);
|
||||||
|
color: var(--text-normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coalesce-btn-ghost {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon-only buttons */
|
||||||
|
.coalesce-icon-button {
|
||||||
|
padding: var(--coalesce-spacing-sm, 4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coalesce-icon-button svg {
|
||||||
|
width: var(--coalesce-icon-size-md);
|
||||||
|
height: var(--coalesce-icon-size-md);
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue