formalconf 2.0.20 → 2.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/formalconf.js +243 -22
  2. package/package.json +1 -1
@@ -1,12 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
3
7
  var __export = (target, all) => {
4
8
  for (var name in all)
5
9
  __defProp(target, name, {
6
10
  get: all[name],
7
11
  enumerable: true,
8
12
  configurable: true,
9
- set: (newValue) => all[name] = () => newValue
13
+ set: __exportSetter.bind(all, name)
10
14
  });
11
15
  };
12
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -457,7 +461,7 @@ async function isFirstRun() {
457
461
  const themesExist = await dirHasContents(THEMES_DIR);
458
462
  return !configsExist && !themesExist;
459
463
  }
460
- var HOME_DIR, CONFIG_DIR, THEME_TARGET_DIR, BACKGROUNDS_TARGET_DIR, scriptPath, ROOT_DIR, CONFIGS_DIR, THEMES_DIR, HOOKS_DIR, PKG_CONFIG_PATH, PKG_LOCK_PATH, THEME_CONFIG_PATH, TEMPLATES_DIR, TEMPLATES_MANIFEST_PATH, GENERATED_DIR, BUNDLED_TEMPLATES_DIR, BUNDLED_MANIFEST_PATH, GTK_DIR, COLLOID_DIR, QT_DIR, KVANTUM_CONFIG_DIR, KVANTUM_THEME_DIR;
464
+ var HOME_DIR, CONFIG_DIR, THEME_TARGET_DIR, BACKGROUNDS_TARGET_DIR, scriptPath, ROOT_DIR, CONFIGS_DIR, THEMES_DIR, HOOKS_DIR, PKG_CONFIG_PATH, PKG_LOCK_PATH, THEME_CONFIG_PATH, TEMPLATES_DIR, TEMPLATES_MANIFEST_PATH, GENERATED_DIR, BUNDLED_TEMPLATES_DIR, BUNDLED_MANIFEST_PATH, GTK_DIR, COLLOID_DIR, GTK_OVERRIDES_DIR, QT_DIR, KVANTUM_CONFIG_DIR, KVANTUM_THEME_DIR;
461
465
  var init_paths = __esm(() => {
462
466
  init_runtime();
463
467
  init_platform();
@@ -480,6 +484,7 @@ var init_paths = __esm(() => {
480
484
  BUNDLED_MANIFEST_PATH = join(BUNDLED_TEMPLATES_DIR, "templates.json");
481
485
  GTK_DIR = join(CONFIG_DIR, "gtk");
482
486
  COLLOID_DIR = join(GTK_DIR, "colloid-gtk-theme");
487
+ GTK_OVERRIDES_DIR = join(GTK_DIR, "overrides");
483
488
  QT_DIR = join(CONFIG_DIR, "qt");
484
489
  KVANTUM_CONFIG_DIR = join(HOME_DIR, ".config", "Kvantum");
485
490
  KVANTUM_THEME_DIR = join(KVANTUM_CONFIG_DIR, "FormalConf");
@@ -3026,6 +3031,8 @@ $default-dark: ${colloid.accent.dark};
3026
3031
  // src/lib/gtk/colloid.ts
3027
3032
  import { existsSync as existsSync7 } from "fs";
3028
3033
  import { join as join6 } from "path";
3034
+ import { symlink, unlink, lstat } from "fs/promises";
3035
+ import { homedir as homedir2 } from "os";
3029
3036
  async function checkGtkDependencies() {
3030
3037
  const [git, sassc] = await Promise.all([
3031
3038
  commandExists("git"),
@@ -3117,6 +3124,46 @@ function getGtkThemeName(themeName, mode) {
3117
3124
  const modeCapitalized = mode === "dark" ? "Dark" : "Light";
3118
3125
  return `formalconf-${themeName}-${modeCapitalized}`;
3119
3126
  }
3127
+ async function applyGtkOverride(overrideName, mode) {
3128
+ const overrideDir = join6(GTK_OVERRIDES_DIR, overrideName);
3129
+ if (!existsSync7(overrideDir)) {
3130
+ return {
3131
+ success: false,
3132
+ themeName: "",
3133
+ error: `GTK override "${overrideName}" not found in ${GTK_OVERRIDES_DIR}`
3134
+ };
3135
+ }
3136
+ const installTarget = join6(homedir2(), ".local", "share", "themes", overrideName);
3137
+ await ensureDir2(join6(homedir2(), ".local", "share", "themes"));
3138
+ try {
3139
+ const stat = await lstat(installTarget);
3140
+ if (stat.isSymbolicLink() || stat.isDirectory()) {
3141
+ await unlink(installTarget);
3142
+ }
3143
+ } catch {}
3144
+ await symlink(overrideDir, installTarget, "dir");
3145
+ const hasGsettings = await commandExists("gsettings");
3146
+ if (hasGsettings) {
3147
+ await exec([
3148
+ "gsettings",
3149
+ "set",
3150
+ "org.gnome.desktop.interface",
3151
+ "gtk-theme",
3152
+ overrideName
3153
+ ]);
3154
+ await exec([
3155
+ "gsettings",
3156
+ "set",
3157
+ "org.gnome.desktop.interface",
3158
+ "color-scheme",
3159
+ `prefer-${mode}`
3160
+ ]);
3161
+ }
3162
+ return {
3163
+ success: true,
3164
+ themeName: overrideName
3165
+ };
3166
+ }
3120
3167
  async function applyGtkTheme(theme, mode) {
3121
3168
  if (getOS() !== "linux") {
3122
3169
  return {
@@ -3126,6 +3173,10 @@ async function applyGtkTheme(theme, mode) {
3126
3173
  skipReason: "GTK theming only available on Linux"
3127
3174
  };
3128
3175
  }
3176
+ const overrideName = theme.gtk?.override?.[mode];
3177
+ if (overrideName) {
3178
+ return applyGtkOverride(overrideName, mode);
3179
+ }
3129
3180
  const palette = mode === "dark" ? theme.dark : theme.light;
3130
3181
  if (!palette) {
3131
3182
  return {
@@ -3622,6 +3673,7 @@ function hexToColorVariable(hex) {
3622
3673
  strip: normalized.slice(1),
3623
3674
  rgb: `rgb(${r},${g},${b})`,
3624
3675
  rgba: `rgba(${r},${g},${b},1)`,
3676
+ decimal: `${r},${g},${b}`,
3625
3677
  r,
3626
3678
  g,
3627
3679
  b,
@@ -3946,6 +3998,8 @@ function applyModifier(color, modifier) {
3946
3998
  return color.rgb;
3947
3999
  case "rgba":
3948
4000
  return color.rgba;
4001
+ case "decimal":
4002
+ return color.decimal;
3949
4003
  case "r":
3950
4004
  return String(color.r);
3951
4005
  case "g":
@@ -3979,6 +4033,7 @@ var init_modifiers = __esm(() => {
3979
4033
  "strip",
3980
4034
  "rgb",
3981
4035
  "rgba",
4036
+ "decimal",
3982
4037
  "r",
3983
4038
  "g",
3984
4039
  "b",
@@ -4240,9 +4295,14 @@ async function getOutputFilename(templateName) {
4240
4295
  return templateName.replace(/\.template$/, "");
4241
4296
  }
4242
4297
  async function getTemplateTargets(templateName) {
4243
- const manifest = await loadBundledManifest();
4244
- const meta = manifest.templates[templateName];
4245
- return meta?.targets ?? [];
4298
+ const installed = await loadTemplatesManifest();
4299
+ const installedMeta = installed.templates[templateName];
4300
+ if (installedMeta?.targets) {
4301
+ return installedMeta.targets;
4302
+ }
4303
+ const bundled = await loadBundledManifest();
4304
+ const bundledMeta = bundled.templates[templateName];
4305
+ return bundledMeta?.targets ?? [];
4246
4306
  }
4247
4307
  async function listInstalledTemplates() {
4248
4308
  if (!existsSync11(TEMPLATES_DIR)) {
@@ -5560,8 +5620,162 @@ var init_template_manager = __esm(() => {
5560
5620
  }
5561
5621
  });
5562
5622
 
5623
+ // src/cli/gtk-manager.ts
5624
+ var exports_gtk_manager = {};
5625
+ __export(exports_gtk_manager, {
5626
+ main: () => main6
5627
+ });
5628
+ import { parseArgs as parseArgs6 } from "util";
5629
+ import { existsSync as existsSync15, statSync as statSync2 } from "fs";
5630
+ import { join as join14, resolve, basename as basename5 } from "path";
5631
+ import { readdir as readdir2, rename, rm } from "fs/promises";
5632
+ import { tmpdir } from "os";
5633
+ function printHelp2() {
5634
+ console.log(`
5635
+ ${colors7.cyan}GTK Theme Manager - Manage pre-built GTK theme overrides${colors7.reset}
5636
+
5637
+ Usage:
5638
+ formalconf gtk <command> [options]
5639
+
5640
+ Commands:
5641
+ ${colors7.blue}import${colors7.reset} <path.tar.gz> Import a GTK theme from a tar.gz archive
5642
+ ${colors7.blue}list${colors7.reset} List installed GTK override themes
5643
+ ${colors7.blue}remove${colors7.reset} <name> Remove an installed GTK override theme
5644
+
5645
+ Options:
5646
+ -h, --help Show this help message
5647
+
5648
+ Examples:
5649
+ formalconf gtk import ~/Downloads/Kanagawa_Dark.tar.gz
5650
+ formalconf gtk list
5651
+ formalconf gtk remove "Kanagawa Dark"
5652
+ `);
5653
+ }
5654
+ async function main6() {
5655
+ const { positionals, values } = parseArgs6({
5656
+ args: process.argv.slice(2),
5657
+ options: {
5658
+ help: { type: "boolean", short: "h" }
5659
+ },
5660
+ allowPositionals: true,
5661
+ strict: false
5662
+ });
5663
+ const [subCommand, ...args] = positionals;
5664
+ if (values.help || !subCommand) {
5665
+ printHelp2();
5666
+ process.exit(0);
5667
+ }
5668
+ switch (subCommand) {
5669
+ case "import":
5670
+ if (!args[0]) {
5671
+ console.error(`${colors7.red}Error: Path to tar.gz file required${colors7.reset}`);
5672
+ process.exit(1);
5673
+ }
5674
+ await handleImport(args[0]);
5675
+ break;
5676
+ case "list":
5677
+ await handleList2();
5678
+ break;
5679
+ case "remove":
5680
+ if (!args[0]) {
5681
+ console.error(`${colors7.red}Error: Theme name required${colors7.reset}`);
5682
+ process.exit(1);
5683
+ }
5684
+ await handleRemove(args[0]);
5685
+ break;
5686
+ default:
5687
+ console.error(`${colors7.red}Unknown command: ${subCommand}${colors7.reset}`);
5688
+ printHelp2();
5689
+ process.exit(1);
5690
+ }
5691
+ }
5692
+ async function handleImport(archivePath) {
5693
+ const resolved = resolve(archivePath);
5694
+ if (!existsSync15(resolved)) {
5695
+ console.error(`${colors7.red}Error: File not found: ${resolved}${colors7.reset}`);
5696
+ process.exit(1);
5697
+ }
5698
+ if (!resolved.endsWith(".tar.gz") && !resolved.endsWith(".tgz")) {
5699
+ console.error(`${colors7.red}Error: File must be a .tar.gz or .tgz archive${colors7.reset}`);
5700
+ process.exit(1);
5701
+ }
5702
+ const tempDir = join14(tmpdir(), `formalconf-gtk-import-${Date.now()}`);
5703
+ await ensureDir2(tempDir);
5704
+ console.log(`${colors7.cyan}Extracting ${basename5(resolved)}...${colors7.reset}`);
5705
+ const extractResult = await exec(["tar", "xzf", resolved, "-C", tempDir]);
5706
+ if (!extractResult.success) {
5707
+ console.error(`${colors7.red}Error: Failed to extract archive${colors7.reset}`);
5708
+ await rm(tempDir, { recursive: true, force: true });
5709
+ process.exit(1);
5710
+ }
5711
+ const entries = await readdir2(tempDir);
5712
+ const dirs = entries.filter((entry) => statSync2(join14(tempDir, entry)).isDirectory());
5713
+ if (dirs.length === 0) {
5714
+ console.error(`${colors7.red}Error: Archive contains no directories${colors7.reset}`);
5715
+ await rm(tempDir, { recursive: true, force: true });
5716
+ process.exit(1);
5717
+ }
5718
+ await ensureDir2(GTK_OVERRIDES_DIR);
5719
+ for (const dir of dirs) {
5720
+ const sourcePath = join14(tempDir, dir);
5721
+ const destPath = join14(GTK_OVERRIDES_DIR, dir);
5722
+ if (existsSync15(destPath)) {
5723
+ await rm(destPath, { recursive: true, force: true });
5724
+ }
5725
+ await rename(sourcePath, destPath);
5726
+ console.log(`${colors7.green}Imported: ${dir}${colors7.reset}`);
5727
+ console.log(`${colors7.dim} Use in theme JSON: "gtk": { "override": { "dark": "${dir}" } }${colors7.reset}`);
5728
+ }
5729
+ await rm(tempDir, { recursive: true, force: true });
5730
+ }
5731
+ async function handleList2() {
5732
+ if (!existsSync15(GTK_OVERRIDES_DIR)) {
5733
+ console.log(`${colors7.dim}No GTK overrides installed${colors7.reset}`);
5734
+ return;
5735
+ }
5736
+ const entries = await readdir2(GTK_OVERRIDES_DIR);
5737
+ const dirs = entries.filter((entry) => statSync2(join14(GTK_OVERRIDES_DIR, entry)).isDirectory());
5738
+ if (dirs.length === 0) {
5739
+ console.log(`${colors7.dim}No GTK overrides installed${colors7.reset}`);
5740
+ return;
5741
+ }
5742
+ console.log(`
5743
+ ${colors7.cyan}Installed GTK overrides:${colors7.reset}`);
5744
+ for (const dir of dirs) {
5745
+ console.log(` ${colors7.blue}•${colors7.reset} ${dir}`);
5746
+ }
5747
+ console.log();
5748
+ }
5749
+ async function handleRemove(name) {
5750
+ const targetPath = join14(GTK_OVERRIDES_DIR, name);
5751
+ if (!existsSync15(targetPath)) {
5752
+ console.error(`${colors7.red}Error: Override "${name}" not found${colors7.reset}`);
5753
+ process.exit(1);
5754
+ }
5755
+ await rm(targetPath, { recursive: true, force: true });
5756
+ console.log(`${colors7.green}Removed: ${name}${colors7.reset}`);
5757
+ }
5758
+ var colors7, isMainModule6;
5759
+ var init_gtk_manager = __esm(() => {
5760
+ init_paths();
5761
+ init_runtime();
5762
+ colors7 = {
5763
+ red: "\x1B[0;31m",
5764
+ green: "\x1B[0;32m",
5765
+ blue: "\x1B[0;34m",
5766
+ yellow: "\x1B[1;33m",
5767
+ cyan: "\x1B[0;36m",
5768
+ dim: "\x1B[2m",
5769
+ reset: "\x1B[0m"
5770
+ };
5771
+ isMainModule6 = process.argv[1]?.includes("gtk-manager");
5772
+ if (isMainModule6) {
5773
+ main6().catch(console.error);
5774
+ }
5775
+ });
5776
+
5563
5777
  // src/cli/formalconf.tsx
5564
- import { parseArgs as parseArgs6 } from "node:util";
5778
+ import { parseArgs as parseArgs7 } from "node:util";
5565
5779
  import { useState as useState11, useEffect as useEffect7 } from "react";
5566
5780
  import { render, useApp as useApp2, useInput as useInput11 } from "ink";
5567
5781
  import { Spinner as Spinner2 } from "@inkjs/ui";
@@ -5704,7 +5918,7 @@ function StatusIndicator({
5704
5918
  // package.json
5705
5919
  var package_default = {
5706
5920
  name: "formalconf",
5707
- version: "2.0.20",
5921
+ version: "2.0.22",
5708
5922
  description: "Dotfiles management TUI for macOS and Linux - config management, package sync, and theme switching",
5709
5923
  type: "module",
5710
5924
  main: "./dist/formalconf.js",
@@ -7928,7 +8142,7 @@ function ThemeMenu({ onBack }) {
7928
8142
  init_paths();
7929
8143
  init_runtime();
7930
8144
  import { jsxDEV as jsxDEV20 } from "react/jsx-dev-runtime";
7931
- function printHelp2() {
8145
+ function printHelp3() {
7932
8146
  console.log(`
7933
8147
  FormalConf - Dotfiles Management TUI
7934
8148
 
@@ -7938,6 +8152,7 @@ Usage:
7938
8152
  formalconf config <cmd> Config management (stow, unstow, status, list)
7939
8153
  formalconf pkg-sync [flags] Sync packages from pkg-config.json
7940
8154
  formalconf template <cmd> Template management (update, list, check)
8155
+ formalconf gtk <cmd> GTK override management (import, list, remove)
7941
8156
 
7942
8157
  Options:
7943
8158
  -h, --help Show this help message
@@ -8023,8 +8238,8 @@ function App() {
8023
8238
  ]
8024
8239
  }, undefined, true, undefined, this);
8025
8240
  }
8026
- async function main6() {
8027
- const { positionals, values } = parseArgs6({
8241
+ async function main7() {
8242
+ const { positionals, values } = parseArgs7({
8028
8243
  args: process.argv.slice(2),
8029
8244
  options: {
8030
8245
  help: { type: "boolean", short: "h" }
@@ -8034,7 +8249,7 @@ async function main6() {
8034
8249
  });
8035
8250
  const [subcommand] = positionals;
8036
8251
  if (values.help && !subcommand) {
8037
- printHelp2();
8252
+ printHelp3();
8038
8253
  process.exit(0);
8039
8254
  }
8040
8255
  if (subcommand) {
@@ -8042,34 +8257,40 @@ async function main6() {
8042
8257
  theme: "set-theme",
8043
8258
  config: "config-manager",
8044
8259
  "pkg-sync": "pkg-sync",
8045
- template: "template-manager"
8260
+ template: "template-manager",
8261
+ gtk: "gtk-manager"
8046
8262
  };
8047
8263
  const scriptName = scriptMap[subcommand];
8048
8264
  if (!scriptName) {
8049
8265
  console.error(`Unknown subcommand: ${subcommand}`);
8050
- printHelp2();
8266
+ printHelp3();
8051
8267
  process.exit(1);
8052
8268
  }
8053
8269
  process.argv = [process.argv[0], scriptName, ...process.argv.slice(3)];
8054
8270
  switch (subcommand) {
8055
8271
  case "theme": {
8056
- const { main: main7 } = await Promise.resolve().then(() => (init_set_theme(), exports_set_theme));
8057
- await main7();
8272
+ const { main: main8 } = await Promise.resolve().then(() => (init_set_theme(), exports_set_theme));
8273
+ await main8();
8058
8274
  break;
8059
8275
  }
8060
8276
  case "config": {
8061
- const { main: main7 } = await Promise.resolve().then(() => (init_config_manager(), exports_config_manager));
8062
- await main7();
8277
+ const { main: main8 } = await Promise.resolve().then(() => (init_config_manager(), exports_config_manager));
8278
+ await main8();
8063
8279
  break;
8064
8280
  }
8065
8281
  case "pkg-sync": {
8066
- const { main: main7 } = await Promise.resolve().then(() => (init_pkg_sync(), exports_pkg_sync));
8067
- await main7();
8282
+ const { main: main8 } = await Promise.resolve().then(() => (init_pkg_sync(), exports_pkg_sync));
8283
+ await main8();
8068
8284
  break;
8069
8285
  }
8070
8286
  case "template": {
8071
- const { main: main7 } = await Promise.resolve().then(() => (init_template_manager(), exports_template_manager));
8072
- await main7();
8287
+ const { main: main8 } = await Promise.resolve().then(() => (init_template_manager(), exports_template_manager));
8288
+ await main8();
8289
+ break;
8290
+ }
8291
+ case "gtk": {
8292
+ const { main: main8 } = await Promise.resolve().then(() => (init_gtk_manager(), exports_gtk_manager));
8293
+ await main8();
8073
8294
  break;
8074
8295
  }
8075
8296
  }
@@ -8077,4 +8298,4 @@ async function main6() {
8077
8298
  }
8078
8299
  render(/* @__PURE__ */ jsxDEV20(App, {}, undefined, false, undefined, this));
8079
8300
  }
8080
- main6();
8301
+ main7();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "formalconf",
3
- "version": "2.0.20",
3
+ "version": "2.0.22",
4
4
  "description": "Dotfiles management TUI for macOS and Linux - config management, package sync, and theme switching",
5
5
  "type": "module",
6
6
  "main": "./dist/formalconf.js",