Making a theme
A theme is one CSS file. What it must declare, what the installer does to it on the way in, and the two ways it differs from every stylesheet you have written before.
On this page
A theme is one stylesheet that gives Tintero’s own CSS variables different values. To try one you
need no manifest, no build step and no plugin: write a .css file and load it from
Settings → General → Style.
That is the whole mechanism. Everything below follows from it.
The smallest theme that works
:root {
--dark-bg: #10131a;
--dark-menu: #171b24;
--dark-secondary: #151922;
--dark-tertiary: #1e2430;
--dark-quaternary: #2a3243;
--text-primary: #d6e0f5;
--text-secondary: #8ea2c6;
--text-tertiary: #6b7c9c;
--accent-color: #5b9dd9;
--accent-color-hover: #7cb4e6;
--border-color: #2a3243;
--button-hover: #1e2430;
}
Those are the 12 variables that every theme shipped with Tintero sets. The theme variable reference lists all 157 of them, with a count of how many of the 29 built-in themes bother with each one.
Two ways this is not like a normal stylesheet
Some colours are written twice, and the second copy is not a colour
Tintero fades panels in and out by writing rgba(var(--dark-bg-rgba), 0.6). For that to work,
--dark-bg-rgba has to hold three bare numbers rather than a colour:
:root {
--dark-bg: #10131a;
--dark-bg-rgba: 16, 19, 26;
}
11 variables come in pairs like that, and the built-in themes write both halves by hand. The reference page lists them.
Plugins get your colours too
Every plugin runs in its own sealed frame, and Tintero copies the current variables into each of
them, then pushes updates when somebody switches theme. A plugin reading var(--text-primary) is
reading yours.
So if your text and background do not contrast, you break plugin panels too, and those are the panels whose authors have no way to test against your theme. Contrast is not only about the editor.
The rest of the file
The variables are the part with rules attached. Everything else in the file is ordinary CSS and gets applied exactly as you wrote it. The template theme uses that for the things variables cannot reach:
:root {
/* … your variables … */
}
/* Everything below is plain CSS against the real application DOM. */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-thumb {
background: var(--accent-color);
border-radius: 4px;
}
Testing it
- Save your file as
theme.css. - Settings → General → Style → Local themes → Upload theme, and pick it.
- Name it when prompted. It applies immediately.
- Edit and use Replace to reload, rather than uploading a second copy.
Tintero refuses the file if it is not a .css, if it is bigger than
500 KB, or if there are no braces in it anywhere. That is the entire check,
which cuts both ways: a typo in a variable name is not an error, it is just a variable that
quietly does nothing. If a colour will not take, check the spelling against the reference before
you look anywhere else.
Packaging it for other people
Four files at the root of a repository:
theme.css the stylesheet
theme.json the manifest, below
preview.png a screenshot, 800 × 600 recommended
README.md what it looks like and who it is for
theme.json is what the browser inside the app reads about you:
{
"name": "Midnight Harbour",
"id": "midnight-harbour",
"version": "1.0.0",
"author": "Your Name",
"description": "A cool, low-contrast dark theme for long nights",
"repository": "https://github.com/you/midnight-harbour",
"preview": "preview.png",
"license": "MIT",
"tags": ["dark", "cool", "minimal"],
"colors": {
"primary": "#5b9dd9",
"background": "#10131a",
"text": "#d6e0f5"
}
}
Every field is required. colors is the three-swatch preview on your card, so make it match what
the theme actually looks like rather than what you were going for. The
theme manifest reference has the field types straight from the
app.
Then read publishing a theme, which is where that version string has to start agreeing with two other places.