Terminal Workbench v1.1.1

A terminal-inspired Obsidian theme with full dark and light modes, a
consistent monospace "manifest" idiom across properties, code blocks,
tabs, and breadcrumbs, styled Mermaid diagrams, square-rounded tags,
and custom task states.

Includes a GitHub Pages showcase, a portable design spec, and a release
workflow that publishes manifest.json and theme.css on version tags.
This commit is contained in:
Real-Fruit-Snacks 2026-07-05 08:14:27 -04:00
commit e85ddd6337
10 changed files with 2360 additions and 0 deletions

24
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,24 @@
name: Release Obsidian theme
on:
push:
tags:
- "*"
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
tag="${GITHUB_REF#refs/tags/}"
gh release create "$tag" \
--title="$tag" \
manifest.json theme.css

10
.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
# Dev tooling and process artifacts — never ship these
.claude/
docs/preview.html
docs/superpowers/
# OS / editor / build noise
.DS_Store
node_modules/
*.log
.obsidian/

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Matt and Codex
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

85
README.md Normal file
View file

@ -0,0 +1,85 @@
# Terminal Workbench
[![Latest release](https://img.shields.io/github/v/release/Real-Fruit-Snacks/terminal-workbench?label=release&color=2a9d6e)](https://github.com/Real-Fruit-Snacks/terminal-workbench/releases/latest)
[![License: MIT](https://img.shields.io/github/license/Real-Fruit-Snacks/terminal-workbench?color=2a9d6e)](LICENSE)
[![Obsidian](https://img.shields.io/badge/obsidian-1.5.0%2B-483699)](https://obsidian.md)
A modern terminal-inspired theme for [Obsidian](https://obsidian.md), built for people who spend the day in panes, shells, logs, editors, and command palettes.
The design goal is not retro green-on-black nostalgia. It is a calm, dense, high-contrast working surface: graphite backgrounds, crisp typography, restrained ANSI-style accents, readable code, and pane chrome that feels close to a modern terminal without turning your notes into a novelty skin.
**[View the live showcase](https://real-fruit-snacks.github.io/terminal-workbench/)** for both modes, the full palette, and feature details.
## Highlights
- Full dark and light modes, each a deliberate palette rather than an inversion
- A consistent "terminal manifest" idiom across the interface: monospace micro-labels for properties, code block headers, tab titles, and breadcrumbs
- Code blocks with a header band, language label, and framed styling that matches between editing and reading views
- Custom task states with distinct checkbox colors: done, cancelled, deferred, and important
- Styled Mermaid flowchart, state, sequence, and class diagrams that follow the theme palette
- Respects your Obsidian settings: accent color, interface, text, and monospace fonts, and font size all flow through
- Print-friendly: decorative elements are stripped from PDF export
## Installation
### Community themes
Once available in the community directory:
1. Open `Settings > Appearance`.
2. Under **Themes**, select **Manage**.
3. Search for `Terminal Workbench` and select **Install and use**.
### Manual
1. Create the folder `<your vault>/.obsidian/themes/Terminal Workbench/`.
2. Download `theme.css` and `manifest.json` from the [latest release](https://github.com/Real-Fruit-Snacks/terminal-workbench/releases/latest) and copy them into that folder.
3. Open Obsidian and go to `Settings > Appearance > Themes`.
4. Choose `Terminal Workbench`.
Requires Obsidian `1.5.0` or newer.
## Respecting your settings
Terminal Workbench builds on Obsidian's own settings rather than replacing them:
- The accent color follows `Settings > Appearance > Accent color` if you customize it; otherwise the theme's terminal green is used.
- Interface, text, and monospace fonts set under `Settings > Appearance` take priority over the theme's font stacks.
- Font size is controlled by the Appearance font-size slider, untouched by the theme.
## Customization
Terminal Workbench includes settings for the [Style Settings](https://github.com/mgmeyers/obsidian-style-settings) community plugin:
- Primary, secondary, and warm accent colors, configurable separately for light and dark mode
- Editor, UI, and code fonts
- Editor line width and UI corner radius
- Compact workspace mode
- Soft neon highlights
- Active-line terminal prompt marker
Suggested fonts (the theme falls back to system fonts without them):
- Editor and code: Berkeley Mono, JetBrains Mono, Cascadia Code, IBM Plex Mono
- Interface: Inter, SF Pro Text, Segoe UI
## Compatibility
The theme uses `color-mix()` for derived tints, supported by every desktop build and current mobile build that meets the minimum app version. On very old Android WebViews the theme falls back to static colors for selection, hover, and glow effects; other tints degrade gracefully.
## Development
| Path | Purpose |
|---|---|
| `theme.css` | The theme |
| `manifest.json` | Theme metadata |
| `versions.json` | Release compatibility map |
| `docs/index.html` | Showcase page (GitHub Pages) |
| `docs/THEME-SPEC.md` | Portable design specification for reusing this visual system elsewhere |
| `.github/workflows/release.yml` | Creates a GitHub release with `manifest.json` and `theme.css` when a version tag is pushed |
To cut a release: bump `version` in `manifest.json`, add the entry to `versions.json`, then push a tag with the same version number.
## License
[MIT](LICENSE)

0
docs/.nojekyll Normal file
View file

196
docs/THEME-SPEC.md Normal file
View file

@ -0,0 +1,196 @@
# Terminal Workbench — Portable Design Spec
A platform-agnostic specification of the Terminal Workbench visual system. Hand this to any tool, framework, or designer to reproduce the theme's look in a terminal emulator, a website, a code editor, a dashboard, a slide deck — anywhere. It captures **what** the theme is (colors, type, shape, motion, the design philosophy) independent of Obsidian's specific CSS class names.
> Origin: distilled from the Terminal Workbench Obsidian theme v1.1.0. The Obsidian implementation lives in `theme.css`; this document is the reusable core.
---
## 1. Design philosophy
The one paragraph that governs every decision below:
> **A calm, dense, high-contrast working surface for people who live in panes, shells, logs, and code — not retro green-on-black novelty.** Graphite backgrounds, crisp typography, restrained ANSI-style accents, readable code, and chrome that feels close to a modern terminal. The interface stays quiet; signal (links, prompts, active elements, syntax) carries the color. When in doubt, remove the flourish.
Five principles that fall out of that:
1. **Quiet chrome, loud signal.** Backgrounds, borders, and inactive UI are near-monochrome graphite. Color is spent only on things that mean something: the active pane, a link, a syntax token, a status.
2. **Dense but breathable.** Tight vertical rhythm and small UI text, but generous line-height in prose (1.7) so long reading sessions don't fatigue.
3. **One accent family, used sparingly.** A single green primary + a cyan secondary + a warm amber. Never a rainbow. Semantic red/orange/violet exist only for meaning (error, value, keyword).
4. **Monospace as a UI voice, not just for code.** Structural labels (section headers, tab titles, breadcrumbs, metadata keys) use the mono font in small uppercase with wide tracking — the "terminal manifest" idiom. Prose and long-form body stay in a humanist sans/serif.
5. **Flat, not glassy.** No gradients as decoration, no drop shadows except functional elevation (menus, modals). Depth comes from layered flat surfaces and hairline borders.
---
## 2. Color system
The theme is built on **semantic tokens** that resolve to different raw values in dark and light mode. Always design against the token names; the raw hex is per-mode. This is the whole point of the system — a consumer wires up the token names once and gets both modes.
### 2.1 Accent ramp (mode-aware)
Three accents. In light mode they darken to stay legible on light surfaces.
| Token | Role | Dark | Light |
|---|---|---|---|
| `accent` (primary) | Prompts, active tab, primary action, H2, string literals, success | `#63f2ab` (mint green) | `#007a4d` |
| `accent-alt` (secondary) | Links, H3, metadata, functions, quiet highlights | `#6bdcff` (cyan) | `#006f9e` |
| `warm` | Warnings, text-highlight, H4, unresolved links, properties | `#f0c674` (amber) | `#a46600` |
Semantic hues (used only where they carry meaning — errors, syntax):
| Token | Dark | Light | Used for |
|---|---|---|---|
| `red` | `#ff6e7a` | `#c8324c` | Errors, cancelled state, code tags |
| `orange` | `#f7a35c` | `#b65800` | Code values / numbers |
| `violet` | `#b78cff` | `#7357b8` | Code keywords |
**Rule:** the primary accent should be derivable from / overridable by the host's own accent setting where one exists (e.g. an HSL triple), falling back to the mint green. Don't hard-clobber a user's accent choice.
### 2.2 Surfaces (graphite ramp)
Five background steps from deepest to lightest, plus borders. Depth = stepping through these, never shadows.
| Token | Dark | Light | Role |
|---|---|---|---|
| `bg-0` | `#090c0d` | `#f5f7f4` | Page / editor background (deepest dark / lightest light) |
| `bg-1` | `#0e1214` | `#edf2ee` | Sidebars, secondary panels, title/tab bar |
| `bg-2` | `#13191c` | `#e2eae5` | Form fields, code block body, table header |
| `bg-3` | `#182024` | `#d6e1db` | Hover states, active tab block, code header band |
| `bg-4` | `#202a2f` | `#c8d5cf` | Highest raised surface |
| `border` | `#2a363d` | `#bfcbc5` | Default hairline (1px) |
| `border-strong` | `#39484f` | `#9daea7` | Hover / emphasized dividers |
**Layering rule (important for panels):** a nested panel steps to the next lighter surface in dark mode and the next *darker* surface in light mode — the ordinal always means "further from the page." A code block is a good test case: page → body one step in → header band one step further. Keep at least ~1.1:1 luminance contrast between adjacent layers or they blur together (this is the exact bug that made the light-mode code block look flat before being deepened).
### 2.3 Text
| Token | Dark | Light | Role |
|---|---|---|---|
| `text-normal` | `#dce4df` | `#17201d` | Primary body text |
| `text-soft` | `#b4c3bd` | `#34443f` | Secondary text, code default |
| `text-muted` | `#879994` | `#60706a` | Labels, inactive tabs, captions |
| `text-faint` | `#63736f` | `#81918a` | Separators, icons, placeholder, glyphs |
| `text-on-accent` | `#07100d` | `#f9fbf8` | Text sitting on an accent fill |
**Contrast:** target WCAG AA (4.5:1) for body and small text. Note that a bright dark-mode accent (e.g. mint on near-black) often needs to be *darkened* — not lightened — for light mode to keep small-text contrast; the light accents above are chosen for exactly this. Verify small colored text (tags, labels) specifically, not just body.
### 2.4 Derived tints
Translucent tints are generated from the accents rather than hand-picked, so they track a changed accent automatically. Pattern: `mix(accent, transparent, N%)`.
| Purpose | Recipe |
|---|---|
| Selection background | `accent` @ ~20% (dark) / ~17% (light) |
| Active-line / row highlight | `accent-alt` @ ~7.5% |
| Nav item active background | `accent` @ ~10.5% |
| Blockquote background | `accent` @ ~7% |
| Tag background / border | `accent` @ 13% fill, 28% border |
| Text highlight (mark) | `warm` @ ~22% |
| Focus ring | `accent` @ ~18%, as a 2px outline |
Provide static fallbacks where the mixing function may be unsupported (old engines): a flat pre-mixed hex for the load-bearing ones (selection, hover, glow).
---
## 3. Typography
Three font roles. The consumer supplies actual families; these are the defaults and the *usage rules* matter more than the specific fonts.
| Role | Default stack | Used for |
|---|---|---|
| `font-mono` | Berkeley Mono → JetBrains Mono → Cascadia Code → IBM Plex Mono → SFMono-Regular → Consolas → monospace | Code, and all "manifest" UI labels |
| `font-ui` | Inter → SF Pro Text → Segoe UI → system-ui → sans-serif | Interface chrome, nav, prose (interface) |
| `font-text` | same as mono here (editor is monospace by design) | Editor / reading body |
**Respect host font settings:** if the platform lets a user pick fonts, the theme's stacks should be a *fallback layer*, not an override. Users' choices win.
### The "terminal manifest" label idiom
This is the theme's signature UI move — reuse it for any structural label:
```
font: var(--font-mono);
font-size: 10.5px; /* 9.511px depending on prominence */
font-weight: 600700;
letter-spacing: 0.060.09em;
text-transform: uppercase;
color: text-muted; /* or text-faint for the quietest */
```
Applied to: section/property headings ("PROPERTIES"), code-block language labels, tab titles, breadcrumb segments. It's what makes disparate UI regions feel like one system.
### Prose type scale
| Element | Size | Weight | Color | Notes |
|---|---|---|---|---|
| Body | 15px | 400 | text-normal | line-height 1.7 |
| Inline title / H1 | 2.1em / 1.72em | 760 | text-normal | H1/H2 get a fading underline rule |
| H2 | 1.38em | 740 | **accent** | |
| H3 | 1.16em | 720 | **accent-alt** | |
| H4 | 1.04em | 700 | **warm** | |
| H5H6 | 0.95em | 700 | text-muted | uppercase, wide tracking |
| Inline code | 0.92em | — | code-default on bg-2, hairline border, pill radius | mono |
Line-height: `1.7` normal (prose), `1.45` tight (UI), `1.62` code.
---
## 4. Shape, spacing, motion
| Property | Value | Notes |
|---|---|---|
| Corner radius (base) | 6px | `radius-s` = 4px, `radius-m` = 6px, `radius-l` = 8px |
| Pill radius | 999px | toggles, slider thumbs |
| Tag / chip radius | 4px (`radius-s`) | tags, small chips — square with rounded corners, not oval |
| Checkbox radius | 4px | |
| Border width | 1px hairline everywhere | the primary way surfaces are defined |
| Border on single-sided accents | 0 radius | rounded corners only with full borders |
| Pane shadow | `0 20px 60px rgba(0,0,0,0.22)` | menus/modals/popovers only — the one place shadows are allowed |
| Optional "soft neon" glow | `0 0 18px mix(accent, transparent, 28%)` | opt-in accent glow on active elements; off by default |
**Motion:** transitions only on interactive state changes (background, color, border, box-shadow), ~120ms ease. **Gate all motion behind `prefers-reduced-motion`** — no animation for users who opt out.
**Density:** offer a compact mode that tightens UI font sizes and control heights (~15% smaller) without touching prose readability.
---
## 5. Component patterns
How the tokens compose into recurring UI, described behaviorally so they port to any widget system:
- **Active pane/tab:** solid `bg-3` block fill + accent-colored mono uppercase label. Seated flush in its bar (no detached floating outline). Optional top accent line + glow when "soft neon" is on.
- **Inactive tab/nav item:** transparent background, `text-muted` label; on hover → subtle `bg` hover tint + brighter text; active nav item gets an inset accent left-bar (2px).
- **Panels (code blocks, callouts, embeds, metadata):** hairline border, `radius-m`, background one surface-step from the page. Structural header uses the manifest label idiom, separated by a faded hairline.
- **Callouts:** tinted from the callout's semantic color — `mix(color, page, ~9%)` fill, `mix(color, border, ~34%)` border, 3px solid color left-bar, no shadow.
- **Inputs:** `bg` field, hairline border, `radius`; focus = accent border + 2px accent-tint ring, no glow.
- **Primary button:** accent fill, `text-on-accent`, weight 650. Hover lightens the accent.
- **Tables:** collapsed hairline grid, `radius-m` outer, header on `bg-2`, alternating row tint at ~2.53% opacity, hover row tint from `accent-alt` @ ~7%.
- **Tags/chips:** accent tint fill + border, `radius-s` (square with rounded corners), small; hover inverts to solid accent + `text-on-accent`. Reserve the full pill radius for toggles and slider thumbs.
- **Checkboxes/states:** drive fill and border from a single `checkbox-color` variable so per-state variants (done/cancelled/deferred/important → accent/red/cyan/amber) just reassign that one variable rather than restyling the control. This is the cleanest way to expose stateful color.
- **Scrollbars:** thin (10px), transparent track, thumb = `text-faint` @ ~46% with a transparent border via background-clip so it reads as inset.
---
## 6. Both modes are mandatory
Every token above has a dark and light value. Design and verify in both. Common pitfalls this theme hit and fixed:
- A dark-mode accent usually must **darken** (not lighten) for light mode to keep contrast.
- Layered surfaces need enough luminance gap in *both* modes — light mode is where panels tend to collapse into the page.
- If the platform applies its own dark-mode filter to embedded content (Obsidian pixel-inverts Mermaid, for example), account for it rather than fighting it with a counter-filter.
Provide `color-scheme: dark` / `light` (or the platform equivalent) so native controls (scrollbars, form widgets) match.
---
## 7. What to hand a tool
When asking another system to "make this theme," give it:
1. **Section 1** (philosophy) verbatim — it resolves ambiguous judgment calls.
2. **Section 2** color tables — the token→value map for both modes.
3. **Section 3** the three font roles + the manifest label idiom.
4. **Sections 45** for shape/motion and the component behaviors relevant to that platform.
5. A note on which surfaces exist in the target (a terminal has far fewer than an editor) so it maps tokens to what's actually there.
The deliverable from any consumer should be checkable against Section 6: does it work in both modes, with adequate contrast, quiet chrome, and color spent only on signal?

291
docs/index.html Normal file
View file

@ -0,0 +1,291 @@
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Terminal Workbench — an Obsidian theme</title>
<meta name="description" content="A modern terminal-inspired Obsidian theme: graphite backgrounds, crisp typography, restrained ANSI-style accents, and readable code in dark and light modes.">
<style>
:root[data-theme="dark"] {
--bg-0: #090c0d; --bg-1: #0e1214; --bg-2: #13191c; --bg-3: #182024;
--border: #2a363d; --border-strong: #39484f;
--text: #dce4df; --text-soft: #b4c3bd; --muted: #879994; --faint: #63736f;
--accent: #63f2ab; --accent-alt: #6bdcff; --warm: #f0c674; --red: #ff6e7a;
--violet: #b78cff; --orange: #f7a35c;
--on-accent: #07100d; --code-bg: #0f1517; --code-header: #0c1113;
color-scheme: dark;
}
:root[data-theme="light"] {
--bg-0: #f5f7f4; --bg-1: #edf2ee; --bg-2: #e2eae5; --bg-3: #d6e1db;
--border: #bfcbc5; --border-strong: #9daea7;
--text: #17201d; --text-soft: #34443f; --muted: #60706a; --faint: #81918a;
--accent: #007a4d; --accent-alt: #006f9e; --warm: #a46600; --red: #c8324c;
--violet: #7357b8; --orange: #b65800;
--on-accent: #f9fbf8; --code-bg: #e2eae5; --code-header: #d6e1db;
color-scheme: light;
}
* { box-sizing: border-box; }
html, body { margin: 0; }
body {
background: var(--bg-0);
color: var(--text);
font-family: "Inter", "SF Pro Text", "Segoe UI", system-ui, sans-serif;
font-size: 15px;
line-height: 1.7;
}
.mono { font-family: "Berkeley Mono", "JetBrains Mono", "Cascadia Code", "IBM Plex Mono", "SFMono-Regular", Consolas, monospace; }
.label {
font-family: "Berkeley Mono", "JetBrains Mono", "Cascadia Code", "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 10.5px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
color: var(--muted);
}
a { color: var(--accent-alt); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }
.wrap { max-width: 960px; margin: 0 auto; padding: 0 24px; }
.topbar {
position: sticky; top: 0; z-index: 10;
background: var(--bg-1); border-bottom: 1px solid var(--border);
}
.topbar-inner { display: flex; align-items: center; justify-content: space-between; height: 46px; }
.topbar .label { color: var(--accent); }
.topbar-links { display: flex; align-items: center; gap: 18px; }
.topbar-links a { color: var(--muted); font-size: 13px; }
.topbar-links a:hover { color: var(--text); text-decoration: none; }
.toggle {
font: inherit; font-size: 12px; cursor: pointer;
background: var(--bg-2); color: var(--text-soft);
border: 1px solid var(--border); border-radius: 6px; padding: 4px 12px;
}
.toggle:hover { border-color: var(--border-strong); color: var(--text); }
.hero { padding: 72px 0 40px; }
.hero h1 {
font-family: "Berkeley Mono", "JetBrains Mono", "Cascadia Code", "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
font-size: 40px; font-weight: 760; line-height: 1.15; margin: 0 0 4px;
}
.hero h1 .prompt { color: var(--accent); }
.hero p.tagline { color: var(--text-soft); max-width: 620px; margin: 14px 0 26px; }
.btns { display: flex; gap: 12px; flex-wrap: wrap; }
.btn {
display: inline-block; padding: 9px 18px; border-radius: 6px;
font-size: 13.5px; font-weight: 650; border: 1px solid var(--border);
}
.btn-primary { background: var(--accent); color: var(--on-accent); border-color: transparent; }
.btn-primary:hover { text-decoration: none; filter: brightness(1.08); }
.btn-quiet { color: var(--text-soft); background: var(--bg-1); }
.btn-quiet:hover { text-decoration: none; color: var(--text); border-color: var(--border-strong); }
.window {
margin: 28px 0 0; border: 1px solid var(--border); border-radius: 8px;
background: var(--bg-0); overflow: hidden;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.22);
}
.tabbar {
display: flex; align-items: center; justify-content: space-between;
background: var(--bg-1); border-bottom: 1px solid var(--border); padding: 5px 10px;
}
.tabs { display: flex; align-items: center; gap: 4px; }
.tab {
padding: 5px 12px; border-radius: 4px;
font-family: "Berkeley Mono", "JetBrains Mono", Consolas, monospace;
font-size: 10.5px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
color: var(--muted);
}
.tab.active { background: var(--bg-3); color: var(--accent); }
.tab-plus { color: var(--faint); font-size: 14px; padding: 0 8px; }
.crumbrow {
display: flex; align-items: center; justify-content: center;
padding: 8px 12px; border-bottom: 1px solid var(--border);
font-family: "Berkeley Mono", "JetBrains Mono", Consolas, monospace; font-size: 11.5px; color: var(--muted);
}
.crumbrow .sep { color: var(--faint); padding: 0 6px; }
.crumbrow .here { color: var(--text); }
.page { padding: 30px 36px 40px; }
.page h2.h1 { font-family: inherit; font-size: 24px; font-weight: 760; margin: 0 0 10px; }
.page .h2 { color: var(--accent); font-size: 18px; font-weight: 740; margin: 26px 0 8px; }
.page .h2::after { content: ""; display: block; height: 1px; margin-top: 6px;
background: linear-gradient(90deg, color-mix(in srgb, currentColor 42%, transparent), transparent); }
.page p { margin: 10px 0; color: var(--text); }
.tag {
display: inline-block; padding: 2px 10px; border-radius: 4px;
background: color-mix(in srgb, var(--accent) 13%, transparent);
border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
color: var(--accent); font-size: 11.5px; font-weight: 650;
}
.quote {
border-left: 2px solid var(--accent);
background: color-mix(in srgb, var(--accent) 7%, transparent);
border-radius: 0 4px 4px 0; padding: 10px 16px; margin: 14px 0; color: var(--text-soft);
}
.quote::before { content: ">"; color: var(--accent); font-family: Consolas, monospace; font-weight: 700; margin-right: 8px; }
.codeblock { border: 1px solid var(--border); border-radius: 6px; overflow: hidden; margin: 14px 0; background: var(--code-bg); }
.codehead {
display: flex; justify-content: space-between; align-items: center;
background: var(--code-header); border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
padding: 5px 12px;
}
.codehead .glyph { font-family: Consolas, monospace; font-size: 9.5px; font-weight: 700; letter-spacing: 0.09em; color: var(--faint); }
.codebody { padding: 13px 16px; font-family: "Berkeley Mono", "JetBrains Mono", Consolas, monospace; font-size: 12.5px; line-height: 1.65; overflow-x: auto; }
.codebody .kw { color: var(--violet); } .codebody .fn { color: var(--accent-alt); }
.codebody .str { color: var(--accent); } .codebody .pn { color: var(--muted); }
.codebody .pr { color: var(--warm); } .codebody .vl { color: var(--orange); }
.tasks { list-style: none; padding: 0; margin: 10px 0; }
.tasks li { display: flex; align-items: center; gap: 10px; padding: 3px 0; }
.box { width: 15px; height: 15px; border-radius: 4px; border: 1px solid var(--border-strong); display: inline-block; flex: none; }
.box.done { background: var(--accent); border-color: var(--accent); }
.box.cancel { background: var(--red); border-color: var(--red); }
.box.defer { background: var(--accent-alt); border-color: var(--accent-alt); }
.box.imp { background: var(--warm); border-color: var(--warm); }
.strike { text-decoration: line-through; color: var(--faint); }
section.block { padding: 48px 0 8px; }
section.block > .label { display: block; padding-bottom: 8px; border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent); margin-bottom: 22px; }
.swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.swatch { border: 1px solid var(--border); border-radius: 6px; overflow: hidden; background: var(--bg-1); }
.swatch .chip { height: 52px; }
.swatch .meta { padding: 8px 10px; }
.swatch .name { font-size: 12px; font-weight: 650; color: var(--text-soft); }
.swatch .hex { font-family: Consolas, monospace; font-size: 11px; color: var(--muted); }
.features { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
.feature { border: 1px solid var(--border); border-radius: 6px; background: var(--bg-1); padding: 16px 18px; }
.feature .name { font-size: 13.5px; font-weight: 700; color: var(--text); margin-bottom: 6px; }
.feature p { font-size: 13px; color: var(--muted); margin: 0; line-height: 1.6; }
ol.steps { color: var(--text-soft); font-size: 14px; padding-left: 20px; }
ol.steps code { font-family: Consolas, monospace; font-size: 0.92em; background: var(--bg-2); border: 1px solid var(--border); border-radius: 4px; padding: 1px 6px; }
footer { margin-top: 56px; border-top: 1px solid var(--border); padding: 22px 0 40px; color: var(--faint); font-size: 12.5px; }
footer a { color: var(--muted); }
</style>
</head>
<body>
<div class="topbar">
<div class="wrap topbar-inner">
<span class="label">Terminal Workbench</span>
<div class="topbar-links">
<a href="https://github.com/Real-Fruit-Snacks/terminal-workbench">GitHub</a>
<a href="https://github.com/Real-Fruit-Snacks/terminal-workbench/releases/latest">Releases</a>
<button class="toggle" id="mode-toggle" aria-label="Toggle color scheme">light mode</button>
</div>
</div>
</div>
<div class="wrap">
<section class="hero">
<h1><span class="prompt">$</span> terminal-workbench</h1>
<p class="tagline">
A modern terminal-inspired theme for Obsidian. Not retro green-on-black nostalgia —
a calm, dense, high-contrast working surface: graphite backgrounds, crisp typography,
restrained ANSI-style accents, and readable code in both dark and light modes.
</p>
<div class="btns">
<a class="btn btn-primary" href="https://github.com/Real-Fruit-Snacks/terminal-workbench#installation">Install</a>
<a class="btn btn-quiet" href="https://github.com/Real-Fruit-Snacks/terminal-workbench">View source</a>
</div>
<div class="window" aria-label="Preview of the theme inside Obsidian">
<div class="tabbar">
<div class="tabs">
<span class="tab">gym tracker</span>
<span class="tab active">web server</span>
<span class="tab-plus">+</span>
</div>
<span class="tab-plus">&#8943;</span>
</div>
<div class="crumbrow">
Pentesting<span class="sep">/</span>File Transfer<span class="sep">/</span>Python<span class="sep">/</span><span class="here">Web Server</span>
</div>
<div class="page">
<h2 class="h1">Web Server</h2>
<p>Spin up a quick file transfer endpoint, watch the logs, and keep
<span class="tag">#latency</span> and <span class="tag">#errors</span> in view during warmup.</p>
<div class="quote">The theme should feel like a serious terminal setup: crisp, fast, readable, and good at 2am.</div>
<div class="h2">Serve the directory</div>
<div class="codeblock">
<div class="codehead"><span class="glyph">&gt;_</span><span class="glyph">python</span></div>
<div class="codebody"><span class="kw">import</span> http.server<br>
<br>
<span class="pr">PORT</span> <span class="pn">=</span> <span class="vl">8000</span><br>
handler <span class="pn">=</span> http.server.<span class="fn">SimpleHTTPRequestHandler</span><br>
<span class="kw">with</span> socketserver.<span class="fn">TCPServer</span>((<span class="str">""</span>, <span class="pr">PORT</span>), handler) <span class="kw">as</span> httpd:<br>
&nbsp;&nbsp;&nbsp;&nbsp;httpd.<span class="fn">serve_forever</span>()</div>
</div>
<div class="h2">Checklist</div>
<ul class="tasks">
<li><span class="box"></span> Open command palette</li>
<li><span class="box done"></span> <span class="strike">Verify active task styling</span></li>
<li><span class="box cancel"></span> <span class="strike">Cancelled task</span></li>
<li><span class="box defer"></span> <span style="color: var(--accent-alt);">Deferred task</span></li>
<li><span class="box imp"></span> <span style="color: var(--warm); font-weight: 700;">Important task</span></li>
</ul>
</div>
</div>
</section>
<section class="block">
<span class="label">Palette</span>
<div class="swatches" id="swatches"></div>
</section>
<section class="block">
<span class="label">Features</span>
<div class="features">
<div class="feature"><div class="name">Two deliberate modes</div><p>Dark and light are separate palettes, not an inversion. Accents darken in light mode to hold contrast for small text.</p></div>
<div class="feature"><div class="name">Terminal manifest idiom</div><p>Monospace micro-labels unify properties, code block headers, tab titles, and breadcrumbs into one visual system.</p></div>
<div class="feature"><div class="name">Framed code blocks</div><p>A header band with language label and consistent framing in both editing and reading views.</p></div>
<div class="feature"><div class="name">Task states</div><p>Done, cancelled, deferred, and important tasks each get a distinct checkbox color driven by native Obsidian variables.</p></div>
<div class="feature"><div class="name">Respects your settings</div><p>Your accent color, fonts, and font size flow through the theme instead of being overridden.</p></div>
<div class="feature"><div class="name">Style Settings support</div><p>Accents per mode, fonts, line width, radius, compact mode, soft neon, and a terminal prompt marker.</p></div>
</div>
</section>
<section class="block">
<span class="label">Install</span>
<ol class="steps">
<li>Open <code>Settings &gt; Appearance</code> in Obsidian.</li>
<li>Under <strong>Themes</strong>, select <strong>Manage</strong> and search for <code>Terminal Workbench</code> (once accepted into the community directory).</li>
<li>Or install manually: copy <code>theme.css</code> and <code>manifest.json</code> from the <a href="https://github.com/Real-Fruit-Snacks/terminal-workbench/releases/latest">latest release</a> into <code>.obsidian/themes/Terminal Workbench/</code>.</li>
</ol>
</section>
<footer>
MIT licensed. Built for Obsidian 1.5.0 and newer.
<a href="https://github.com/Real-Fruit-Snacks/terminal-workbench">Source on GitHub</a>.
</footer>
</div>
<script>
const tokens = [
["accent", "#63f2ab", "#007a4d"], ["accent-alt", "#6bdcff", "#006f9e"],
["warm", "#f0c674", "#a46600"], ["red", "#ff6e7a", "#c8324c"],
["violet", "#b78cff", "#7357b8"], ["orange", "#f7a35c", "#b65800"],
["bg-0", "#090c0d", "#f5f7f4"], ["bg-1", "#0e1214", "#edf2ee"],
["bg-2", "#13191c", "#e2eae5"], ["bg-3", "#182024", "#d6e1db"],
["border", "#2a363d", "#bfcbc5"], ["text", "#dce4df", "#17201d"]
];
const root = document.documentElement;
const grid = document.getElementById("swatches");
function renderSwatches() {
const dark = root.getAttribute("data-theme") === "dark";
grid.innerHTML = tokens.map(([name, d, l]) => (
'<div class="swatch"><div class="chip" style="background:' + (dark ? d : l) + '"></div>' +
'<div class="meta"><div class="name">' + name + '</div>' +
'<div class="hex">' + (dark ? d : l) + '</div></div></div>'
)).join("");
}
const btn = document.getElementById("mode-toggle");
function setMode(mode) {
root.setAttribute("data-theme", mode);
btn.textContent = mode === "dark" ? "light mode" : "dark mode";
try { localStorage.setItem("tw-mode", mode); } catch (e) {}
renderSwatches();
}
btn.addEventListener("click", () => {
setMode(root.getAttribute("data-theme") === "dark" ? "light" : "dark");
});
let saved = null;
try { saved = localStorage.getItem("tw-mode"); } catch (e) {}
setMode(saved === "light" || saved === "dark" ? saved : "dark");
</script>
</body>
</html>

6
manifest.json Normal file
View file

@ -0,0 +1,6 @@
{
"name": "Terminal Workbench",
"version": "1.1.1",
"minAppVersion": "1.5.0",
"author": "Matt and Codex"
}

1711
theme.css Normal file

File diff suppressed because it is too large Load diff

16
versions.json Normal file
View file

@ -0,0 +1,16 @@
{
"1.0.0": "1.5.0",
"1.0.1": "1.5.0",
"1.0.2": "1.5.0",
"1.0.3": "1.5.0",
"1.0.4": "1.5.0",
"1.0.5": "1.5.0",
"1.0.6": "1.5.0",
"1.0.7": "1.5.0",
"1.0.8": "1.5.0",
"1.0.9": "1.5.0",
"1.0.10": "1.5.0",
"1.0.11": "1.5.0",
"1.1.0": "1.5.0",
"1.1.1": "1.5.0"
}