Set default code backgrounds to fafafa for 0.1.4

This commit is contained in:
jqml 2026-07-19 16:47:26 +01:00
parent 0338782dcc
commit 3235d36045
7 changed files with 185 additions and 39 deletions

View file

@ -8,7 +8,7 @@ This plugin changes appearance by applying scoped CSS custom properties. Test pr
## Features
- Reusable stored style profiles, including a built-in Default profile for native styling.
- Reusable stored style profiles, including a built-in Default profile with native styling plus `#fafafa` code backgrounds.
- Active global profile settings for typography, headings, links, tables, code, blockquotes, callouts, images, file explorer styling, and custom CSS.
- Path-specific overrides for folders, files, and path-contains matching.
- Static CSS rules with custom properties scoped to active Markdown views and matching file paths.
@ -18,7 +18,7 @@ This plugin changes appearance by applying scoped CSS custom properties. Test pr
## Profiles and Default behavior
The Default profile represents native Obsidian styling with no Style Controller CSS. Stored profiles can be applied to the global settings or used as path-specific overrides. The active profile for a note is resolved from the global settings plus matching enabled overrides in their saved order.
The Default profile keeps native Obsidian styling except that inline-code and fenced-code backgrounds are actively set to `#fafafa`. Both fields can still be cleared independently to return that code type to native theme styling. Stored profiles can be applied to the global settings or used as path-specific overrides. The active profile for a note is resolved from the global settings plus matching enabled overrides in their saved order.
## Path overrides
@ -38,18 +38,18 @@ The plugin uses the packaged `styles.css`; it does not create runtime stylesheet
## Code background smoke test
1. Enable **Inline bg** and **Block bg**.
2. Set both to `#fafafa`.
3. Confirm inline and block previews visually match.
4. Inspect the visible fenced-code container and confirm `background-color` is `rgb(250, 250, 250)`.
5. Change only **Block bg** and confirm only fenced blocks change.
6. Turn **Block bg** Off and confirm native rendering returns.
7. Test reading view.
8. Test Live Preview.
9. Switch profiles and verify no stale background remains.
10. Open two notes with different path overrides and verify isolation.
11. Disable and re-enable the plugin and verify native styling is restored during cleanup.
12. Repeat in light and dark themes.
1. Reset the Default profile.
2. Confirm **Inline bg** shows `#fafafa` and On.
3. Confirm **Block bg** shows `#fafafa` and On.
4. Confirm inline and fenced previews visually match.
5. Inspect both computed backgrounds and confirm `rgb(250, 250, 250)`.
6. Create a new profile and confirm both defaults are On with `#fafafa`.
7. Turn **Block bg** Off and confirm fenced blocks return to native styling.
8. Turn it On with `#fafafa` and confirm that background returns.
9. Restart Obsidian and confirm the state persists.
10. Test reading view and Live Preview.
11. Test light and dark themes.
12. Confirm custom existing profile colors were not overwritten.
## Privacy and network behavior

View file

@ -1,7 +1,7 @@
{
"id": "style-controller",
"name": "Style Controller",
"version": "0.1.3",
"version": "0.1.4",
"minAppVersion": "1.13.0",
"description": "Manage reusable style profiles, path overrides, and visual settings through a native settings interface.",
"author": "JQML",

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "style-controller",
"version": "0.1.3",
"version": "0.1.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "style-controller",
"version": "0.1.3",
"version": "0.1.4",
"license": "MIT",
"devDependencies": {
"@types/node": "^20.11.30",

View file

@ -1,6 +1,6 @@
{
"name": "style-controller",
"version": "0.1.3",
"version": "0.1.4",
"description": "Manage reusable style profiles, path overrides, and visual settings through a native settings interface.",
"main": "main.js",
"scripts": {

View file

@ -11,6 +11,9 @@ import {
Modal
} from "obsidian";
const SETTINGS_SCHEMA_VERSION = 1;
const DEFAULT_CODE_BACKGROUND = "#fafafa";
const DEFAULT_PROFILE = {
fontFamily: "",
textSize: "",
@ -58,10 +61,10 @@ const DEFAULT_PROFILE = {
tableBorderColor: "",
tableRowAltBackground: "",
codeFontFamily: "",
codeBackground: "",
codeBackground: DEFAULT_CODE_BACKGROUND,
codeColor: "",
codeBlockFontFamily: "",
codeBlockBackground: "",
codeBlockBackground: DEFAULT_CODE_BACKGROUND,
codeBlockColor: "",
blockquoteBorderColor: "",
blockquoteBackground: "",
@ -71,6 +74,12 @@ const DEFAULT_PROFILE = {
customCss: ""
};
const LEGACY_DEFAULT_PROFILE = {
...DEFAULT_PROFILE,
codeBackground: "",
codeBlockBackground: ""
};
const DEFAULT_OVERRIDE_MODULES = {
baseText: false,
links: false,
@ -225,6 +234,7 @@ const PROFILE_GROUP_FIELDS = Object.entries(STYLE_FIELD_REGISTRY).reduce((groups
}, {});
const DEFAULT_SETTINGS = {
schemaVersion: SETTINGS_SCHEMA_VERSION,
enabled: true,
activeSettingsTab: "global",
global: DEFAULT_PROFILE,
@ -338,7 +348,7 @@ const OBSIDIAN_PRO_CONFIGURATION = {
const NATIVE_DEFAULT_CONFIGURATION = {
id: "builtin-native-default",
name: "Default",
description: "Native Obsidian styling with no Style Controller CSS.",
description: "Native Obsidian styling with active #fafafa inline-code and block-code backgrounds.",
data: createNativeConfigurationData()
};
@ -498,6 +508,9 @@ export default class StyleControllerPlugin extends Plugin {
async loadSettings() {
const loaded = await this.loadData();
this.settings = normalizeSettings(loaded);
if (Number(loaded?.schemaVersion || 0) < SETTINGS_SCHEMA_VERSION) {
await this.saveData(this.settings);
}
}
async saveSettings() {
@ -612,10 +625,15 @@ export default class StyleControllerPlugin extends Plugin {
};
function normalizeSettings(loaded) {
const settings = { ...DEFAULT_SETTINGS, ...(loaded || {}) };
const source = loaded && typeof loaded === "object" ? loaded : {};
const settings = { ...DEFAULT_SETTINGS, ...source };
settings.enabled = true;
settings.activeSettingsTab = settings.activeSettingsTab || "global";
settings.global = normalizeProfile(settings.global);
settings.global = Object.prototype.hasOwnProperty.call(source, "global")
? normalizeOptionalProfile(source.global)
: createDefaultProfile();
migrateLegacyDefaultCodeBackgrounds(source, settings);
settings.schemaVersion = SETTINGS_SCHEMA_VERSION;
settings.callouts = normalizeCallouts(settings.callouts);
settings.overrides = Array.isArray(settings.overrides)
? settings.overrides.map(normalizeOverride)
@ -650,7 +668,9 @@ function normalizeStoredConfiguration(config) {
function normalizeConfigurationData(data) {
return {
enabled: true,
global: normalizeProfile(data?.global),
global: data && Object.prototype.hasOwnProperty.call(data, "global")
? normalizeOptionalProfile(data.global)
: createDefaultProfile(),
callouts: normalizeCallouts(data?.callouts),
overrides: Array.isArray(data?.overrides) ? data.overrides.map(normalizeOverride) : []
};
@ -661,10 +681,36 @@ function isBuiltinConfigurationId(id) {
}
function normalizeProfile(profile) {
const source = profile || {};
const source = profile && typeof profile === "object" ? profile : DEFAULT_PROFILE;
return sanitizeProfile({ ...DEFAULT_PROFILE, ...source }, source);
}
function normalizeOptionalProfile(profile) {
const source = profile && typeof profile === "object" ? profile : {};
return sanitizeProfile({ ...blankProfileData(), ...source }, source);
}
function createDefaultProfile() {
return normalizeProfile(DEFAULT_PROFILE);
}
function migrateLegacyDefaultCodeBackgrounds(source, settings) {
if (Number(source.schemaVersion || 0) >= SETTINGS_SCHEMA_VERSION) return false;
const savedProfile = source.global;
if (!savedProfile || (!profileMatches(savedProfile, LEGACY_DEFAULT_PROFILE) && !profileMatches(savedProfile, blankProfileData()))) {
return false;
}
settings.global.codeBackground = DEFAULT_CODE_BACKGROUND;
settings.global.codeBlockBackground = DEFAULT_CODE_BACKGROUND;
return true;
}
function profileMatches(profile, expected) {
return Object.keys(DEFAULT_PROFILE).every((key) => (
String(profile?.[key] ?? "").trim() === String(expected[key] ?? "").trim()
));
}
function sanitizeProfile(profile, source = {}) {
const normalized = { ...profile };
const oldBaseDefaults =
@ -680,9 +726,6 @@ function sanitizeProfile(profile, source = {}) {
normalized.lineHeight = "";
}
if (!Object.prototype.hasOwnProperty.call(source, "codeBlockFontFamily")) normalized.codeBlockFontFamily = "";
if (!Object.prototype.hasOwnProperty.call(source, "codeBlockBackground")) normalized.codeBlockBackground = "";
if (!Object.prototype.hasOwnProperty.call(source, "codeBlockColor")) normalized.codeBlockColor = "";
normalized.imageAlignment = normalizeImageAlignment(normalized.imageAlignment);
normalized.imageWidth = normalizeCssSizeText(normalized.imageWidth);
normalized.imageRespectExplicitSize = normalizeImageRespectExplicitSize(normalized.imageRespectExplicitSize);
@ -702,7 +745,11 @@ function normalizeImageRespectExplicitSize(value) {
function createNativeConfigurationData() {
return normalizeConfigurationData({
enabled: true,
global: blankProfileData(),
global: {
...blankProfileData(),
codeBackground: DEFAULT_CODE_BACKGROUND,
codeBlockBackground: DEFAULT_CODE_BACKGROUND
},
callouts: blankObjectLike(DEFAULT_SETTINGS.callouts),
overrides: []
});
@ -1753,7 +1800,7 @@ class StyleControllerSettingTab extends PluginSettingTab {
const confirmed = await confirmWithModal(
this.app,
"Apply Default configuration?",
"This clears active Style Controller styling so the active theme regains control. Saved configurations will remain.",
"This restores native styling except for the active #fafafa inline-code and block-code backgrounds. Saved configurations will remain.",
"Apply Default"
);
if (!confirmed) return;
@ -1897,10 +1944,10 @@ class StyleControllerSettingTab extends PluginSettingTab {
["tableBorderColor", "Table border", "#3b4252"],
["tableRowAltBackground", "Alt row bg", "#151b22"],
["codeFontFamily", "Inline code font", "JetBrains Mono, Menlo, monospace"],
["codeBackground", "Inline code bg", "#1f2937"],
["codeBackground", "Inline code bg", DEFAULT_CODE_BACKGROUND],
["codeColor", "Inline code text", "#f8f8f2"],
["codeBlockFontFamily", "Code block font", "JetBrains Mono, Menlo, monospace"],
["codeBlockBackground", "Code block bg", "#1f2937"],
["codeBlockBackground", "Code block bg", DEFAULT_CODE_BACKGROUND],
["codeBlockColor", "Code block base text", "#f8f8f2"],
["blockquoteBorderColor", "Quote border", "#4f8cff"],
["blockquoteBackground", "Quote bg", "#111827"]
@ -2088,10 +2135,10 @@ class StyleControllerSettingTab extends PluginSettingTab {
["tableBorderColor", "Table border", "#3b4252"],
["tableRowAltBackground", "Alt row bg", "#151b22"],
["codeFontFamily", "Inline code font", "JetBrains Mono, Menlo, monospace"],
["codeBackground", "Inline code bg", "#1f2937"],
["codeBackground", "Inline code bg", DEFAULT_CODE_BACKGROUND],
["codeColor", "Inline code text", "#f8f8f2"],
["codeBlockFontFamily", "Code block font", "JetBrains Mono, Menlo, monospace"],
["codeBlockBackground", "Code block bg", "#1f2937"],
["codeBlockBackground", "Code block bg", DEFAULT_CODE_BACKGROUND],
["codeBlockColor", "Code block base text", "#f8f8f2"],
["blockquoteBorderColor", "Quote border", "#4f8cff"],
["blockquoteBackground", "Quote bg", "#111827"]
@ -2132,10 +2179,10 @@ class StyleControllerSettingTab extends PluginSettingTab {
this.renderControlSubsection(parent, "Code", profile, [
["codeFontFamily", "Inline font", "JetBrains Mono, Menlo, monospace"],
["codeBackground", "Inline bg", "#1f2937"],
["codeBackground", "Inline bg", DEFAULT_CODE_BACKGROUND],
["codeColor", "Inline text", "#f8f8f2"],
["codeBlockFontFamily", "Block font", "JetBrains Mono, Menlo, monospace"],
["codeBlockBackground", "Block bg", "#1f2937"],
["codeBlockBackground", "Block bg", DEFAULT_CODE_BACKGROUND],
["codeBlockColor", "Block base text", "#f8f8f2"]
], () => this.renderCodePreview(parent, profile));
@ -2772,9 +2819,13 @@ class StyleControllerSettingTab extends PluginSettingTab {
export {
BLOCK_CODE_BACKGROUND_SELECTORS,
BLOCK_CODE_TEXT_SELECTORS,
DEFAULT_CODE_BACKGROUND,
DEFAULT_PROFILE,
DEFAULT_SETTINGS,
INLINE_CODE_SELECTORS,
NATIVE_DEFAULT_CONFIGURATION,
PROFILE_FIELDS,
SETTINGS_SCHEMA_VERSION,
STYLE_FIELD_REGISTRY,
STYLE_SCOPE_CLASS,
applyProfileCssVariables,
@ -2782,7 +2833,12 @@ export {
clearProfileCssVariables,
configurationToExport,
createConfigurationSnapshot,
createDefaultProfile,
createNativeConfigurationData,
hasActiveValue,
migrateLegacyDefaultCodeBackgrounds,
normalizeHexColor,
normalizeOptionalProfile,
normalizeProfile,
normalizeSettings,
parseConfigurationImport

View file

@ -49,14 +49,22 @@ const {
default: StyleControllerPlugin,
BLOCK_CODE_BACKGROUND_SELECTORS,
BLOCK_CODE_TEXT_SELECTORS,
DEFAULT_CODE_BACKGROUND,
DEFAULT_PROFILE,
INLINE_CODE_SELECTORS,
NATIVE_DEFAULT_CONFIGURATION,
SETTINGS_SCHEMA_VERSION,
STYLE_FIELD_REGISTRY,
STYLE_SCOPE_CLASS,
applyProfileCssVariables,
clearProfileCssVariables,
configurationToExport,
createConfigurationSnapshot,
createDefaultProfile,
createNativeConfigurationData,
hasActiveValue,
normalizeHexColor,
normalizeOptionalProfile,
normalizeProfile,
normalizeSettings,
parseConfigurationImport
@ -139,6 +147,31 @@ test("inline and block code fields have independent authoritative registry entri
assert.ok(!inline.selectors.some((selector) => block.selectors.includes(selector)));
});
test("real default profiles actively enable #fafafa inline and block backgrounds", () => {
assert.equal(DEFAULT_CODE_BACKGROUND, "#fafafa");
assert.equal(DEFAULT_PROFILE.codeBackground, "#fafafa");
assert.equal(DEFAULT_PROFILE.codeBlockBackground, "#fafafa");
assert.equal(hasActiveValue(DEFAULT_PROFILE.codeBackground), true);
assert.equal(hasActiveValue(DEFAULT_PROFILE.codeBlockBackground), true);
const created = createDefaultProfile();
const newSettings = normalizeSettings(null);
const reset = createNativeConfigurationData();
const bundledDefault = NATIVE_DEFAULT_CONFIGURATION.data.global;
for (const profile of [created, newSettings.global, reset.global, bundledDefault]) {
assert.equal(profile.codeBackground, "#fafafa");
assert.equal(profile.codeBlockBackground, "#fafafa");
assert.equal(hasActiveValue(profile.codeBackground), true);
assert.equal(hasActiveValue(profile.codeBlockBackground), true);
}
const element = fakeElement();
applyProfileCssVariables(element, created);
assert.equal(element.css.get("--osc-code-background"), "#fafafa");
assert.equal(element.css.get("--osc-code-block-background"), "#fafafa");
});
test("identical #fafafa inline and block values survive normalize, save, load, export, and import", () => {
const fixture = {
codeFontFamily: "Menlo, monospace",
@ -166,12 +199,12 @@ test("identical #fafafa inline and block values survive normalize, save, load, e
test("block variable is applied when enabled and removed without a fallback when disabled or switched", () => {
const element = fakeElement();
const enabled = normalizeProfile({ codeBlockBackground: "#fafafa" });
const enabled = normalizeProfile({ codeBackground: "", codeBlockBackground: "#fafafa" });
applyProfileCssVariables(element, enabled);
assert.equal(element.css.get("--osc-code-block-background"), "#fafafa");
assert.equal(element.css.has("--osc-code-background"), false);
applyProfileCssVariables(element, normalizeProfile({ codeBackground: "#123456" }));
applyProfileCssVariables(element, normalizeProfile({ codeBackground: "#123456", codeBlockBackground: "" }));
assert.equal(element.css.has("--osc-code-block-background"), false);
assert.equal(element.css.get("--osc-code-background"), "#123456");
@ -180,6 +213,62 @@ test("block variable is applied when enabled and removed without a fallback when
assert.equal(element.css.has("--osc-code-background"), false);
});
test("legacy default migration is narrow, idempotent, and preserves later explicit Off", () => {
const legacyDefault = {
...DEFAULT_PROFILE,
codeBackground: "",
codeBlockBackground: ""
};
const migrated = normalizeSettings({ schemaVersion: 0, global: legacyDefault });
assert.equal(migrated.schemaVersion, SETTINGS_SCHEMA_VERSION);
assert.equal(migrated.global.codeBackground, "#fafafa");
assert.equal(migrated.global.codeBlockBackground, "#fafafa");
assert.deepEqual(normalizeSettings(migrated).global, migrated.global);
migrated.global.codeBackground = "";
migrated.global.codeBlockBackground = "";
const explicitlyOff = normalizeSettings(migrated);
assert.equal(explicitlyOff.global.codeBackground, "");
assert.equal(explicitlyOff.global.codeBlockBackground, "");
assert.equal(hasActiveValue(explicitlyOff.global.codeBackground), false);
assert.equal(hasActiveValue(explicitlyOff.global.codeBlockBackground), false);
const oldBundledDefault = Object.fromEntries(Object.keys(DEFAULT_PROFILE).map((key) => [key, ""]));
const migratedBundled = normalizeSettings({ global: oldBundledDefault });
assert.equal(migratedBundled.global.codeBackground, "#fafafa");
assert.equal(migratedBundled.global.codeBlockBackground, "#fafafa");
});
test("migration preserves custom values, customized profiles, imports, and optional overrides", () => {
const customized = {
...DEFAULT_PROFILE,
textColor: "#123456",
codeBackground: "",
codeBlockBackground: ""
};
const customProfile = normalizeSettings({ schemaVersion: 0, global: customized });
assert.equal(customProfile.global.codeBackground, "");
assert.equal(customProfile.global.codeBlockBackground, "");
const customColors = normalizeSettings({
schemaVersion: 0,
global: { ...DEFAULT_PROFILE, codeBackground: "#112233", codeBlockBackground: "#445566" }
});
assert.equal(customColors.global.codeBackground, "#112233");
assert.equal(customColors.global.codeBlockBackground, "#445566");
const imported = parseConfigurationImport(JSON.stringify({
name: "Custom code",
data: { global: { codeBackground: "#abcdef", codeBlockBackground: "" } }
}));
assert.equal(imported.data.global.codeBackground, "#abcdef");
assert.equal(imported.data.global.codeBlockBackground, "");
const optional = normalizeOptionalProfile({});
assert.equal(optional.codeBackground, "");
assert.equal(optional.codeBlockBackground, "");
});
test("path overrides resolve and apply independently per Markdown leaf", () => {
const settings = normalizeSettings({
global: { codeBlockBackground: "#fafafa" },

View file

@ -2,5 +2,6 @@
"0.1.0": "1.5.0",
"0.1.1": "1.13.0",
"0.1.2": "1.13.0",
"0.1.3": "1.13.0"
"0.1.3": "1.13.0",
"0.1.4": "1.13.0"
}