Reorganize imports

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2024-12-21 23:32:29 +02:00
parent 0ae56e6e25
commit 98ce774210
189 changed files with 253 additions and 260 deletions

View File

@@ -0,0 +1,2 @@
node_modules/
@girs/

View File

@@ -0,0 +1,23 @@
import { App } from "astal/gtk3"
import Bar from "./widget/Bar"
import { monitorFile } from "astal/file"
import { exec } from "astal/process"
import GLib from "gi://GLib"
const HOME = GLib.getenv("HOME")
const css = `${HOME}/.config/astal/theme.css`;
const scss = `${HOME}/.config/astal/theme.sass`;
monitorFile(scss, () => {
exec(`sassc ${scss} ${css}`);
App.apply_css(css, true);
});
exec(`sassc ${scss} ${css}`);
App.start({
css,
main() {
App.get_monitors().map(Bar)
},
})

View File

@@ -0,0 +1,26 @@
export const SRC: string
declare module "inline:*" {
const content: string
export default content
}
declare module "*.scss" {
const content: string
export default content
}
declare module "*.sass" {
const content: string
export default content
}
declare module "*.blp" {
const content: string
export default content
}
declare module "*.css" {
const content: string
export default content
}

View File

@@ -0,0 +1,3 @@
export const range = (length: number, start = 1) => {
return Array.from({ length }, (n, i) => i + start);
};

View File

@@ -0,0 +1,20 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"experimentalDecorators": true,
"strict": true,
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"jsxImportSource": "/nix/store/ii2w7wv88fjvmldn8kzz8ni20kzpkld4-astal-gjs/share/astal/gjs/gtk3",
"paths": {
"astal": [
"/nix/store/ii2w7wv88fjvmldn8kzz8ni20kzpkld4-astal-gjs/share/astal/gjs"
],
"astal/*": [
"/nix/store/ii2w7wv88fjvmldn8kzz8ni20kzpkld4-astal-gjs/share/astal/gjs/*"
]
},
}
}

View File

@@ -0,0 +1,29 @@
import { App, Astal, Gtk, Gdk } from 'astal/gtk3'
import Launcher from './components/Launcher';
import Workspace from './components/Workspaces';
import Date from './components/Date';
import Systray from './components/Tray';
const anchor = Astal.WindowAnchor.TOP
| Astal.WindowAnchor.LEFT
| Astal.WindowAnchor.RIGHT;
export default (monitor: Gdk.Monitor) => <window
className='bar'
gdkmonitor={monitor}
exclusivity={Astal.Exclusivity.EXCLUSIVE}
anchor={anchor}
application={App}>
<centerbox className='widgets'>
<box hexpand halign={Gtk.Align.START}>
<Launcher />
<Workspace />
</box>
<box hexpand halign={Gtk.Align.CENTER}>
<Date />
</box>
<box hexpand halign={Gtk.Align.END}>
<Systray />
</box>
</centerbox>
</window>

View File

@@ -0,0 +1,13 @@
import { Variable } from 'astal/variable';
import { GLib } from 'astal';
const time = Variable<string>("").poll(1000, () => GLib.DateTime.new_now_local().format('%H:%M - %A, %d %B %Y')!)
export default () => <button className='date'>
<label
className='label'
onDestroy={() => time.drop()}
label={time()}
/>
</button>;

View File

@@ -0,0 +1,7 @@
import { execAsync } from "astal/process"
export default () => <button
className="launcher"
onClickRelease={() => execAsync('bash -c "rofi -cache-dir $XDG_CACHE_HOME/rofi -show drun"')}>
<icon className="icon" icon="nix-snowflake-symbolic" />;
</button>;

View File

@@ -0,0 +1,30 @@
import { App, Gdk } from 'astal/gtk3'
import { bind } from 'astal'
import Tray from 'gi://AstalTray'
const tray = Tray.get_default()
const TrayButton = ({ item }: { item: Tray.TrayItem }) => {
const menu = item.create_menu();
return <button
className='item'
tooltipMarkup={bind(item, 'tooltipMarkup')}
onClickRelease={self => {
menu?.popup_at_widget(self, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null)
}}
onDestroy={() => menu?.destroy()}
>
<icon
className='icon'
gIcon={bind(item, 'gicon')} />
</button>;
}
export default () => <box className='systray'>
{
bind(tray, 'items').as(items => items.map(item => {
if (item.iconThemePath) App.add_icons(item.iconThemePath);
return <TrayButton item={item} />;
}))}
</box>;

View File

@@ -0,0 +1,44 @@
import { bind, Binding, Variable } from "astal";
import Hyprland from "gi://AstalHyprland";
import { range } from '../../lib';
const hyprland = Hyprland.get_default();
const Workspace = ({ id }: { id: number }) => {
const className = Variable.derive(
[bind(hyprland, "workspaces"), bind(hyprland, "focusedWorkspace")],
(workspaces, focused) => {
const workspace = workspaces.find((w) => w.id === id);
if (!workspace) return "button";
const occupied = workspace.get_clients().length > 0;
const active = focused.id === id;
return `button ${active ? "active" : occupied && "occupied"}`;
},
);
return <box vertical>
<box vexpand />
<eventbox
onClickRelease={() => hyprland.dispatch("workspace", `${id}`)}
>
<label
className={className()}
/>
</eventbox>
<box vexpand />
</box>;
};
export default () => <eventbox
className="workspaces"
onScroll={(_, e) => {
hyprland.dispatch("workspace", e.delta_y > 0 ? "+1" : "-1");
}}
>
<box>
{range(10).map((i) => <Workspace id={i} />)}
</box>
</eventbox>

View File

@@ -0,0 +1,43 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
inputs,
...
}:
{
home-manager.users.${user} = {
imports = [ inputs.ags.homeManagerModules.default ];
programs.ags = {
enable = true;
configDir = ./config;
systemd.enable = true;
extraPackages = with pkgs; [
inputs.ags.packages.${pkgs.system}.hyprland
inputs.ags.packages.${pkgs.system}.tray
sassc
hyprland
nixos-icons
(pkgs.callPackage ../cliphist/rofi.nix { })
];
};
theme.template."${home}/.config/astal/theme.sass".source = ./theme.sass;
systemd.user = {
targets.tray.Unit = {
BindsTo = [ "ags.service" ];
After = [
"graphical-session.target"
"ags.service"
];
};
};
};
}

View File

@@ -0,0 +1,73 @@
.bar
background-color: {{colors.surface.default.hex}}
@mixin interactive
min-height: {{custom.font_size}}pt
border-radius: .5 * {{custom.font_size}}pt
padding: 2pt
margin: 0 2pt 0
transition: .25s
background-color: {{colors.surface.default.hex}}
&:hover
background-color: {{colors.surface_container_high.default.hex}}
&:active
background-color: {{colors.surface_container_highest.default.hex}}
.widgets
padding: .2 * {{custom.padding}}pt
.launcher
@include interactive
min-width: {{custom.font_size}}pt
.icon
font-size: {{custom.font_size}}pt
padding: 0 .3 * {{custom.padding}}pt
color: {{colors.on_surface.default.hex}}
.workspaces
@include interactive
.button
font-size: 0
transition: .5s
margin: 0 .3 * {{custom.padding}}pt
background-color: {{colors.outline_variant.default.hex}}
min-width: .4 * {{custom.font_size}}pt
min-height: .4 * {{custom.font_size}}pt
border-radius: .5 * {{custom.font_size}}pt
&.occupied
background-color: {{colors.on_surface.default.hex}}
min-width: .6 * {{custom.font_size}}pt
min-height: .6 * {{custom.font_size}}pt
border-radius: .5 * {{custom.font_size}}pt
&.active
background-color: {{colors.primary.default.hex}}
min-width: 1.67 * {{custom.font_size}}pt
min-height: {{custom.font_size}}pt
border-radius: .4 * {{custom.font_size}}pt
.date
@include interactive
.label
color: {{colors.on_surface.default.hex}}
font-size: {{custom.font_size}}pt
font-family: {{custom.font_sans_serif_all}}
font-weight: 500
margin: 0 .5 * {{custom.padding}}pt
.systray
.item
@include interactive
.icon
font-size: {{custom.font_size}}pt
padding: 0 .3 * {{custom.padding}}pt
color: {{colors.on_surface.default.hex}}

View File

@@ -0,0 +1,18 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
services.blueman.enable = true;
home-manager.users.${user} = {
services.blueman-applet.enable = true;
systemd.user.services.blueman-applet.Unit.After = [ "graphical-session.target" ];
};
}

View File

@@ -0,0 +1,20 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ lib, pkgs, ... }:
{
users.users.${user}.extraGroups = [
"video"
"inputs"
];
home-manager.users.${user}.wayland.windowManager.hyprland.settings.bindle =
let
brightnessctl = lib.meta.getExe pkgs.brightnessctl;
in
[
", XF86MonBrightnessUp, exec, ${brightnessctl} -q s 5%+"
", XF86MonBrightnessDown, exec, ${brightnessctl} -q s 5%-"
];
}

View File

@@ -0,0 +1,29 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user} = {
programs.btop.settings.color_theme = "matugen";
theme = {
template."${home}/.config/btop/themes/matugen.theme".source = ./theme.theme;
reloadExtraConfig = "${
lib.meta.getExe (
pkgs.writeShellApplication {
name = "reload-btop";
runtimeInputs = with pkgs; [ procps ];
text = "exec pkill btop -SIGUSR2";
}
)
} &";
};
};
}

View File

@@ -0,0 +1,50 @@
theme[main_bg]="{{colors.surface.default.hex}}"
theme[main_fg]="{{colors.on_surface.default.hex}}"
theme[title]="{{colors.on_surface.default.hex}}"
theme[hi_fg]="{{colors.primary.default.hex}}"
theme[selected_bg]="{{colors.primary_container.default.hex}}"
theme[selected_fg]="{{colors.on_primary_container.default.hex}}"
theme[inactive_fg]="{{colors.surface_variant.default.hex}}"
theme[graph_text]="{{colors.on_surface_variant.default.hex}}"
theme[proc_misc]="{{colors.primary.default.hex}}"
theme[cpu_box]="{{colors.outline.default.hex}}"
theme[mem_box]="{{colors.outline.default.hex}}"
theme[net_box]="{{colors.outline.default.hex}}"
theme[proc_box]="{{colors.outline.default.hex}}"
theme[div_line]="{{colors.outline_variant.default.hex}}"
theme[temp_start]="{{colors.primary.default.hex}}"
theme[temp_mid]=""
theme[temp_end]="{{colors.error.default.hex}}"
theme[cpu_start]="{{colors.primary.default.hex}}"
theme[cpu_mid]=""
theme[cpu_end]="{{colors.error.default.hex}}"
theme[used_start]="{{colors.primary.default.hex}}"
theme[used_mid]=""
theme[used_end]="{{colors.secondary.default.hex}}"
theme[available_start]="{{colors.tertiary.default.hex}}"
theme[available_mid]=""
theme[available_end]="{{colors.secondary.default.hex}}"
theme[cached_start]="{{colors.primary.default.hex}}"
theme[cached_mid]=""
theme[cached_end]="{{colors.secondary.default.hex}}"
theme[free_start]="{{colors.tertiary.default.hex}}"
theme[free_mid]=""
theme[free_end]="{{colors.secondary.default.hex}}"
theme[download_start]="{{colors.primary.default.hex}}"
theme[download_mid]=""
theme[download_end]="{{colors.secondary.default.hex}}"
theme[upload_start]="{{colors.primary.default.hex}}"
theme[upload_mid]=""
theme[upload_end]="{{colors.tertiary.default.hex}}"

View File

@@ -0,0 +1,21 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user} = {
services.cbatticon = {
enable = true;
lowLevelPercent = 20;
criticalLevelPercent = 10;
};
systemd.user.services.cbatticon.Unit.After = [ "graphical-session.target" ];
};
}

View File

@@ -0,0 +1,44 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, ... }:
{
programs.chromium = {
enable = true;
extraOpts = {
DefaultSearchProviderEnabled = true;
DefaultSearchProviderName = "DuckDuckGo";
DefaultSearchProviderIconURL = "https://duckduckgo.com/favicon.ico";
DefaultSearchProviderSearchURL = "https://duckduckgo.com/?q={searchTerms}";
DefaultSearchProviderSuggestURL = "https://duckduckgo.com/ac/?q={searchTerms}&type=list";
DefaultBrowserSettingEnabled = false;
DefaultDownloadDirectory = "$HOME/Downloads";
PasswordManagerEnabled = false;
HomepageIsNewTabPage = true;
};
};
environment.persistence = {
"/persist"."${home}/.config/chromium" = { };
"/cache"."${home}/.cache/chromium" = { };
};
home-manager.users.${user} = {
programs.chromium = {
enable = true;
extensions = [
"oldceeleldhonbafppcapldpdifcinji" # LanguageTool
"nngceckbapebfimnlniiiahkandclblb" # Bitwarden
"eimadpbcbfnmbkopoojfekhnkhdbieeh" # Dark Reader
"doojmbjmlfjjnbmnoijecmcbfeoakpjm" # NoScript
"gebbhagfogifgggkldgodflihgfeippi" # Return YouTube Dislike
"mnjggcdmjocbbbhaepdhchncahnbgone" # Sponsorblock
"cjpalhdlnbpafiamejdnhcphjbkeiagm" # uBlock Origin
"jinjaccalgkegednnccohejagnlnfdag" # Violentmonkey
"fpnmgdkabkmnadcjpehmlllkndpkmiak" # Wayback Machine
];
};
};
}

View File

@@ -0,0 +1,85 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
environment.persistence."/cache"."${home}/.cache/cliphist" = { };
home-manager.users.${user} = {
home.packages = with pkgs; [
wl-clipboard
cliphist
];
systemd.user.services = {
cliphist = {
Unit = {
Description = "Clipboard manager";
BindsTo = [ "graphical-session.target" ];
After = [
"graphical-session.target"
config.environment.persistence."/cache"."${home}/.cache/cliphist".mount
];
};
Service.ExecStart = lib.meta.getExe (
pkgs.writeShellApplication {
name = "init-cliphist";
runtimeInputs = with pkgs; [
wl-clipboard
cliphist
];
text = "exec wl-paste --watch cliphist store";
}
);
Install.WantedBy = [ "graphical-session.target" ];
};
cliphist-image = {
Unit = {
Description = "Clipboard manager (images)";
BindsTo = [ "graphical-session.target" ];
After = [
"graphical-session.target"
config.environment.persistence."/cache"."${home}/.cache/cliphist".mount
];
};
Service.ExecStart = lib.meta.getExe (
pkgs.writeShellApplication {
name = "init-cliphist-image";
runtimeInputs = with pkgs; [
wl-clipboard
cliphist
];
text = "exec wl-paste --type image --watch cliphist store";
}
);
Install.WantedBy = [ "graphical-session.target" ];
};
};
wayland.windowManager.hyprland.settings.bind =
let
cliphist-rofi = lib.meta.getExe (
pkgs.callPackage ./rofi.nix { rofi = hmConfig.programs.rofi.finalPackage; }
);
cliphist = lib.meta.getExe pkgs.cliphist;
in
[
"$mod, v, exec, ${cliphist-rofi}"
"$mod_Ctrl, v, exec, ${cliphist} wipe"
];
};
}

View File

@@ -0,0 +1,31 @@
{
rofi ? throw "rofi package is required",
lib,
pkgs,
...
}:
let
copy = lib.meta.getExe (
pkgs.writeShellApplication {
name = "copy";
runtimeInputs = with pkgs; [
cliphist
wl-clipboard
];
text = builtins.readFile ./scripts/copy.sh;
}
);
delete = lib.meta.getExe (
pkgs.writeShellApplication {
name = "delete";
runtimeInputs = with pkgs; [ cliphist ];
text = builtins.readFile ./scripts/delete.sh;
}
);
in
pkgs.writeShellApplication {
name = "cliphist-rofi";
runtimeInputs = [ rofi ];
text = "rofi -modi \"copy:${copy},delete:${delete}\" -show copy";
}

View File

@@ -0,0 +1,13 @@
list() {
echo -en "\0keep-selection\x1ftrue\n"
cliphist list
}
handle() {
cliphist decode <<< "$1" | wl-copy
}
case ${ROFI_RETV} in
0) list ;;
1) handle "$@" ;;
esac

View File

@@ -0,0 +1,13 @@
list() {
echo -en "\0keep-selection\x1ftrue\n"
cliphist list
}
handle() {
cliphist delete <<< "$1"
}
case ${ROFI_RETV} in
0) list ;;
1) handle "$@" && list ;;
esac

View File

@@ -0,0 +1,265 @@
diff --git a/data/darktableconfig.xml.in b/data/darktableconfig.xml.in
index 83eadf8a35..39ed8d43d7 100644
--- a/data/darktableconfig.xml.in
+++ b/data/darktableconfig.xml.in
@@ -1524,6 +1524,22 @@
<longdescription>file naming pattern used for a import session</longdescription>
</dtconfig>
+ <dtconfig prefs="import" section="session">
+ <name>session/conflict_padding</name>
+ <type>int</type>
+ <default>2</default>
+ <shortdescription>burst file name conflict number padding</shortdescription>
+ <longdescription>set the padding length for conflict resolution (e.g., 001, 002).</longdescription>
+ </dtconfig>
+
+ <dtconfig prefs="import" section="session">
+ <name>session/import_existing_sidecar</name>
+ <type>bool</type>
+ <default>true</default>
+ <shortdescription>import existing sidecar files</shortdescription>
+ <longdescription>import existing sidecar files (XMP, IPTC, etc.) when importing images</longdescription>
+ </dtconfig>
+
<dtconfig>
<name>plugins/lighttable/layout</name>
<type>int</type>
diff --git a/src/common/import_session.c b/src/common/import_session.c
index e83ef4de62..4d0c4efa0c 100644
--- a/src/common/import_session.c
+++ b/src/common/import_session.c
@@ -266,48 +266,42 @@ const char *dt_import_session_filename(struct dt_import_session_t *self, gboolea
char *pattern = _import_session_filename_pattern();
if(pattern == NULL)
{
- dt_print(DT_DEBUG_ALWAYS, "[import_session] Failed to get session filaname pattern.\n");
+ dt_print(DT_DEBUG_ALWAYS, "[import_session] Failed to get session filename pattern.\n");
return NULL;
}
+ self->vp->retry_count = 0;
+
/* verify that expanded path and filename yields a unique file */
const char *path = dt_import_session_path(self, TRUE);
if(use_filename)
result_fname = g_strdup(self->vp->filename);
else
- result_fname = _import_session_filename_from_pattern(self, pattern);
-
- char *fname = g_build_path(G_DIR_SEPARATOR_S, path, result_fname, (char *)NULL);
- char *previous_fname = fname;
- if(g_file_test(fname, G_FILE_TEST_EXISTS) == TRUE)
{
- dt_print(DT_DEBUG_ALWAYS, "[import_session] File %s exists.\n", fname);
do
{
- /* file exists, yield a new filename */
+ /* generate filename based on the current retry_count */
g_free(result_fname);
result_fname = _import_session_filename_from_pattern(self, pattern);
- fname = g_build_path(G_DIR_SEPARATOR_S, path, result_fname, (char *)NULL);
- dt_print(DT_DEBUG_ALWAYS, "[import_session] Testing %s.\n", fname);
- /* check if same filename was yielded as before */
- if(strcmp(previous_fname, fname) == 0)
+ char *test_path = g_build_path(G_DIR_SEPARATOR_S, path, result_fname, (char *)NULL);
+
+ if(g_file_test(test_path, G_FILE_TEST_EXISTS) == TRUE)
{
- g_free(previous_fname);
- g_free(fname);
- dt_control_log(_(
- "couldn't expand to a unique filename for session, please check your import session settings."));
- return NULL;
+ dt_print(DT_DEBUG_ALWAYS, "[import_session] File %s exists, retrying.\n", test_path);
+ self->vp->retry_count++;
+ g_free(test_path);
+ }
+ else
+ {
+ g_free(test_path);
+ break;
}
- g_free(previous_fname);
- previous_fname = fname;
-
- } while(g_file_test(fname, G_FILE_TEST_EXISTS) == TRUE);
+ } while(TRUE);
}
- g_free(previous_fname);
g_free(pattern);
self->current_filename = result_fname;
diff --git a/src/common/variables.c b/src/common/variables.c
index 1474cc32e8..820f88414b 100644
--- a/src/common/variables.c
+++ b/src/common/variables.c
@@ -914,6 +914,14 @@ static char *_get_base_value(dt_variables_params_t *params, char **variable)
else if(_has_prefix(variable, "DARKTABLE.NAME")
|| _has_prefix(variable, "DARKTABLE_NAME"))
result = g_strdup(PACKAGE_NAME);
+
+ else if(_has_prefix(variable, "CONFLICT_PADDING"))
+ {
+ int pad_length = dt_conf_get_int("session/conflict_padding");
+ if(pad_length < 0) pad_length = 0;
+ result = g_strdup_printf("%0*u", pad_length, params->retry_count);
+ }
+
else
{
// go past what looks like an invalid variable. we only expect to
diff --git a/src/common/variables.h b/src/common/variables.h
index 86052a9a3d..a5d616a94c 100644
--- a/src/common/variables.h
+++ b/src/common/variables.h
@@ -29,6 +29,9 @@ typedef struct dt_variables_params_t
/** used for expanding variables that uses filename $(FILE_FOLDER) $(FILE_NAME) and $(FILE_EXTENSION). */
const gchar *filename;
+ /** used for conflict resolution in filename expansion */
+ int retry_count;
+
/** used for expanding variable $(JOBCODE) */
const gchar *jobcode;
diff --git a/src/control/jobs/control_jobs.c b/src/control/jobs/control_jobs.c
index a9fab6f0ea..27bceab782 100644
--- a/src/control/jobs/control_jobs.c
+++ b/src/control/jobs/control_jobs.c
@@ -1566,7 +1566,7 @@ static int32_t dt_control_export_job_run(dt_job_t *job)
{
// IPTC character encoding not set by user, so we set the default utf8 here
settings->metadata_export = dt_util_dstrcat(settings->metadata_export,
- "\1%s\1%s",
+ "\1%s\1%s",
iptc_envelope_characterset,
"\x1b%G"); // ESC % G
}
@@ -2265,6 +2265,59 @@ void dt_control_write_sidecar_files()
FALSE));
}
+static gboolean _copy_file(const char *source, const char *destination)
+{
+ gchar *data = NULL;
+ gsize size = 0;
+
+ if(!g_file_get_contents(source, &data, &size, NULL))
+ {
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to read file `%s`", source);
+ return FALSE;
+ }
+
+ if(!g_file_set_contents(destination, data, size, NULL))
+ {
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to write file `%s`", destination);
+ g_free(data);
+ return FALSE;
+ }
+
+ g_free(data);
+ return TRUE;
+}
+
+static void _copy_timestamps(const char *source, const char *destination)
+{
+ struct stat statbuf;
+ if(stat(source, &statbuf) == 0)
+ {
+#ifdef _WIN32
+ struct utimbuf times;
+ times.actime = statbuf.st_atime;
+ times.modtime = statbuf.st_mtime;
+ utime(destination, &times);
+#else
+ struct timeval times[2];
+ times[0].tv_sec = statbuf.st_atime;
+ times[1].tv_sec = statbuf.st_mtime;
+#ifdef __APPLE__
+#ifndef _POSIX_SOURCE
+ times[0].tv_usec = statbuf.st_atimespec.tv_nsec * 0.001;
+ times[1].tv_usec = statbuf.st_mtimespec.tv_nsec * 0.001;
+#else
+ times[0].tv_usec = statbuf.st_atimensec * 0.001;
+ times[1].tv_usec = statbuf.st_mtimensec * 0.001;
+#endif
+#else
+ times[0].tv_usec = statbuf.st_atim.tv_nsec * 0.001;
+ times[1].tv_usec = statbuf.st_mtim.tv_nsec * 0.001;
+#endif
+ utimes(destination, times);
+#endif
+ }
+}
+
static int _control_import_image_copy(const char *filename,
char **prev_filename,
char **prev_output,
@@ -2308,37 +2361,37 @@ static int _control_import_image_copy(const char *filename,
g_free(basename);
}
- if(!g_file_set_contents(output, data, size, NULL))
+ if(!_copy_file(filename, output))
{
- dt_print(DT_DEBUG_CONTROL, "[import_from] failed to write file %s\n", output);
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to copy file %s", filename);
res = FALSE;
}
else
{
-#ifdef _WIN32
- struct utimbuf times;
- times.actime = statbuf.st_atime;
- times.modtime = statbuf.st_mtime;
- utime(output, &times); // set origin file timestamps
-#else
- struct timeval times[2];
- times[0].tv_sec = statbuf.st_atime;
- times[1].tv_sec = statbuf.st_mtime;
-#ifdef __APPLE__
-#ifndef _POSIX_SOURCE
- times[0].tv_usec = statbuf.st_atimespec.tv_nsec * 0.001;
- times[1].tv_usec = statbuf.st_mtimespec.tv_nsec * 0.001;
-#else
- times[0].tv_usec = statbuf.st_atimensec * 0.001;
- times[1].tv_usec = statbuf.st_mtimensec * 0.001;
-#endif
-#else
- times[0].tv_usec = statbuf.st_atim.tv_nsec * 0.001;
- times[1].tv_usec = statbuf.st_mtim.tv_nsec * 0.001;
-#endif
- utimes(output, times); // set origin file timestamps
-#endif
+ _copy_timestamps(filename, output);
+ }
+ gboolean import_existing_sidecar = dt_conf_get_bool("session/import_existing_sidecar");
+ if(import_existing_sidecar)
+ {
+ char *xml_filename = g_strdup_printf("%s.xmp", filename);
+ if(g_file_test(xml_filename, G_FILE_TEST_EXISTS))
+ {
+ char *xml_output = g_strdup_printf("%s.xmp", output);
+ if(_copy_file(xml_filename, xml_output))
+ _copy_timestamps(xml_filename, xml_output);
+ else
+ {
+ dt_print(DT_DEBUG_CONTROL, "[import_from] failed to copy sidecar %s", xml_filename);
+ res = FALSE;
+ }
+ g_free(xml_output);
+ }
+ g_free(xml_filename);
+ }
+
+ if(res)
+ {
const dt_imgid_t imgid = dt_image_import(dt_import_session_film_id(session),
output, FALSE, FALSE);
if(!imgid) dt_control_log(_("error loading file `%s'"), output);

View File

@@ -0,0 +1,56 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
nixpkgs.overlays = [
(final: prev: {
darktable = prev.darktable.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [ ./better-copy-and-import.patch ];
});
})
];
environment.persistence = {
"/persist"."${home}/.config/darktable" = { };
"/cache"."${home}/.cache/darktable" = { };
};
home-manager.users.${user} =
let
hald-clut = pkgs.fetchFromGitHub {
owner = "cedeber";
repo = "hald-clut";
rev = "3b3180f82d4dcea1e6e8c5648473539a910d7f49";
sha256 = "sha256-R8vyYmcsfk49QsSV3v0QblXcO6U0oIfDyxbHPLwSMdo=";
};
in
{
home.packages = with pkgs; [ darktable ];
xdg.configFile = {
"darktable/darktablerc".source = (pkgs.formats.keyValue { }).generate "darktablerc" {
"compress_xmp_tags" = "never";
"database/create_snapshot" = "once a day";
"rating_one_double_tap" = true;
"run_crawler_on_start" = true;
"ui_last/theme" = "darktable-elegant-darker";
"ui_last/grouping" = true;
"plugins/darkroom/lut3d/def_path" = "${home}/.config/darktable/luts";
"opencl" = false;
"plugins/lighttable/overlays/1/0" = 0;
"plugins/lighttable/overlays/1/1" = 3;
"plugins/lighttable/overlays/1/2" = 3;
"plugins/darkroom/modulegroups/last_preset" = "modules: all";
"session/base_directory_pattern" = "${home}/Pictures/Darktable";
"session/filename_pattern" =
"$(EXIF.YEAR)-$(EXIF.MONTH)-$(EXIF.DAY)_$(EXIF.HOUR)-$(EXIF.MINUTE)-$(EXIF.SECOND)_$(CONFLICT_PADDING).$(FILE_EXTENSION)";
"session/sub_directory_pattern" = "";
"setup_import_directory" = true;
};
"darktable/luts".source = "${hald-clut}/HaldCLUT";
};
};
}

View File

@@ -0,0 +1,73 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ lib, pkgs, ... }:
{
nixpkgs.overlays = [
(final: prev: {
vesktop = prev.vesktop.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [ ./readonly-fix.patch ];
});
})
];
environment.persistence = {
"/persist"."${home}/.config/vesktop" = { };
"/cache" = {
"${home}/.config/vesktop/sessionData/Cache" = { };
"${home}/.config/vesktop/sessionData/Code Cache" = { };
"${home}/.config/vesktop/sessionData/DawnGraphiteCache" = { };
"${home}/.config/vesktop/sessionData/DawnWebGPUCache" = { };
"${home}/.config/vesktop/sessionData/GPUCache" = { };
};
};
home-manager.users.${user} = {
home.packages = with pkgs; [ vesktop ];
xdg.configFile."vesktop/state.json".source = (pkgs.formats.json { }).generate "state.json" {
firstLaunch = false;
};
xdg.configFile."vesktop/settings.json".source = (pkgs.formats.json { }).generate "settings.json" {
discordBranch = "stable";
minimizeToTray = false;
arRPC = false;
};
xdg.configFile."vesktop/settings/settings.json".source =
(pkgs.formats.json { }).generate "settings.json"
{
autoUpdate = false;
tray = false;
plugins = {
MessageEventsAPI.enabled = true;
MessageUpdaterAPI.enabled = true;
UserSettingsAPI.enabled = true;
AlwaysTrust.enabled = true;
BetterGifAltText.enabled = true;
BetterRoleContext = {
enabled = true;
roleIconFileFormat = "png";
};
ClearURLs.enabled = true;
FakeNitro.enabled = true;
MessageClickActions.enabled = true;
MessageLogger = {
enabled = true;
deleteStyle = "overlay";
};
NoF1.enabled = true;
NoOnboardingDelay.enabled = true;
NoReplyMention = {
enabled = true;
userList = "";
};
};
enabledThemes = [ "matugen.theme.css" ];
};
theme.template."${home}/.config/vesktop/themes/matugen.theme.css".source = ./theme.css;
};
}

View File

@@ -0,0 +1,17 @@
diff --git a/src/main/settings.ts b/src/main/settings.ts
index 6fad97f..dfc64e3 100644
--- a/src/main/settings.ts
+++ b/src/main/settings.ts
@@ -26,8 +26,10 @@ function loadSettings<T extends object = any>(file: string, name: string) {
const store = new SettingsStore(settings);
store.addGlobalChangeListener(o => {
- mkdirSync(dirname(file), { recursive: true });
- writeFileSync(file, JSON.stringify(o, null, 4));
+ try {
+ mkdirSync(dirname(file), { recursive: true });
+ writeFileSync(file, JSON.stringify(o, null, 4));
+ } catch {}
});
return store;

View File

@@ -0,0 +1,76 @@
/*
@name Matugen
@author Matugen
@version 0.0.1
@description Theme configured via NixOS or Home Manager.
*/
.theme-dark {
--bg-overlay-2: {{colors.surface_container_high.dark.hex}};
--home-background: {{colors.surface_container_high.dark.hex}};
--background-primary: {{colors.surface_container_high.dark.hex}};
--background-secondary: {{colors.surface_container.dark.hex}};
--background-secondary-alt: {{colors.surface_container.dark.hex}};
--background-accent: {{colors.surface_container.dark.hex}};
--background-modifier-hover: {{colors.surface_container.dark.hex}};
--background-tertiary: {{colors.surface_container_low.dark.hex}};
--background-floating: {{colors.surface_container_low.dark.hex}};
--background-modifier-selected: {{colors.primary_container.dark.hex}};
--background-modifier-accent: {{colors.outline_variant.dark.hex}};
--channeltextarea-background: {{colors.surface_container.dark.hex}};
--text-normal: {{colors.on_surface.dark.hex}};
--text-secondary: {{colors.on_surface_variant.dark.hex}};
--text-muted: {{colors.outline.dark.hex}};
--text-link: {{colors.primary.dark.hex}};
--interactive-normal: {{colors.on_surface.dark.hex}};
--interactive-hover: {{colors.on_surface.dark.hex}};
--interactive-active: {{colors.on_primary_container.dark.hex}};
--interactive-muted: {{colors.outline_variant.dark.hex}};
--channels-default: {{colors.outline.dark.hex}};
--channel-icon: {{colors.outline.dark.hex}};
--header-primary: {{colors.on_surface.dark.hex}};
--header-secondary: {{colors.on_surface_variant.dark.hex}};
}
.theme-light {
--bg-overlay-2: {{colors.surface_container_high.light.hex}};
--home-background: {{colors.surface_container_high.light.hex}};
--background-primary: {{colors.surface_container_high.light.hex}};
--background-secondary: {{colors.surface_container.light.hex}};
--background-secondary-alt: {{colors.surface_container.light.hex}};
--background-accent: {{colors.surface_container.light.hex}};
--background-modifier-hover: {{colors.surface_container.light.hex}};
--background-tertiary: {{colors.surface_container_low.light.hex}};
--background-floating: {{colors.surface_container_low.light.hex}};
--background-modifier-selected: {{colors.primary_container.light.hex}};
--background-modifier-accent: {{colors.outline_variant.light.hex}};
--channeltextarea-background: {{colors.surface_container.light.hex}};
--text-normal: {{colors.on_surface.light.hex}};
--text-secondary: {{colors.on_surface_variant.light.hex}};
--text-muted: {{colors.outline.light.hex}};
--text-link: {{colors.primary.light.hex}};
--interactive-normal: {{colors.on_surface.light.hex}};
--interactive-hover: {{colors.on_surface.light.hex}};
--interactive-active: {{colors.on_primary_container.light.hex}};
--interactive-muted: {{colors.outline_variant.light.hex}};
--channels-default: {{colors.outline.light.hex}};
--channel-icon: {{colors.outline.light.hex}};
--header-primary: {{colors.on_surface.light.hex}};
--header-secondary: {{colors.on_surface_variant.light.hex}};
}

View File

@@ -0,0 +1,23 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
home-manager.users.${user} = {
programs.rofi.plugins = with pkgs; [ rofi-emoji-wayland ];
wayland.windowManager.hyprland.settings.bind = [
# Super + Shift + :
"$mod_Shift, code:47, exec, ${lib.meta.getExe hmConfig.programs.rofi.finalPackage} -cache-dir ${home}/.cache/rofi -modi emoji -show emoji"
];
};
}

View File

@@ -0,0 +1,101 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ lib, pkgs, ... }:
{
environment.persistence = {
"/persist"."${home}/.mozilla" = { };
"/cache"."${home}/.cache/mozilla" = { };
};
home-manager.users.${user} = {
programs.firefox = {
enable = true;
policies = {
DisableTelemetry = true;
DisableFirefoxStudies = true;
DontCheckDefaultBrowser = true;
DisablePocket = true;
DefaultDownloadDirectory = "$HOME/Downloads";
OfferToSaveLogins = false;
AutofillAddressEnabled = false;
AutofillCreditCardEnabled = false;
Preferences = {
"browser.aboutConfig.showWarning" = false;
"browser.contentblocking.category" = "strict";
"browser.download.useDownloadDir" = false;
"browser.newtabpage.activity-stream.feeds.section.topstories" = false;
"browser.newtabpage.activity-stream.showSponsored" = false;
"browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
"browser.toolbars.bookmarks.visibility" = true;
"browser.sessionstore.restore_on_demand" = true;
"browser.sessionstore.restore_pinned_tabs_on_demand" = false;
"browser.translations.automaticallyPopup" = false;
};
};
profiles.default = {
settings."extensions.autoDisableScopes" = 0;
extensions = with pkgs.nur.repos.rycee.firefox-addons; [
languagetool
bitwarden
darkreader
noscript
sponsorblock
ublock-origin
violentmonkey
wayback-machine
];
search = {
default = "DuckDuckGo";
privateDefault = "DuckDuckGo";
order = [
"DuckDuckGo"
"Google"
"Wikipedia (en)"
"Nix Packages"
"Nix Options"
"Home Manager Options"
];
force = true;
engines = {
"Google".metaData.alias = "@g";
"DuckDuckGo".metaData.alias = "@d";
"Wikipedia (en)".metaData.alias = "@w";
"Nix" = {
urls = [
{
template = "https://mynixos.com/search";
params = [
{
name = "q";
value = "{searchTerms}";
}
];
}
];
icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
definedAliases = [ "@n" ];
};
};
};
};
};
xdg.mimeApps.defaultApplications = lib.attrsets.genAttrs [
"text/html"
"x-scheme-handler/http"
"x-scheme-handler/https"
"x-scheme-handler/about"
"x-scheme-handler/unknown"
] (_: "firefox.desktop");
home.sessionVariables.DEFAULT_BROWSER = lib.meta.getExe pkgs.firefox;
wayland.windowManager.hyprland.settings.bind = [ "$mod, b, exec, ${lib.meta.getExe pkgs.firefox}" ];
};
}

View File

@@ -0,0 +1,85 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
environment.persistence."/persist" = {
"${home}/.steam" = { };
"${home}/.local/share/Steam" = { };
};
programs = {
steam = {
enable = true;
localNetworkGameTransfers.openFirewall = true;
extest.enable = true;
protontricks.enable = true;
};
gamescope = {
enable = true;
args = [
"--rt"
"-f"
];
};
gamemode.enable = true;
};
home-manager.users.${user} = {
systemd.user = {
services.steam-ln =
let
steamLn = lib.meta.getExe (
pkgs.writeShellApplication {
name = "steam-ln";
runtimeInputs = with pkgs; [ coreutils ];
text = builtins.readFile ./scripts/steam-ln.sh;
}
);
in
{
Unit = {
Description = "Sync Steam games with Games directory";
After = [
config.environment.persistence."/persist"."${home}/.local/share/Steam".mount
config.environment.persistence."/persist"."${home}/Games".mount
];
DefaultDependencies = false;
};
Service = {
ExecStart = steamLn;
Type = "oneshot";
};
Install.WantedBy = [ "graphical-session.target" ];
};
paths.steam-ln = {
Unit = {
Description = "Monitor Steam games directory for changes";
After = [
config.environment.persistence."/persist"."${home}/.local/share/Steam".mount
config.environment.persistence."/persist"."${home}/Games".mount
];
};
Path.PathChanged = "${home}/.local/share/Steam/steamapps/common";
Install.WantedBy = [ "graphical-session.target" ];
};
};
home = {
packages = with pkgs; [ protonup ];
sessionVariables.STEAM_EXTRA_COMPAT_TOOLS_PATHS = "${home}/.steam/root/compatibilitytools.d";
};
};
}

View File

@@ -0,0 +1,57 @@
STEAM="${HOME}/.local/share/Steam/steamapps/common"
GAMES="${HOME}/Games"
EXCLUDE=(
"Proton - Experimental"
"SteamLinuxRuntime_sniper"
"Steamworks Shared"
"Steam.dll"
)
is_excluded() {
local dir=$1
for exclude in "${EXCLUDE[@]}"; do
if [[ "${dir}" == "${exclude}" ]]; then
return 0
fi
done
return 1
}
for game in "${STEAM}"/*/; do
name=$(basename "${game}")
if is_excluded "${name}"; then
echo "Excluding ${name} from symlink creation."
continue
fi
if [[ -L "${GAMES}/${name}" ]]; then
continue
fi
if [[ -d "${GAMES}/${name}" || -f "${GAMES}/${name}" ]]; then
>&2 echo "Error: ${name} is already a regular directory or file."
continue
fi
echo "Creating symlink for ${name}..."
ln -s "${game}" "${GAMES}/${name}"
done
for link in "${GAMES}"/*; do
target=$(readlink "${link}")
if [[ ! "${target}" == "${STEAM}/"* ]]; then
continue
fi
name=$(basename "${target}")
if [[ -e "${target}" ]] && ! is_excluded "${name}"; then
continue
fi
echo "Removing symlink ${link}..."
rm "${link}"
done

View File

@@ -0,0 +1,108 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
# FIXME: https://github.com/lassekongo83/adw-gtk3/issues/267
nixpkgs.overlays = [
(final: prev: {
adw-gtk3 = prev.adw-gtk3.overrideAttrs (oldAttrs: rec {
pname = "adw-gtk3";
version = "5.3";
src = pkgs.fetchFromGitHub {
owner = "lassekongo83";
repo = pname;
rev = "v${version}";
sha256 = "sha256-DpJLX9PJX1Q8dDOx7YOXQzgNECsKp5uGiCVTX6iSlbI=";
};
});
})
];
home-manager.users.${user} = {
gtk = {
enable = true;
theme = {
package = pkgs.adw-gtk3;
name = "adw-gtk3-dark";
};
font = {
name = builtins.head hmConfig.theme.font.sansSerif.names;
package = builtins.head hmConfig.theme.font.sansSerif.packages;
inherit (hmConfig.theme.font) size;
};
iconTheme = {
name = builtins.head hmConfig.theme.icon.names;
package = builtins.head hmConfig.theme.icon.packages;
};
gtk2.configLocation = "${home}/.config/gtk-2.0/gtkrc";
gtk3.extraCss = "@import './theme.css';";
gtk4.extraCss = "@import './theme.css';";
};
home = {
pointerCursor.gtk.enable = true;
file =
{
".icons/default/index.theme".enable = false;
}
// builtins.listToAttrs (
builtins.map (name: {
name = ".icons/${name}";
value.enable = false;
}) (hmConfig.theme.icon.names ++ hmConfig.theme.cursor.names)
);
};
theme.template = {
"${home}/.config/gtk-3.0/theme.css".source = ./theme.css;
"${home}/.config/gtk-4.0/theme.css".source = ./theme.css;
};
theme.initExtraConfig = "${
lib.meta.getExe (
pkgs.writeShellApplication {
name = "theme-gtk";
runtimeInputs = with pkgs; [
dbus
dconf
];
text = ''
MODE=$(cat "${hmConfig.theme.configDir}/mode")
if [ "$MODE" = "light" ]; then
GTK_THEME="adw-gtk3"
else
GTK_THEME="adw-gtk3-dark"
fi
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
DCONF_DBUS_RUN_SESSION=""
else
DCONF_DBUS_RUN_SESSION="dbus-run-session --dbus-daemon=dbus-daemon"
fi
$DCONF_DBUS_RUN_SESSION bash -c "
dconf write /org/gnome/desktop/interface/gtk-theme \"'$GTK_THEME'\"
dconf write /org/gnome/desktop/interface/color-scheme \"'prefer-$MODE'\"
"
'';
}
)
} &";
};
}

View File

@@ -0,0 +1,48 @@
@define-color window_bg_color alpha({{colors.surface.default.hex}}, {{custom.opacity}});
@define-color window_fg_color {{colors.on_surface.default.hex}};
@define-color view_bg_color @window_bg_color;
@define-color view_fg_color @window_fg_color;
@define-color accent_bg_color {{colors.primary_container.default.hex}};
@define-color accent_fg_color {{colors.on_primary_container.default.hex}};
@define-color accent_color {{colors.primary.default.hex}};
@define-color headerbar_bg_color @window_bg_color;
@define-color headerbar_fg_color @window_fg_color;
@define-color headerbar_backdrop_color alpha({{colors.surface_variant.default.hex}}, {{custom.opacity}});
@define-color headerbar_shade_color {{colors.shadow.default.hex}};
@define-color card_bg_color alpha({{colors.surface_container.default.hex}}, {{custom.opacity}});
@define-color card_fg_color {{colors.on_surface_variant.default.hex}};
@define-color card_shade_color {{colors.shadow.default.hex}};
@define-color popover_bg_color @window_bg_color;
@define-color popover_fg_color @window_fg_color;
@define-color dialog_bg_color @window_bg_color;
@define-color dialog_fg_color @window_fg_color;
@define-color sidebar_bg_color @card_bg_color;
@define-color sidebar_fg_color @card_fg_color;
@define-color sidebar_backdrop_color alpha({{colors.surface_variant.default.hex}}, {{custom.opacity}});
@define-color sidebar_shade_color @card_shade_color;
@define-color warning_bg_color {{colors.warning_container.default.hex}};
@define-color warning_fg_color {{colors.on_warning_container.default.hex}};
@define-color warning_color {{colors.warning.default.hex}};
@define-color error_bg_color {{colors.error_container.default.hex}};
@define-color error_fg_color {{colors.on_error_container.default.hex}};
@define-color error_color {{colors.error.default.hex}};
@define-color success_bg_color {{colors.success_container.default.hex}};
@define-color success_fg_color {{colors.on_success_container.default.hex}};
@define-color success_color {{colors.success.default.hex}};
@define-color destructive_bg_color {{colors.danger_container.default.hex}};
@define-color destructive_fg_color {{colors.on_danger_container.default.hex}};
@define-color destructive_color {{colors.danger.default.hex}};
@define-color panel_bg_color @window_bg_color;
@define-color panel_fg_color @window_fg_color;

View File

@@ -0,0 +1,156 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
programs.hyprland.enable = true;
home-manager.users.${user} = {
imports = [ ./options.nix ];
wayland.windowManager.hyprland = {
enable = true;
settings = {
"$mod" = "Super_L";
"$term" = lib.meta.getExe pkgs.kitty;
bind = [
"$mod, Return, exec, $term"
"$mod, `, togglespecialworkspace"
"$mod, 1, workspace, 1"
"$mod, 2, workspace, 2"
"$mod, 3, workspace, 3"
"$mod, 4, workspace, 4"
"$mod, 5, workspace, 5"
"$mod, 6, workspace, 6"
"$mod, 7, workspace, 7"
"$mod, 8, workspace, 8"
"$mod, 9, workspace, 9"
"$mod, 0, workspace, 10"
"$mod_Shift, `, movetoworkspacesilent, special"
"$mod_Shift, 1, movetoworkspacesilent, 1"
"$mod_Shift, 2, movetoworkspacesilent, 2"
"$mod_Shift, 3, movetoworkspacesilent, 3"
"$mod_Shift, 4, movetoworkspacesilent, 4"
"$mod_Shift, 5, movetoworkspacesilent, 5"
"$mod_Shift, 6, movetoworkspacesilent, 6"
"$mod_Shift, 7, movetoworkspacesilent, 7"
"$mod_Shift, 8, movetoworkspacesilent, 8"
"$mod_Shift, 9, movetoworkspacesilent, 9"
"$mod_Shift, 0, movetoworkspacesilent, 10"
"$mod_Ctrl, Space, workspaceopt, allfloat"
"$mod, left, movefocus, l"
"$mod, h, movefocus, l"
"$mod, down, movefocus, d"
"$mod, j, movefocus, d"
"$mod, up, movefocus, u"
"$mod, k, movefocus, u"
"$mod, right, movefocus, r"
"$mod, l, movefocus, r"
"$mod_Shift, left, movewindow, l"
"$mod_Shift, h, movewindow, l"
"$mod_Shift, down, movewindow, d"
"$mod_Shift, j, movewindow, d"
"$mod_Shift, up, movewindow, u"
"$mod_Shift, k, movewindow, u"
"$mod_Shift, right, movewindow, r"
"$mod_Shift, l, movewindow, r"
"$mod, Tab, cyclenext"
"$mod, Tab, bringactivetotop"
"$mod_Shift, Tab, cyclenext, prev"
"$mod_Shift, Tab, bringactivetotop"
"$mod, f, fullscreen, 0"
"$mod, m, fullscreen, 1"
"$mod, p, pin"
"$mod, Space, togglefloating"
"$mod, Space, centerwindow"
"$mod, q, killactive"
"Ctrl_Alt, Delete, exit"
];
binde = [
"$mod_Ctrl, left, resizeactive, -20 0"
"$mod_Ctrl, h, resizeactive, -20 0"
"$mod_Ctrl, down, resizeactive, 0 20"
"$mod_Ctrl, j, resizeactive, 0 20"
"$mod_Ctrl, up, resizeactive, 0 -20"
"$mod_Ctrl, k, resizeactive, 0 -20"
"$mod_Ctrl, right, resizeactive, 20 0"
"$mod_Ctrl, l, resizeactive, 20 0"
];
bindm = [
"$mod, mouse:272, movewindow"
"$mod, mouse:273, resizewindow"
];
input = {
accel_profile = "flat";
kb_layout = "us,gr";
kb_options = "grp:alt_shift_toggle";
};
gestures = {
workspace_swipe = true;
workspace_swipe_min_fingers = true;
workspace_swipe_forever = true;
workspace_swipe_cancel_ratio = 0.2;
};
misc = {
disable_hyprland_logo = true;
disable_splash_rendering = true;
new_window_takes_over_fullscreen = 2;
};
decoration.blur = {
passes = 2;
popups = true;
};
input.touchpad.natural_scroll = true;
xwayland.force_zero_scaling = true;
};
extraConfig = "source = ./theme.conf";
};
programs.zsh.loginExtra = lib.mkAfter ''
if [ -z "$WAYLAND_DISPLAY" ] && [ -n "$XDG_VTNR" ] && [ "$XDG_VTNR" -eq 1 ]; then
Hyprland &> /tmp/hyprland.log
fi
'';
theme = {
template."${home}/.config/hypr/theme.conf".source = ./theme.conf;
reloadExtraConfig = "${
lib.meta.getExe (
pkgs.writeShellApplication {
name = "reload-hyprland";
runtimeInputs = with pkgs; [ hyprland ];
text = "exec hyprctl reload";
}
)
} &";
};
home.sessionVariables.NIXOS_OZONE_WL = "1";
};
}

View File

@@ -0,0 +1,43 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.wayland.windowManager.hyprland;
in
{
options.wayland.windowManager.hyprland =
with lib;
with types;
{
initExtraConfig = mkOption {
type = lines;
default = "";
description = "Extra configuration lines to add to exec-once";
};
reloadExtraConfig = mkOption {
type = lines;
default = "";
description = "Extra configuration lines to add to exec";
};
};
config = {
wayland.windowManager.hyprland.settings.exec-once = lib.meta.getExe (
pkgs.writeShellApplication {
name = "init-hyprland";
text = cfg.initExtraConfig;
}
);
wayland.windowManager.hyprland.settings.exec = lib.meta.getExe (
pkgs.writeShellApplication {
name = "reload-hyprland";
text = cfg.reloadExtraConfig;
}
);
};
}

View File

@@ -0,0 +1,25 @@
general {
gaps_in = {{custom.padding}}
gaps_out = {{custom.padding_double}}
col.inactive_border = rgba({{colors.surface.default.hex_stripped}}{{custom.opacity_hex | to_lower}})
col.active_border = rgb({{colors.primary.default.hex_stripped}})
}
decoration {
rounding = {{custom.radius}}
shadow {
color = rgba({{colors.shadow.default.hex_stripped}}{{custom.opacity_shadow_hex | to_lower}})
}
blur {
size = {{custom.blur}}
}
}
misc {
col.splash = rgb({{colors.on_surface.default.hex_stripped}})
background_color = rgb({{colors.surface.default.hex_stripped}})
font_family = {{custom.font_sans_serif}}
splash_font_family = {{custom.font_monospace}}
}

View File

@@ -0,0 +1,42 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user} = {
home = {
packages = with pkgs; [
hyprshot
swappy
];
sessionVariables.HYPRSHOT_DIR = "Pictures/screenshots";
};
wayland.windowManager.hyprland.settings.bind =
let
hyprshot = lib.meta.getExe pkgs.hyprshot;
date = "${pkgs.coreutils}/bin/date";
filename = "\"$(${date} +'%Y-%m-%d-%H%M%S.png')\"";
swappyWrapper = lib.meta.getExe (
pkgs.writeShellApplication {
name = "swappy-wrapper";
runtimeInputs = with pkgs; [ swappy ];
text = "exec swappy -f \"$1\"";
}
);
in
[
", Print, exec, ${hyprshot} -m output -m active -f ${filename}"
"Shift, Print, exec, ${hyprshot} -m output -m active -f ${filename} -- ${swappyWrapper}"
", XF86SelectiveScreenshot, exec, ${hyprshot} -m region -z -f ${filename}"
"Shift, XF86SelectiveScreenshot, exec, ${hyprshot} -m region -z -f ${filename} -- ${swappyWrapper}"
];
};
}

View File

@@ -0,0 +1,47 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
environment.persistence."/cache"."${home}/.cache/kitty" = { };
home-manager.users.${user} = {
programs.kitty = {
enable = true;
font = {
name = builtins.head hmConfig.theme.font.monospace.names;
package = builtins.head hmConfig.theme.font.monospace.packages;
inherit (hmConfig.theme.font) size;
};
extraConfig = ''
confirm_os_window_close 0
include theme.conf
'';
};
theme = {
template."${home}/.config/kitty/theme.conf".source = ./theme.conf;
reloadExtraConfig = "${
lib.meta.getExe (
pkgs.writeShellApplication {
name = "reload-kitty";
runtimeInputs = with pkgs; [ procps ];
text = "exec pkill kitty -SIGUSR1";
}
)
} &";
};
};
}

View File

@@ -0,0 +1,29 @@
background_tint 0.0
background_opacity {{custom.opacity}}
background {{colors.surface.default.hex}}
foreground {{colors.on_surface.default.hex}}
selection_background {{colors.primary.default.hex}}
selection_foreground {{colors.on_primary.default.hex}}
url_color {{colors.tertiary.default.hex}}
cursor {{colors.on_surface.default.hex}}
color0 {{colors.surface.default.hex}}
color1 {{colors.red.default.hex}}
color2 {{colors.green.default.hex}}
color3 {{colors.yellow.default.hex}}
color4 {{colors.blue.default.hex}}
color5 {{colors.magenta.default.hex}}
color6 {{colors.cyan.default.hex}}
color7 {{colors.on_surface.default.hex}}
color8 {{colors.outline_variant.default.hex}}
color9 {{colors.red.default.hex | set_lightness: 5.0}}
color10 {{colors.green.default.hex | set_lightness: 5.0}}
color11 {{colors.yellow.default.hex | set_lightness: 5.0}}
color12 {{colors.blue.default.hex | set_lightness: 5.0}}
color13 {{colors.magenta.default.hex | set_lightness: 5.0}}
color14 {{colors.cyan.default.hex | set_lightness: 5.0}}
color15 {{colors.on_surface_variant.default.hex}}

View File

@@ -0,0 +1,39 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
environment.persistence = {
"/persist"."${home}/.config/libreoffice/4/user" = { };
"/cache"."${home}/.config/libreoffice/4/cache" = { };
};
home-manager.users.${user} = {
home.packages = with pkgs; [
libreoffice-fresh
hunspell
hunspellDicts.en-us-large
hunspellDicts.el-gr
];
xdg.configFile."libreoffice/4/user/registrymodifications.xcu" = {
force = true;
text = ''
<?xml version="1.0" encoding="UTF-8"?>
<oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="ShowTipOfTheDay" oor:op="fuse"><value>false</value></prop></item>
<item oor:path="/org.openoffice.Office.Common/Misc"><prop oor:name="FirstRun" oor:op="fuse"><value>false</value></prop></item>
<item oor:path="/org.openoffice.Setup/Office"><prop oor:name="ooSetupInstCompleted" oor:op="fuse"><value>true</value></prop></item>
<item oor:path="/org.openoffice.Setup/Product"><prop oor:name="ooSetupLastVersion" oor:op="fuse"><value>${lib.lists.last (lib.strings.splitString "/" pkgs.libreoffice-fresh.meta.changelog)}</value></prop></item>
<item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeDonateShown" oor:op="fuse"><value>0</value></prop></item>
<item oor:path="/org.openoffice.Setup/Product"><prop oor:name="LastTimeGetInvolvedShown" oor:op="fuse"><value>0</value></prop></item>
'';
};
};
}

View File

@@ -0,0 +1,12 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user} = {
home.packages = with pkgs; [ networkmanagerapplet ];
services.network-manager-applet.enable = true;
systemd.user.services.network-manager-applet.Unit.After = [ "graphical-session.target" ];
};
}

View File

@@ -0,0 +1,45 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, pkgs, ... }:
let
hmConfig = config.home-manager.users.${user};
in
{
boot = {
kernelModules = [ "v4l2loopback" ];
extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ];
extraModprobeConfig = ''
options v4l2loopback devices=1 video_nr=1 card_label="OBS Cam" exclusive_caps=1
'';
};
environment.persistence = {
"/persist"."${home}/.config/obs-studio" = { };
};
home-manager.users.${user} = {
imports = [ ./options.nix ];
programs.obs-studio.enable = true;
xdg.configFile."obs-studio/basic/profiles/Untitled/basic.ini".source =
(pkgs.formats.ini { }).generate "basic.ini"
{
SimpleOutput = {
FilePath = "${home}/Videos";
VBitrate = 4000;
ABitrate = 320;
RecEncoder = "nvenc_hevc";
FileNameWithoutSpace = true;
};
Video = with hmConfig.programs.obs-studio.resolution; {
BaseCX = base.x;
BaseCY = base.y;
OutputCX = output.x;
OutputCY = output.y;
};
};
};
}

View File

@@ -0,0 +1,31 @@
{ lib, ... }:
{
options.programs.obs-studio.resolution =
with lib;
with types;
{
base = {
x = mkOption {
type = int;
description = "Base resolution width.";
};
y = mkOption {
type = int;
description = "Base resolution height.";
};
};
output = {
x = mkOption {
type = int;
description = "Output resolution width.";
};
y = mkOption {
type = int;
description = "Output resolution height.";
};
};
};
}

View File

@@ -0,0 +1,3 @@
!*/.obsidian/bookmarks.json
*/.obsidian
.nomedia

View File

@@ -0,0 +1,27 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.better-word-count";
version = "0.10.1";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "8ff00d7e9aed03d8cf38215b742a2a2251cc2ea2";
# owner = "lukeleppan";
repo = "better-word-count";
# rev = version;
hash = "sha256-wA0vycuUHr7icgAJ/d85j3bbwqlefXnSyRUXgCmqyOE=";
};
patches = [ ./package-lock.patch ];
makeCacheWritable = true;
npmDepsHash = "sha256-K+NGIKsSNzGHGcAofsl0WcNsTFt/y38zUdGUZL013xg=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./dist/main.js $out/main.js
cp ./src/styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,35 @@
diff --git a/package-lock.json b/package-lock.json
index 3fa99a5..71302ec 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,7 @@
},
"devDependencies": {
"@codemirror/commands": "^6.1.2",
- "@codemirror/language": "https://github.com/lishid/cm-language",
+ "@codemirror/language": "https://github.com/karaolidis/cm-language#package-lock",
"@codemirror/search": "^6.2.2",
"@codemirror/state": "^6.1.2",
"@codemirror/view": "^6.4.0",
@@ -49,7 +49,7 @@
},
"node_modules/@codemirror/language": {
"version": "6.10.1",
- "resolved": "git+ssh://git@github.com/lishid/cm-language.git#2644bfc27afda707a7e1f3aedaf3ca7120f63cd9",
+ "resolved": "git+ssh://git@github.com/karaolidis/cm-language.git#d6238f0a9e17e20d604cee67a47d3a93b00dd41c",
"dev": true,
"dependencies": {
"@codemirror/state": "^6.0.0",
diff --git a/package.json b/package.json
index 2537f1e..ba6bfff 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,7 @@
"license": "MIT",
"devDependencies": {
"@codemirror/commands": "^6.1.2",
- "@codemirror/language": "https://github.com/lishid/cm-language",
+ "@codemirror/language": "https://github.com/karaolidis/cm-language#package-lock",
"@codemirror/search": "^6.2.2",
"@codemirror/state": "^6.1.2",
"@codemirror/view": "^6.4.0",

View File

@@ -0,0 +1,30 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.custom-sort";
version = "2.1.14";
src = pkgs.fetchFromGitHub {
owner = "SebastianMC";
repo = "obsidian-custom-sort";
rev = version;
hash = "sha256-DM2aKCsFC2Z4a/ZX95ZMBzshBx2C2Z8a7j94ABS2UGI=";
};
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-RdR+S6WQj2AAoxJnAowNa1etr/Xfp6HnhM7rMYJh8o8=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./dist/main.js $out/main.js
'';
}

View File

@@ -0,0 +1,25 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.dataview";
version = "0.5.67";
src = pkgs.fetchFromGitHub {
owner = "blacksmithgu";
repo = "obsidian-dataview";
rev = version;
hash = "sha256-AbK1J1a8bqkPCe9dqADAfR/q/j/kRGa8qouj9GJQErc=";
};
patches = [ ./package-lock.patch ];
makeCacheWritable = true;
npmDepsHash = "sha256-FsPLpWcS27VWrDm5G1ZT6zvfOfYmKNLHzmjiXEmpGKE=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./build/main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,90 @@
diff --git a/package-lock.json b/package-lock.json
index 0c1b0bd..df26135 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,15 +1,15 @@
{
"name": "obsidian-dataview",
- "version": "0.5.66",
+ "version": "0.5.67",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "obsidian-dataview",
- "version": "0.5.66",
+ "version": "0.5.67",
"license": "MIT",
"dependencies": {
- "@codemirror/language": "https://github.com/lishid/cm-language",
+ "@codemirror/language": "https://github.com/karaolidis/cm-language#package-lock",
"@codemirror/state": "^6.0.1",
"@codemirror/view": "^6.0.1",
"emoji-regex": "^10.0.0",
@@ -687,29 +687,28 @@
"dev": true
},
"node_modules/@codemirror/language": {
- "version": "6.6.0",
- "resolved": "git+ssh://git@github.com/lishid/cm-language.git#1aadcc247f20ccfda76424a9f853dbb4ee203fdc",
- "license": "MIT",
+ "version": "6.10.1",
+ "resolved": "git+ssh://git@github.com/karaolidis/cm-language.git#d6238f0a9e17e20d604cee67a47d3a93b00dd41c",
"dependencies": {
"@codemirror/state": "^6.0.0",
- "@codemirror/view": "^6.0.0",
- "@lezer/common": "^1.0.0",
+ "@codemirror/view": "^6.23.0",
+ "@lezer/common": "^1.1.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0",
"style-mod": "^4.0.0"
}
},
"node_modules/@codemirror/state": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.1.tgz",
- "integrity": "sha512-RupHSZ8+OjNT38zU9fKH2sv+Dnlr8Eb8sl4NOnnqz95mCFTZUaiRP8Xv5MeeaG0px2b8Bnfe7YGwCV3nsBhbuw=="
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz",
+ "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A=="
},
"node_modules/@codemirror/view": {
- "version": "6.19.0",
- "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.19.0.tgz",
- "integrity": "sha512-XqNIfW/3GaaF+T7Q1jBcRLCPm1NbrR2DBxrXacSt1FG+rNsdsNn3/azAfgpUoJ7yy4xgd8xTPa3AlL+y0lMizQ==",
+ "version": "6.28.4",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.28.4.tgz",
+ "integrity": "sha512-QScv95fiviSQ/CaVGflxAvvvDy/9wi0RFyDl4LkHHWiMr/UPebyuTspmYSeN5Nx6eujcPYwsQzA6ZIZucKZVHQ==",
"dependencies": {
- "@codemirror/state": "^6.1.4",
+ "@codemirror/state": "^6.4.0",
"style-mod": "^4.1.0",
"w3c-keyname": "^2.2.4"
}
@@ -1133,9 +1132,9 @@
}
},
"node_modules/@lezer/common": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.4.tgz",
- "integrity": "sha512-lZHlk8p67x4aIDtJl6UQrXSOP6oi7dQR3W/geFVrENdA1JDaAJWldnVqVjPMJupbTKbzDfFcePfKttqVidS/dg=="
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz",
+ "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ=="
},
"node_modules/@lezer/highlight": {
"version": "1.1.6",
diff --git a/package.json b/package.json
index db15b53..d3605a0 100644
--- a/package.json
+++ b/package.json
@@ -47,7 +47,7 @@
"rollup-plugin-web-worker-loader": "^1.6.1"
},
"dependencies": {
- "@codemirror/language": "https://github.com/lishid/cm-language",
+ "@codemirror/language": "https://github.com/karaolidis/cm-language#package-lock",
"@codemirror/state": "^6.0.1",
"@codemirror/view": "^6.0.1",
"emoji-regex": "^10.0.0",

View File

@@ -0,0 +1,28 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.excalidraw";
version = "2.2.8";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "9f5811b0f849b0f1a6a842945a81b605f65a9bdb";
# owner = "zsviczian";
repo = "obsidian-excalidraw-plugin";
# rev = version;
hash = "sha256-/YbbGFYWkzBxdIFpFNn85D8oXJsFrgndq3KZmMSxcvw=";
};
npmDepsHash = "sha256-KgsmcGj8WbWLCxaXMNA8anGcmOq0BzuDtdeNqS8ra8E=";
npmPackFlags = [ "--ignore-scripts" ];
configurePhase = ''
mkdir dist
'';
installPhase = ''
mkdir -p $out
cp ./dist/manifest.json $out/manifest.json
cp ./dist/main.js $out/main.js
cp ./dist/styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,24 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.folder-note";
version = "0.7.3";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "2d14ccb5179beb48c3df87108170aeda067584ac";
# owner = "xpgo";
repo = "obsidian-folder-note-plugin";
# rev = version;
hash = "sha256-Ub0u+hMbkzxeUjzVmA61S0ClXR9E3KrYTqhrJBQj0Wg=";
};
npmDepsHash = "sha256-4v6QwwooxsXy+mbiKriylpKa8NOK8pWZixezY+H6wxo=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,31 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.kanban";
version = "2.0.51";
src = pkgs.fetchFromGitHub {
owner = "mgmeyers";
repo = "obsidian-kanban";
rev = version;
hash = "sha256-NahypggwPrub2KxRBAn54ZpEInP1V+6l/xmUKUt6myA=";
};
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-eof2W9Ja4RlmjQ0SnaF/jadHX3GRkCRrMwZU2z0M/Jk=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,35 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.languagetool";
version = "0.3.7";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "a7bb62f767decbd55b14702c35e24954459e77ca";
# owner = "Clemens-E";
repo = "obsidian-languagetool-plugin";
# rev = version;
hash = "sha256-LeSK9ctdKW6P3AoOWHxHmGxIlOXDOVd1nhsWXdRSiZY=";
};
patches = [ ./settings-notification.patch ];
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-749RGQmg9Mte7TR6k3qP6xcb8+rj/C60LYLbF8j8gNc=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,12 @@
diff --git a/src/index.ts b/src/index.ts
index 00cccfe..43e6107 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -42,7 +42,6 @@ export default class LanguageToolPlugin extends Plugin {
try {
await this.saveSettings();
await this.loadSettings();
- new Notice('updated LanguageTool Settings, please confirm your server URL in the settings tab', 10000);
} catch (e) {
console.error(e);
}

View File

@@ -0,0 +1,22 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.linter";
version = "1.25.0";
src = pkgs.fetchFromGitHub {
owner = "platers";
repo = "obsidian-linter";
rev = version;
hash = "sha256-jf3tIE6zDD5VCrkWWgxpANqrYUqJunESD08bVJB2H54=";
};
npmDepsHash = "sha256-Bln8cD04ACdj73xXrcG6RVlET1D1bfMsRZqaejbAedo=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./src/styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,24 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.map-view";
version = "5.0.2";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "22e13b87e43dc5a5e40240e7de216ed8f638e741";
# owner = "esm7";
repo = "obsidian-map-view";
# rev = version;
hash = "sha256-n++PIWsaxAFnbfzlD0sWMs5+ljOXjA+ft6d/m/p2oq8=";
};
npmDepsHash = "sha256-AzJfluB+KjGudESedQxX4BxStnELeFDHO+h+f73ihuA=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./dist/manifest.json $out/manifest.json
cp ./dist/main.js $out/main.js
cp ./dist/styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,24 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.minimal-settings";
version = "8.0.2";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "2bdab8f00be4b98600e40d6a2ecac8be359c99dd";
# owner = "kepano";
repo = "obsidian-minimal-settings";
# rev = version;
hash = "sha256-JI7I1n6ZiWdzemoLFGt7C3RF+HQgh9BmmI3owZNm944=";
};
npmDepsHash = "sha256-N9wfFsbpcO53Lno6sM4OvXywUqn9L2DpS4HfmjL1Ld4=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,22 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.outliner";
version = "4.8.1";
src = pkgs.fetchFromGitHub {
owner = "vslinko";
repo = "obsidian-outliner";
rev = version;
hash = "sha256-LfkK1c3khA75UZQMJStvV2bccHTz4eMqtEIC8jPFKBM=";
};
npmDepsHash = "sha256-EVSunBtuOo93Zhq95u80j/MArRZaAyKdcwUz61qHXiQ=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,21 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.read-it-later";
version = "0.4.0";
src = pkgs.fetchFromGitHub {
owner = "DominikPieper";
repo = "obsidian-ReadItLater";
rev = version;
hash = "sha256-yaEgYH9jfjumZJ/kD/jj2NDTsuvP6EmyfYXEj5E8Q0Q=";
};
npmDepsHash = "sha256-OOhdusXBbxSl8S2uCGTqkTDYEbO5FxOlH8cehwU3LjY=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
'';
}

View File

@@ -0,0 +1,33 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.style-settings";
version = "1.0.8";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "57ef34b6d8903451311db63084eef80b7b7e1a62";
# owner = "mgmeyers";
repo = "obsidian-style-settings";
# rev = version;
hash = "sha256-ZxYkd0kyDnHwPt5Z1iFpRgQHLKhN4O9S5S7Izz5hd9E=";
};
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-Wf5pIbhSdo/rOs/TDqRjiS2JxWWbWsI2IOqCW78gFkU=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,31 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation rec {
pname = "obsidian.plugins.tasks";
version = "7.6.1";
src = pkgs.fetchFromGitHub {
owner = "obsidian-tasks-group";
repo = "obsidian-tasks";
rev = version;
hash = "sha256-7VvoaX2WkKrg2WpR+JQcpT73rAhZXJ3FXr2BBUIwrmA=";
};
offlineCache = pkgs.fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-3ReJNZKgecKTbXTWZGSY2hBLHysdbr/iKFS9tgCJvW0=";
};
nativeBuildInputs = with pkgs; [
nodejs
yarnConfigHook
yarnBuildHook
npmHooks.npmInstallHook
];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
cp ./styles.css $out/styles.css
'';
}

View File

@@ -0,0 +1,23 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.plugins.url-into-selection";
version = "1.7.0";
src = pkgs.fetchFromGitHub {
owner = "karaolidis";
rev = "9f85d59be28797b7ef16c452fa3c4093f60b3bab";
# owner = "denolehov";
repo = "obsidian-url-into-selection";
# rev = version;
hash = "sha256-MQV8CMzCha0MUGLh4c1WuHVXRiCPEwtSgd3Xoj/81hA=";
};
npmDepsHash = "sha256-tThyrhezHZ29JUzx5sy2SfoZIGYP0DOQBctxYB5O1P4=";
npmPackFlags = [ "--ignore-scripts" ];
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./main.js $out/main.js
'';
}

View File

@@ -0,0 +1,18 @@
:root {
--replete-custom-separators-vertical-padding: 4px;
--replete-custom-separators-left-margin: -12px;
}
.nav-files-container [class*=nav-]:has(:is(
[data-path="Inbox"],
[data-path="Dreams"],
[data-path="Work"],
[data-path="Random"],
))::after {
content:'';
display:block;
height:1px;
width:calc(100% + 32px);
background:linear-gradient(to right, var(--tab-outline-color), transparent);
margin:var(--replete-custom-separators-vertical-padding) 0 var(--replete-custom-separators-vertical-padding) var(--replete-custom-separators-left-margin);
}

View File

@@ -0,0 +1,27 @@
{ pkgs, ... }:
pkgs.buildNpmPackage rec {
pname = "obsidian.themes.minimal";
version = "7.7.7";
src = pkgs.fetchFromGitHub {
owner = "kepano";
repo = "obsidian-minimal";
rev = version;
hash = "sha256-Atb9ZVou4EkfppV7VvTEMG/UruKlADctbXL1M8vvhxQ=";
};
npmDepsHash = "sha256-PzsZv/On8ci6EkF3WE4aez3/jQu5AqyJxFUzJk+Pn0c=";
npmPackFlags = [ "--ignore-scripts" ];
nativeBuildInputs = with pkgs; [ sass ];
buildPhase = ''
npx grunt cssmin
'';
installPhase = ''
mkdir -p $out
cp ./manifest.json $out/manifest.json
cp ./theme.css $out/theme.css
'';
}

View File

@@ -0,0 +1,720 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
environment.persistence."/cache"."${home}/.config/obsidian" = { };
home-manager.users.${user} = {
imports = [ ./options.nix ];
programs.obsidian = {
enable = true;
sharedSettings = {
app = {
defaultViewMode = "preview";
livePreview = false;
readableLineLength = true;
showLineNumber = true;
tabSize = 2;
promptDelete = false;
trashOption = "local";
alwaysUpdateLinks = true;
newFileLocation = "folder";
newFileFolderPath = "inbox";
newLinkFormat = "absolute";
showUnsupportedFiles = true;
attachmentFolderPath = "./assets";
};
corePlugins = [
"bookmarks"
{
name = "canvas";
options = {
newFileLocation = "folder";
newFileFolderPath = "Inbox";
defaultWheelBehavior = "zoom";
};
}
"canvas"
{
name = "command-palette";
options = {
pinned = [
"file-explorer:new-file"
"canvas:new-file"
"obsidian-excalidraw-plugin:excalidraw-autocreate-on-current"
"obsidian-kanban:create-new-kanban-board"
"obsidian-read-it-later:save-clipboard-to-notice"
];
};
}
"editor-status"
"file-explorer"
"global-search"
"graph"
"note-composer"
"outgoing-link"
"outline"
"page-preview"
"slash-command"
"switcher"
"tag-pane"
];
communityPlugins = [
{
pkg = pkgs.callPackage ./config/plugins/better-word-count { };
options = {
statusBar = [
{
prefix = "";
suffix = " words";
metric = {
type = 0;
counter = 0;
};
}
];
altBar = [
{
prefix = "";
suffix = " files";
metric = {
type = 2;
counter = 6;
};
}
];
countComments = true; # Inverse
};
}
{
pkg = pkgs.callPackage ./config/plugins/custom-sort { };
options = {
suspended = false;
statusBarEntryEnabled = false;
notificationsEnabled = false;
customSortContextSubmenu = false;
bookmarksGroupToConsumeAsOrderingReference = "Sort";
bookmarksContextMenus = false;
};
}
{
pkg = pkgs.callPackage ./config/plugins/dataview { };
options = {
enableDataviewJs = true;
enableInlineDataviewJs = true;
warnOnEmptyResult = false;
defaultDateFormat = "dd/MM/yyyy";
defaultDateTimeFormat = "HH:mm - dd/MM/yyyy";
};
}
{
pkg = pkgs.callPackage ./config/plugins/excalidraw { };
options = {
folder = "Inbox";
templateFilePath = "Templates";
scriptFolderPath = "Scripts";
compress = false;
drawingFilenamePrefix = "";
drawingEmbedPrefixWithFilename = false;
drawingFilenameDateTime = "YYYY-MM-DD-HH.mm.ss";
previewImageType = "SVG";
previewMatchObsidianTheme = true;
defaultPenMode = "mobile";
parseTODO = true;
focusOnFileTab = true;
pngExportScale = 2;
exportWithTheme = false;
exportWithBackground = false;
exportEmbedScene = true;
showReleaseNotes = false;
showNewVersionNotification = false;
};
}
{
pkg = pkgs.callPackage ./config/plugins/folder-note { };
options = {
folderNoteHide = false;
folderNoteStrInit = "";
};
}
{
pkg = pkgs.callPackage ./config/plugins/kanban { };
options = {
move-tags = true;
move-dates = true;
date-display-format = "DD/MM/YYYY";
show-relative-date = true;
date-picker-week-start = 1;
inline-metadata-position = "footer";
move-task-metadata = true;
show-archive-all = false;
show-board-settings = false;
};
}
{
pkg = pkgs.callPackage ./config/plugins/languagetool { };
options = {
shouldAutoCheck = true;
pickyMode = true;
staticLanguage = "auto";
englishVariety = "en-US";
};
}
{
pkg = pkgs.callPackage ./config/plugins/linter { };
options = {
lintOnSave = true;
displayChanged = false;
lintOnFileChange = true;
ruleConfigs = {
add-blank-line-after-yaml.enabled = true;
dedupe-yaml-array-values.enabled = true;
escape-yaml-special-characters = {
enabled = true;
try-to-escape-single-line-arrays = true;
};
format-tags-in-yaml.enabled = true;
format-yaml-array = {
enabled = true;
default-array-style = "multi-line";
};
sort-yaml-array-values.enabled = true;
capitalize-headings = {
enabled = true;
ignore-words = "";
};
header-increment = {
enabled = true;
start-at-h2 = true;
};
headings-start-line.enabled = true;
remove-trailing-punctuation-in-heading.enabled = true;
auto-correct-common-misspellings.enabled = true;
blockquote-style.enabled = true;
convert-bullet-list-markers.enabled = true;
emphasis-style = {
enabled = true;
style = "asterisk";
};
no-bare-urls = {
enabled = true;
no-bare-uris = true;
};
ordered-list-style.enabled = true;
quote-style.enabled = true;
remove-consecutive-list-markers.enabled = true;
remove-empty-list-markers.enabled = true;
remove-hyphenated-line-breaks.enabled = true;
remove-multiple-spaces.enabled = true;
strong-style = {
enabled = true;
style = "asterisk";
};
two-spaces-between-lines-with-content.enabled = true;
unordered-list-style = {
enabled = true;
list-style = "-";
};
compact-yaml = {
enabled = true;
inner-new-lines = true;
};
consecutive-blank-lines.enabled = true;
empty-line-around-blockquotes.enabled = true;
empty-line-around-code-fences.enabled = true;
empty-line-around-math-blocks.enabled = true;
empty-line-around-tables.enabled = true;
heading-blank-lines.enabled = true;
line-break-at-document-end.enabled = true;
move-math-block-indicators-to-their-own-line.enabled = true;
paragraph-blank-lines.enabled = true;
remove-empty-lines-between-list-markers-and-checklists.enabled = true;
remove-link-spacing.enabled = true;
space-after-list-markers.enabled = true;
trailing-spaces.enabled = true;
add-blockquote-indentation-on-paste.enabled = true;
prevent-double-checklist-indicator-on-paste.enabled = true;
prevent-double-list-item-indicator-on-paste.enabled = true;
remove-hyphens-on-paste.enabled = true;
remove-leading-or-trailing-whitespace-on-paste.enabled = true;
remove-leftover-footnotes-from-quote-on-paste.enabled = true;
remove-multiple-blank-lines-on-paste.enabled = true;
};
customRegexes = [
{
label = "Open Double Quote";
find = "";
replace = "\"";
flags = "gm";
}
{
label = "Close Double Quote";
find = "";
replace = "\"";
flags = "gm";
}
{
label = "Elipsis";
find = "";
replace = "...";
flags = "gm";
}
{
label = "Open Quote";
find = "";
replace = "'";
flags = "gm";
}
{
label = "Close Quote";
find = "";
replace = "'";
flags = "gm";
}
{
label = "Long Dash";
find = "";
replace = "---";
flags = "gm";
}
{
label = "Short Dash";
find = "";
replace = "--";
flags = "gm";
}
{
label = "Long Dash with Text";
find = "([^\\s])---([^\\s])";
replace = "$1 --- $2";
flags = "gm";
}
{
label = "Short Dash with Text";
find = "([^\\s])--([^\\s])";
replace = "$1 -- $2";
flags = "gm";
}
];
commonStyles = {
removeUnnecessaryEscapeCharsForMultiLineArrays = true;
};
};
}
{
pkg = pkgs.callPackage ./config/plugins/map-view { };
options = {
"markerIconRules" = [
{
"ruleName" = "default";
"preset" = true;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-circle";
"markerColor" = "blue";
};
}
{
"ruleName" = "#restaurant";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-utensils";
"markerColor" = "red";
};
}
{
"ruleName" = "#bar";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-martini-glass";
"markerColor" = "purple";
};
}
{
"ruleName" = "#coffee";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-mug-hot";
"markerColor" = "purple";
};
}
{
"ruleName" = "#culture";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-building-columns";
"markerColor" = "black";
};
}
{
"ruleName" = "#shopping";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-shopping-bag";
"markerColor" = "yellow";
};
}
{
"ruleName" = "#entertainment";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-microphone";
"markerColor" = "pink";
};
}
{
"ruleName" = "#nature";
"preset" = false;
"iconDetails" = {
"prefix" = "fas";
"icon" = "fa-tree";
"markerColor" = "green";
};
}
];
"searchProvider" = "google";
"geocodingApiMethod" = "path";
"geocodingApiPath" = hmConfig.sops.secrets."google/geocoding".path;
"useGooglePlaces" = true;
"letZoomBeyondMax" = true;
"showGeolinkPreview" = true;
"newNotePath" = "Inbox";
};
}
{
pkg = pkgs.callPackage ./config/plugins/minimal-settings { };
options = {
editorFont = "var(--font-monospace)";
};
}
{
pkg = pkgs.callPackage ./config/plugins/outliner { };
options = {
styleLists = false;
stickCursor = "never";
};
}
{
pkg = pkgs.callPackage ./config/plugins/read-it-later { };
options = {
inboxDir = "Inbox";
assetsDir = "Inbox/assets";
openNewNote = true;
youtubeNote = ''
---
source: %videoURL%
---
%videoPlayer%
'';
vimeoNote = ''
---
source: %videoURL%
---
%videoPlayer%
'';
bilibiliNote = ''
---
source: %videoURL%
---
%videoPlayer%
'';
twitterNote = ''
---
source: %tweetURL%
---
%tweetContent%
'';
parsableArticleNote = ''
---
source: %articleURL%
---
%articleContent%
'';
mastodonNote = ''
---
source: %tootURL%
---
> %tootContent%
'';
stackExchangeNote = ''
---
source: %questionURL%
---
Author: [%authorName%](%authorProfileURL%)
%questionContent%
***
%topAnswer%
%answers%
'';
stackExchangeAnswer = ''
Answered by: [%authorName%](%authorProfileURL%)
> %answerContent%
'';
tikTokNote = ''
---
source: %videoURL%
---
%videoDescription%
%videoPlayer%
'';
notParsableArticleNote = ''
---
source: %articleURL%
---
%previewURL%
'';
textSnippetNote = "%content%";
};
}
(pkgs.callPackage ./config/plugins/style-settings { })
{
pkg = pkgs.callPackage ./config/plugins/tasks { };
options = {
globalQuery = "short mode";
globalFilter = "#todo";
removeGlobalFilter = true;
setCreatedDate = true;
statusSettings = {
coreStatuses = [
{
symbol = " ";
name = "to-do";
nextStatusSymbol = "/";
type = "TODO";
}
{
symbol = "x";
name = "done";
nextStatusSymbol = " ";
type = "DONE";
}
];
customStatuses = [
{
symbol = "/";
name = "in-progress";
nextStatusSymbol = "x";
type = "IN_PROGRESS";
}
{
symbol = "-";
name = "canceled";
nextStatusSymbol = " ";
type = "CANCELLED";
}
{
symbol = ">";
name = "forwarded";
nextStatusSymbol = "/";
type = "IN_PROGRESS";
}
{
symbol = "<";
name = "scheduling";
nextStatusSymbol = "/";
type = "TODO";
}
{
symbol = "?";
name = "question";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "!";
name = "important";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "*";
name = "star";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "\"";
name = "quote";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "l";
name = "location";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "b";
name = "bookmark";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "i";
name = "information";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "S";
name = "savings";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "I";
name = "idea";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "p";
name = "pros";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "c";
name = "cons";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "f";
name = "fire";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "k";
name = "key";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "w";
name = "win";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "u";
name = "up";
nextStatusSymbol = " ";
type = "TODO";
}
{
symbol = "d";
name = "down";
nextStatusSymbol = " ";
type = "TODO";
}
];
};
};
}
(pkgs.callPackage ./config/plugins/url-into-selection { })
];
cssSnippets = [ ./config/snippets/file-explorer-separators.css ];
themes = [ (pkgs.callPackage ./config/themes/minimal { }) ];
hotkeys = {
"command-palette:open" = [ { key = "F1"; } ];
"app:open-help" = [ ];
"editor:swap-line-down" = [
{
modifiers = [ "Alt" ];
key = "ArrowDown";
}
];
"editor:swap-line-up" = [
{
modifiers = [ "Alt" ];
key = "ArrowUp";
}
];
"editor:fold-all" = [
{
modifiers = [
"Alt"
"Mod"
];
key = "T";
}
];
"editor:add-cursor-above" = [
{
modifiers = [
"Mod"
"Shift"
];
key = "ArrowUp";
}
];
"editor:add-cursor-below" = [
{
modifiers = [
"Mod"
"Shift"
];
key = "ArrowDown";
}
];
"obsidian-outliner:move-list-item-up" = [ ];
"obsidian-outliner:move-list-item-down" = [ ];
};
};
};
theme.template = lib.attrsets.mapAttrs' (
_: vault:
lib.attrsets.nameValuePair
"${home}/${vault.target}/.obsidian/plugins/obsidian-style-settings/data.json"
{
source = ./theme.json;
}
) hmConfig.programs.obsidian.vaults;
sops.secrets."google/geocoding".sopsFile = ../../../../../../secrets/personal/secrets.yaml;
wayland.windowManager.hyprland.settings.bind = [ "$mod, o, exec, ${pkgs.obsidian}/bin/obsidian" ];
};
}

View File

@@ -0,0 +1,504 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.programs.obsidian;
corePlugins = [
"audio-recorder"
"backlink"
"bookmarks"
"canvas"
"command-palette"
"daily-notes"
"editor-status"
"file-explorer"
"file-recovery"
"global-search"
"graph"
"markdown-importer"
"note-composer"
"outgoing-link"
"outline"
"page-preview"
"properties"
"publish"
"random-note"
"slash-command"
"slides"
"switcher"
"sync"
"tag-pane"
"templates"
"word-count"
"workspaces"
"zk-prefixer"
];
toCssName = path: lib.strings.removeSuffix ".css" (builtins.baseNameOf path);
in
{
options.programs.obsidian =
with lib;
with types;
let
corePluginsOptions =
{ config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether to enable the plugin.";
};
name = mkOption {
type = enum corePlugins;
description = "The plugin.";
};
options = mkOption {
type = attrsOf anything;
description = "Plugin options to include.";
default = { };
};
};
};
communityPluginsOptions =
{ config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether to enable the plugin.";
};
pkg = mkOption {
type = package;
description = "The plugin package.";
};
options = mkOption {
type = attrsOf anything;
description = "Options to include in the plugin's `data.json`.";
default = { };
};
};
};
checkCssPath = path: lib.filesystem.pathIsRegularFile path && lib.strings.hasSuffix ".css" path;
cssSnippetsOptions =
{ config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether to enable the snippet.";
};
name = mkOption {
type = str;
defaultText = literalExpression "lib.strings.removeSuffix \".css\" (builtins.baseNameOf source)";
description = "Name of the snippet.";
};
source = mkOption {
type = nullOr (addCheck path checkCssPath);
description = "Path of the source file.";
default = null;
};
text = mkOption {
type = nullOr str;
description = "Text of the file.";
default = null;
};
};
config.name = mkDefault (toCssName config.source);
};
themesOptions =
{ config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether to set the theme as active.";
};
pkg = mkOption {
type = package;
description = "The theme package.";
};
};
};
hotkeysOptions =
{ config, ... }:
{
options = {
modifiers = mkOption {
type = listOf str;
description = "The hotkey modifiers.";
default = [ ];
};
key = mkOption {
type = str;
description = "The hotkey.";
};
};
};
extraFilesOptions =
{ name, config, ... }:
{
options = {
source = mkOption {
type = nullOr path;
description = "Path of the source file or directory.";
default = null;
};
text = mkOption {
type = nullOr str;
description = "Text of the file.";
default = null;
};
target = mkOption {
type = str;
defaultText = literalExpression "name";
description = "Path to target relative to the vault's directory.";
};
};
config.target = mkDefault name;
};
in
{
enable = mkEnableOption "obsidian";
package = mkPackageOption pkgs "obsidian" { };
sharedSettings = {
app = mkOption {
description = "Settings to write to app.json.";
type = raw;
default = { };
};
appearance = mkOption {
description = "Settings to write to appearance.json.";
type = raw;
default = { };
};
corePlugins = mkOption {
description = "Core plugins to activate.";
type = raw;
default = [
"backlink"
"bookmarks"
"canvas"
"command-palette"
"daily-notes"
"editor-status"
"file-explorer"
"file-recovery"
"global-search"
"graph"
"note-composer"
"outgoing-link"
"outline"
"page-preview"
"switcher"
"tag-pane"
"templates"
"word-count"
];
};
communityPlugins = mkOption {
description = "Community plugins to install and activate.";
type = raw;
default = [ ];
};
cssSnippets = mkOption {
description = "CSS snippets to install.";
type = raw;
default = [ ];
};
themes = mkOption {
description = "Themes to install.";
type = raw;
default = [ ];
};
hotkeys = mkOption {
description = "Hotkeys to configure.";
type = raw;
default = { };
};
extraFiles = mkOption {
description = "Extra files to link to the vault directory.";
type = raw;
default = { };
};
};
vaults = mkOption {
description = "List of vaults to create.";
type = attrsOf (
submodule (
{ name, config, ... }:
{
options = {
enable = mkOption {
type = bool;
default = true;
description = "Whether this vault should be generated.";
};
target = mkOption {
type = str;
defaultText = literalExpression "name";
description = "Path to target vault relative to the user's {env}`HOME`.";
};
settings = {
app = mkOption {
description = "Settings to write to app.json.";
type = attrsOf anything;
default = cfg.sharedSettings.app;
};
appearance = mkOption {
description = "Settings to write to appearance.json.";
type = attrsOf anything;
default = cfg.sharedSettings.appearance;
};
corePlugins = mkOption {
description = "Core plugins to activate.";
type = listOf (coercedTo (enum corePlugins) (p: { name = p; }) (submodule corePluginsOptions));
default = cfg.sharedSettings.corePlugins;
};
communityPlugins = mkOption {
description = "Community plugins to install and activate.";
type = listOf (coercedTo package (p: { pkg = p; }) (submodule communityPluginsOptions));
default = cfg.sharedSettings.communityPlugins;
};
cssSnippets = mkOption {
description = "CSS snippets to install.";
type = listOf (
coercedTo (addCheck path checkCssPath) (p: { source = p; }) (submodule cssSnippetsOptions)
);
default = cfg.sharedSettings.cssSnippets;
};
themes = mkOption {
description = "Themes to install.";
type = listOf (coercedTo package (p: { pkg = p; }) (submodule themesOptions));
default = cfg.sharedSettings.themes;
};
hotkeys = mkOption {
description = "Hotkeys to configure.";
type = attrsOf (listOf (submodule hotkeysOptions));
default = cfg.sharedSettings.hotkeys;
};
extraFiles = mkOption {
description = "Extra files to link to the vault directory.";
type = attrsOf (submodule extraFilesOptions);
default = cfg.sharedSettings.extraFiles;
};
};
};
config.target = mkDefault name;
}
)
);
default = { };
};
};
config =
let
vaults = builtins.filter (vault: vault.enable == true) (builtins.attrValues cfg.vaults);
getManifest =
item:
let
manifest = builtins.fromJSON (builtins.readFile "${item.pkg}/manifest.json");
in
manifest.id or manifest.name;
in
lib.mkIf cfg.enable {
home = {
packages = [ cfg.package ];
file =
let
mkApp = vault: {
name = "${vault.target}/.obsidian/app.json";
value.source = (pkgs.formats.json { }).generate "app.json" vault.settings.app;
};
mkAppearance = vault: {
name = "${vault.target}/.obsidian/appearance.json";
value =
let
enabledCssSnippets = builtins.filter (snippet: snippet.enable) vault.settings.cssSnippets;
activeTheme = lib.lists.findSingle (
theme: theme.enable
) null (throw "Only one theme can be enabled at a time.") vault.settings.themes;
in
{
source = (pkgs.formats.json { }).generate "appearance.json" (
vault.settings.appearance
// {
enabledCssSnippets = builtins.map (snippet: snippet.name) enabledCssSnippets;
}
// lib.attrsets.optionalAttrs (activeTheme != null) { cssTheme = getManifest activeTheme; }
);
};
};
mkCorePlugins =
vault:
[
{
name = "${vault.target}/.obsidian/core-plugins.json";
value.source = (pkgs.formats.json { }).generate "core-plugins.json" (
builtins.map (plugin: plugin.name) vault.settings.corePlugins
);
}
{
name = "${vault.target}/.obsidian/core-plugins-migration.json";
value.source = (pkgs.formats.json { }).generate "core-plugins-migration.json" (
builtins.listToAttrs (
builtins.map (name: {
inherit name;
value = builtins.any (plugin: name == plugin.name && plugin.enable) vault.settings.corePlugins;
}) corePlugins
)
);
}
]
++ builtins.map (plugin: {
name = "${vault.target}/.obsidian/${plugin.name}.json";
value.source = (pkgs.formats.json { }).generate "${plugin.name}.json" plugin.options;
}) (builtins.filter (plugin: plugin.options != { }) vault.settings.corePlugins);
mkCommunityPlugins =
vault:
[
{
name = "${vault.target}/.obsidian/community-plugins.json";
value.source = (pkgs.formats.json { }).generate "community-plugins.json" (
builtins.map getManifest (builtins.filter (plugin: plugin.enable) vault.settings.communityPlugins)
);
}
]
++ builtins.map (plugin: {
name = "${vault.target}/.obsidian/plugins/${getManifest plugin}";
value = {
source = plugin.pkg;
recursive = true;
};
}) vault.settings.communityPlugins
++ builtins.map (plugin: {
name = "${vault.target}/.obsidian/plugins/${getManifest plugin}/data.json";
value.source = (pkgs.formats.json { }).generate "data.json" plugin.options;
}) (builtins.filter (plugin: plugin.options != { }) vault.settings.communityPlugins);
mkCssSnippets =
vault:
builtins.map (snippet: {
name = "${vault.target}/.obsidian/snippets/${snippet.name}.css";
value =
if snippet.source != null then { inherit (snippet) source; } else { inherit (snippet) text; };
}) vault.settings.cssSnippets;
mkThemes =
vault:
builtins.map (theme: {
name = "${vault.target}/.obsidian/themes/${getManifest theme}";
value.source = theme.pkg;
}) vault.settings.themes;
mkHotkeys = vault: {
name = "${vault.target}/.obsidian/hotkeys.json";
value.source = (pkgs.formats.json { }).generate "hotkeys.json" vault.settings.hotkeys;
};
mkExtraFiles =
vault:
builtins.map (file: {
name = "${vault.target}/.obsidian/${file.target}";
value = if file.source != null then { inherit (file) source; } else { inherit (file) text; };
}) (builtins.attrValues vault.settings.extraFiles);
in
builtins.listToAttrs (
lib.lists.flatten (
builtins.map (vault: [
(mkApp vault)
(mkAppearance vault)
(mkCorePlugins vault)
(mkCommunityPlugins vault)
(mkCssSnippets vault)
(mkThemes vault)
(mkHotkeys vault)
(mkExtraFiles vault)
]) vaults
)
);
};
xdg.configFile."obsidian/obsidian.json".source = (pkgs.formats.json { }).generate "obsidian.json" {
vaults = builtins.listToAttrs (
builtins.map (vault: {
name = builtins.hashString "md5" vault.target;
value = {
path = "${config.home.homeDirectory}/${vault.target}";
} // (lib.attrsets.optionalAttrs ((builtins.length vaults) == 1) { open = true; });
}) vaults
);
updateDisabled = true;
};
assertions = [
{
assertion = builtins.all (
vault:
builtins.all (snippet: snippet.source == null || snippet.text == null) vault.settings.cssSnippets
) (builtins.attrValues cfg.vaults);
message = "Only one of `source` and `text` must be set";
}
{
assertion = builtins.all (
vault:
builtins.all (file: file.source == null || file.text == null) (
builtins.attrValues vault.settings.extraFiles
)
) (builtins.attrValues cfg.vaults);
message = "Only one of `source` and `text` must be set";
}
];
};
}

View File

@@ -0,0 +1,88 @@
{
"minimal-style@@base@@light": "{{colors.surface.light.hex}}",
"minimal-style@@base@@dark": "{{colors.surface.dark.hex}}",
"minimal-style@@bg1@@light": "{{colors.surface.light.hex}}",
"minimal-style@@bg1@@dark": "{{colors.surface.dark.hex}}",
"minimal-style@@bg2@@light": "{{colors.surface_container.light.hex}}",
"minimal-style@@bg2@@dark": "{{colors.surface_container.dark.hex}}",
"minimal-style@@bg3@@light": "{{colors.surface_container_highest.light.hex}}",
"minimal-style@@bg3@@dark": "{{colors.surface_container_highest.dark.hex}}",
"minimal-style@@ui1@@light": "{{colors.outline_variant.light.hex}}",
"minimal-style@@ui1@@dark": "{{colors.outline_variant.dark.hex}}",
"minimal-style@@ui2@@light": "{{colors.outline.light.hex}}",
"minimal-style@@ui2@@dark": "{{colors.outline.dark.hex}}",
"minimal-style@@ui3@@light": "{{colors.primary.light.hex}}",
"minimal-style@@ui3@@dark": "{{colors.primary.dark.hex}}",
"minimal-style@@ax1@@light": "{{colors.primary.light.hex}}",
"minimal-style@@ax1@@dark": "{{colors.primary.dark.hex}}",
"minimal-style@@ax2@@light": "{{colors.on_primary_container.light.hex}}",
"minimal-style@@ax2@@dark": "{{colors.on_primary_container.dark.hex}}",
"minimal-style@@ax3@@light": "{{colors.primary.light.hex}}",
"minimal-style@@ax3@@dark": "{{colors.primary.dark.hex}}",
"minimal-style@@sp1@@light": "{{colors.on_primary_container.light.hex}}",
"minimal-style@@sp1@@dark": "{{colors.on_primary_container.dark.hex}}",
"minimal-style@@color-red@@light": "{{colors.red.light.hex}}",
"minimal-style@@color-red@@dark": "{{colors.red.dark.hex}}",
"minimal-style@@color-orange@@light": "{{colors.orange.light.hex}}",
"minimal-style@@color-orange@@dark": "{{colors.orange.dark.hex}}",
"minimal-style@@color-yellow@@light": "{{colors.yellow.light.hex}}",
"minimal-style@@color-yellow@@dark": "{{colors.yellow.dark.hex}}",
"minimal-style@@color-green@@light": "{{colors.green.light.hex}}",
"minimal-style@@color-green@@dark": "{{colors.green.dark.hex}}",
"minimal-style@@color-cyan@@light": "{{colors.cyan.light.hex}}",
"minimal-style@@color-cyan@@dark": "{{colors.cyan.dark.hex}}",
"minimal-style@@color-blue@@light": "{{colors.blue.light.hex}}",
"minimal-style@@color-blue@@dark": "{{colors.blue.dark.hex}}",
"minimal-style@@color-purple@@light": "{{colors.magenta.light.hex}}",
"minimal-style@@color-purple@@dark": "{{colors.magenta.dark.hex}}",
"minimal-style@@color-pink@@light": "{{colors.pink.light.hex}}",
"minimal-style@@color-pink@@dark": "{{colors.pink.dark.hex}}",
"minimal-style@@blockquote-color@@light": "{{colors.on_surface_variant.light.hex}}",
"minimal-style@@blockquote-color@@dark": "{{colors.on_surface_variant.dark.hex}}",
"minimal-style@@canvas-dot-pattern@@light": "{{colors.outline_variant.light.hex}}",
"minimal-style@@canvas-dot-pattern@@dark": "{{colors.outline_variant.dark.hex}}",
"minimal-style@@tag-color@@light": "{{colors.on_primary_container.light.hex}}",
"minimal-style@@tag-color@@dark": "{{colors.on_primary_container.dark.hex}}",
"minimal-style@@tag-background@@light": "{{colors.primary_container.light.hex}}",
"minimal-style@@tag-background@@dark": "{{colors.primary_container.dark.hex}}",
"minimal-style@@tag-background-hover@@light": "{{colors.on_primary.light.hex}}",
"minimal-style@@tag-background-hover@@dark": "{{colors.on_primary.dark.hex}}",
"minimal-style@@tx1@@light": "{{colors.on_surface.light.hex}}",
"minimal-style@@tx1@@dark": "{{colors.on_surface.dark.hex}}",
"minimal-style@@tx2@@light": "{{colors.on_surface_variant.light.hex}}",
"minimal-style@@tx2@@dark": "{{colors.on_surface_variant.dark.hex}}",
"minimal-style@@tx3@@light": "{{colors.outline.light.hex}}",
"minimal-style@@tx3@@dark": "{{colors.outline.dark.hex}}",
"minimal-style@@hl1@@light": "{{colors.primary_container.light.hex}}",
"minimal-style@@hl1@@dark": "{{colors.primary_container.dark.hex}}",
"minimal-style@@text-formattin@@light": "{{colors.outline_variant.light.hex}}",
"minimal-style@@text-formattin@@dark": "{{colors.outline_variant.dark.hex}}",
"minimal-style@@code-comment@@light": "{{colors.outline.light.hex}}",
"minimal-style@@code-comment@@dark": "{{colors.outline.dark.hex}}",
"minimal-style@@code-function@@light": "{{colors.functions.light.hex}}",
"minimal-style@@code-function@@dark": "{{colors.functions.dark.hex}}",
"minimal-style@@code-keyword@@light": "{{colors.keywords.light.hex}}",
"minimal-style@@code-keyword@@dark": "{{colors.keywords.dark.hex}}",
"minimal-style@@code-important@@light": "{{colors.info.light.hex}}",
"minimal-style@@code-important@@dark": "{{colors.info.dark.hex}}",
"minimal-style@@code-property@@light": "{{colors.properties.light.hex}}",
"minimal-style@@code-property@@dark": "{{colors.properties.dark.hex}}",
"minimal-style@@code-string@@light": "{{colors.strings.light.hex}}",
"minimal-style@@code-string@@dark": "{{colors.strings.dark.hex}}",
"minimal-style@@code-tag@@light": "{{colors.properties.light.hex}}",
"minimal-style@@code-tag@@dark": "{{colors.properties.dark.hex}}",
"minimal-style@@code-value@@light": "{{colors.numbers.light.hex}}",
"minimal-style@@code-value@@dark": "{{colors.numbers.dark.hex}}",
"minimal-style@@image-radius": "{{custom.radius}}",
"minimal-style@@blockquote-border-thickness": 4,
"minimal-style@@minimal-code-scroll": true,
"minimal-style@@h1-l": true,
"minimal-style@@h2-l": true,
"minimal-style@@image-muted": 1,
"minimal-style@@active-line-on": true,
"minimal-style@@minimal-strike-lists": true,
"minimal-style@@metadata-heading-off": true,
"minimal-style@@metadata-icons-off": true,
"minimal-style@@hide-help": true,
"minimal-style@@row-hover": true
}

View File

@@ -0,0 +1,30 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, pkgs, ... }:
let
hmConfig = config.home-manager.users.${user};
in
{
home-manager.users.${user} = {
home.packages = [ (pkgs.callPackage ./package.nix { }) ];
xdg.configFile."OpenLens/lens-user-store.json".source =
(pkgs.formats.json { }).generate "lens-user-store.json"
{
__internal__ = {
migrations = {
version = "6.5.0";
};
};
preferences = {
colorTheme = "system";
editorConfiguration.fontFamily = builtins.head hmConfig.theme.font.monospace.names;
terminalConfig.fontFamily = builtins.head hmConfig.theme.font.monospace.names;
terminalCopyOnSelect = true;
};
};
};
}

View File

@@ -0,0 +1,34 @@
# https://github.com/NixOS/nixpkgs/commit/4b29fd82fc757855333ef222742a48d7176eabb9#diff-b8be2fa008db0ba3e0c782ccc6d04465140ce1e59d9e58ba1942c9e9384ce58bL39
{ lib, pkgs }:
pkgs.appimageTools.wrapType2 rec {
pname = "openlens";
version = "6.5.2-366";
src = pkgs.fetchurl {
url = "https://github.com/MuhammedKalkan/OpenLens/releases/download/v${version}/OpenLens-${version}.x86_64.AppImage";
sha256 = "sha256-ZAltAS/U/xh4kCT7vQ+NHAzWV7z0uE5GMQICHKSdj8k=";
};
appimageContents = pkgs.appimageTools.extractType2 {
inherit pname version src;
};
unshareIpc = false;
extraInstallCommands = ''
install -m 444 -D ${appimageContents}/open-lens.desktop $out/share/applications/${pname}.desktop
install -m 444 -D ${appimageContents}/usr/share/icons/hicolor/512x512/apps/open-lens.png \
$out/share/icons/hicolor/512x512/apps/${pname}.png
substituteInPlace $out/share/applications/${pname}.desktop \
--replace 'Icon=open-lens' 'Icon=${pname}' \
--replace 'Exec=AppRun' 'Exec=${pname}'
'';
meta = with lib; {
description = "Kubernetes IDE";
homepage = "https://github.com/MuhammedKalkan/OpenLens";
license = licenses.mit;
mainProgram = "openlens";
platforms = [ "x86_64-linux" ];
};
}

View File

@@ -0,0 +1,35 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ lib, pkgs, ... }:
{
home-manager.users.${user} = {
home.packages = with pkgs; [ pavucontrol ];
wayland.windowManager.hyprland.settings =
let
wpctl = "${pkgs.wireplumber}/bin/wpctl";
playerctl = lib.meta.getExe pkgs.playerctl;
in
{
bindle = [
", XF86AudioRaiseVolume, exec, ${wpctl} set-volume @DEFAULT_AUDIO_SINK@ -l 2.0 2%+"
", XF86AudioLowerVolume, exec, ${wpctl} set-volume @DEFAULT_AUDIO_SINK@ -l 2.0 2%-"
"Ctrl, XF86AudioRaiseVolume, exec, ${wpctl} set-volume @DEFAULT_AUDIO_SOURCE@ -l 1.0 2%+"
"Ctrl, XF86AudioLowerVolume, exec, ${wpctl} set-volume @DEFAULT_AUDIO_SOURCE@ -l 1.0 2%-"
", XF86AudioNext, exec, ${playerctl} next"
", XF86AudioPrev, exec, ${playerctl} previous"
"Ctrl, XF86AudioNext, exec, ${playerctl} position 10+"
"Ctrl, XF86AudioPrev, exec, ${playerctl} position 10-"
];
bindl = [
", XF86AudioMute, exec, ${wpctl} set-mute @DEFAULT_AUDIO_SINK@ toggle"
", XF86AudioMicMute, exec, ${wpctl} set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
", XF86AudioPlay, exec, ${playerctl} play-pause"
", XF86AudioStop, exec, ${playerctl} stop"
];
};
};
}

View File

@@ -0,0 +1,42 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
lib,
config,
pkgs,
...
}:
{
environment.persistence."/cache"."${home}/.config/qalculate/qalculate-gtk.history" = { };
home-manager.users.${user} = {
home.packages = with pkgs; [ qalculate-gtk ];
xdg.configFile."qalculate/qalculate-gtk.cfg".source =
(pkgs.formats.ini { }).generate "qalculate-gtk.cfg"
{
General = {
allow_multiple_instances = 1;
width = 500;
save_history_separately = 1;
auto_update_exchange_rates = 1;
local_currency_conversion = 1;
use_binary_prefixes = 1;
persistent_keypad = 1;
copy_ascii = 1;
copy_ascii_without_units = 1;
};
Mode = {
calculate_as_you_type = 1;
excessive_parenthesis = 1;
};
};
wayland.windowManager.hyprland.settings = {
bind = [ ", XF86Calculator, exec, ${lib.meta.getExe pkgs.qalculate-gtk}" ];
windowrulev2 = [ "float, class:(qalculate-gtk)" ];
};
};
}

View File

@@ -0,0 +1,566 @@
[%General]
x11drag=menubar_and_primary_toolbar
alt_mnemonic=true
left_tabs=false
attach_active_tab=false
mirror_doc_tabs=false
group_toolbar_buttons=true
toolbar_item_spacing=0
toolbar_interior_spacing=2
spread_progressbar=true
composite=true
menu_shadow_depth=16
spread_menuitems=true
tooltip_shadow_depth=7
splitter_width=1
scroll_width=9
scroll_arrows=false
scroll_min_extent=60
slider_width=2
slider_handle_width=23
slider_handle_length=22
tickless_slider_handle_size=22
center_toolbar_handle=true
check_size=24
textless_progressbar=false
progressbar_thickness=2
menubar_mouse_tracking=true
toolbutton_style=1
double_click=false
translucent_windows=false
blurring=false
popup_blurring=false
vertical_spin_indicators=false
spin_button_width=24
fill_rubberband=false
merge_menubar_with_toolbar=true
small_icon_size=16
large_icon_size=32
button_icon_size=16
toolbar_icon_size=16
combo_as_lineedit=true
animate_states=true
button_contents_shift=false
combo_menu=true
hide_combo_checkboxes=true
combo_focus_rect=false
groupbox_top_label=true
inline_spin_indicators=true
joined_inactive_tabs=false
layout_spacing=6
layout_margin=9
scrollbar_in_view=true
transient_scrollbar=true
transient_groove=true
submenu_overlap=0
tooltip_delay=0
tree_branch_line=true
no_window_pattern=false
opaque=vlc
reduce_window_opacity=0
respect_DE=true
scrollable_menu=false
submenu_delay=150
no_inactiveness=false
reduce_menu_opacity=0
click_behavior=0
contrast=1.00
dialog_button_layout=0
intensity=1.00
saturation=1.00
shadowless_popup=false
drag_from_buttons=false
menu_blur_radius=0
tooltip_blur_radius=0
[GeneralColors]
window.color={{colors.surface.default.hex}}
base.color={{colors.surface.default.hex}}
alt.base.color={{colors.surface_container.default.hex}}
button.color={{colors.surface_container_highest.default.hex}}
light.color={{colors.surface_container_highest.default.hex}}
mid.light.color={{colors.surface_container_high.default.hex}}
dark.color={{colors.surface_container_low.default.hex}}
mid.color={{colors.surface_container.default.hex}}
highlight.color={{colors.primary.default.hex}}
inactive.highlight.color={{colors.primary.default.hex}}
text.color={{colors.on_surface.default.hex}}
window.text.color={{colors.on_surface.default.hex}}
button.text.color={{colors.on_surface.default.hex}}
disabled.text.color={{colors.outline.default.hex}}
tooltip.text.color={{colors.on_surface.default.hex}}
highlight.text.color={{colors.on_surface.default.hex}}
link.color={{colors.primary.default.hex}}
link.visited.color={{colors.secondary.default.hex}}
progress.indicator.text.color={{colors.on_surface.default.hex}}
[Hacks]
transparent_ktitle_label=true
transparent_dolphin_view=true
transparent_pcmanfm_sidepane=true
blur_translucent=false
transparent_menutitle=true
respect_darkness=true
kcapacitybar_as_progressbar=true
force_size_grip=true
iconless_pushbutton=true
iconless_menu=false
disabled_icon_opacity=100
lxqtmainmenu_iconsize=16
normal_default_pushbutton=true
single_top_toolbar=true
tint_on_mouseover=0
transparent_pcmanfm_view=true
no_selection_tint=true
transparent_arrow_button=true
middle_click_scroll=false
opaque_colors=false
kinetic_scrolling=false
scroll_jump_workaround=true
centered_forms=false
noninteger_translucency=false
style_vertical_toolbars=false
blur_only_active_window=true
[PanelButtonCommand]
frame=true
frame.element=button
frame.top=6
frame.bottom=6
frame.left=6
frame.right=6
interior=true
interior.element=button
indicator.size=8
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
text.shadow=0
text.margin=4
text.iconspacing=4
indicator.element=arrow
frame.expansion=0
[PanelButtonTool]
inherits=PanelButtonCommand
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
text.bold=false
indicator.element=arrow
indicator.size=0
frame.expansion=0
[ToolbarButton]
frame=true
frame.element=tbutton
interior.element=tbutton
frame.top=16
frame.bottom=16
frame.left=16
frame.right=16
indicator.element=tarrow
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
text.bold=false
frame.expansion=32
[Dock]
inherits=PanelButtonCommand
interior.element=dock
frame.element=dock
frame.top=1
frame.bottom=1
frame.left=1
frame.right=1
text.normal.color={{colors.on_surface.default.hex}}
[DockTitle]
inherits=PanelButtonCommand
frame=false
interior=false
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.bold=false
[IndicatorSpinBox]
inherits=PanelButtonCommand
frame=true
interior=true
frame.top=2
frame.bottom=2
frame.left=2
frame.right=2
indicator.element=spin
indicator.size=8
text.normal.color={{colors.on_surface.default.hex}}
text.margin.top=2
text.margin.bottom=2
text.margin.left=2
text.margin.right=2
[RadioButton]
inherits=PanelButtonCommand
frame=false
interior.element=radio
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
min_width=+0.3font
min_height=+0.3font
[CheckBox]
inherits=PanelButtonCommand
frame=false
interior.element=checkbox
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
min_width=+0.3font
min_height=+0.3font
[Focus]
inherits=PanelButtonCommand
frame=true
frame.element=focus
frame.top=2
frame.bottom=2
frame.left=2
frame.right=2
frame.patternsize=14
[GenericFrame]
inherits=PanelButtonCommand
frame=true
interior=false
frame.element=common
interior.element=common
frame.top=1
frame.bottom=1
frame.left=1
frame.right=1
[LineEdit]
inherits=PanelButtonCommand
frame.element=lineedit
interior.element=lineedit
frame.top=6
frame.bottom=6
frame.left=6
frame.right=6
text.margin.top=2
text.margin.bottom=2
text.margin.left=2
text.margin.right=2
[ToolbarLineEdit]
frame.element=lineedit
interior.element=lineedit
[DropDownButton]
inherits=PanelButtonCommand
indicator.element=arrow-down
[IndicatorArrow]
indicator.element=arrow
indicator.size=8
[ToolboxTab]
inherits=PanelButtonCommand
text.normal.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
[Tab]
inherits=PanelButtonCommand
interior.element=tab
text.margin.left=8
text.margin.right=8
text.margin.top=0
text.margin.bottom=0
frame.element=tab
indicator.element=tab
indicator.size=22
frame.top=8
frame.bottom=8
frame.left=8
frame.right=8
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
frame.expansion=0
text.bold=false
[TabFrame]
inherits=PanelButtonCommand
frame.element=tabframe
interior.element=tabframe
frame.top=24
frame.bottom=24
frame.left=24
frame.right=24
[TreeExpander]
inherits=PanelButtonCommand
indicator.size=8
indicator.element=tree
[HeaderSection]
inherits=PanelButtonCommand
interior.element=header
frame.element=header
frame.top=0
frame.bottom=1
frame.left=1
frame.right=1
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
frame.expansion=0
[SizeGrip]
indicator.element=resize-grip
[Toolbar]
inherits=PanelButtonCommand
indicator.element=toolbar
indicator.size=5
text.margin=0
interior.element=menubar
frame.element=menubar
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
frame.left=6
frame.right=6
frame.top=0
frame.bottom=1
frame.expansion=0
[Slider]
inherits=PanelButtonCommand
frame.element=slider
focusFrame=true
interior.element=slider
frame.top=3
frame.bottom=3
frame.left=3
frame.right=3
[SliderCursor]
inherits=PanelButtonCommand
frame=false
interior.element=slidercursor
[Progressbar]
inherits=PanelButtonCommand
frame.element=progress
interior.element=progress
text.margin=0
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
text.bold=false
frame.expansion=8
[ProgressbarContents]
inherits=PanelButtonCommand
frame=true
frame.element=progress-pattern
interior.element=progress-pattern
[ItemView]
inherits=PanelButtonCommand
text.margin=0
frame.element=itemview
interior.element=itemview
frame.top=4
frame.bottom=4
frame.left=4
frame.right=4
text.margin.top=0
text.margin.bottom=0
text.margin.left=8
text.margin.right=8
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
min_width=+0.3font
min_height=+0.3font
frame.expansion=0
[Splitter]
interior.element=splitter
frame=false
indicator.size=0
[Scrollbar]
inherits=PanelButtonCommand
indicator.element=arrow
indicator.size=12
[ScrollbarSlider]
inherits=PanelButtonCommand
frame.element=scrollbarslider
interior=false
frame.left=5
frame.right=5
frame.top=5
frame.bottom=5
indicator.element=grip
indicator.size=12
[ScrollbarGroove]
inherits=PanelButtonCommand
interior=false
frame=false
[Menu]
inherits=PanelButtonCommand
frame.top=8
frame.bottom=8
frame.left=8
frame.right=8
frame.element=menu
interior.element=menu
text.normal.color={{colors.on_surface.default.hex}}
text.shadow=false
text.bold=false
[MenuItem]
inherits=PanelButtonCommand
frame=true
frame.element=menuitem
interior.element=menuitem
indicator.element=menuitem
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.margin.top=0
text.margin.bottom=0
text.margin.left=6
text.margin.right=6
frame.top=4
frame.bottom=4
frame.left=12
frame.right=12
text.bold=false
frame.expansion=0
[MenuBar]
inherits=PanelButtonCommand
frame.element=menubar
interior.element=menubar
frame.bottom=0
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
frame.expansion=0
text.bold=false
[MenuBarItem]
inherits=PanelButtonCommand
interior=true
interior.element=menubaritem
frame.element=menubaritem
frame.top=2
frame.bottom=2
frame.left=2
frame.right=2
text.margin.left=4
text.margin.right=4
text.margin.top=0
text.margin.bottom=0
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
text.bold=false
min_width=+0.3font
min_height=+0.3font
frame.expansion=0
[TitleBar]
inherits=PanelButtonCommand
frame=false
text.margin.top=2
text.margin.bottom=2
text.margin.left=2
text.margin.right=2
interior.element=titlebar
indicator.size=16
indicator.element=mdi
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.bold=false
text.italic=true
frame.expansion=0
[ComboBox]
inherits=PanelButtonCommand
frame.element=combo
interior.element=combo
frame.top=6
frame.bottom=6
frame.left=6
frame.right=6
text.margin.top=2
text.margin.bottom=2
text.margin.left=2
text.margin.right=2
text.focus.color={{colors.on_surface.default.hex}}
text.press.color={{colors.on_surface.default.hex}}
text.toggle.color={{colors.on_surface.default.hex}}
[GroupBox]
inherits=GenericFrame
frame=false
text.shadow=0
text.margin=0
text.normal.color={{colors.on_surface.default.hex}}
text.focus.color={{colors.on_surface.default.hex}}
text.bold=false
frame.expansion=0
[TabBarFrame]
inherits=GenericFrame
frame=false
frame.element=tabBarFrame
interior=false
frame.top=0
frame.bottom=0
frame.left=0
frame.right=0
[ToolTip]
inherits=GenericFrame
frame.top=6
frame.bottom=6
frame.left=6
frame.right=6
interior=true
text.shadow=0
text.margin=6
interior.element=tooltip
frame.element=tooltip
frame.expansion=6
[StatusBar]
inherits=GenericFrame
frame=false
interior=false
[Window]
interior=true
interior.element=window
frame=true
frame.element=window
frame.bottom=10
frame.top=10

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 216 KiB

View File

@@ -0,0 +1,46 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
{
home-manager.users.${user} = {
qt = {
enable = true;
platformTheme.name = "qtct";
style.package = with pkgs; [
libsForQt5.qtstyleplugin-kvantum
qt6Packages.qtstyleplugin-kvantum
];
};
home.sessionVariables = {
QT_QPA_PLATFORM = "wayland";
QT_QPA_PLATFORMTHEME = "qt5ct";
};
theme.template = {
# https://github.com/GabePoel/KvLibadwaita/blob/main/src/KvLibadwaita/KvLibadwaita.kvconfig
"${home}/.config/Kvantum/KvAdwQt/KvAdwQt.kvconfig".source = ./KvAdwQt/KvAdwQt.kvconfig;
# https://github.com/GabePoel/KvLibadwaita/blob/main/src/KvLibadwaita/KvLibadwaita.svg
"${home}/.config/Kvantum/KvAdwQt/KvAdwQt.svg".source = ./KvAdwQt/KvAdwQt.svg;
};
xdg.configFile =
let
qtConfig = (pkgs.formats.ini { }).generate "qt5ct.conf" { Appearance.style = "kvantum"; };
in
{
"qt5ct/qt5ct.conf".source = qtConfig;
"qt6ct/qt6ct.conf".source = qtConfig;
"Kvantum/kvantum.kvconfig".source = (pkgs.formats.ini { }).generate "kvantum.kvconfig" {
General.theme = "KvAdwQt";
};
};
};
}

View File

@@ -0,0 +1,28 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
environment.persistence."/cache"."${home}/.cache/rofi" = { };
home-manager.users.${user} = {
programs.rofi = {
enable = true;
package = pkgs.rofi-wayland;
font = builtins.head hmConfig.theme.font.monospace.names;
};
wayland.windowManager.hyprland.settings.bind = [
"$mod, r, exec, ${lib.meta.getExe hmConfig.programs.rofi.finalPackage} -cache-dir ${home}/.cache/rofi -modi drun,window -show drun"
];
};
}

View File

@@ -0,0 +1,51 @@
:root {
--spice-text: {{colors.primary.default.hex}};
--spice-subtext: {{colors.on_surface_variant.default.hex}};
--spice-nav-active: {{colors.primary.default.hex}};
--spice-nav-active-text: {{colors.surface.default.hex}};
--spice-main: {{colors.surface.default.hex}};
--spice-main-secondary: {{colors.surface_container.default.hex}};
--spice-main-elevated: {{colors.surface_container_high.default.hex}};
--spice-sidebar: {{colors.surface.default.hex}};
--spice-card: {{colors.surface_container_high.default.hex}};
--spice-shadow: {{colors.shadow.default.hex}};
--spice-button: {{colors.primary.default.hex}};
--spice-button-active: {{colors.primary.default.hex}};
--spice-button-secondary: {{colors.on_surface_variant.default.hex}};
--spice-button-disabled: {{colors.outline_variant.default.hex}};
--spice-player: {{colors.surface_container_high.default.hex}};
--spice-play-button: {{colors.primary.default.hex}};
--spice-playback-bar: {{colors.primary.default.hex}};
--spice-tab-active: {{colors.surface_container.default.hex}};
--spice-selected-row: {{colors.on_surface.default.hex}};
--spice-highlight: {{colors.surface_container.default.hex}};
--spice-highlight-elevated: {{colors.surface_container_high.default.hex}};
--spice-notification: {{colors.surface_container_high.default.hex}};
--spice-notification-error: {{colors.error_container.default.hex}};
--spice-misc: {{colors.on_surface.default.hex}};
--spice-rgb-text: {{colors.primary.default.red}}, {{colors.primary.default.green}}, {{colors.primary.default.blue}};
--spice-rgb-subtext: {{colors.on_surface_variant.default.red}}, {{colors.on_surface_variant.default.green}}, {{colors.on_surface_variant.default.blue}};
--spice-rgb-nav-active: {{colors.primary.default.red}}, {{colors.primary.default.green}}, {{colors.primary.default.blue}};
--spice-rgb-nav-active-text: {{colors.surface.default.red}}, {{colors.surface.default.green}}, {{colors.surface.default.blue}};
--spice-rgb-main: {{colors.surface.default.red}}, {{colors.surface.default.green}}, {{colors.surface.default.blue}};
--spice-rgb-main-secondary: {{colors.surface_container.default.red}}, {{colors.surface_container.default.green}}, {{colors.surface_container.default.blue}};
--spice-rgb-main-elevated: {{colors.surface_container_high.default.red}}, {{colors.surface_container_high.default.green}}, {{colors.surface_container_high.default.blue}};
--spice-rgb-sidebar: {{colors.surface.default.red}}, {{colors.surface.default.green}}, {{colors.surface.default.blue}};
--spice-rgb-card: {{colors.surface_container_high.default.red}}, {{colors.surface_container_high.default.green}}, {{colors.surface_container_high.default.blue}};
--spice-rgb-shadow: {{colors.shadow.default.red}}, {{colors.shadow.default.green}}, {{colors.shadow.default.blue}};
--spice-rgb-button: {{colors.primary.default.red}}, {{colors.primary.default.green}}, {{colors.primary.default.blue}};
--spice-rgb-button-active: {{colors.primary.default.red}}, {{colors.primary.default.green}}, {{colors.primary.default.blue}};
--spice-rgb-button-secondary: {{colors.primary_container.default.red}}, {{colors.primary_container.default.green}}, {{colors.primary_container.default.blue}};
--spice-rgb-button-disabled: {{colors.outline_variant.default.red}}, {{colors.outline_variant.default.green}}, {{colors.outline_variant.default.blue}};
--spice-rgb-player: {{colors.surface_container_high.default.red}}, {{colors.surface_container_high.default.green}}, {{colors.surface_container_high.default.blue}};
--spice-rgb-play-button: {{colors.primary.default.red}}, {{colors.primary.default.green}}, {{colors.primary.default.blue}};
--spice-rgb-playback-bar: {{colors.primary.default.red}}, {{colors.primary.default.green}}, {{colors.primary.default.blue}};
--spice-rgb-tab-active: {{colors.surface_container.default.red}}, {{colors.surface_container.default.green}}, {{colors.surface_container.default.blue}};
--spice-rgb-selected-row: {{colors.on_surface.default.red}}, {{colors.on_surface.default.green}}, {{colors.on_surface.default.blue}};
--spice-rgb-highlight: {{colors.surface_container.default.red}}, {{colors.surface_container.default.green}}, {{colors.surface_container.default.blue}};
--spice-rgb-highlight-elevated: {{colors.surface_container_high.default.red}}, {{colors.surface_container_high.default.green}}, {{colors.surface_container_high.default.blue}};
--spice-rgb-notification: {{colors.surface_container_high.default.red}}, {{colors.surface_container_high.default.green}}, {{colors.surface_container_high.default.blue}};
--spice-rgb-notification-error: {{colors.error_container.default.red}}, {{colors.error_container.default.green}}, {{colors.error_container.default.blue}};
--spice-rgb-misc: {{colors.on_surface.default.red}}, {{colors.on_surface.default.green}}, {{colors.on_surface.default.blue}};
}

View File

@@ -0,0 +1 @@
app.autostart-mode="off"

View File

@@ -0,0 +1,7 @@
audio.crossfade_v2=true
audio.allow_downgrade=false
audio.sync_bitrate_enumeration=4
audio.play_bitrate_enumeration=4
audio.play_bitrate_non_metered_migrated=true
audio.play_bitrate_non_metered_enumeration=4
ui.track_notifications_enabled=false

View File

@@ -0,0 +1,90 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
inputs,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
networking.firewall = {
allowedTCPPorts = [ 57621 ];
allowedUDPPorts = [ 5353 ];
};
environment.persistence = {
"/persist"."${home}/.config/spotify" = { };
"/cache"."${home}/.cache/spotify" = { };
};
home-manager.users.${user} = {
imports = [ inputs.spicetify-nix.homeManagerModules.default ];
programs.spicetify =
let
spicePkgs = inputs.spicetify-nix.legacyPackages.${pkgs.system};
in
{
enable = true;
spicetifyPackage = pkgs.spicetify-cli.overrideAttrs (oldAttrs: {
patches = oldAttrs.patches or [ ] ++ [ ./user-colors.patch ];
});
theme = spicePkgs.themes.sleek // {
extraCommands = ''
export COLORS_CSS_PATH="${home}/.config/spotify/colors.css"
'';
additionalCss = ''
.main-topBar-topbarContentRight button {
background-color: unset !important;
}
'';
};
enabledExtensions = with spicePkgs.extensions; [
loopyLoop
trashbin
fullAlbumDate
phraseToPlaylist
songStats
copyToClipboard
betterGenres
adblock
autoSkip
];
};
sops.secrets."spotify/username".sopsFile = ../../../../../../secrets/personal/secrets.yaml;
xdg.configFile = {
"spotify/prefs.init" = {
source = ./config/prefs;
onChange = ''
${config.lib.runtime.merge.keyValue} "${home}/.config/spotify/prefs.init" "${home}/.config/spotify/prefs"
'';
};
"spotify/prefs-user.init" = {
source = ./config/prefs-user;
onChange = ''
user = $(cat "${hmConfig.sops.secrets."spotify/username".path}")
${config.lib.runtime.merge.keyValue} "${home}/.config/spotify/prefs-user.init" "${home}/.config/spotify/Users/''${user}-user/prefs"
'';
};
};
theme.template."${home}/.config/spotify/colors.css".source = ./colors.css;
wayland.windowManager.hyprland.settings.bind = [
"$mod, m, exec, ${lib.meta.getExe hmConfig.programs.spicetify.spicedSpotify}"
];
};
}

View File

@@ -0,0 +1,31 @@
diff --git a/src/apply/apply.go b/src/apply/apply.go
index 47f1346..47badab 100644
--- a/src/apply/apply.go
+++ b/src/apply/apply.go
@@ -2,6 +2,7 @@ package apply
import (
"fmt"
+ "errors"
"os"
"path/filepath"
"strings"
@@ -65,10 +66,17 @@ func AdditionalOptions(appsFolderPath string, flags Flag) {
// To not use custom css, set `themeFolder` to blank string
// To use default color scheme, set `scheme` to `nil`
func UserCSS(appsFolderPath, themeFolder string, scheme map[string]string) {
+ colorsSrc := os.Getenv("COLORS_CSS_PATH")
colorsDest := filepath.Join(appsFolderPath, "xpui", "colors.css")
- if err := os.WriteFile(colorsDest, []byte(getColorCSS(scheme)), 0700); err != nil {
+
+ if len(colorsSrc) == 0 {
+ utils.Fatal(errors.New("COLORS_CSS_PATH environment variable is not set"))
+ }
+
+ if err := os.Symlink(colorsSrc, colorsDest); err != nil {
utils.Fatal(err)
}
+
cssDest := filepath.Join(appsFolderPath, "xpui", "user.css")
if err := os.WriteFile(cssDest, []byte(getUserCSS(themeFolder)), 0700); err != nil {
utils.Fatal(err)

View File

@@ -0,0 +1,68 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
utils,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
themeSwww = lib.meta.getExe (
pkgs.writeShellApplication {
name = "theme-swww";
runtimeInputs = with pkgs; [
coreutils
swww
];
text = "exec swww img \"${hmConfig.theme.configDir}/wallpaper\"";
}
);
in
{
environment.persistence."/cache"."${home}/.cache/swww" = { };
home-manager.users.${user} = {
home.packages = with pkgs; [ swww ];
systemd.user.services.swww = {
Unit = {
Description = "Wallpaper daemon";
BindsTo = [ "graphical-session.target" ];
After = [
"graphical-session.target"
config.environment.persistence."/cache"."${home}/.cache/swww".mount
];
};
Service = {
Type = "forking";
ExecStart = lib.meta.getExe (
pkgs.writeShellApplication {
name = "init-swww";
runtimeInputs = with pkgs; [ swww ];
text = "exec swww init";
}
);
ExecStartPost = themeSwww;
ExecStop = lib.meta.getExe (
pkgs.writeShellApplication {
name = "kill-swww";
runtimeInputs = with pkgs; [ swww ];
text = "exec swww kill";
}
);
};
Install.WantedBy = [ "graphical-session.target" ];
};
theme.reloadExtraConfig = "${themeSwww} &";
};
}

View File

@@ -0,0 +1,29 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
inputs,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
themeBin = lib.meta.getExe hmConfig.theme.pkg;
in
{
environment.persistence."/persist"."${home}/.config/theme" = { };
home-manager.users.${user} = {
imports = [ ./options.nix ];
theme.enable = true;
wayland.windowManager.hyprland.settings.bind = [
"Ctrl_Alt, r, exec, ${themeBin}"
"Ctrl_Alt, t, exec, ${themeBin} toggle"
];
};
}

View File

@@ -0,0 +1,532 @@
{
config,
inputs,
lib,
pkgs,
...
}:
let
cfg = config.theme;
init = pkgs.writeShellApplication {
name = "theme-init";
runtimeInputs = with pkgs; [ matugen ];
text = ''
[[ ! -d "${cfg.configDir}" ]] && mkdir -p "${cfg.configDir}"
[[ ! -L "${cfg.configDir}"/wallpaper ]] && ln -sf "${cfg.wallpaper}" "${cfg.configDir}"/wallpaper
[[ ! -f "${cfg.configDir}"/mode ]] && echo "${cfg.mode}" > "${cfg.configDir}"/mode
matugen image "${cfg.configDir}/wallpaper" \
--type scheme-${cfg.flavour} \
--mode "$(cat "${cfg.configDir}/mode")" \
--contrast ${builtins.toString cfg.contrast}
${cfg.initExtraConfig}
'';
};
reload = pkgs.writeShellApplication {
name = "theme-reload";
text = cfg.reloadExtraConfig;
};
theme = pkgs.writeShellApplication {
name = "theme";
runtimeInputs = with pkgs; [ coreutils ];
runtimeEnv = {
CONFIG = cfg.configDir;
DEFAULT_WALLPAPER = cfg.wallpaper;
DEFAULT_MODE = cfg.mode;
INIT = lib.meta.getExe init;
RELOAD = lib.meta.getExe reload;
};
text = builtins.readFile ./theme.sh;
};
in
{
# https://github.com/Theaninova/TheaninovOS/blob/master/modules/home-manager/theme/md3-evo.nix
options.theme =
with lib;
with types;
{
enable = mkEnableOption "theme";
configDir = mkOption {
type = str;
default = "${config.xdg.configHome}/theme";
description = "The path to the theme config directory.";
};
wallpaper = mkOption {
type = path;
description = "The path to the default wallpaper";
};
pkg = mkOption {
type = package;
default = theme;
readOnly = true;
description = "The package containing the `theme` script";
};
initExtraConfig = mkOption {
type = lines;
default = "";
description = "Extra configuration lines to add to the theme initialization script.";
};
reloadExtraConfig = mkOption {
type = lines;
default = "";
description = "Extra configuration lines to add to the theme reload script.";
};
template = mkOption {
type = attrsOf (
submodule (
{ name, config, ... }:
{
options = {
source = mkOption {
type = nullOr path;
description = "Path of the source file or directory.";
default = null;
};
text = mkOption {
type = nullOr str;
description = "Text of the file.";
default = null;
};
target = mkOption {
type = str;
defaultText = literalExpression "name";
description = "Path to target relative to the user's {env}`HOME`.";
};
};
config.target = mkDefault name;
}
)
);
default = { };
description = "Templates to fill with theme colors.";
};
flavour = mkOption {
type = enum [
"content"
"expressive"
"fidelity"
"fruit-salad"
"monochrome"
"neutral"
"rainbow"
"tonal-spot"
];
default = "tonal-spot";
description = "The flavour of the theme.";
};
mode = mkOption {
type = enum [
"dark"
"light"
];
default = "dark";
description = "The default mode of the theme.";
};
contrast = mkOption {
type = numbers.between (-1) 1;
default = 0;
description = "Use a modified contrast.";
};
opacity = mkOption {
type = numbers.between 0 1;
default = 1;
description = "The opacity of apps.";
};
radius = mkOption {
type = ints.unsigned;
default = 8;
description = "The radius of corners.";
};
padding = mkOption {
type = ints.unsigned;
default = 8;
description = "The padding of windows.";
};
blur = mkOption {
type = ints.unsigned;
default = 0;
description = "The blur amount of windows.";
};
color = {
semantic = {
blend = mkOption {
type = bool;
default = true;
description = "Blend the colors.";
};
danger = mkOption {
type = str;
default = "#ff0000";
description = "The color of danger.";
};
warning = mkOption {
type = str;
default = "#ffff00";
description = "The color of warning.";
};
success = mkOption {
type = str;
default = "#00ff00";
description = "The color of success.";
};
info = mkOption {
type = str;
default = "#0000ff";
description = "The color of info.";
};
};
syntax = {
blend = mkOption {
type = bool;
default = true;
description = "Blend the colors.";
};
keywords = mkOption {
type = str;
default = "#ff8000";
description = "The color of keywords.";
};
functions = mkOption {
type = str;
default = "#0000ff";
description = "The color of functions.";
};
properties = mkOption {
type = str;
default = "#ff00ff";
description = "The color of properties.";
};
constants = mkOption {
type = str;
default = "#ff00ff";
description = "The color of constants.";
};
strings = mkOption {
type = str;
default = "#00ff00";
description = "The color of variables.";
};
numbers = mkOption {
type = str;
default = "#00ffff";
description = "The color of numbers.";
};
structures = mkOption {
type = str;
default = "#ffff00";
description = "The color of structures.";
};
types = mkOption {
type = str;
default = "#00ffff";
description = "The color of types.";
};
};
basic = {
blend = mkOption {
type = bool;
default = true;
description = "Blend the colors.";
};
red = mkOption {
type = str;
default = "#ff0000";
description = "The color of red.";
};
orange = mkOption {
type = str;
default = "#ff8000";
description = "The color of orange.";
};
yellow = mkOption {
type = str;
default = "#ffff00";
description = "The color of yellow.";
};
green = mkOption {
type = str;
default = "#00ff00";
description = "The color of green.";
};
cyan = mkOption {
type = str;
default = "#00ffff";
description = "The color of cyan.";
};
blue = mkOption {
type = str;
default = "#0000ff";
description = "The color of blue.";
};
magenta = mkOption {
type = str;
default = "#ff00ff";
description = "The color of magenta.";
};
pink = mkOption {
type = str;
default = "#ffc0cb";
description = "The color of pink.";
};
};
};
font = {
sansSerif = {
names = mkOption {
type = listOf str;
default = [ "Roboto" ];
description = "The sans serif font families.";
};
packages = mkOption {
type = listOf package;
default = with pkgs; [ roboto ];
description = "The sans serif font packages.";
};
};
serif = {
names = mkOption {
type = listOf str;
default = [ "Roboto Serif" ];
description = "The serif font families.";
};
packages = mkOption {
type = listOf package;
default = with pkgs; [ roboto-serif ];
description = "The serif font packages.";
};
};
monospace = {
names = mkOption {
type = listOf str;
default = [ "JetBrainsMono Nerd Font" ];
description = "The monospace font families.";
};
packages = mkOption {
type = listOf package;
default = with pkgs; [ nerd-fonts.jetbrains-mono ];
description = "The monospace font packages.";
};
};
emoji = {
names = mkOption {
type = listOf str;
default = [
"Noto Emoji"
"Font Awesome"
];
description = "The emoji font families.";
};
packages = mkOption {
type = listOf package;
default = with pkgs; [
noto-fonts-color-emoji
font-awesome
];
description = "The emoji font packages.";
};
};
size = mkOption {
type = ints.positive;
default = 12;
description = "The font size.";
};
};
icon = {
names = mkOption {
type = listOf str;
default = [ "Adwaita" ];
description = "The icon theme names.";
};
packages = mkOption {
type = listOf package;
default = with pkgs; [
adwaita-icon-theme
nixos-icons
];
description = "The icon theme packages.";
};
};
cursor = {
names = mkOption {
type = listOf str;
default = [ "Adwaita" ];
description = "The cursor names.";
};
packages = mkOption {
type = listOf package;
default = with pkgs; [ adwaita-icon-theme ];
description = "The cursor theme packages.";
};
size = mkOption {
type = ints.positive;
default = 32;
description = "The cursor size.";
};
};
};
config = lib.mkIf cfg.enable {
home = {
activation.themeInit = inputs.home-manager.lib.hm.dag.entryAfter [
"writeBoundary"
"dconfSettings"
] "run ${lib.meta.getExe init}";
packages =
with pkgs;
[
matugen
theme
]
++ cfg.font.sansSerif.packages
++ cfg.font.serif.packages
++ cfg.font.monospace.packages
++ cfg.font.emoji.packages
++ cfg.icon.packages
++ cfg.cursor.packages;
pointerCursor = {
name = builtins.head cfg.cursor.names;
package = builtins.head cfg.cursor.packages;
inherit (cfg.cursor) size;
};
};
fonts.fontconfig = {
enable = true;
defaultFonts = {
sansSerif = cfg.font.sansSerif.names;
serif = cfg.font.serif.names;
monospace = cfg.font.monospace.names;
emoji = cfg.font.emoji.names;
};
};
xdg.configFile."matugen/config.toml".source = (
(pkgs.formats.toml { }).generate "matugen" {
config = {
custom_colors =
let
mkColor = category: color: {
color = cfg.color.${category}.${color};
blend = cfg.color.${category}.blend;
};
in
{
danger = mkColor "semantic" "danger";
warning = mkColor "semantic" "warning";
success = mkColor "semantic" "success";
info = mkColor "semantic" "info";
red = mkColor "basic" "red";
orange = mkColor "basic" "orange";
yellow = mkColor "basic" "yellow";
green = mkColor "basic" "green";
cyan = mkColor "basic" "cyan";
blue = mkColor "basic" "blue";
magenta = mkColor "basic" "magenta";
pink = mkColor "basic" "pink";
keywords = mkColor "syntax" "keywords";
functions = mkColor "syntax" "functions";
properties = mkColor "syntax" "properties";
constants = mkColor "syntax" "constants";
strings = mkColor "syntax" "strings";
numbers = mkColor "syntax" "numbers";
structures = mkColor "syntax" "structures";
types = mkColor "syntax" "types";
};
custom_keywords =
let
zeroPad = hex: if builtins.stringLength hex == 1 then "0${hex}" else hex;
percentageToHex = percentage: zeroPad (lib.trivial.toHexString (builtins.floor (percentage * 255)));
in
{
flavour = cfg.flavour;
contrast = builtins.toString cfg.contrast;
radius = builtins.toString cfg.radius;
padding = builtins.toString cfg.padding;
padding_double = builtins.toString (cfg.padding * 2);
blur = builtins.toString cfg.blur;
opacity = builtins.toString cfg.opacity;
opacity_hex = builtins.toString (percentageToHex cfg.opacity);
opacity_shadow = builtins.toString (cfg.opacity * 0.75);
opacity_shadow_hex = builtins.toString (percentageToHex (cfg.opacity * 0.75));
font_size = builtins.toString cfg.font.size;
font_sans_serif = builtins.head cfg.font.sansSerif.names;
font_sans_serif_all = builtins.concatStringsSep ", " cfg.font.sansSerif.names;
font_serif = builtins.head cfg.font.serif.names;
font_serif_all = builtins.concatStringsSep ", " cfg.font.serif.names;
font_monospace = builtins.head cfg.font.monospace.names;
font_monospace_all = builtins.concatStringsSep ", " cfg.font.monospace.names;
font_emoji = builtins.head cfg.font.emoji.names;
font_emoji_all = builtins.concatStringsSep ", " cfg.font.emoji.names;
};
};
templates = builtins.mapAttrs (name: template: {
input_path = template.source or (pkgs.writeText name template.text);
output_path = template.target;
}) cfg.template;
}
);
};
}

View File

@@ -0,0 +1,94 @@
WALLPAPER=""
MODE=""
set_wallpaper() {
if [[ -f "$1" ]]; then
WALLPAPER="$1"
else
echo "Invalid wallpaper path: $1"
exit 1
fi
}
set_mode() {
if [[ "$1" = "light" ]] || [[ "$1" = "dark" ]]; then
MODE="$1"
else
echo "Invalid mode: $1. Use 'light' or 'dark'."
exit 1
fi
}
toggle_mode() {
if [[ "$(cat "${CONFIG}"/mode)" = "light" ]]; then
MODE="dark"
else
MODE="light"
fi
}
show_usage() {
echo "Usage: theme {toggle|light|dark|mode <mode>|wallpaper <file> [mode]}"
}
finish() {
[[ -n "${WALLPAPER}" ]] && ln -sf "${WALLPAPER}" "${CONFIG}"/wallpaper
[[ -n "${MODE}" ]] && echo "${MODE}" > "${CONFIG}"/mode
"${INIT}" > /dev/null
"${RELOAD}" > /dev/null
}
if [[ $# -eq 0 ]]; then
finish
else
case "$1" in
toggle)
if [[ $# -eq 1 ]]; then
toggle_mode
else
show_usage
exit 1
fi
;;
light)
if [[ $# -eq 1 ]]; then
set_mode "light"
else
show_usage
exit 1
fi
;;
dark)
if [[ $# -eq 1 ]]; then
set_mode "dark"
else
show_usage
exit 1
fi
;;
mode)
if [[ $# -eq 2 ]]; then
set_mode "$2"
else
show_usage
exit 1
fi
;;
wallpaper)
if [[ $# -ge 2 ]] && [[ $# -le 3 ]]; then
set_wallpaper "$2"
[[ $# -eq 3 ]] && set_mode "$3"
else
show_usage
exit 1
fi
;;
*)
show_usage
exit 1
;;
esac
finish
fi

View File

@@ -0,0 +1,17 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user} = {
home.packages = with pkgs; [ transmission_4-gtk ];
xdg.configFile."transmission/settings.json".source =
(pkgs.formats.json { }).generate "settings.json"
{
user-has-given-informed-consent = true;
torrent-complete-sound-enabled = false;
};
};
}

View File

@@ -0,0 +1,124 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
...
}:
let
hmConfig = config.home-manager.users.${user};
in
{
environment.persistence = {
"/persist"."${home}/.config/Code" = { };
# Bastard: https://github.com/microsoft/vscode/issues/3884
"/cache" = {
"${home}/.config/Code/Cache" = { };
"${home}/.config/Code/CachedConfigurations" = { };
"${home}/.config/Code/CachedData" = { };
"${home}/.config/Code/CachedExtensionVSIXs" = { };
"${home}/.config/Code/CachedExtensions" = { };
"${home}/.config/Code/CachedProfilesData" = { };
"${home}/.config/Code/Code Cache" = { };
"${home}/.config/Code/DawnCache" = { };
"${home}/.config/Code/GPUCache" = { };
"${home}/.config/Code/Service Worker/CacheStorage" = { };
"${home}/.config/Code/Service Worker/ScriptCache" = { };
};
};
home-manager.users.${user} = {
programs.vscode = {
enable = true;
mutableExtensionsDir = false;
extensions = with pkgs.vscode-extensions; [
mkhl.direnv
mhutchie.git-graph
ms-azuretools.vscode-docker
ms-vsliveshare.vsliveshare
github.copilot
naumovs.color-highlight
signageos.signageos-vscode-sops
];
userSettings = {
"diffEditor.ignoreTrimWhitespace" = false;
"editor.accessibilitySupport" = "off";
"editor.cursorBlinking" = "phase";
"editor.cursorSmoothCaretAnimation" = "on";
"editor.fontFamily" = builtins.concatStringsSep ", " hmConfig.theme.font.monospace.names;
"editor.fontLigatures" = true;
"editor.fontSize" = hmConfig.theme.font.size;
"editor.formatOnPaste" = true;
"editor.formatOnSave" = true;
"editor.formatOnType" = true;
"editor.indentSize" = "tabSize";
"editor.inlineSuggest.enabled" = true;
"editor.largeFileOptimizations" = false;
"editor.linkedEditing" = true;
"editor.renderFinalNewline" = "on";
"editor.smoothScrolling" = true;
"editor.stickyScroll.enabled" = true;
"editor.suggestSelection" = "first";
"editor.tabSize" = 2;
"editor.unicodeHighlight.includeComments" = true;
"editor.unicodeHighlight.nonBasicASCII" = true;
"explorer.confirmDelete" = false;
"explorer.confirmDragAndDrop" = false;
"explorer.confirmPasteNative" = false;
"extensions.autoCheckUpdates" = false;
"extensions.autoUpdate" = false;
"extensions.ignoreRecommendations" = true;
"files.autoSave" = "afterDelay";
"files.eol" = "\n";
"files.insertFinalNewline" = true;
"files.trimFinalNewlines" = true;
"files.trimTrailingWhitespace" = true;
"git.allowForcePush" = true;
"git.alwaysSignOff" = true;
"git.autofetch" = "all";
"git.closeDiffOnOperation" = true;
"git.confirmForcePush" = false;
"git.confirmSync" = false;
"git.enableCommitSigning" = true;
"git.enableSmartCommit" = true;
"git.ignoreRebaseWarning" = true;
"git.openRepositoryInParentFolders" = "always";
"git.path" = lib.meta.getExe pkgs.git;
"mergeEditor.diffAlgorithm" = "advanced";
"security.workspace.trust.enabled" = false;
"telemetry.telemetryLevel" = "off";
"terminal.external.linuxExec" = "kitty";
"terminal.integrated.confirmOnExit" = "hasChildProcesses";
"terminal.integrated.copyOnSelection" = true;
"terminal.integrated.fontFamily" =
builtins.concatStringsSep ", " hmConfig.theme.font.monospace.names;
"terminal.integrated.fontSize" = hmConfig.theme.font.size;
"update.mode" = "none";
"window.autoDetectHighContrast" = false;
"window.menuBarVisibility" = "toggle";
"workbench.editor.historyBasedLanguageDetection" = true;
"workbench.list.smoothScrolling" = true;
"typescript.updateImportsOnFileMove.enabled" = "always";
};
};
home.file.".vscode/argv.json".source = (pkgs.formats.json { }).generate "argv.json" {
password-store = "basic";
};
imports = [
./langs/c
./langs/nix
./langs/python
./langs/svelte
];
wayland.windowManager.hyprland.settings.bind = [ "$mod, c, exec, ${lib.meta.getExe pkgs.vscode}" ];
};
}

View File

@@ -0,0 +1,10 @@
{ pkgs, ... }:
{
programs.vscode.extensions =
with pkgs;
with vscode-extensions;
[
ms-vscode.cpptools
ms-vscode.cmake-tools
];
}

View File

@@ -0,0 +1,19 @@
{ lib, pkgs, ... }:
{
programs.vscode = {
userSettings = {
"nix.enableLanguageServer" = true;
"nix.serverPath" = lib.meta.getExe pkgs.nil;
"nix.serverSettings" = {
nil.formatting.command = [
(lib.meta.getExe pkgs.nix)
"fmt"
"--"
"--"
];
};
};
extensions = with pkgs; with vscode-extensions; [ jnoortheen.nix-ide ];
};
}

View File

@@ -0,0 +1,15 @@
{ pkgs, ... }:
{
programs.vscode.extensions =
with pkgs;
with vscode-extensions;
[
ms-python.python
ms-python.vscode-pylance
ms-python.debugpy
ms-python.pylint
ms-toolsai.jupyter
ms-toolsai.jupyter-renderers
njpwerner.autodocstring
];
}

View File

@@ -0,0 +1,15 @@
{ pkgs, ... }:
{
programs.vscode = {
userSettings = {
"svelte.enable-ts-plugin" = true;
};
extensions =
with pkgs;
with vscode-extensions;
[
svelte.svelte-vscode
];
};
}

View File

@@ -0,0 +1,8 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ pkgs, ... }:
{
home-manager.users.${user}.home.packages = with pkgs; [ wev ];
}

View File

@@ -0,0 +1,11 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, ... }:
{
home-manager.users.${user} = {
home.pointerCursor.x11.enable = true;
xresources.path = "${home}/.config/X11/xresources";
};
}

View File

@@ -0,0 +1,11 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{ config, pkgs, ... }:
{
home-manager.users.${user}.xdg.portal = {
xdgOpenUsePortal = true;
extraPortals = with pkgs; [ xdg-desktop-portal-gtk ];
};
}