add obs, etc

This commit is contained in:
Scott Scoble 2026-05-21 11:07:40 -07:00
parent 746b703d70
commit f367c42651
16 changed files with 844 additions and 31 deletions

View file

@ -81,6 +81,7 @@
./home/sscoble.nix
./home/pi.nix
./home/wgu.nix
./home/macos.nix
{
home.homeDirectory = "/Users/sscoble";
nixpkgs.config.allowUnfree = true;

56
home/bin/lid-handler.sh Executable file
View file

@ -0,0 +1,56 @@
#!/usr/bin/env bash
# ~/.config/hypr/scripts/lid-handler.sh
# Handles laptop lid close/open events for Hyprland.
# Called by Hyprland bindl (runs in user session context).
# Usage: lid-handler.sh close|open
set -euo pipefail
EVENT="${1:-}" # "close" or "open"
# Determine lid state if not provided
if [ -z "$EVENT" ]; then
LID_STATE=$(cat /proc/acpi/button/lid/LID0/state 2>/dev/null || cat /proc/acpi/button/lid/LID/state 2>/dev/null || echo "open")
if echo "$LID_STATE" | grep -qi "closed"; then
EVENT="close"
else
EVENT="open"
fi
fi
# Detect monitors via hyprctl
INTERNAL=$(hyprctl monitors -j 2>/dev/null | jq -r '.[] | select(.name | startswith("eDP")) | .name' | head -1 || echo "")
EXTERNAL=$(hyprctl monitors -j 2>/dev/null | jq -r '.[] | select(.name | startswith("eDP") | not) | .name' | head -1 || echo "")
# Fallback: try known names from hyprland.conf
[ -z "$INTERNAL" ] && INTERNAL="eDP-1"
[ -z "$EXTERNAL" ] && EXTERNAL="DP-3"
case "$EVENT" in
close)
if [ -n "$EXTERNAL" ]; then
# Move all workspaces to the external display first
WORKSPACES=$(hyprctl workspaces -j 2>/dev/null | jq -r '.[].id' || echo "")
for ws in $WORKSPACES; do
hyprctl dispatch moveworkspacetomonitor "$ws" "$EXTERNAL" 2>/dev/null || true
done
# Set external as primary (scale factor 1)
hyprctl keyword monitor "$EXTERNAL",preferred,auto,1 2>/dev/null || true
# Disable internal display
if [ -n "$INTERNAL" ]; then
hyprctl keyword monitor "$INTERNAL,disable" 2>/dev/null || true
fi
notify-send -t 3000 "Lid Closed" "Switched to $EXTERNAL as primary display"
else
notify-send -t 3000 "Lid Closed" "No external display detected — locking"
hyprlock 2>/dev/null || true
fi
;;
open)
# Re-enable internal display alongside external
if [ -n "$INTERNAL" ]; then
hyprctl keyword monitor "$INTERNAL,preferred,auto,1" 2>/dev/null || true
notify-send -t 3000 "Lid Opened" "Internal display $INTERNAL re-enabled"
fi
;;
esac

View file

@ -5,6 +5,8 @@
home.packages = with pkgs; [
# pi + qmd (from overlay)
qmd
# Browser
chromium
# Terminal
ghostty
zellij
@ -19,6 +21,8 @@
awww
btop
fuzzel
# Screen recording / streaming
obs-studio
# Lock + idle
hyprlock
hypridle
@ -40,9 +44,13 @@
bibata-cursors
papirus-icon-theme
adw-gtk3
beos-r5-icons
haiku-cursor
# Network / containers / system
networkmanagerapplet
firefox
gh
winetricks
cabextract # required by winetricks for .cab extraction
tailscale
docker
dive
@ -53,24 +61,58 @@
nmap
tcpdump
speedtest-cli
protonmail-bridge-gui
];
# === Proton Mail Bridge user service (starts at login) ===
systemd.user.services.protonmail-bridge = {
Unit = {
Description = "Proton Mail Bridge";
After = [ "network-online.target" "graphical-session.target" ];
Wants = [ "network-online.target" ];
};
Service = {
Type = "simple";
ExecStart = "${pkgs.protonmail-bridge}/bin/protonmail-bridge --non-interactive";
Restart = "on-failure";
RestartSec = "5";
};
Install = {
WantedBy = [ "graphical-session.target" ];
};
};
# === GTK / QT theming ===
gtk = {
enable = true;
theme.name = "adw-gtk3-dark";
iconTheme.name = "Papirus-Dark";
iconTheme.name = "BeOS-r5";
cursorTheme = {
name = "Bibata-Modern-Classic";
name = "Haiku_Cursor";
size = 24;
};
gtk3.extraConfig = {
gtk-application-prefer-dark-theme = 1;
};
gtk4.extraConfig = {
gtk-application-prefer-dark-theme = 1;
};
};
qt = {
enable = true;
platformTheme.name = "gtk";
platformTheme.name = "gtk3";
style.name = "adwaita-dark";
};
# === libadwaita dark mode ===
dconf.settings = {
"org/gnome/desktop/interface" = {
color-scheme = "prefer-dark";
};
};
# === Hyprland WM config ===
home.file.".config/hypr/hyprland.conf" = {
force = true;
@ -165,7 +207,7 @@
layer = "top"; position = "top"; height = 32; spacing = 4; margin = "6 8 0 8";
modules-left = [ "hyprland/workspaces" ];
modules-center = [ "clock" ];
modules-right = [ "tray" "pulseaudio" "backlight" "battery" "network" "cpu" "temperature" "memory" ];
modules-right = [ "tray" "bluetooth" "pulseaudio" "backlight" "battery" "network" "cpu" "temperature" "memory" ];
"hyprland/workspaces" = {
format = "{icon}";
@ -175,7 +217,7 @@
};
persistent_workspaces = { "1" = []; "2" = []; "3" = []; "4" = []; "5" = []; };
};
clock = { format = "{:%a %b %d %H:%M}"; tooltip-format = "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>"; };
clock = { format = "{:%a %b %d %I:%M %p}"; tooltip-format = "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>"; };
cpu = { format = " {usage}%"; };
temperature = { format = " {temperatureC}°C"; interval = 10; thermal-zone = 5; };
memory = { format = "󰍛 {}%"; };
@ -193,6 +235,15 @@
format = "{icon} {volume}%"; format-bluetooth = "{icon}󰂯 {volume}%"; format-muted = "󰝟";
format-icons.default = [ "󰕿" "󰖀" "󰕾" ]; on-click = "pavucontrol";
};
bluetooth = {
format = "󰂯";
format-connected = "󰂯 {device_alias}";
format-disabled = "";
format-no-controller = "";
format-off = "󰂲";
tooltip-format = "{device_alias} — {device_address}";
on-click = "blueman-manager";
};
tray.spacing = 10;
};
};
@ -204,7 +255,7 @@
#workspaces button { padding: 0 6px; color: #6c7086; background: transparent; border-radius: 4px; }
#workspaces button.active { color: #cdd6f4; background: #45475a; }
#workspaces button:hover { color: #cdd6f4; background: #313244; }
#clock, #cpu, #memory, #backlight, #battery, #network, #pulseaudio, #tray { padding: 0 10px; color: #cdd6f4; }
#clock, #cpu, #memory, #backlight, #battery, #network, #pulseaudio, #bluetooth, #tray { padding: 0 10px; color: #cdd6f4; }
#cpu.warning, #memory.warning, #battery.warning { color: #f9e2af; }
#cpu.critical, #memory.critical, #battery.critical { color: #f38ba8; }
tooltip { background: rgba(30,30,46,0.95); border: 1px solid #45475a; border-radius: 6px; }
@ -213,7 +264,7 @@
# === Rofi launcher ===
home.file.".config/rofi/config.rasi" = {
force = true;
source = ./rofi-config.rasi;
source = ./spotlight-dark.rasi;
};
# === Dunst notifications ===
home.file.".config/dunst/dunstrc".text = ''
@ -230,8 +281,110 @@
[urgency_normal] background = "#1e1e2e"; foreground = "#cdd6f4"; timeout = 5
[urgency_critical] background = "#f38ba8"; foreground = "#1e1e2e"; timeout = 0
'';
# === Lid handler ===
home.file.".config/hypr/scripts/lid-handler.sh" = {
force = true;
executable = true;
source = ./bin/lid-handler.sh;
};
# === Wallpaper rotation ===
home.file.".local/bin/wallpaper-rotate" = {
force = true;
source = ./wallpaper-rotate.sh;
};
# === BeOS cursor theme installer ===
home.file.".local/bin/install-beos-cursor" = {
force = true;
executable = true;
text = ''
#!/usr/bin/env bash
set -euo pipefail
CURSOR_NAME="BeOS"
ICONS_DIR="$HOME/.local/share/icons"
CURSOR_DIR="$ICONS_DIR/$CURSOR_NAME"
echo "==> BeOS Cursor Installer"
echo ""
if [ -d "$CURSOR_DIR" ] && [ -f "$CURSOR_DIR/index.theme" ]; then
echo " ✅ BeOS cursor already installed at $CURSOR_DIR"
echo ""
echo "To switch to it:"
echo " gsettings set org.gnome.desktop.interface cursor-theme BeOS"
echo " # Or update ~/.config/gtk-3.0/settings.ini:"
echo " # gtk-cursor-theme-name=BeOS"
exit 0
fi
echo "To install BeOS cursors:"
echo " 1. Open https://www.gnome-look.org/p/999293/ in your browser"
echo " 2. Download the BeOS-Cursors.tar.gz"
echo " 3. Run: install-beos-cursor /path/to/BeOS-Cursors.tar.gz"
echo ""
if [ $# -eq 0 ]; then
echo "No file provided. See instructions above."
exit 1
fi
ARCHIVE="$1"
if [ ! -f "$ARCHIVE" ]; then
echo " ❌ File not found: $ARCHIVE"
exit 1
fi
echo "==> Installing BeOS cursor from $ARCHIVE..."
mkdir -p "$ICONS_DIR"
tar xzf "$ARCHIVE" -C "$ICONS_DIR" 2>/dev/null || tar xzf "$ARCHIVE" -C "$ICONS_DIR" --strip-components=1 2>/dev/null || true
if [ -f "$CURSOR_DIR/index.theme" ]; then
echo " ✅ Installed to $CURSOR_DIR"
echo ""
echo "Now switch to BeOS cursor:"
echo " gsettings set org.gnome.desktop.interface cursor-theme BeOS"
else
# Try to find what was extracted
echo " Checking extracted directories..."
find "$ICONS_DIR" -name "index.theme" -exec dirname {} \\; 2>/dev/null | head -5
echo ""
echo "The extracted cursor directories are listed above."
fi
'';
};
# === Logos Bible Software (Wine) ===
# Helper script: first run installs Logos, subsequent runs launch it
home.file.".local/bin/logos" = {
force = true;
executable = true;
text = ''
#!/usr/bin/env bash
# Launch Logos Bible Software as a Chromium web app
exec chromium --app="https://app.logos.com" --name="Logos" "$@"
'';
};
# Logos web app icon
home.file.".local/share/icons/hicolor/scalable/apps/logos.svg".source = ./logos-icon.svg;
# Desktop entry for Logos web app
home.file.".local/share/applications/logos.desktop" = {
force = true;
text = ''
[Desktop Entry]
Type=Application
Name=Logos Bible Software
Comment=Logos Bible Software (Web App)
Exec=logos
Icon=logos
Terminal=false
Categories=Office;Education;Network;
StartupWMClass=logos
MimeType=x-scheme-handler/logos;
'';
};
}

View file

@ -4,7 +4,7 @@ monitor=,preferred,auto,1
monitor=DP-3,preferred,auto,1.5
env = XCURSOR_SIZE,24
env = XCURSOR_THEME,Bibata-Modern-Classic
env = XCURSOR_THEME,Haiku_Cursor
env = GTK_THEME,adw-gtk3-dark
env = QT_QPA_PLATFORMTHEME,gtk2
@ -14,11 +14,12 @@ exec-once = wl-paste --type text --watch cliphist store
exec-once = wl-paste --type image --watch cliphist store
exec-once = hypridle
exec-once = ~/.local/bin/wallpaper-rotate
exec-once = blueman-applet
# Auto-launch apps into their workspaces
exec-once = [workspace 1 silent] ghostty -e zellij
exec-once = [workspace 3 silent] firefox
exec-once = [workspace 4 silent] discord
# Auto-launch apps (window rules place them in correct workspaces)
exec-once = ghostty -e zellij
exec-once = firefox
exec-once = discord
input {
kb_layout = us
@ -85,9 +86,11 @@ bind = $mainMod SHIFT, Return, exec, ghostty
bind = $mainMod, B, exec, firefox
bind = $mainMod, D, exec, fuzzel
bind = $mainMod, Space, exec, fuzzel
bind = $mainMod SHIFT, Space, exec, rofi -show drun
bind = $mainMod, V, exec, cliphist list | rofi -dmenu | cliphist decode | wl-copy
bind = $mainMod, N, exec, thunar
bind = $mainMod, L, exec, hyprlock
bind = $mainMod, X, exec, blueman-manager
bind = $mainMod, Q, killactive
bind = $mainMod, F, fullscreen
bind = $mainMod, G, togglefloating
@ -137,6 +140,10 @@ bindel = , XF86MonBrightnessDown, exec, brightnessctl set 5%-
bind = $mainMod SHIFT, Q, exec, hyprctl dispatch exit
bind = $mainMod SHIFT, R, exec, hyprctl reload
# Lid switch: close → external display only, open → restore internal
bindl = , switch:on:Lid Switch, exec, ~/.config/hypr/scripts/lid-handler.sh close
bindl = , switch:off:Lid Switch, exec, ~/.config/hypr/scripts/lid-handler.sh open
windowrule = match:class ^(pavucontrol)$, float on
windowrule = match:class ^(firefox)$, match:title PIP, float on

4
home/logos-icon.svg Normal file
View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
<rect width="48" height="48" rx="8" fill="#2c2c2c"/>
<text font-family="Georgia, serif" font-size="28" font-weight="bold" fill="#f0c040" x="50%" y="55%" text-anchor="middle" dominant-baseline="central">L</text>
</svg>

After

Width:  |  Height:  |  Size: 306 B

270
home/macos.nix Normal file
View file

@ -0,0 +1,270 @@
{ config, pkgs, lib, ... }:
{
# === macOS-specific configuration ===
home.packages = with pkgs; [
# macOS window manager
aerospace
# Keyboard remapping (GUI app — download separately or install via brew)
# brew install --cask karabiner-elements
];
# =============================================================================
# KEYBOARD GOAL: Consistent finger positions across keyboards
#
# ThinkPad T490 (Linux): Ctrl | Super(Win) | Alt | Space
# Keychron V10M (macOS): Ctrl | Alt(⌥) | Cmd | Space ← remapped
# After remap (macOS): Ctrl | Super(Cmd) | Alt | Space
#
# Muscle memory:
# Middle key → Super/Cmd = WM actions (workspaces, focus, move)
# Next to space → Alt/Option = app shortcuts
#
# Remap: Physical Alt(⌥) → Cmd(⌘), Physical Cmd(⌘) → Alt(⌥)
# Applied via Karabiner-Elements, targeted to Keychron only.
#
# To find your Keychron's vendor/product IDs:
# 1. Open Karabiner-Elements → EventViewer tab
# 2. Press a key on the Keychron
# 3. Note the "VendorID" and "ProductID" values
# 4. Update them in the JSON below
#
# =============================================================================
home.file.".config/karabiner/karabiner.json" = {
force = true;
text = builtins.toJSON {
global = {
check_for_updates_on_startup = false;
show_in_menu_bar = false;
show_profile_name_in_menu_bar = false;
};
profiles = [
{
name = "Default";
selected = true;
simple_modifications = [];
fn_function_keys = [];
virtual_hid_keyboard = {
keyboard_type = "ansi";
caps_lock_delay_microseconds = 0;
};
devices = [];
complex_modifications = {
parameters = {
"basic.simultaneous_threshold_milliseconds" = 50;
"basic.to_if_held_down_threshold_milliseconds" = 500;
"basic.to_delayed_action_delay_milliseconds" = 500;
"basic.to_if_alone_timeout_milliseconds" = 1000;
};
rules = [
{
description = "Keychron V10M: swap Option ↔ Command (match ThinkPad bottom row)";
manipulators = [
{
# Physical Alt(⌥) → sends Cmd(⌘) = Super/WM key
type = "basic";
from = {
key_code = "left_alt";
modifiers = { optional = [ "any" ]; };
};
to = [ { key_code = "left_gui"; } ];
conditions = [
{
type = "device_if";
identifiers = [
{
# ⚠ UPDATE THESE with your Keychron's IDs
vendor_id = 0;
product_id = 0;
description = "Keychron V10M (Alice 75)";
}
];
}
];
}
{
# Physical Cmd(⌘) → sends Alt(⌥) = Alt key
type = "basic";
from = {
key_code = "left_gui";
modifiers = { optional = [ "any" ]; };
};
to = [ { key_code = "left_alt"; } ];
conditions = [
{
type = "device_if";
identifiers = [
{
vendor_id = 0;
product_id = 0;
}
];
}
];
}
];
}
];
};
}
];
};
};
# =============================================================================
# AEROSPACE — macOS Tiling Window Manager
#
# Keybindings use `cmd` (Super after remap) to match Hyprland's SUPER:
# Middle key + number → switch workspace
# Middle key + h/j/k/l → focus direction
# Middle key + tab → focus next window (cycle through all workspaces)
# Middle key + shift → move window
#
# macOS-native Cmd+Tab (now Alt+Tab after remap) still cycles apps.
# =============================================================================
home.file.".config/aerospace/aerospace.toml" = {
force = true;
text = ''
# =============================================================================
# Aerospace — macOS Tiling Window Manager
#
# Keybinding conventions (after Keychron remap matches ThinkPad):
# cmd (middle key) = SUPER — WM actions
# alt (next to space) = ALT — app shortcuts
# =============================================================================
# --- General ---
[general]
border = true
gaps = {
inner = { px = 6, vertical = 8, horizontal = 8 },
outer = { px = 4, px-monitor-workspace = 4, bottom = 6 },
}
# =============================================================================
# WORKSPACE SWITCHING — cmd = middle key
# =============================================================================
[mode.main.binding]
# Switch to workspace
cmd-1 = "workspace 1"
cmd-2 = "workspace 2"
cmd-3 = "workspace 3"
cmd-4 = "workspace 4"
cmd-5 = "workspace 5"
cmd-6 = "workspace 6"
cmd-7 = "workspace 7"
cmd-8 = "workspace 8"
cmd-9 = "workspace 9"
# Move window to workspace
cmd-shift-1 = "move-node-to-workspace 1"
cmd-shift-2 = "move-node-to-workspace 2"
cmd-shift-3 = "move-node-to-workspace 3"
cmd-shift-4 = "move-node-to-workspace 4"
cmd-shift-5 = "move-node-to-workspace 5"
cmd-shift-6 = "move-node-to-workspace 6"
cmd-shift-7 = "move-node-to-workspace 7"
cmd-shift-8 = "move-node-to-workspace 8"
cmd-shift-9 = "move-node-to-workspace 9"
# =============================================================================
# FOCUS NAVIGATION — Vim-style with cmd (middle key)
# =============================================================================
cmd-h = "focus left"
cmd-j = "focus down"
cmd-k = "focus up"
cmd-l = "focus right"
# Tab through windows across all workspaces
cmd-tab = "focus next"
# =============================================================================
# WINDOW MANAGEMENT
# =============================================================================
cmd-f = "fullscreen"
cmd-w = "close"
cmd-t = "floating toggle"
cmd-d = "layout tiles horizontal vertical"
cmd-shift-d = "layout tiles vertical horizontal"
# =============================================================================
# LAYOUT MANAGEMENT
# =============================================================================
cmd-r = "mode resize"
cmd-shift-h = "move left"
cmd-shift-j = "move down"
cmd-shift-k = "move up"
cmd-shift-l = "move right"
# =============================================================================
# RESIZE MODE
# =============================================================================
[mode.resize.binding]
cmd-h = "resize -50 0"
cmd-j = "resize 0 50"
cmd-k = "resize 0 -50"
cmd-l = "resize 50 0"
escape = "mode main"
enter = "mode main"
# =============================================================================
# MISC
# =============================================================================
cmd-shift-period = "reload-config"
cmd-backslash = "layout v_accordion"
cmd-shift-slash = "layout h_accordion"
# =============================================================================
# APP CYCLING
#
# macOS natively handles app cycling via Cmd+Tab.
# After Karabiner remap, the physical key next to spacebar now sends Alt,
# so what was Cmd+Tab is now available as a distinct chord.
# We use cmd+tab (middle key + tab) for Aerospace's "focus next" above,
# and the macOS native cycle is still accessible via alt+tab (next-to-space + tab).
# =============================================================================
'';
};
# =============================================================================
# HELPER: Find Keychron keyboard IDs for Karabiner
# =============================================================================
home.file.".local/bin/find-keychron-id" = {
force = true;
executable = true;
text = ''
#!/usr/bin/env bash
# Find your Keychron's vendor/product IDs for Karabiner-Elements config.
#
# Usage: ./find-keychron-id
#
# If Karabiner EventViewer is running, check its log for recent key events.
LOG="$HOME/.local/share/karabiner/eventviewer.log"
if [ -f "$LOG" ]; then
echo "Checking Karabiner EventViewer log..."
grep -i "keychron\|vendor_id\|product_id" "$LOG" 2>/dev/null | tail -10
fi
# Alternative: use ioreg to list HID devices
echo ""
echo "All HID keyboard devices (look for Keychron):"
ioreg -p IOUSB -l -w 0 | grep -A 10 -i "keyboard\|keychron" 2>/dev/null || \\
ioreg -r -c IOUSBDevice -l -w 0 | grep -A 15 -i "keychron\|keyboard" | grep -E "vendor|product|idProduct|idVendor|USB Product Name" | head -20
echo ""
echo "Or press a key on your Keychron and run:"
echo " hidutil list 2>/dev/null | grep -i keychron"
echo ""
echo "Then update vendor_id and product_id (as DECIMAL numbers) in:"
echo " ~/.config/karabiner/karabiner.json"
echo ""
echo " e.g. if vendor_id=0x3434, product_id=0x0408"
echo " then in JSON: vendor_id=13364, product_id=1032"
'';
};
}

150
home/spotlight-dark.rasi Normal file
View file

@ -0,0 +1,150 @@
/* Spotlight-Dark — macOS-inspired Rofi theme */
configuration {
modi: "drun,run,window";
show-icons: true;
icon-theme: "Papirus-Dark";
drun-display-format: "{name}";
font: "JetBrainsMono Nerd Font 14";
matching: "fuzzy";
terminal: "ghostty";
fuzzy-match: true;
scrollbar: false;
sidebar-mode: false;
}
* {
bg-col: rgba(30, 30, 46, 0.93);
bg-alt: rgba(49, 50, 68, 0.95);
fg-col: rgba(205, 214, 244, 1.0);
fg-dim: rgba(205, 214, 244, 0.5);
sel-bg: rgba(137, 180, 250, 0.18);
urgent-col: rgba(243, 139, 168, 1.0);
border-col: rgba(137, 180, 250, 0.0);
}
window {
width: 520px;
location: center;
anchor: center;
fullscreen: false;
y-offset: -120px;
border: 0px;
border-radius: 14px;
background-color: @bg-col;
text-color: @fg-col;
padding: 0;
}
mainbox {
padding: 0;
children: [ inputbar, listview ];
spacing: 0;
}
inputbar {
padding: 14px 18px;
background-color: @bg-alt;
border-radius: 14px 14px 0 0;
margin: 0;
children: [ entry, case-indicator ];
spacing: 8;
}
entry {
background: transparent;
text-color: @fg-col;
caret-color: @fg-col;
placeholder-color: @fg-dim;
placeholder: "Search apps, commands...";
expand: true;
horizontal-align: 0;
vertical-align: 0.5;
font: "JetBrainsMono Nerd Font 14";
}
case-indicator {
background: transparent;
text-color: @fg-dim;
font: "JetBrainsMono Nerd Font 10";
spacing: 0;
}
listview {
background: transparent;
padding: 6px 0;
lines: 8;
columns: 1;
spacing: 0;
cycle: true;
dynamic: true;
scrollbar: false;
layout: vertical;
}
element {
padding: 10px 18px;
border-radius: 0;
text-color: @fg-col;
background-color: transparent;
}
element normal.normal {
background-color: transparent;
text-color: @fg-col;
}
element selected.normal {
background-color: @sel-bg;
text-color: @fg-col;
}
element urgent.normal {
text-color: @urgent-col;
}
element-icon {
size: 22px;
padding: 0 12px 0 0;
horizontal-align: 0;
vertical-align: 0.5;
}
element-text {
padding: 0;
vertical-align: 0.5;
horizontal-align: 0;
text-color: inherit;
font: "JetBrainsMono Nerd Font 12";
}
element-text selected {
text-color: @fg-col;
}
message {
margin: 0;
padding: 10px 18px;
border-radius: 0 0 14px 14px;
background-color: @bg-alt;
text-color: @fg-dim;
}
textbox {
padding: 4px 8px;
text-color: @fg-dim;
}
button {
padding: 4px;
border-radius: 4px;
text-color: @fg-col;
}
scrollbar {
width: 4px;
border: 0;
handle-width: 4px;
handle-color: @border-col;
}

View file

@ -45,20 +45,22 @@
# === Git Config ===
programs.git = {
enable = true;
userName = "Scott Scoble";
userEmail = "sscoble@scobleclaw.dev";
extraConfig = {
settings = {
user = {
name = "Scott Scoble";
email = "sscoble@scobleclaw.dev";
};
init.defaultBranch = "main";
pull.rebase = true;
push.autoSetupRemote = true;
core.editor = "nvim";
};
aliases = {
lol = "log --graph --oneline --decorate --all";
co = "checkout";
br = "branch";
st = "status";
ci = "commit";
alias = {
lol = "log --graph --oneline --decorate --all";
co = "checkout";
br = "branch";
st = "status";
ci = "commit";
};
};
};
@ -156,7 +158,7 @@
l = "ls -CF";
nix-clean = "sudo nix-collect-garbage -d && nix-collect-garbage -d";
};
initExtra = ''
initContent = ''
# Nix flake shortcuts (adapts to platform)
if command -v nixos-rebuild &>/dev/null; then
alias nr="sudo nixos-rebuild switch --flake git+https://os.scoble.me/forgejo/sscoble/laptop-config.git#laptop"

View file

@ -8,7 +8,6 @@
# Browsers
brave
firefox
# Note-taking
obsidian

View file

@ -10,6 +10,49 @@
# Session variables
environment.sessionVariables.NIXOS_OZONE_WL = "1";
# === Lid close behavior ===
# Don't suspend when lid closes — external display stays active
services.logind = {
lidSwitch = "ignore";
lidSwitchExternalPower = "ignore";
lidSwitchDocked = "ignore";
};
# Fallback ACPI handler for lid events outside Hyprland session
# Primary handling is done via Hyprland bindl in hyprland.conf
services.acpid = {
enable = true;
handlers.lid = {
event = "button/lid.*";
action = ''
${pkgs.bash}/bin/bash -c '
LID_STATE=$(cat /proc/acpi/button/lid/LID0/state 2>/dev/null || cat /proc/acpi/button/lid/LID/state 2>/dev/null || echo "open")
if echo "$LID_STATE" | grep -qi "closed"; then
EVENT="close"
else
EVENT="open"
fi
for user_dir in /run/user/*/hypr/; do
[ -d "$user_dir" ] || continue
SIG=$(ls "$user_dir" 2>/dev/null | head -1)
[ -z "$SIG" ] && continue
UID=$(basename $(dirname "$user_dir"))
USER=$(id -nu $UID 2>/dev/null || echo "sscoble")
HOME_DIR=$(getent passwd "$USER" | cut -d: -f6)
USER_SCRIPT="$HOME_DIR/.config/hypr/scripts/lid-handler.sh"
if [ -x "$USER_SCRIPT" ]; then
sudo -u "$USER" \
XDG_RUNTIME_DIR="/run/user/$UID" \
HYPRLAND_INSTANCE_SIGNATURE="$SIG" \
"$USER_SCRIPT" "$EVENT"
fi
break
done
'
'';
};
};
# Security — required for hyprlock
security.pam.services.hyprlock = {};
@ -82,6 +125,15 @@
hardware.bluetooth.enable = true;
hardware.bluetooth.powerOnBoot = true;
# Bluetooth manager (GUI pairing, tray applet)
# Note: using manual setup instead of services.blueman.enable to avoid
# a systemd unit bug (duplicate ExecStart in blueman-applet.service).
# The applet is launched via exec-once in hyprland.conf instead.
environment.systemPackages = with pkgs; [ blueman ];
services.dbus.packages = with pkgs; [ blueman ];
systemd.user.services.blueman-applet = { enable = false; };
systemd.user.services.blueman-manager = { enable = false; };
# NetworkManager applet
programs.nm-applet.enable = true;
}

View file

@ -43,8 +43,15 @@
wineWow64Packages.stable
];
# DNS fallback (Tailscale MagicDNS sometimes blocks public resolvers)
networking.nameservers = [ "1.1.1.1" "8.8.8.8" ];
# === WiFi / NetworkManager (imperative — not idempotent) ===
# We move between SSIDs regularly, so NO declarative wifi networks here.
# Use nm-applet (tray) or nmcli (CLI) to connect to any SSID at runtime.
# Connections persist across reboots via /etc/NetworkManager/system-connections/
networking.networkmanager.enable = true;
# DNS handed out by NM to each connection; Tailscale MagicDNS can interfere
# with public resolvers, so we inject Cloudflare + Google as fallbacks.
networking.networkmanager.insertNameservers = [ "1.1.1.1" "8.8.8.8" ];
# Passwordless sudo for sscoble
security.sudo.extraRules = [

View file

@ -20,7 +20,7 @@
# Enable network printer discovery via mDNS/Bonjour
services.avahi = {
enable = true;
nssmdns = true;
nssmdns4 = true;
publish = {
enable = true;
addresses = true;

View file

@ -63,7 +63,51 @@
# === powertop ===
powerManagement.powertop.enable = true;
# Skip thermald — conflicts with throttled (enabled by nixos-hardware)
# === throttled — undervolt + raise trip temp for better sustained perf ===
services.throttled = {
extraConfig = ''
[GENERAL]
Enabled: True
Sysfs_Power_Path: /sys/class/power_supply/AC*/online
Autoreload: True
[BATTERY]
Update_Rate_s: 30
PL1_Tdp_W: 29
PL1_Duration_s: 28
PL2_Tdp_W: 29
PL2_Duration_S: 0.002
Trip_Temp_C: 85
cTDP: 0
Disable_BDPROCHOT: False
[AC]
Update_Rate_s: 5
PL1_Tdp_W: 44
PL1_Duration_s: 28
PL2_Tdp_W: 44
PL2_Duration_S: 0.002
Trip_Temp_C: 97
cTDP: 0
Disable_BDPROCHOT: False
[UNDERVOLT.BATTERY]
CORE: -70
GPU: -50
CACHE: -70
UNCORE: -40
ANALOGIO: -40
[UNDERVOLT.AC]
CORE: -80
GPU: -50
CACHE: -80
UNCORE: -50
ANALOGIO: -50
'';
};
# Skip thermald — conflicts with throttled
services.thermald.enable = false;
# === zram swap (faster + saves NVMe writes) ===
@ -135,11 +179,14 @@
# === Tailscale (consistent cluster access from any network) ===
services.tailscale.enable = true;
# === Proton Mail Bridge (local IMAP/SMTP for Proton Mail) ===
# The systemd user service is defined in home/desktop.nix
# === NVMe tools ===
environment.systemPackages = with pkgs; [ nvme-cli ];
environment.systemPackages = with pkgs; [ nvme-cli protonmail-bridge ];
# === Touchpad & TrackPoint ===
services.xserver.libinput = {
services.libinput = {
enable = true;
touchpad = {
tapping = true;

View file

@ -2,4 +2,7 @@ final: prev: {
qmd = final.writeShellScriptBin "qmd" ''
exec ${final.bun}/bin/bunx --bun @tobilu/qmd "$@"
'';
beos-r5-icons = final.callPackage ./pkgs/beos-r5-icons { };
haiku-cursor = final.callPackage ./pkgs/haiku-cursor { };
}

View file

@ -0,0 +1,34 @@
{ lib, stdenvNoCC, fetchFromGitHub }:
stdenvNoCC.mkDerivation {
pname = "beos-r5-icons";
version = "2021-03-24";
src = fetchFromGitHub {
owner = "jcherven";
repo = "BeOS-r5-Icons";
rev = "1c1067eabaeb0196c12606ac19b2aed4496bc15e";
hash = "sha256-6qnOWMdwgK9tKifHXSF6s1KjHkdIG/jnM9Te43cVOjo=";
};
installPhase = ''
mkdir -p $out/share/icons/BeOS-r5
cp -pr * $out/share/icons/BeOS-r5/
# Remove broken symlinks (icon theme has some dangling links)
find $out/share/icons/BeOS-r5 -type l -not -exec test -e {} \; -delete
rm -f $out/share/icons/BeOS-r5/screenshot.png
rm -f $out/share/icons/BeOS-r5/.icon-theme.cache
'';
meta = with lib; {
description = "Classic BeOS r5 icons for Linux desktops";
longDescription = ''
A large collection of BeOS & period-correct icons.
Includes icons from BeOS-r5, Zeta OS, Haiku OS, KDEclassic, and more.
'';
homepage = "https://github.com/jcherven/BeOS-r5-Icons";
license = licenses.gpl2Plus;
platforms = platforms.linux;
maintainers = [ ];
};
}

View file

@ -0,0 +1,28 @@
{ lib, stdenvNoCC, fetchurl }:
stdenvNoCC.mkDerivation {
pname = "haiku-cursor";
version = "linux-02";
src = fetchurl {
url = "https://github.com/leath-dub/Haiku_Cursor/releases/download/linux-02/Haiku_Cursor.tgz";
hash = "sha256-AXgo+jqrCjEyDpWL6GnpUAbvx3Oje+7zQvnIC8j1uz0=";
};
installPhase = ''
mkdir -p $out/share/icons/Haiku_Cursor
cp -pr * $out/share/icons/Haiku_Cursor/
'';
meta = with lib; {
description = "Haiku/BeOS-style XCursor theme";
longDescription = ''
A port of the Haiku cursor set as an XCursor theme.
These cursors are faithful to the BeOS/Haiku look.
'';
homepage = "https://github.com/leath-dub/Haiku_Cursor";
license = licenses.mit;
platforms = platforms.linux;
maintainers = [ ];
};
}