Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2024-11-25 18:30:57 +00:00
parent 4b90073952
commit 609a028414
41 changed files with 392 additions and 496 deletions

134
flake.lock generated
View File

@@ -2,25 +2,66 @@
"nodes": {
"ags": {
"inputs": {
"astal": "astal",
"nixpkgs": [
"nixpkgs"
],
"systems": "systems"
]
},
"locked": {
"lastModified": 1728326430,
"narHash": "sha256-tV1ABHuA1HItMdCTuNdA8fMB+qw7LpjvI945VwMSABI=",
"owner": "Aylur",
"lastModified": 1732307740,
"narHash": "sha256-ZDsYdZOtg5qkK/wfLLB83B3SI+fE32S+/6Ey0ggHODM=",
"owner": "aylur",
"repo": "ags",
"rev": "60180a184cfb32b61a1d871c058b31a3b9b0743d",
"rev": "81159966eb8b39b66c3efc133982fd76920c9605",
"type": "github"
},
"original": {
"owner": "Aylur",
"owner": "aylur",
"repo": "ags",
"type": "github"
}
},
"astal": {
"inputs": {
"nixpkgs": [
"ags",
"nixpkgs"
]
},
"locked": {
"lastModified": 1731952585,
"narHash": "sha256-Sh1E7sJd8JJM3PCU1ZOei/QWz97OLCENIi2rTRoaniw=",
"owner": "aylur",
"repo": "astal",
"rev": "664c7a4ddfcf48c6e8accd3c33bb94424b0e8609",
"type": "github"
},
"original": {
"owner": "aylur",
"repo": "astal",
"type": "github"
}
},
"astal_2": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1732491849,
"narHash": "sha256-Q8Ailv1RQhhlRDa4xAqvhjKam9sYNJ7Sr0G+WwARKGU=",
"owner": "aylur",
"repo": "astal",
"rev": "b7af61d770510b1c797e1c7137a4da934cdca7a2",
"type": "github"
},
"original": {
"owner": "aylur",
"repo": "astal",
"type": "github"
}
},
"disko": {
"inputs": {
"nixpkgs": [
@@ -28,11 +69,11 @@
]
},
"locked": {
"lastModified": 1729281548,
"narHash": "sha256-MuojlSnwAJAwfhgmW8ZtZrwm2Sko4fqubCvReqbUzYw=",
"lastModified": 1732540163,
"narHash": "sha256-5EYzmoTpem2IB9JWzd41sL98pz3lyyCSTiCjv08i4Uk=",
"owner": "nix-community",
"repo": "disko",
"rev": "a6a3179ddf396dfc28a078e2f169354d0c137125",
"rev": "2ed5e30fc7e34adf455db8b02b9151d3922a54ea",
"type": "github"
},
"original": {
@@ -59,14 +100,14 @@
},
"flake-utils": {
"inputs": {
"systems": "systems_2"
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
@@ -82,11 +123,11 @@
]
},
"locked": {
"lastModified": 1729507872,
"narHash": "sha256-5ChymD+5No/9lt1b4C3nlDigKLLyelcWy5KhgutbK2g=",
"lastModified": 1732554302,
"narHash": "sha256-qaS1xo2CDWo2IwT/otu03nTxs06BzY5ZOF4Azev7fUc=",
"owner": "karaolidis",
"repo": "home-manager",
"rev": "44e29caf69a545978e6018c6df42ac0bc228df0d",
"rev": "32fe2dc4964fc14c59d42dfcd1ea7f23d2ed7949",
"type": "github"
},
"original": {
@@ -98,11 +139,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1729507870,
"narHash": "sha256-m/kt901Md6uYHdLSFqGNvYFKd3cYbNlQsunip7pqTMQ=",
"lastModified": 1732554299,
"narHash": "sha256-VlbdJzanpnWMMBvfj7Ge81Fe9j3EAnVMIL+EkX2BU8k=",
"owner": "karaolidis",
"repo": "nixpkgs",
"rev": "ba1134c0cd1f0b06f6607747db0bcbeaac4cfe3f",
"rev": "9397502b911602897f06d97708a7398f4f6fc075",
"type": "github"
},
"original": {
@@ -112,29 +153,13 @@
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1729357638,
"narHash": "sha256-66RHecx+zohbZwJVEPF7uuwHeqf8rykZTMCTqIrOew4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "bb8c2cf7ea0dd2e18a52746b2c3a5b0c73b93c22",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nur": {
"locked": {
"lastModified": 1729491640,
"narHash": "sha256-k2mR4w+yvko/JsWaH+1fIqjWRFixEs+jv/lNw8qnfkQ=",
"lastModified": 1732552240,
"narHash": "sha256-P0lWDHJ7OPXx+clV/F5n+WIRSWhSAmLlPYFoSDzDvPw=",
"owner": "nix-community",
"repo": "NUR",
"rev": "41ca6cfe238fdfab2831386c5a65f5c0a01e1cfd",
"rev": "bdd3c9465129b14b148cdc98e152433347b9b974",
"type": "github"
},
"original": {
@@ -146,6 +171,7 @@
"root": {
"inputs": {
"ags": "ags",
"astal": "astal_2",
"disko": "disko",
"flake-utils": "flake-utils",
"home-manager": "home-manager",
@@ -159,15 +185,14 @@
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
]
},
"locked": {
"lastModified": 1729394972,
"narHash": "sha256-fADlzOzcSaGsrO+THUZ8SgckMMc7bMQftztKFCLVcFI=",
"lastModified": 1732186149,
"narHash": "sha256-N9JGWe/T8BC0Tss2Cv30plvZUYoiRmykP7ZdY2on2b0=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "c504fd7ac946d7a1b17944d73b261ca0a0b226a5",
"rev": "53c853fb1a7e4f25f68805ee25c83d5de18dc699",
"type": "github"
},
"original": {
@@ -184,11 +209,11 @@
]
},
"locked": {
"lastModified": 1729484282,
"narHash": "sha256-VnLaP3OH9rP/+5ZuEsETSyyKtBif5l3mNL3YOxPhBVo=",
"lastModified": 1732508213,
"narHash": "sha256-0rfdpRO1KnesH0XHv8mAHmfsPQXnHiwiu79sN3nCy/0=",
"owner": "Gerg-L",
"repo": "spicetify-nix",
"rev": "7dcfbba64faedd15574e6df5d89b2bcf5bb20128",
"rev": "4841814c6e22958aff9dd8c68fd2153237fbf15e",
"type": "github"
},
"original": {
@@ -198,21 +223,6 @@
}
},
"systems": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",

View File

@@ -49,8 +49,13 @@
url = "github:numtide/flake-utils";
};
astal = {
url = "github:aylur/astal";
inputs.nixpkgs.follows = "nixpkgs";
};
ags = {
url = "github:Aylur/ags";
url = "github:aylur/ags";
inputs.nixpkgs.follows = "nixpkgs";
};

View File

@@ -10,9 +10,10 @@
timeout = 1;
efi.canTouchEfiVariables = true;
};
initrd.systemd.enable = true;
kernelPackages = pkgs.linuxPackages_latest;
# FIXME: https://github.com/NixOS/nixpkgs/issues/357643
# kernelPackages = pkgs.linuxPackages_latest;
kernelPackages = pkgs.linuxKernel.packages.linux_6_11;
supportedFilesystems = [
"btrfs"
"ntfs"

View File

@@ -19,7 +19,11 @@
users.${user} = {
home.stateVersion = "24.11";
systemd.user.startServices = true;
nix.settings = config.nix.settings;
nix.settings.experimental-features = [
"nix-command"
"flakes"
];
};
};
}

View File

@@ -1,3 +0,0 @@
node_modules
types
bun.lockb

View File

@@ -1,7 +0,0 @@
{
"arrowParens": "avoid",
"bracketSameLine": true,
"bracketSpacing": true,
"singleQuote": true,
"trailingComma": "all"
}

View File

@@ -1,25 +0,0 @@
{ pkgs, ... }:
pkgs.stdenv.mkDerivation {
pname = "ags.config";
version = "0.0.1";
src = ./.;
nativeBuildInputs = with pkgs; [ bun ];
phases = [
"buildPhase"
"installPhase"
];
buildPhase = ''
bun build $src/src/index.ts --outfile=index.js \
--external="file://$src/*" \
--external="gi://*"
'';
installPhase = ''
mkdir -p $out/share
cp index.js $out/share/config.js
'';
}

View File

@@ -1,116 +0,0 @@
/* eslint no-use-before-define: 0 */
import globals from 'globals';
import pluginJs from '@eslint/js';
import tseslint from 'typescript-eslint';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import unicorn from 'eslint-plugin-unicorn';
import prettier from 'eslint-plugin-prettier';
import tsParser from '@typescript-eslint/parser';
export default [
{ files: ['**/*.{js,mjs,cjs,ts}'] },
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
{
plugins: {
'@typescript-eslint': typescriptEslint,
unicorn,
prettier,
},
languageOptions: {
globals: {
...globals.browser,
},
parser: tsParser,
ecmaVersion: 5,
sourceType: 'script',
parserOptions: {
project: ['./tsconfig.json'],
},
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
rules: {
curly: ['error', 'multi-line'],
'eol-last': ['error', 'always'],
semi: ['error', 'always'],
quotes: ['error', 'single'],
'no-await-in-loop': 'warn',
'no-constructor-return': 'error',
'no-duplicate-imports': 'error',
'no-self-compare': 'error',
'no-unreachable-loop': 'error',
'no-trailing-spaces': 'error',
'no-console': 'warn',
'no-shadow': 'off',
'@typescript-eslint/no-shadow': ['error'],
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error'],
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': ['error'],
'@typescript-eslint/require-await': 'warn',
'@typescript-eslint/no-misused-promises': ['error', {
checksVoidReturn: false,
}],
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'default',
format: ['camelCase'],
leadingUnderscore: 'allowSingleOrDouble',
},
{
selector: 'variableLike',
format: ['camelCase', 'PascalCase'],
leadingUnderscore: 'allowSingleOrDouble',
},
{
selector: 'memberLike',
format: ['camelCase'],
},
{
selector: 'typeLike',
format: ['PascalCase'],
},
{
selector: 'property',
format: ['snake_case'],
},
{
selector: 'method',
format: ['camelCase'],
},
{
selector: ['enumMember', 'enum'],
format: ['UPPER_CASE'],
}
],
'unicorn/empty-brace-spaces': 'off',
'unicorn/expiring-todo-comments': 'off',
'unicorn/no-array-for-each': 'off',
'unicorn/filename-case': ['error', {
case: 'camelCase',
}],
'unicorn/numeric-separators-style': 'off',
'unicorn/prevent-abbreviations': 'off',
},
"ignores": ["*.config.js"]
}
];

View File

@@ -1,23 +0,0 @@
{
"name": "ags",
"module": "index.ts",
"type": "module",
"scripts": {
"lint": "eslint ."
},
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.6.0",
"@types/bun": "^1.1.6",
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.14.1",
"eslint": "9.x",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^54.0.0",
"globals": "^15.6.0",
"typescript-eslint": "^7.14.1"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}

View File

@@ -1,19 +0,0 @@
import gtk from 'gi://Gtk?version=3.0';
import gdk from 'gi://Gdk';
import { range } from 'lib';
import themeInit from 'theme';
import bar from 'widgets/bar/bar';
const forMonitors = (widget: (monitor: number) => gtk.Window) => {
const n = gdk.Display.get_default()?.get_n_monitors() || 1;
return range(n, 0).flatMap(widget);
};
App.config({
style: themeInit(),
windows: [
...forMonitors(bar),
]
});
Utils.execAsync('systemd-notify --ready')

View File

@@ -1,25 +0,0 @@
export default () => {
const css = `${App.configDir}/theme.css`;
const scss = `${App.configDir}/theme.sass`;
let themeExists = true;
try {
Utils.readFile(scss);
Utils.exec(`sassc ${scss} ${css}`);
} catch (error) {
console.error(error);
themeExists = false;
}
Utils.monitorFile(
`${App.configDir}/theme.sass`,
function () {
Utils.exec(`sassc ${scss} ${css}`);
App.resetCss();
App.applyCss(css);
},
);
return themeExists ? css : undefined;
};

View File

@@ -1,39 +0,0 @@
import gap from './gap/gap';
import launcher from './launcher/launcher';
import workspace from './workspace/workspace';
import date from './date/date';
import systray from './systray/systray';
export default (monitor: number) => Widget.Window({
monitor,
class_name: 'bar',
name: `bar${monitor}`,
exclusivity: 'exclusive',
anchor: ['top', 'right', 'left'],
child: Widget.CenterBox({
class_name: 'widgets',
start_widget: Widget.Box({
hexpand: true,
hpack: 'start',
children: [
launcher(),
gap(),
workspace(),
],
}),
center_widget: Widget.Box({
hexpand: true,
hpack: 'center',
children: [
date(),
],
}),
end_widget: Widget.Box({
hexpand: true,
hpack: 'end',
children: [
systray(),
],
}),
}),
});

View File

@@ -1,10 +0,0 @@
const icon = () => Widget.Icon({
class_name: 'icon',
icon: 'edit-paste-symbolic',
});
export default () => Widget.EventBox({
class_name: 'clipboard',
child: icon(),
onPrimaryClick: () => Utils.execAsync('cliphist-rofi'),
});

View File

@@ -1,18 +0,0 @@
import glib from 'gi://GLib';
const clock = Variable(glib.DateTime.new_now_local(), {
poll: [1000, () => glib.DateTime.new_now_local()]
});
const time = Utils.derive([clock], (c) => c.format('%H:%M - %A, %d %B %Y') || '');
const label = () => Widget.Label({
class_name: 'label',
justification: 'center',
label: time.bind(),
});
export default () => Widget.EventBox({
class_name: 'date',
child: label(),
});

View File

@@ -1,3 +0,0 @@
export default () => Widget.Box({
class_name: 'gap',
});

View File

@@ -1,10 +0,0 @@
const icon = () => Widget.Icon({
class_name: 'icon',
icon: 'nix-snowflake-symbolic',
});
export default () => Widget.EventBox({
class_name: 'launcher',
child: icon(),
onPrimaryClick: () => Utils.execAsync('bash -c "rofi -cache-dir $XDG_CACHE_HOME/rofi -show drun"'),
});

View File

@@ -1,16 +0,0 @@
import gdk from 'gi://Gdk';
const systemtray = await Service.import('systemtray');
const systrayItem = item => Widget.EventBox({
class_name: 'item',
tooltip_markup: item.bind('tooltip_markup'),
child: Widget.Icon({ class_name: 'icon' }).bind('icon', item, 'icon'),
onPrimaryClick: (_, event: gdk.Event) => item.activate(event),
onSecondaryClick: (_, event: gdk.Event) => item.openMenu(event),
});
export default () => Widget.Box({
class_name: 'systray',
children: systemtray.bind('items').as(i => i.map(systrayItem))
});

View File

@@ -1,23 +0,0 @@
import { range } from 'lib';
const hyprland = await Service.import('hyprland');
const dispatch = ws => hyprland.messageAsync(`dispatch workspace ${ws}`);
const workspaceButton = (i: number) => Widget.Label({
class_name: 'button',
attribute: i,
vpack: 'center',
setup: self => self.hook(hyprland, () => {
self.toggleClassName('active', hyprland.active.workspace.id === i);
self.toggleClassName('occupied', (hyprland.getWorkspace(i)?.windows || 0) > 0);
}),
});
export default () => Widget.EventBox({
class_name: 'workspace',
onScrollUp: () => dispatch('e-1'),
onScrollDown: () => dispatch('e+1'),
child: Widget.Box({
children: range(10).map(workspaceButton),
}),
});

View File

@@ -1,18 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"lib": [
"ES2022"
],
"allowJs": true,
"checkJs": true,
"strict": true,
"noImplicitAny": false,
"baseUrl": "./src",
"typeRoots": [
"./types",
],
"skipLibCheck": true,
}
}

View File

@@ -1,63 +0,0 @@
{
user ? throw "user argument is required",
home ? throw "home argument is required",
}:
{
config,
lib,
pkgs,
inputs,
...
}:
let
agsConfig = pkgs.callPackage ./config { };
in
{
home-manager.users.${user} = {
imports = [ inputs.ags.homeManagerModules.default ];
programs.ags.enable = true;
xdg.configFile."ags/config.js".source = "${agsConfig}/share/config.js";
theme.template."${home}/.config/ags/theme.sass".source = ./theme.sass;
systemd.user = {
targets.tray.Unit = {
BindsTo = [ "ags.service" ];
After = [
"graphical-session.target"
"ags.service"
];
};
services.ags = {
Unit = {
Description = "Desktop widget shell";
BindsTo = [ "graphical-session.target" ];
After = [ "graphical-session.target" ];
};
Service = {
Type = "notify";
NotifyAccess = "all";
ExecStart = lib.meta.getExe (
pkgs.writeShellApplication {
name = "init-ags";
runtimeInputs = with pkgs; [
inputs.ags.packages.${stdenv.hostPlatform.system}.default
sassc
hyprland
nixos-icons
libdbusmenu-gtk3
(pkgs.callPackage ../cliphist/rofi.nix { })
];
text = "exec ags";
}
);
};
Install.WantedBy = [ "graphical-session.target" ];
};
};
};
}

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,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

@@ -4,8 +4,12 @@
@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}}
@@ -15,12 +19,7 @@
.widgets
padding: .2 * {{custom.padding}}pt
.gap
min-height: {{custom.font_size}}pt
min-width: .5 * {{custom.padding}}pt
.launcher
.clipboard
@include interactive
min-width: {{custom.font_size}}pt
@@ -30,7 +29,7 @@
padding: 0 .3 * {{custom.padding}}pt
color: {{colors.on_surface.default.hex}}
.workspace
.workspaces
@include interactive
.button

View File

@@ -7,7 +7,10 @@ general {
decoration {
rounding = {{custom.radius}}
col.shadow = rgba({{colors.shadow.default.hex_stripped}}{{custom.opacity_shadow_hex | to_lower}})
shadow {
color = rgba({{colors.shadow.default.hex_stripped}}{{custom.opacity_shadow_hex | to_lower}})
}
blur {
size = {{custom.blur}}

View File

@@ -3,6 +3,9 @@
home ? throw "home argument is required",
}:
{ config, pkgs, ... }:
let
hmConfig = config.home-manager.users.${user};
in
{
boot = {
kernelModules = [ "v4l2loopback" ];
@@ -17,6 +20,8 @@
};
home-manager.users.${user} = {
imports = [ ./options.nix ];
programs.obs-studio.enable = true;
xdg.configFile."obs-studio/basic/profiles/Untitled/basic.ini".source =
@@ -29,6 +34,12 @@
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

@@ -706,7 +706,7 @@ in
theme.template = lib.attrsets.mapAttrs' (
_: vault:
lib.attrsets.nameValuePair "${vault.target}/.obsidian/plugins/obsidian-style-settings/data.json" {
lib.attrsets.nameValuePair "${home}/${vault.target}/.obsidian/plugins/obsidian-style-settings/data.json" {
source = ./theme.json;
}
) hmConfig.programs.obsidian.vaults;

View File

@@ -89,7 +89,6 @@ in
"git.openRepositoryInParentFolders" = "always";
"git.path" = lib.meta.getExe pkgs.git;
"mergeEditor.diffAlgorithm" = "advanced";
"open-in-browser.default" = "firefox";
"security.workspace.trust.enabled" = false;
"telemetry.telemetryLevel" = "off";
"terminal.external.linuxExec" = "kitty";
@@ -102,6 +101,7 @@ in
"window.menuBarVisibility" = "toggle";
"workbench.editor.historyBasedLanguageDetection" = true;
"workbench.list.smoothScrolling" = true;
"typescript.updateImportsOnFileMove.enabled" = "always";
};
};

View File

@@ -149,8 +149,21 @@
programs = {
zsh.loginExtra = lib.mkBefore (builtins.readFile ./scripts/card.sh);
# VSCode does not play well with fractional scaling
vscode.userSettings."window.zoomLevel" = (1.25 - 1) / 0.2;
obs-studio.resolution = {
base = {
x = 4096;
y = 2560;
};
output = {
x = 2048;
y = 1280;
};
};
};
theme = {

View File

@@ -33,7 +33,7 @@ in
(import ../../common/user/configs/console/xdg { inherit user home; })
(import ../../common/user/configs/console/yt-dlp { inherit user home; })
(import ../../common/user/configs/console/zsh { inherit user home; })
(import ../../common/user/configs/gui/ags { inherit user home; })
(import ../../common/user/configs/gui/astal { inherit user home; })
(import ../../common/user/configs/gui/bluetooth { inherit user home; })
(import ../../common/user/configs/gui/brightnessctl { inherit user home; })
(import ../../common/user/configs/gui/btop { inherit user home; })