From 0c8fa3a2a270747f3dbb54fe8792f3f0aec997e3 Mon Sep 17 00:00:00 2001 From: Ryan Schanzenbacher Date: Mon, 3 Aug 2026 01:22:44 -0400 Subject: Initial commit: combined darwin + guix-linux home-manager flake Supersedes nix-dotfiles (darwin) and guix-dotfiles' ad-hoc nix-home-manager flake (linux). See README.md/MIGRATION.md. --- MIGRATION.md | 221 ++ README.md | 44 + files/CACerts/RyanCA.crt | 11 + files/Wallpapers/1685362396481634.jpg | Bin 0 -> 933436 bytes files/Wallpapers/1693169418078790.jpg | Bin 0 -> 1326027 bytes files/Wallpapers/1694792956043641.jpg | Bin 0 -> 5067847 bytes files/Wallpapers/1708470532817406.jpg | Bin 0 -> 3801100 bytes files/Wallpapers/1720750738377603.jpg | Bin 0 -> 177477 bytes files/Wallpapers/1720751011150282.png | Bin 0 -> 1746731 bytes files/Wallpapers/1723625710776950.jpg | Bin 0 -> 602989 bytes files/Wallpapers/1723626275390685.jpg | Bin 0 -> 388798 bytes files/Wallpapers/1728661127589872.jpg | Bin 0 -> 1892757 bytes files/Wallpapers/4yglzy4rkh4d1.jpeg | Bin 0 -> 1877217 bytes files/Wallpapers/7xosa7um3ohd1.jpg | Bin 0 -> 8550632 bytes files/Wallpapers/83juiltm3ohd1.jpg | Bin 0 -> 2357200 bytes files/Wallpapers/CN62QXJ.jpg | Bin 0 -> 146377 bytes files/Wallpapers/above-clouds.jpg | Bin 0 -> 535067 bytes files/Wallpapers/alena-aenami-bluehour-1k.jpg | Bin 0 -> 632441 bytes files/Wallpapers/alena-aenami-budapest.jpg | Bin 0 -> 815957 bytes files/Wallpapers/alena-aenami-cave-1k.jpg | Bin 0 -> 479749 bytes .../alena-aenami-close-to-the-sun-1920.jpg | Bin 0 -> 567195 bytes files/Wallpapers/alena-aenami-cold-1k.jpg | Bin 0 -> 635856 bytes files/Wallpapers/alena-aenami-cosmo-1k.jpg | Bin 0 -> 616567 bytes files/Wallpapers/alena-aenami-downtown-1k.jpg | Bin 0 -> 605445 bytes files/Wallpapers/alena-aenami-dreamy-1k.jpg | Bin 0 -> 698119 bytes files/Wallpapers/alena-aenami-eclipse-1k.jpg | Bin 0 -> 505917 bytes files/Wallpapers/alena-aenami-end-1k.jpg | Bin 0 -> 612182 bytes files/Wallpapers/alena-aenami-eternity-1080px.jpg | Bin 0 -> 612516 bytes files/Wallpapers/alena-aenami-kosmos19001.jpg | Bin 0 -> 438105 bytes .../alena-aenami-light-at-the-end-hd.jpg | Bin 0 -> 855710 bytes files/Wallpapers/alena-aenami-lights-1k.jpg | Bin 0 -> 607579 bytes files/Wallpapers/alena-aenami-lines1k.jpg | Bin 0 -> 689660 bytes files/Wallpapers/alena-aenami-mountains1k.jpg | Bin 0 -> 863496 bytes files/Wallpapers/alena-aenami-new-year1k.jpg | Bin 0 -> 489358 bytes files/Wallpapers/alena-aenami-orangemoon1900p.jpg | Bin 0 -> 884416 bytes files/Wallpapers/alena-aenami-portal-1k.jpg | Bin 0 -> 741511 bytes files/Wallpapers/alena-aenami-reflect1k.jpg | Bin 0 -> 863258 bytes files/Wallpapers/alena-aenami-serenity-1k.jpg | Bin 0 -> 712975 bytes files/Wallpapers/alena-aenami-sky1k.jpg | Bin 0 -> 992731 bytes files/Wallpapers/alena-aenami-solar-1k.jpg | Bin 0 -> 736011 bytes files/Wallpapers/alena-aenami-tl-002-1k.png | Bin 0 -> 2472437 bytes files/Wallpapers/alena-aenami-wait.jpg | Bin 0 -> 632782 bytes files/Wallpapers/alena-aenami-wings-hd.jpg | Bin 0 -> 756726 bytes files/Wallpapers/alena-aenami-you-1k-2.jpg | Bin 0 -> 543184 bytes files/Wallpapers/autumn1.jpg | Bin 0 -> 1084113 bytes files/Wallpapers/autumn1.png | Bin 0 -> 3956950 bytes files/Wallpapers/dawn-mountains-vibrant.jpg | Bin 0 -> 692972 bytes files/Wallpapers/lake-winter.jpg | Bin 0 -> 1118701 bytes files/Wallpapers/miku.png | Bin 0 -> 1268697 bytes files/Wallpapers/mountains.jpg | Bin 0 -> 1097089 bytes files/Wallpapers/northern-lights-2.jpg | Bin 0 -> 2106126 bytes files/Wallpapers/northern-lights-bridge.jpg | Bin 0 -> 590574 bytes files/Wallpapers/ooglygoo.png | Bin 0 -> 1286896 bytes files/Wallpapers/purple-grass.jpg | Bin 0 -> 2298196 bytes files/Wallpapers/purple-intersection.jpg | Bin 0 -> 490043 bytes files/Wallpapers/purple-lakescape.jpg | Bin 0 -> 4375129 bytes files/Wallpapers/sah1k8tm3ohd1.jpg | Bin 0 -> 1940378 bytes files/Wallpapers/scarecrow.jpg | Bin 0 -> 458024 bytes files/Wallpapers/snow-1.jpg | Bin 0 -> 944602 bytes files/Wallpapers/snow-2.jpg | Bin 0 -> 1825815 bytes files/Wallpapers/spong.jpg | Bin 0 -> 1982607 bytes files/Wallpapers/vfcfyfyehhi31.png | Bin 0 -> 2168863 bytes files/Wallpapers/w7ufw5eb3cuz.jpg | Bin 0 -> 66045 bytes files/Wallpapers/wallhaven-832y1o.jpg | Bin 0 -> 1989130 bytes files/Wallpapers/wallhaven-gwwkql.jpg | Bin 0 -> 5690712 bytes files/Wallpapers/wallhaven-k81776.jpg | Bin 0 -> 2194722 bytes files/Wallpapers/wallhaven-lywpjl.jpg | Bin 0 -> 7061949 bytes flake.lock | 312 ++ flake.nix | 99 + hosts/RyanMac/configuration.nix | 438 +++ modules/darwin/random-wallpaper/default.nix | 29 + .../darwin/random-wallpaper/wallpaper-daemon.swift | 51 + users/ryan/aerc/accounts.conf | 24 + users/ryan/aerc/aerc.conf | 569 ++++ users/ryan/aerc/binds.conf | 150 + users/ryan/aerc/signature_personal | 3 + users/ryan/aerc/signature_rit_personal | 5 + users/ryan/aerc/templates/quoted_reply | 6 + users/ryan/aerc/templates/thanks | 7 + users/ryan/common.nix | 180 ++ users/ryan/darwin.nix | 68 + users/ryan/hammerspoon/init.lua | 35 + users/ryan/linux.nix | 162 + users/ryan/linux/alacritty/alacritty.yml | 15 + users/ryan/linux/firefox-nightly/default.nix | 193 ++ users/ryan/linux/firefox-nightly/policies.nix | 130 + users/ryan/linux/foot/foot.ini | 7 + users/ryan/linux/hypr/family_guy.mp4 | Bin 0 -> 20881473 bytes users/ryan/linux/hypr/hypridle.conf | 16 + users/ryan/linux/hypr/hyprland.conf | 336 ++ users/ryan/linux/hypr/hyprlock.conf | 57 + users/ryan/linux/hypr/kanshi.conf | 22 + users/ryan/linux/hypr/monitors.conf | 2 + users/ryan/linux/hypr/pyprland.toml | 5 + users/ryan/linux/hypr/scripts/autostart.sh | 40 + users/ryan/linux/hypr/scripts/perf_mode.sh | 14 + users/ryan/linux/hypr/subwaysurfer.webm | Bin 0 -> 77979199 bytes users/ryan/linux/mailvelope/gpgmejson.json | 7 + users/ryan/linux/mailvelope/start.sh | 4 + users/ryan/linux/mpv/scripts/easycrop.lua | 254 ++ users/ryan/linux/pulseaudio/client.conf | 1 + users/ryan/linux/spotify-player/app.toml | 34 + users/ryan/linux/tridactyl/native_main | Bin 0 -> 514233 bytes users/ryan/linux/tridactyl/tridactyl.json | 7 + users/ryan/linux/waybar/config | 167 + users/ryan/linux/waybar/modules/check-for-music.sh | 7 + users/ryan/linux/waybar/modules/spotify.sh | 19 + users/ryan/linux/waybar/modules/storage.sh | 25 + users/ryan/linux/waybar/modules/weather.sh | 77 + users/ryan/linux/waybar/style.css | 77 + users/ryan/linux/wpaperd/config.toml | 4 + users/ryan/modules/nvim/default.nix | 53 + .../extraConfigs/after/ftplugin/mail/custom.vim | 2 + .../after/ftplugin/markdown/custom.vim | 2 + users/ryan/modules/nvim/init.lua | 26 + users/ryan/modules/nvim/init.vim | 27 + users/ryan/modules/simple-bar/default.nix | 30 + users/ryan/modules/simple-bar/server.nix | 34 + .../simple-bar-source/.github/FUNDING.yml | 1 + .../.github/ISSUE_TEMPLATE/bug_report.md | 32 + .../.github/ISSUE_TEMPLATE/documentation_error.md | 21 + .../.github/ISSUE_TEMPLATE/feature_request.md | 19 + .../.github/pull_request_template.md | 38 + .../simple-bar/simple-bar-source/.gitignore | 4 + .../simple-bar/simple-bar-source/.prettierrc | 1 + .../simple-bar-source/CODE_OF_CONDUCT.md | 128 + .../simple-bar/simple-bar-source/CONTRIBUTING.md | 47 + .../modules/simple-bar/simple-bar-source/LICENSE | 21 + .../modules/simple-bar/simple-bar-source/README.md | 73 + .../simple-bar/simple-bar-source/SECURITY.md | 9 + .../simple-bar/simple-bar-source/eslint.config.mjs | 52 + .../simple-bar-source/images/logo-simple-bar.png | Bin 0 -> 6365 bytes .../simple-bar-source/images/preview.png | Bin 0 -> 417752 bytes .../modules/simple-bar/simple-bar-source/index.jsx | 267 ++ .../simple-bar/simple-bar-source/lib/aerospace.js | 102 + .../simple-bar/simple-bar-source/lib/app-icons.js | 254 ++ .../lib/components/aerospace-context.jsx | 117 + .../lib/components/aerospace/opened-apps.jsx | 33 + .../lib/components/aerospace/process.jsx | 72 + .../lib/components/aerospace/space.jsx | 84 + .../lib/components/aerospace/spaces.jsx | 67 + .../lib/components/aerospace/window.jsx | 99 + .../lib/components/data/battery.jsx | 183 ++ .../lib/components/data/browser-track.jsx | 147 + .../simple-bar-source/lib/components/data/cpu.jsx | 153 + .../lib/components/data/crypto.jsx | 160 + .../lib/components/data/data-widget-loader.jsx | 37 + .../lib/components/data/data-widget.jsx | 136 + .../lib/components/data/date-display.jsx | 118 + .../lib/components/data/github.jsx | 105 + .../simple-bar-source/lib/components/data/gpu.jsx | 128 + .../lib/components/data/graph.jsx | 87 + .../lib/components/data/keyboard.jsx | 108 + .../lib/components/data/memory.jsx | 134 + .../simple-bar-source/lib/components/data/mic.jsx | 152 + .../simple-bar-source/lib/components/data/mpd.jsx | 228 ++ .../lib/components/data/music.jsx | 161 + .../lib/components/data/netstats.jsx | 182 ++ .../lib/components/data/next-meeting.jsx | 310 ++ .../lib/components/data/notifications.jsx | 189 ++ .../lib/components/data/sound.jsx | 156 + .../lib/components/data/specter.jsx | 24 + .../lib/components/data/spotify.jsx | 189 ++ .../lib/components/data/stock.jsx | 211 ++ .../simple-bar-source/lib/components/data/time.jsx | 144 + .../lib/components/data/user-widgets.jsx | 181 ++ .../lib/components/data/viscosity-vpn.jsx | 144 + .../lib/components/data/weather.jsx | 214 ++ .../simple-bar-source/lib/components/data/wifi.jsx | 154 + .../lib/components/data/youtube-music.jsx | 191 ++ .../simple-bar-source/lib/components/data/zoom.jsx | 107 + .../simple-bar-source/lib/components/error.jsx | 42 + .../lib/components/icons/icon.jsx | 40 + .../lib/components/icons/icons.jsx | 337 ++ .../lib/components/icons/library/ableton.jsx | 13 + .../lib/components/icons/library/activity.jsx | 9 + .../lib/components/icons/library/add.jsx | 9 + .../components/icons/library/affinity-designer.jsx | 12 + .../components/icons/library/affinity-photo.jsx | 12 + .../icons/library/affinity-publisher.jsx | 12 + .../lib/components/icons/library/airmail.jsx | 12 + .../lib/components/icons/library/alfred.jsx | 9 + .../components/icons/library/android-messages.jsx | 14 + .../components/icons/library/android-studio.jsx | 9 + .../lib/components/icons/library/anki.jsx | 16 + .../lib/components/icons/library/antigravity.jsx | 9 + .../lib/components/icons/library/anytype.jsx | 9 + .../lib/components/icons/library/app-store.jsx | 9 + .../components/icons/library/apple-simulator.jsx | 16 + .../lib/components/icons/library/apple.jsx | 9 + .../lib/components/icons/library/aqua.jsx | 13 + .../lib/components/icons/library/arc.jsx | 14 + .../lib/components/icons/library/atom.jsx | 14 + .../lib/components/icons/library/audacity.jsx | 9 + .../lib/components/icons/library/bambu-studio.jsx | 9 + .../lib/components/icons/library/bank.jsx | 9 + .../lib/components/icons/library/battle-net.jsx | 9 + .../lib/components/icons/library/bear.jsx | 9 + .../lib/components/icons/library/beekeeper.jsx | 13 + .../lib/components/icons/library/bell-off.jsx | 9 + .../lib/components/icons/library/bell.jsx | 9 + .../lib/components/icons/library/bit-warden.jsx | 9 + .../lib/components/icons/library/bitcoin.jsx | 14 + .../lib/components/icons/library/blender.jsx | 9 + .../lib/components/icons/library/book.jsx | 9 + .../lib/components/icons/library/brave-browser.jsx | 9 + .../lib/components/icons/library/bruno.jsx | 11 + .../lib/components/icons/library/c-lion.jsx | 13 + .../lib/components/icons/library/ca-r-r-o-t.jsx | 10 + .../lib/components/icons/library/calendar.jsx | 10 + .../lib/components/icons/library/camera-off.jsx | 9 + .../lib/components/icons/library/camera.jsx | 9 + .../lib/components/icons/library/cancel.jsx | 9 + .../lib/components/icons/library/caprine.jsx | 9 + .../lib/components/icons/library/celo.jsx | 20 + .../lib/components/icons/library/charging.jsx | 9 + .../lib/components/icons/library/chat-gpt.jsx | 13 + .../lib/components/icons/library/chatterino.jsx | 10 + .../lib/components/icons/library/check-box.jsx | 9 + .../components/icons/library/chevron-bottom.jsx | 9 + .../lib/components/icons/library/chevron-left.jsx | 9 + .../lib/components/icons/library/chevron-right.jsx | 9 + .../lib/components/icons/library/chevron-top.jsx | 9 + .../lib/components/icons/library/claude-code.jsx | 12 + .../lib/components/icons/library/claude.jsx | 9 + .../lib/components/icons/library/click-up.jsx | 9 + .../lib/components/icons/library/cline.jsx | 10 + .../lib/components/icons/library/clock.jsx | 10 + .../lib/components/icons/library/close.jsx | 9 + .../lib/components/icons/library/cloud.jsx | 13 + .../lib/components/icons/library/code.jsx | 9 + .../lib/components/icons/library/codex.jsx | 12 + .../lib/components/icons/library/coffee.jsx | 15 + .../lib/components/icons/library/color-picker.jsx | 9 + .../lib/components/icons/library/comfy-ui.jsx | 9 + .../lib/components/icons/library/copilot.jsx | 9 + .../lib/components/icons/library/cp-u.jsx | 10 + .../lib/components/icons/library/cursor.jsx | 9 + .../lib/components/icons/library/data-grip.jsx | 13 + .../lib/components/icons/library/date.jsx | 10 + .../components/icons/library/de-v-o-nthink3.jsx | 13 + .../lib/components/icons/library/deezer.jsx | 9 + .../lib/components/icons/library/default.jsx | 13 + .../lib/components/icons/library/desktop.jsx | 9 + .../lib/components/icons/library/discord.jsx | 9 + .../lib/components/icons/library/docker.jsx | 11 + .../lib/components/icons/library/dollar.jsx | 9 + .../lib/components/icons/library/down-arrow.jsx | 12 + .../lib/components/icons/library/download.jsx | 14 + .../lib/components/icons/library/drafts.jsx | 9 + .../lib/components/icons/library/dropbox.jsx | 9 + .../lib/components/icons/library/element.jsx | 13 + .../lib/components/icons/library/emacs.jsx | 13 + .../lib/components/icons/library/ethereum.jsx | 34 + .../components/icons/library/evernote-legacy.jsx | 10 + .../lib/components/icons/library/face-time.jsx | 9 + .../lib/components/icons/library/figma.jsx | 10 + .../lib/components/icons/library/final-cut-pro.jsx | 9 + .../lib/components/icons/library/finder.jsx | 9 + .../icons/library/firefox-developer-edition.jsx | 9 + .../lib/components/icons/library/firefox.jsx | 9 + .../lib/components/icons/library/fleet.jsx | 13 + .../lib/components/icons/library/fog.jsx | 20 + .../lib/components/icons/library/folx.jsx | 13 + .../lib/components/icons/library/free-tube.jsx | 16 + .../lib/components/icons/library/gear.jsx | 9 + .../lib/components/icons/library/ghostty.jsx | 13 + .../lib/components/icons/library/git-hub.jsx | 9 + .../lib/components/icons/library/gnu-cash.jsx | 13 + .../lib/components/icons/library/go-land.jsx | 13 + .../lib/components/icons/library/good-notes.jsx | 10 + .../lib/components/icons/library/google-chrome.jsx | 12 + .../lib/components/icons/library/goose.jsx | 12 + .../lib/components/icons/library/grammarly.jsx | 9 + .../lib/components/icons/library/helium.jsx | 11 + .../components/icons/library/home-assistant.jsx | 10 + .../lib/components/icons/library/ht-t-pie.jsx | 9 + .../lib/components/icons/library/idea.jsx | 9 + .../lib/components/icons/library/insomnia.jsx | 9 + .../lib/components/icons/library/iris.jsx | 9 + .../lib/components/icons/library/italic.jsx | 9 + .../lib/components/icons/library/joplin.jsx | 13 + .../lib/components/icons/library/kakoune.jsx | 13 + .../lib/components/icons/library/kee-pass-x-c.jsx | 14 + .../components/icons/library/keyboard-maestro.jsx | 9 + .../lib/components/icons/library/keyboard.jsx | 9 + .../lib/components/icons/library/keynote.jsx | 9 + .../components/icons/library/league-of-legends.jsx | 9 + .../lib/components/icons/library/libre-wolf.jsx | 9 + .../lib/components/icons/library/linear.jsx | 9 + .../lib/components/icons/library/lm-studio.jsx | 13 + .../lib/components/icons/library/maestro-ai.jsx | 11 + .../lib/components/icons/library/mail.jsx | 9 + .../lib/components/icons/library/mamp.jsx | 13 + .../lib/components/icons/library/manus.jsx | 17 + .../lib/components/icons/library/matlab.jsx | 9 + .../lib/components/icons/library/mattermost.jsx | 10 + .../lib/components/icons/library/messages.jsx | 9 + .../lib/components/icons/library/mic-off.jsx | 10 + .../lib/components/icons/library/mic-on.jsx | 10 + .../components/icons/library/microsoft-edge.jsx | 14 + .../components/icons/library/microsoft-excel.jsx | 9 + .../components/icons/library/microsoft-outlook.jsx | 11 + .../icons/library/microsoft-power-point.jsx | 9 + .../components/icons/library/microsoft-word.jsx | 9 + .../lib/components/icons/library/mimestream.jsx | 13 + .../lib/components/icons/library/min-browser.jsx | 13 + .../lib/components/icons/library/miro.jsx | 9 + .../lib/components/icons/library/monero-gui.jsx | 12 + .../lib/components/icons/library/mongo-db.jsx | 13 + .../lib/components/icons/library/moon.jsx | 10 + .../lib/components/icons/library/mpv.jsx | 16 + .../lib/components/icons/library/music.jsx | 13 + .../lib/components/icons/library/n8n.jsx | 12 + .../lib/components/icons/library/net-news-wire.jsx | 9 + .../lib/components/icons/library/netease-music.jsx | 9 + .../lib/components/icons/library/no-volume.jsx | 9 + .../lib/components/icons/library/notability.jsx | 13 + .../lib/components/icons/library/notebook-lm.jsx | 9 + .../lib/components/icons/library/notes.jsx | 9 + .../lib/components/icons/library/notion.jsx | 9 + .../lib/components/icons/library/nova.jsx | 12 + .../lib/components/icons/library/numbers.jsx | 9 + .../lib/components/icons/library/ob-s-studio.jsx | 9 + .../lib/components/icons/library/obsidian.jsx | 33 + .../lib/components/icons/library/ollama.jsx | 13 + .../lib/components/icons/library/omni-focus.jsx | 13 + .../lib/components/icons/library/one-password.jsx | 9 + .../lib/components/icons/library/open-book.jsx | 10 + .../lib/components/icons/library/open-claw.jsx | 16 + .../lib/components/icons/library/opencode.jsx | 9 + .../lib/components/icons/library/orb-stack.jsx | 14 + .../lib/components/icons/library/pages.jsx | 9 + .../lib/components/icons/library/parallels.jsx | 13 + .../lib/components/icons/library/paused.jsx | 9 + .../lib/components/icons/library/pdf.jsx | 10 + .../lib/components/icons/library/perplexity.jsx | 9 + .../lib/components/icons/library/php-storm.jsx | 13 + .../lib/components/icons/library/pihole.jsx | 31 + .../lib/components/icons/library/pine.jsx | 13 + .../lib/components/icons/library/pins.jsx | 9 + .../lib/components/icons/library/playing.jsx | 9 + .../lib/components/icons/library/plex.jsx | 13 + .../lib/components/icons/library/podcasts.jsx | 9 + .../lib/components/icons/library/pomodone.jsx | 10 + .../lib/components/icons/library/postman.jsx | 13 + .../lib/components/icons/library/proton-mail.jsx | 13 + .../lib/components/icons/library/py-charm.jsx | 13 + .../lib/components/icons/library/quip.jsx | 10 + .../lib/components/icons/library/qute-browser.jsx | 13 + .../lib/components/icons/library/radar.jsx | 11 + .../lib/components/icons/library/rain.jsx | 15 + .../lib/components/icons/library/ram.jsx | 9 + .../lib/components/icons/library/redis.jsx | 13 + .../lib/components/icons/library/reeder5.jsx | 13 + .../lib/components/icons/library/reminders.jsx | 9 + .../lib/components/icons/library/remnote.jsx | 14 + .../components/icons/library/remote-desktop.jsx | 15 + .../lib/components/icons/library/remove.jsx | 9 + .../lib/components/icons/library/replit.jsx | 9 + .../lib/components/icons/library/rider.jsx | 13 + .../lib/components/icons/library/rocket-chat.jsx | 10 + .../lib/components/icons/library/roon.jsx | 9 + .../lib/components/icons/library/royal-tsx.jsx | 13 + .../lib/components/icons/library/ruby-mine.jsx | 13 + .../lib/components/icons/library/rust-rover.jsx | 13 + .../lib/components/icons/library/safari.jsx | 9 + .../lib/components/icons/library/screens4.jsx | 12 + .../lib/components/icons/library/sequel-ace.jsx | 13 + .../lib/components/icons/library/sequel-pro.jsx | 14 + .../lib/components/icons/library/setapp.jsx | 9 + .../lib/components/icons/library/signal.jsx | 9 + .../lib/components/icons/library/sketch-up.jsx | 12 + .../lib/components/icons/library/sketch.jsx | 9 + .../lib/components/icons/library/skype.jsx | 9 + .../lib/components/icons/library/slack.jsx | 9 + .../lib/components/icons/library/snow.jsx | 18 + .../lib/components/icons/library/spark.jsx | 13 + .../lib/components/icons/library/spotify.jsx | 13 + .../lib/components/icons/library/spotlight.jsx | 9 + .../lib/components/icons/library/spotube.jsx | 10 + .../lib/components/icons/library/statistics.jsx | 9 + .../lib/components/icons/library/stopped.jsx | 9 + .../lib/components/icons/library/storm.jsx | 18 + .../lib/components/icons/library/sublime-text.jsx | 9 + .../lib/components/icons/library/sun.jsx | 13 + .../icons/library/super-productivity.jsx | 9 + .../lib/components/icons/library/table-plus.jsx | 9 + .../lib/components/icons/library/tailscale.jsx | 9 + .../lib/components/icons/library/team-speak.jsx | 13 + .../lib/components/icons/library/teams.jsx | 14 + .../lib/components/icons/library/telegram.jsx | 9 + .../lib/components/icons/library/terminal.jsx | 9 + .../lib/components/icons/library/text.jsx | 13 + .../lib/components/icons/library/thermostat.jsx | 9 + .../lib/components/icons/library/things.jsx | 12 + .../lib/components/icons/library/thunderbird.jsx | 9 + .../lib/components/icons/library/tick-tick.jsx | 9 + .../lib/components/icons/library/tidal.jsx | 9 + .../lib/components/icons/library/todoist.jsx | 9 + .../lib/components/icons/library/tor-browser.jsx | 15 + .../lib/components/icons/library/tower.jsx | 13 + .../lib/components/icons/library/transmit.jsx | 12 + .../lib/components/icons/library/trello.jsx | 9 + .../lib/components/icons/library/twitter.jsx | 9 + .../lib/components/icons/library/up-arrow.jsx | 12 + .../lib/components/icons/library/upload.jsx | 14 + .../lib/components/icons/library/vim.jsx | 9 + .../lib/components/icons/library/vivaldi.jsx | 14 + .../lib/components/icons/library/vl-c.jsx | 9 + .../lib/components/icons/library/vmware-fusion.jsx | 12 + .../lib/components/icons/library/volume-high.jsx | 9 + .../lib/components/icons/library/volume-low.jsx | 9 + .../lib/components/icons/library/volume-muted.jsx | 10 + .../lib/components/icons/library/vp-n-off.jsx | 9 + .../lib/components/icons/library/vp-n.jsx | 9 + .../lib/components/icons/library/vs-codium.jsx | 9 + .../lib/components/icons/library/warp.jsx | 10 + .../lib/components/icons/library/web-storm.jsx | 9 + .../lib/components/icons/library/wechat.jsx | 9 + .../lib/components/icons/library/whats-app.jsx | 9 + .../lib/components/icons/library/widget.jsx | 9 + .../lib/components/icons/library/wifi-off.jsx | 9 + .../lib/components/icons/library/wifi.jsx | 9 + .../lib/components/icons/library/windows.jsx | 9 + .../lib/components/icons/library/xcode.jsx | 12 + .../lib/components/icons/library/youtube-music.jsx | 13 + .../lib/components/icons/library/zed.jsx | 10 + .../lib/components/icons/library/zen-browser.jsx | 11 + .../lib/components/icons/library/zeplin.jsx | 43 + .../lib/components/icons/library/zoom.jsx | 9 + .../lib/components/icons/library/zotero.jsx | 12 + .../lib/components/icons/library/zulip.jsx | 9 + .../lib/components/missives/missive.jsx | 48 + .../lib/components/missives/missives.jsx | 40 + .../settings/aerospace-display-manager.jsx | 83 + .../lib/components/settings/color-picker.jsx | 109 + .../lib/components/settings/icon-picker.jsx | 130 + .../lib/components/settings/settings-component.jsx | 159 + .../lib/components/settings/settings-inner.jsx | 123 + .../lib/components/settings/settings-item.jsx | 143 + .../lib/components/settings/settings-widgets.jsx | 180 ++ .../lib/components/settings/settings.jsx | 94 + .../components/settings/user-widgets-creator.jsx | 297 ++ .../simple-bar-source/lib/components/side-icon.jsx | 32 + .../lib/components/simple-bar-context.jsx | 131 + .../lib/components/yabai-context.jsx | 112 + .../lib/components/yabai/opened-apps.jsx | 55 + .../lib/components/yabai/process.jsx | 102 + .../lib/components/yabai/space-options.jsx | 84 + .../lib/components/yabai/space.jsx | 194 ++ .../lib/components/yabai/spaces.jsx | 109 + .../lib/components/yabai/stickies.jsx | 56 + .../lib/components/yabai/window.jsx | 119 + .../lib/hooks/use-server-socket.js | 221 ++ .../lib/hooks/use-widget-refresh.js | 37 + .../simple-bar-source/lib/schemas/config.json | 1159 +++++++ .../lib/scripts/browser-audio.applescript | 91 + .../lib/scripts/firefox-audio.applescript | 24 + .../lib/scripts/firefox-dev-audio.applescript | 24 + .../lib/scripts/init-aerospace.sh | 26 + .../simple-bar-source/lib/scripts/init-yabai.sh | 102 + .../simple-bar-source/lib/scripts/netstats.sh | 5 + .../simple-bar-source/lib/scripts/next-meeting.sh | 101 + .../lib/scripts/run-command-in-iterm2.applescript | 9 + .../scripts/run-command-in-terminal.applescript | 7 + .../lib/scripts/yabai-set-mode-server.sh | 38 + .../lib/scripts/yabai-set-mode.sh | 40 + .../lib/scripts/zoom-mute-status.applescript | 17 + .../lib/scripts/zoom-video-status.applescript | 17 + .../simple-bar/simple-bar-source/lib/settings.js | 1184 +++++++ .../simple-bar/simple-bar-source/lib/skhd.js | 17 + .../lib/styles/components/data/battery.js | 134 + .../lib/styles/components/data/browser-track.js | 40 + .../lib/styles/components/data/cpu.js | 16 + .../lib/styles/components/data/crypto.js | 9 + .../styles/components/data/data-widget-loader.js | 32 + .../lib/styles/components/data/data-widget.js | 65 + .../lib/styles/components/data/date-display.js | 10 + .../lib/styles/components/data/github.js | 10 + .../lib/styles/components/data/gpu.js | 15 + .../lib/styles/components/data/graph.js | 49 + .../lib/styles/components/data/keyboard.js | 10 + .../lib/styles/components/data/memory.js | 30 + .../lib/styles/components/data/mic.js | 83 + .../lib/styles/components/data/mpd.js | 80 + .../lib/styles/components/data/music.js | 11 + .../lib/styles/components/data/netstats.js | 48 + .../lib/styles/components/data/next-meeting.js | 71 + .../lib/styles/components/data/notifications.js | 68 + .../lib/styles/components/data/sound.js | 83 + .../lib/styles/components/data/specter.js | 55 + .../lib/styles/components/data/spotify.js | 15 + .../lib/styles/components/data/stock.js | 15 + .../lib/styles/components/data/time.js | 85 + .../lib/styles/components/data/viscosity-vpn.js | 17 + .../lib/styles/components/data/weather.js | 163 + .../lib/styles/components/data/wifi.js | 13 + .../lib/styles/components/data/youtube-music.js | 11 + .../lib/styles/components/data/zoom.js | 26 + .../lib/styles/components/missives.js | 89 + .../lib/styles/components/process.js | 161 + .../settings/aerospace-display-manager.js | 101 + .../lib/styles/components/settings/color-picker.js | 83 + .../lib/styles/components/settings/icon-picker.js | 155 + .../lib/styles/components/settings/settings.js | 408 +++ .../components/settings/user-widgets-creator.js | 170 + .../lib/styles/components/side-icon.js | 15 + .../lib/styles/components/spaces/space-options.js | 137 + .../lib/styles/components/spaces/space.js | 152 + .../lib/styles/components/spaces/spaces.js | 50 + .../simple-bar-source/lib/styles/core/base.js | 120 + .../simple-bar-source/lib/styles/core/variables.js | 107 + .../lib/styles/pywal/pywal-colors.js | 15 + .../lib/styles/pywal/pywal-from-desktop.sh | 9 + .../lib/styles/pywal/pywal-gen.sh | 7 + .../simple-bar-source/lib/styles/pywal/pywal.js | 15 + .../simple-bar-source/lib/styles/theme.js | 21 + .../simple-bar-source/lib/styles/themes.js | 72 + .../simple-bar-source/lib/styles/themes/amarena.js | 32 + .../lib/styles/themes/catppuccin-frappe.js | 32 + .../lib/styles/themes/catppuccin-latte.js | 32 + .../lib/styles/themes/catppuccin-macchiato.js | 32 + .../lib/styles/themes/catppuccin-mocha.js | 32 + .../lib/styles/themes/catppuccin.js | 32 + .../simple-bar-source/lib/styles/themes/cisco.js | 32 + .../lib/styles/themes/cyberdream-dark.js | 32 + .../lib/styles/themes/cyberdream-light.js | 32 + .../simple-bar-source/lib/styles/themes/dracula.js | 32 + .../lib/styles/themes/gruvbox-dark.js | 32 + .../lib/styles/themes/gruvbox-light.js | 32 + .../lib/styles/themes/gruvbox-material.js | 32 + .../lib/styles/themes/mac-os-dark.js | 32 + .../lib/styles/themes/mac-os-light.js | 32 + .../lib/styles/themes/material-ocean.js | 32 + .../lib/styles/themes/midsummer-night-dark.js | 32 + .../lib/styles/themes/night-owl.js | 33 + .../lib/styles/themes/night-shift-dark.js | 32 + .../lib/styles/themes/night-shift-light.js | 32 + .../lib/styles/themes/nightfox-dark.js | 32 + .../lib/styles/themes/nightfox-light.js | 32 + .../simple-bar-source/lib/styles/themes/nord.js | 32 + .../lib/styles/themes/one-dark.js | 32 + .../lib/styles/themes/one-light.js | 32 + .../lib/styles/themes/rose-pine-dawn.js | 32 + .../lib/styles/themes/rose-pine-moon.js | 32 + .../lib/styles/themes/rose-pine.js | 32 + .../lib/styles/themes/solarized-dark.js | 32 + .../lib/styles/themes/solarized-light.js | 32 + .../lib/styles/themes/spaceduck.js | 32 + .../simple-bar-source/lib/styles/themes/sylens.js | 32 + .../lib/styles/themes/tokyo-night.js | 32 + .../lib/styles/themes/vscode-dark-modern.js | 32 + .../simple-bar/simple-bar-source/lib/utils.js | 828 +++++ .../simple-bar/simple-bar-source/lib/yabai.js | 128 + .../simple-bar/simple-bar-source/package-lock.json | 3267 ++++++++++++++++++++ .../simple-bar/simple-bar-source/package.json | 17 + users/ryan/modules/simple-bar/simplebarrc | 289 ++ users/ryan/modules/sketchybar/bar-config/README.md | 63 + users/ryan/modules/sketchybar/bar-config/colors.sh | 11 + users/ryan/modules/sketchybar/bar-config/icons.sh | 35 + .../sketchybar/bar-config/plugins/battery.sh | 42 + .../sketchybar/bar-config/plugins/bluetooth.sh | 37 + .../sketchybar/bar-config/plugins/brightness.sh | 29 + .../sketchybar/bar-config/plugins/caffeinate.sh | 21 + .../modules/sketchybar/bar-config/plugins/clock.sh | 3 + .../sketchybar/bar-config/plugins/front_app.sh | 10 + .../modules/sketchybar/bar-config/plugins/mail.sh | 12 + .../sketchybar/bar-config/plugins/network.sh | 45 + .../modules/sketchybar/bar-config/plugins/space.sh | 8 + .../sketchybar/bar-config/plugins/spotify.sh | 20 + .../sketchybar/bar-config/plugins/storage.sh | 27 + .../sketchybar/bar-config/plugins/volume.sh | 36 + .../sketchybar/bar-config/plugins/weather.sh | 56 + .../modules/sketchybar/bar-config/sketchybarrc | 170 + users/ryan/modules/sketchybar/default.nix | 19 + .../ryan/modules/taskwarrior-ubersicht/default.nix | 18 + .../taskwarrior-widget-source/README.md | 7 + .../taskwarrior-widget-source/style.css | 43 + .../taskwarrior-widget-source/taskwarrior.jsx | 203 ++ .../taskwarrior-widget-source/widget.json | 6 + users/ryan/modules/ubersicht/default.nix | 20 + users/ryan/zen/zenPolicies.nix | 127 + users/ryan/zen/zenProfile.nix | 71 + 584 files changed, 28830 insertions(+) create mode 100644 MIGRATION.md create mode 100644 README.md create mode 100644 files/CACerts/RyanCA.crt create mode 100644 files/Wallpapers/1685362396481634.jpg create mode 100644 files/Wallpapers/1693169418078790.jpg create mode 100644 files/Wallpapers/1694792956043641.jpg create mode 100644 files/Wallpapers/1708470532817406.jpg create mode 100644 files/Wallpapers/1720750738377603.jpg create mode 100644 files/Wallpapers/1720751011150282.png create mode 100644 files/Wallpapers/1723625710776950.jpg create mode 100644 files/Wallpapers/1723626275390685.jpg create mode 100644 files/Wallpapers/1728661127589872.jpg create mode 100644 files/Wallpapers/4yglzy4rkh4d1.jpeg create mode 100644 files/Wallpapers/7xosa7um3ohd1.jpg create mode 100644 files/Wallpapers/83juiltm3ohd1.jpg create mode 100644 files/Wallpapers/CN62QXJ.jpg create mode 100644 files/Wallpapers/above-clouds.jpg create mode 100644 files/Wallpapers/alena-aenami-bluehour-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-budapest.jpg create mode 100644 files/Wallpapers/alena-aenami-cave-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-close-to-the-sun-1920.jpg create mode 100644 files/Wallpapers/alena-aenami-cold-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-cosmo-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-downtown-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-dreamy-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-eclipse-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-end-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-eternity-1080px.jpg create mode 100644 files/Wallpapers/alena-aenami-kosmos19001.jpg create mode 100644 files/Wallpapers/alena-aenami-light-at-the-end-hd.jpg create mode 100644 files/Wallpapers/alena-aenami-lights-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-lines1k.jpg create mode 100644 files/Wallpapers/alena-aenami-mountains1k.jpg create mode 100644 files/Wallpapers/alena-aenami-new-year1k.jpg create mode 100644 files/Wallpapers/alena-aenami-orangemoon1900p.jpg create mode 100644 files/Wallpapers/alena-aenami-portal-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-reflect1k.jpg create mode 100644 files/Wallpapers/alena-aenami-serenity-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-sky1k.jpg create mode 100644 files/Wallpapers/alena-aenami-solar-1k.jpg create mode 100644 files/Wallpapers/alena-aenami-tl-002-1k.png create mode 100644 files/Wallpapers/alena-aenami-wait.jpg create mode 100644 files/Wallpapers/alena-aenami-wings-hd.jpg create mode 100644 files/Wallpapers/alena-aenami-you-1k-2.jpg create mode 100644 files/Wallpapers/autumn1.jpg create mode 100644 files/Wallpapers/autumn1.png create mode 100644 files/Wallpapers/dawn-mountains-vibrant.jpg create mode 100644 files/Wallpapers/lake-winter.jpg create mode 100644 files/Wallpapers/miku.png create mode 100644 files/Wallpapers/mountains.jpg create mode 100644 files/Wallpapers/northern-lights-2.jpg create mode 100644 files/Wallpapers/northern-lights-bridge.jpg create mode 100644 files/Wallpapers/ooglygoo.png create mode 100644 files/Wallpapers/purple-grass.jpg create mode 100644 files/Wallpapers/purple-intersection.jpg create mode 100644 files/Wallpapers/purple-lakescape.jpg create mode 100644 files/Wallpapers/sah1k8tm3ohd1.jpg create mode 100644 files/Wallpapers/scarecrow.jpg create mode 100644 files/Wallpapers/snow-1.jpg create mode 100644 files/Wallpapers/snow-2.jpg create mode 100644 files/Wallpapers/spong.jpg create mode 100644 files/Wallpapers/vfcfyfyehhi31.png create mode 100644 files/Wallpapers/w7ufw5eb3cuz.jpg create mode 100644 files/Wallpapers/wallhaven-832y1o.jpg create mode 100644 files/Wallpapers/wallhaven-gwwkql.jpg create mode 100644 files/Wallpapers/wallhaven-k81776.jpg create mode 100644 files/Wallpapers/wallhaven-lywpjl.jpg create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 hosts/RyanMac/configuration.nix create mode 100644 modules/darwin/random-wallpaper/default.nix create mode 100644 modules/darwin/random-wallpaper/wallpaper-daemon.swift create mode 100644 users/ryan/aerc/accounts.conf create mode 100644 users/ryan/aerc/aerc.conf create mode 100644 users/ryan/aerc/binds.conf create mode 100644 users/ryan/aerc/signature_personal create mode 100644 users/ryan/aerc/signature_rit_personal create mode 100644 users/ryan/aerc/templates/quoted_reply create mode 100644 users/ryan/aerc/templates/thanks create mode 100644 users/ryan/common.nix create mode 100644 users/ryan/darwin.nix create mode 100644 users/ryan/hammerspoon/init.lua create mode 100644 users/ryan/linux.nix create mode 100644 users/ryan/linux/alacritty/alacritty.yml create mode 100644 users/ryan/linux/firefox-nightly/default.nix create mode 100644 users/ryan/linux/firefox-nightly/policies.nix create mode 100644 users/ryan/linux/foot/foot.ini create mode 100644 users/ryan/linux/hypr/family_guy.mp4 create mode 100644 users/ryan/linux/hypr/hypridle.conf create mode 100644 users/ryan/linux/hypr/hyprland.conf create mode 100644 users/ryan/linux/hypr/hyprlock.conf create mode 100644 users/ryan/linux/hypr/kanshi.conf create mode 100644 users/ryan/linux/hypr/monitors.conf create mode 100644 users/ryan/linux/hypr/pyprland.toml create mode 100755 users/ryan/linux/hypr/scripts/autostart.sh create mode 100755 users/ryan/linux/hypr/scripts/perf_mode.sh create mode 100644 users/ryan/linux/hypr/subwaysurfer.webm create mode 100644 users/ryan/linux/mailvelope/gpgmejson.json create mode 100755 users/ryan/linux/mailvelope/start.sh create mode 100644 users/ryan/linux/mpv/scripts/easycrop.lua create mode 100644 users/ryan/linux/pulseaudio/client.conf create mode 100644 users/ryan/linux/spotify-player/app.toml create mode 100755 users/ryan/linux/tridactyl/native_main create mode 100644 users/ryan/linux/tridactyl/tridactyl.json create mode 100644 users/ryan/linux/waybar/config create mode 100755 users/ryan/linux/waybar/modules/check-for-music.sh create mode 100755 users/ryan/linux/waybar/modules/spotify.sh create mode 100755 users/ryan/linux/waybar/modules/storage.sh create mode 100755 users/ryan/linux/waybar/modules/weather.sh create mode 100644 users/ryan/linux/waybar/style.css create mode 100644 users/ryan/linux/wpaperd/config.toml create mode 100644 users/ryan/modules/nvim/default.nix create mode 100644 users/ryan/modules/nvim/extraConfigs/after/ftplugin/mail/custom.vim create mode 100644 users/ryan/modules/nvim/extraConfigs/after/ftplugin/markdown/custom.vim create mode 100644 users/ryan/modules/nvim/init.lua create mode 100644 users/ryan/modules/nvim/init.vim create mode 100644 users/ryan/modules/simple-bar/default.nix create mode 100644 users/ryan/modules/simple-bar/server.nix create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/.github/FUNDING.yml create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/bug_report.md create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/documentation_error.md create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/feature_request.md create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/.github/pull_request_template.md create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/.gitignore create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/.prettierrc create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/CODE_OF_CONDUCT.md create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/CONTRIBUTING.md create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/LICENSE create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/README.md create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/SECURITY.md create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/eslint.config.mjs create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/images/logo-simple-bar.png create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/images/preview.png create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/index.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/aerospace.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/app-icons.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace-context.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/opened-apps.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/process.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/space.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/spaces.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/window.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/browser-track.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/cpu.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/crypto.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/data-widget-loader.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/data-widget.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/date-display.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/github.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/gpu.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/graph.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/keyboard.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/memory.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/mic.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/mpd.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/music.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/netstats.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/next-meeting.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/notifications.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/sound.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/specter.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/spotify.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/stock.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/time.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/user-widgets.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/weather.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/wifi.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/youtube-music.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/zoom.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/error.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/icon.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/icons.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ableton.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/activity.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/add.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-designer.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-photo.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-publisher.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/airmail.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/alfred.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/android-messages.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/android-studio.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/anki.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/antigravity.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/anytype.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/app-store.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/apple-simulator.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/apple.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/aqua.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/arc.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/atom.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/audacity.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bambu-studio.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bank.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/battle-net.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bear.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/beekeeper.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bell-off.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bell.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bit-warden.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bitcoin.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/blender.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/book.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/brave-browser.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bruno.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/c-lion.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ca-r-r-o-t.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/calendar.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/camera-off.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/camera.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cancel.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/caprine.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/celo.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/charging.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chat-gpt.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chatterino.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/check-box.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-bottom.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-left.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-right.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-top.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/claude-code.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/claude.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/click-up.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cline.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/clock.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/close.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cloud.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/code.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/codex.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/coffee.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/color-picker.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/comfy-ui.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/copilot.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cp-u.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cursor.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/data-grip.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/date.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/de-v-o-nthink3.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/deezer.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/default.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/desktop.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/discord.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/docker.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/dollar.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/down-arrow.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/download.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/drafts.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/dropbox.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/element.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/emacs.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ethereum.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/evernote-legacy.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/face-time.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/figma.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/final-cut-pro.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/finder.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/firefox-developer-edition.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/firefox.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/fleet.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/fog.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/folx.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/free-tube.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/gear.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ghostty.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/git-hub.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/gnu-cash.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/go-land.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/good-notes.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/google-chrome.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/goose.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/grammarly.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/helium.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/home-assistant.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ht-t-pie.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/idea.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/insomnia.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/iris.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/italic.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/joplin.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/kakoune.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/kee-pass-x-c.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keyboard-maestro.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keyboard.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keynote.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/league-of-legends.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/libre-wolf.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/linear.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/lm-studio.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/maestro-ai.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mail.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mamp.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/manus.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/matlab.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mattermost.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/messages.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mic-off.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mic-on.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-edge.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-excel.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-outlook.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-power-point.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-word.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mimestream.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/min-browser.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/miro.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/monero-gui.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mongo-db.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/moon.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mpv.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/music.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/n8n.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/net-news-wire.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/netease-music.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/no-volume.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notability.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notebook-lm.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notes.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notion.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/nova.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/numbers.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ob-s-studio.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/obsidian.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ollama.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/omni-focus.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/one-password.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/open-book.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/open-claw.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/opencode.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/orb-stack.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pages.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/parallels.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/paused.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pdf.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/perplexity.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/php-storm.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pihole.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pine.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pins.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/playing.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/plex.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/podcasts.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pomodone.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/postman.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/proton-mail.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/py-charm.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/quip.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/qute-browser.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/radar.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rain.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ram.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/redis.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/reeder5.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/reminders.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remnote.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remote-desktop.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remove.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/replit.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rider.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rocket-chat.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/roon.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/royal-tsx.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ruby-mine.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rust-rover.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/safari.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/screens4.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sequel-ace.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sequel-pro.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/setapp.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/signal.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sketch-up.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sketch.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/skype.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/slack.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/snow.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spark.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotify.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotlight.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotube.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/statistics.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/stopped.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/storm.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sublime-text.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sun.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/super-productivity.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/table-plus.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tailscale.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/team-speak.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/teams.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/telegram.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/terminal.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/text.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/thermostat.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/things.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/thunderbird.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tick-tick.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tidal.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/todoist.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tor-browser.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tower.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/transmit.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/trello.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/twitter.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/up-arrow.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/upload.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vim.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vivaldi.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vl-c.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vmware-fusion.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-high.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-low.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-muted.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vp-n-off.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vp-n.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vs-codium.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/warp.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/web-storm.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wechat.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/whats-app.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/widget.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wifi-off.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wifi.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/windows.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/xcode.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/youtube-music.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zed.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zen-browser.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zeplin.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zoom.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zotero.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zulip.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/missives/missive.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/missives/missives.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/aerospace-display-manager.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/color-picker.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/icon-picker.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-component.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-inner.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-item.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-widgets.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/user-widgets-creator.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/side-icon.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/simple-bar-context.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/yabai-context.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/yabai/opened-apps.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/yabai/process.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/yabai/space-options.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/yabai/space.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/yabai/spaces.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/yabai/stickies.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/components/yabai/window.jsx create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/hooks/use-server-socket.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/hooks/use-widget-refresh.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/schemas/config.json create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/browser-audio.applescript create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/firefox-audio.applescript create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/firefox-dev-audio.applescript create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/init-aerospace.sh create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/init-yabai.sh create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/netstats.sh create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/next-meeting.sh create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/run-command-in-iterm2.applescript create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/run-command-in-terminal.applescript create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/yabai-set-mode-server.sh create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/yabai-set-mode.sh create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/zoom-mute-status.applescript create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/scripts/zoom-video-status.applescript create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/settings.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/skhd.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/battery.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/browser-track.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/cpu.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/crypto.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/data-widget-loader.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/data-widget.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/date-display.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/github.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/gpu.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/graph.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/keyboard.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/memory.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/mic.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/mpd.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/music.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/netstats.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/next-meeting.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/notifications.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/sound.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/specter.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/spotify.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/stock.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/time.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/viscosity-vpn.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/weather.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/wifi.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/youtube-music.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/data/zoom.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/missives.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/process.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/settings/aerospace-display-manager.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/settings/color-picker.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/settings/icon-picker.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/settings/settings.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/settings/user-widgets-creator.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/side-icon.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/spaces/space-options.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/spaces/space.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/components/spaces/spaces.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/core/base.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/core/variables.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/pywal/pywal-colors.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/pywal/pywal-from-desktop.sh create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/pywal/pywal-gen.sh create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/pywal/pywal.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/theme.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/amarena.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/catppuccin-frappe.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/catppuccin-latte.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/catppuccin-macchiato.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/catppuccin-mocha.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/catppuccin.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/cisco.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/cyberdream-dark.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/cyberdream-light.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/dracula.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/gruvbox-dark.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/gruvbox-light.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/gruvbox-material.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/mac-os-dark.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/mac-os-light.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/material-ocean.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/midsummer-night-dark.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/night-owl.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/night-shift-dark.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/night-shift-light.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/nightfox-dark.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/nightfox-light.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/nord.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/one-dark.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/one-light.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/rose-pine-dawn.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/rose-pine-moon.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/rose-pine.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/solarized-dark.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/solarized-light.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/spaceduck.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/sylens.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/tokyo-night.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/styles/themes/vscode-dark-modern.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/utils.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/lib/yabai.js create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/package-lock.json create mode 100755 users/ryan/modules/simple-bar/simple-bar-source/package.json create mode 100644 users/ryan/modules/simple-bar/simplebarrc create mode 100644 users/ryan/modules/sketchybar/bar-config/README.md create mode 100644 users/ryan/modules/sketchybar/bar-config/colors.sh create mode 100644 users/ryan/modules/sketchybar/bar-config/icons.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/battery.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/bluetooth.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/brightness.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/caffeinate.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/clock.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/front_app.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/mail.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/network.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/space.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/spotify.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/storage.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/volume.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/plugins/weather.sh create mode 100755 users/ryan/modules/sketchybar/bar-config/sketchybarrc create mode 100644 users/ryan/modules/sketchybar/default.nix create mode 100644 users/ryan/modules/taskwarrior-ubersicht/default.nix create mode 100755 users/ryan/modules/taskwarrior-ubersicht/taskwarrior-widget-source/README.md create mode 100755 users/ryan/modules/taskwarrior-ubersicht/taskwarrior-widget-source/style.css create mode 100755 users/ryan/modules/taskwarrior-ubersicht/taskwarrior-widget-source/taskwarrior.jsx create mode 100755 users/ryan/modules/taskwarrior-ubersicht/taskwarrior-widget-source/widget.json create mode 100644 users/ryan/modules/ubersicht/default.nix create mode 100644 users/ryan/zen/zenPolicies.nix create mode 100644 users/ryan/zen/zenProfile.nix diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 0000000..0e3f7f4 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,221 @@ +# Migrating guix-dotfiles onto nix-combined + +This repo supersedes `guix-dotfiles/home-config/nix-home-manager` (the ad-hoc +home-manager flake guix-dotfiles was already using) and pulls Linux desktop +config that used to live in `guix-dotfiles/home-config/home-configuration.scm` +into home-manager proper. It does **not** replace Guix itself: package +management, the system config, and three specific home services stay in +Guix (see "Stays in Guix" below). Nothing in `guix-dotfiles` has been edited +by this migration - the changes below are for you to apply by hand. + +## 1. Point `home-manager` at this repo + +In `guix-dotfiles/home-config/home-configuration.scm`, `%home-symlinks` +currently has: + +```scheme +(".config/guix/home-config/nix-home-manager" ".config/home-manager") +``` + +Change the target to wherever you clone `nix-combined`, e.g.: + +```scheme +("/path/to/nix-combined" ".config/home-manager") +``` + +Then switch with `home-manager switch --flake ~/.config/home-manager#ryan` +(the `rebuild` zsh alias does this on Linux). The old +`guix-dotfiles/home-config/nix-home-manager` directory can be deleted once +you've confirmed the new flake builds and switches cleanly. + +**Leave the `nix-config` symlink entry alone for the first switch.** It's +what sets `experimental-features = nix-command flakes` for your user today, +which is what lets `home-manager`/`nix` read this flake at all - +home-manager can't bootstrap its own prerequisite. `linux.nix` now writes +its own `~/.config/nix/nix.conf` and `~/.config/nix/registry.json` via +`xdg.configFile`, so *after* the first successful switch, remove the +`nix-config` entry from `%home-symlinks` too - otherwise HM's files resolve +through that symlink and land as untracked files inside the guix-dotfiles +checkout instead of in the Nix store. + +## 2. Remove entries `home-configuration.scm` now duplicates + +Once nix-combined delivers a path, Guix must stop also writing it, or +activation will collide (two things trying to own the same symlink target). +In `home-configuration.scm`'s `home-xdg-configuration-files-service-type` and +`home-files-service-type`, remove these lines (nix-combined now owns them): + +- `"nvim/init.vim"`, `"nvim/after/ftplugin/markdown/custom.vim"`, + `"nvim/after/ftplugin/mail/custom.vim"` - nix-combined's neovim config + (lazy.nvim-based, in `users/ryan/modules/nvim`) is the canonical one now; + the old vim-plug based `nvim/config/init.vim` + `plug.vim` is superseded. +- `"hypr/monitors.conf"`, `"hypr/pyprland.toml"`, `"hypr/family_guy.mp4"`, + `"hypr/hyprlock.conf"`, `"hypr/hypridle.conf"`, `"hypr/kanshi.conf"`, + `"hypr/subwaysurfer.webm"`, `"hypr/scripts"` (the `hyprland.conf` itself + was already coming from the old nix-home-manager flake, unchanged in + spirit here - just re-homed) +- `"wpaperd"`, `"mpv"`, `"foot"`, `"waybar"`, `"alacritty"`, `"aerc"` +- `"pulse/client.conf"` +- `.local/share/nvim/site/autoload/plug.vim` (dead once nvim is lazy.nvim-based) +- `.local/share/mailvelope`, `.mozilla/native-messaging-hosts/tridactyl.json`, + `.local/share/tridactyl` +- **`.icons`** (from `home-files-service-type`) - this one isn't optional + cleanup, it's a hard prerequisite. Guix delivers `.icons` today as a + single recursive `local-file` symlink, but `linux.nix`'s + `home.pointerCursor` (with `x11.enable = true`) needs to write + `~/.icons/default/index.theme` itself. With the old symlink still in + place, HM can't create a file inside a symlinked-to-store directory and + activation fails outright. Remove this entry before your first + `home-manager switch`. +- `.gitconfig` (nix-combined's `programs.git` now owns this, with the + `filter.lfs` and `[sendemail]` sections merged in - they existed in + guix-dotfiles' `.gitconfig` but were missing from the old nix-dotfiles config) +- `.ssh/config` (same story - nix-combined's `programs.ssh.settings` is a + strict superset: added the `linode` host, the `192.168.216.1` + legacy-algorithm host, the `KexAlgorithms` exclusion on `Host *`, and the + `Match host * exec "gpg-connect-agent ..."` line) +- `.docker/cli-plugins` (docker-compose plugin - if you still want this, + it's cheap to add to `users/ryan/linux.nix`'s `home.file`; it wasn't + carried over because nothing else referenced it and I didn't want to + guess at whether you still use it) + +`hypr/Wallpapers` and the sway config were left alone deliberately - you said +you'd handle wallpapers yourself, and `sway` isn't referenced by anything +active (Hyprland is the real WM; see "Dead/unused" below). + +## 3. Switch the login shell to zsh + +`guix-dotfiles/modules/ryan-config/base-system.scm`'s `base-operating-system` +has: + +```scheme +;(shell (file-append zsh "/bin/zsh")) +``` + +commented out, so your account's login shell is still bash even though the +canonical config (nix-dotfiles, and now nix-combined) is zsh. Uncomment that +line (and rebuild/reconfigure the system) so `programs.zsh` in +`users/ryan/common.nix` is actually what runs on login. Until you do, bash +still runs (Guix's `home-bash-service-type` config, if still present, keeps +working - just don't remove it from `home-configuration.scm` until the shell +is actually switched, or you'll drop to a shell with no rc file at all). + +## Stays in Guix - no home-manager equivalent without systemd + +Home-manager's `services.*` modules assume a systemd user session to +autostart things (or launchd on macOS). Guix uses shepherd instead, and +home-manager has no shepherd backend. These three keep running exactly as +they do today, defined in `guix-dotfiles/modules/ryan-services/`: + +- **`home-pipewire-service-type`** (pipewire + wireplumber daemons) +- **`home-dbus-service-type`** (per-user session dbus, since Guix has no + systemd --user to provide one) +- **`downloads-garbage-collector-service-type`** (the weekly Downloads + cleanup shepherd timer) + +`home-gpg-agent-service-type` is the one service that *did* migrate cleanly: +gpg-agent doesn't need a supervisor. It's socket-activated the same way on +both platforms via the zsh init in `common.nix` +(`gpgconf --launch gpg-agent` + exporting `SSH_AUTH_SOCK`), which is exactly +what nix-dotfiles' darwin config already did. `linux.nix` points +`services.gpg-agent.pinentry.package` at nixpkgs' `pinentry-qt` rather than +Guix's system profile path, so it isn't cross-dependent on Guix. + +`home-spotifyd-service-type` is already commented out/disabled in +`home-configuration.scm` - nothing to do there. + +## Dead/unused - candidates to delete from guix-dotfiles + +Found while comparing the two repos; none of these are referenced by +anything active, so nothing carried them into nix-combined: + +- **fish** (`home-config/fish/`) - the `fish` package is commented out of + `home-configuration.scm`'s package list, but the dotfiles are still + checked in. Orphaned. +- **`.nix-channels`** - classic (non-flake) nix-channel file. Now that + everything is flake-based, this shouldn't be needed. +- **`icons/XCursor-Pro-Dark*`** - not referenced anywhere; only + `Bibata-Modern-*` appears in `hypr/hyprland.conf`. +- **`fonts/Fira Code`, `fonts/Lilex`, `fonts/Monofur For Powerline`, + `fonts/AnonymicePro`, `fonts/MonofurNerdFont`** - superseded by + `nerd-fonts.{fira-code,lilex,anonymice,monofur}` from nixpkgs + (`linux.nix`'s `home.packages`), which ship the same font families. +- **`home-spotifyd-service-type`** usage - already disabled. +- **`alacritty`** - config exists in both repos, but no package installs the + `alacritty` binary in either the guix or the old nix-home-manager config. + `foot` is what's actually wired into the system (Guix package list, + kmscon login). I added `pkgs.alacritty` to `linux.nix` so the config isn't + dead weight, but confirm whether you still use it - if not, drop both the + package and `users/ryan/linux/alacritty/`. +- **`sway` config** - not referenced by anything; Hyprland (via + home-manager) is the actual compositor in use. + +## Additive merges (things nix-dotfiles was missing, now fixed) + +- **aerc**: `signature_personal`, `signature_rit_personal`, + `templates/quoted_reply`, `templates/thanks` existed only in + guix-dotfiles' aerc config, even though `accounts.conf`/`aerc.conf` + already referenced them by path. Copied into `users/ryan/aerc/`. +- **git**: `filter.lfs` and `[sendemail]` sections, merged into + `common.nix`'s `programs.git.settings`. +- **ssh**: `linode`, `192.168.216.1` (legacy host key/pubkey algorithms), + the `KexAlgorithms` exclusion, and the `Match host * exec ...` line, + merged into `common.nix`'s `programs.ssh`. + +## Linux desktop stack re-pin (see also the flake-version conversation) + +The old `guix-dotfiles/home-config/nix-home-manager/flake.nix` pinned +home-manager to a 2024 commit specifically so it'd match separately-pinned +`hyprland`/`hyprlock`/`hyprpicker`/`wpaperd` flake inputs (plus a +`ryan77627/nixGL` fork and a `rust-overlay` pin for wpaperd). Sharing +`common.nix` with the darwin config (which tracks home-manager master) +required moving Linux onto the same nixpkgs/home-manager as darwin. + +The good news: current nixpkgs-unstable now packages `hyprland` (0.52.2), +`hyprlock`, `hypridle`, `hyprpicker`, `wpaperd`, `kanshi`, and `pyprland` +directly, so those five extra flake inputs (and the rust-overlay pin) are +gone entirely - `linux.nix` just uses `pkgs.hyprland` etc. Only two +Linux-specific flake inputs remain in `flake.nix`: + +- `nixgl` (still needed - it exists specifically to patch Guix's mesa/GL + mismatch, unrelated to nixpkgs version) +- `clipboard-sync` (not in nixpkgs) + +**Dropped**: the `hypr-dynamic-cursors` Hyprland plugin (animated cursor +trails). It has no nixpkgs package and pinning a matching flake input just +for one cosmetic plugin didn't seem worth the added re-pin risk. If you want +it back, add it as a flake input with `inputs.nixpkgs.follows = "nixpkgs"` +and pass it as a plugin in `wayland.windowManager.hyprland.plugins`. + +**Dropped**: `mozff` (firefox-nightly flake) - unused. The +`firefox-nightly` module's package line was already commented out in the +guix config; it just configures `programs.firefox` (nixpkgs' own package). + +**Cursor theme changed**: the vendored `Bibata-Modern-Classic-Hyprland` / +`Bibata-Modern-daed9-v1.0.2-x11` asset had oddly-versioned internal theme +names from however that release was originally packaged. Replaced with +nixpkgs' `bibata-cursors` (`home.pointerCursor` in `linux.nix`) - the +`HYPRCURSOR_THEME`/`XCURSOR_THEME` env vars in `hyprland.conf` were updated +to the plain name `Bibata-Modern-Classic` to match. nixpkgs' build doesn't +have a `-Hyprland`-suffixed hyprcursor variant; Hyprland falls back to +rendering the XCursor theme directly, which works fine, just without the +optional cleaner hyprcursor rendering path. + +## Verification note + +`homeConfigurations.ryan` was checked with: + +``` +nix eval --raw .#homeConfigurations.ryan.activationPackage.drvPath +``` + +which forces full module evaluation (catches missing options and +darwin-only packages referenced on Linux) without building anything. + +`darwinConfigurations.RyanMac` could not be evaluated on this machine (no +aarch64-darwin builder). It was verified by structural diff instead: +`flake.nix`'s darwin-facing inputs/outputs, `hosts/RyanMac/configuration.nix`, +and `modules/darwin/random-wallpaper` are unchanged from `nix-dotfiles`; +`common.nix`/`darwin.nix` reproduce `nix-dotfiles/users/ryan/home.nix` +line-for-line except where noted above. Please run +`darwin-rebuild build --flake .#RyanMac` yourself before switching for real. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8476171 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# nix-combined + +One flake, two targets: + +- `darwinConfigurations.RyanMac` - the mac system (nix-darwin + home-manager), + equivalent to what `nix-dotfiles` built. +- `homeConfigurations.ryan` - standalone home-manager for `x86_64-linux`, + meant to run *on top of* Guix System as the home-manager substitute for + what `guix-dotfiles/home-config/home-configuration.scm` used to fully own. + Guix still owns the system config, package management, and three home + services that need shepherd (pipewire, dbus, downloads-gc) - see + `MIGRATION.md`. + +`users/ryan/common.nix` holds everything shared by both (git, ssh, gpg-agent, +starship, zsh, zen-browser, neovim). `darwin.nix` and `linux.nix` hold the +platform-specific rest. + +## Darwin + +``` +sudo nix run --extra-experimental-features "nix-command flakes" github:nix-darwin/nix-darwin -- switch --flake .#RyanMac \ + --option "extra-substituters" "https://virby-nix-darwin.cachix.org" \ + --option "extra-trusted-public-keys" "virby-nix-darwin.cachix.org-1:z9GiEZeBU5bEeoDQjyfHPMGPBaIQJOOvYOOjGMKIlLo=" +``` + +Subsequent rebuilds: `rebuild` (zsh alias) or +`sudo darwin-rebuild switch --flake ~/.config/nix/.` + +## Linux (Guix) + +Requires `experimental-features = nix-command flakes` in +`~/.config/nix/nix.conf` (guix-dotfiles already symlinks this in). + +``` +nix run --extra-experimental-features "nix-command flakes" home-manager -- switch --flake .#ryan +``` + +Subsequent rebuilds: `rebuild` (zsh alias) or +`home-manager switch --flake ~/.config/home-manager#ryan`. + +See `MIGRATION.md` for what needs to change in `guix-dotfiles` for this to +slot in cleanly (symlink target, overlapping config entries to remove, the +zsh login-shell switch), what stays Guix-native and why, and what got +dropped as dead weight along the way. diff --git a/files/CACerts/RyanCA.crt b/files/CACerts/RyanCA.crt new file mode 100644 index 0000000..7fa09c1 --- /dev/null +++ b/files/CACerts/RyanCA.crt @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBmDCCAT2gAwIBAgIQIq6m5IB0yZ1181RHpL6jyjAKBggqhkjOPQQDAjAqMQ8w +DQYDVQQKEwZSeWFuQ0ExFzAVBgNVBAMTDlJ5YW5DQSBSb290IENBMB4XDTIyMTAx +OTIzMjIxNFoXDTMyMTAxNjIzMjIxNFowKjEPMA0GA1UEChMGUnlhbkNBMRcwFQYD +VQQDEw5SeWFuQ0EgUm9vdCBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAhR +Z3X7MTDDzvPAuW9JM8Rn4MU283Y3Wa2a1RiyTxo2XGlEB8HPgfL7MwRccUlCiABl +zPHkaYUvrjJrq7PjsuejRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG +AQH/AgEBMB0GA1UdDgQWBBS4/S97d94NQoK+G+Lh9T76LVCxXDAKBggqhkjOPQQD +AgNJADBGAiEA5WVKjNUN1x4+X17XnD+H5QKLgs+M/mFfyk3yPY1aMtoCIQCnGAu9 +wrKUglPbAPcQ1Qs47qeBubJu5um1v+mi0+MGPg== +-----END CERTIFICATE----- diff --git a/files/Wallpapers/1685362396481634.jpg b/files/Wallpapers/1685362396481634.jpg new file mode 100644 index 0000000..fd49cae Binary files /dev/null and b/files/Wallpapers/1685362396481634.jpg differ diff --git a/files/Wallpapers/1693169418078790.jpg b/files/Wallpapers/1693169418078790.jpg new file mode 100644 index 0000000..8156108 Binary files /dev/null and b/files/Wallpapers/1693169418078790.jpg differ diff --git a/files/Wallpapers/1694792956043641.jpg b/files/Wallpapers/1694792956043641.jpg new file mode 100644 index 0000000..431e96b Binary files /dev/null and b/files/Wallpapers/1694792956043641.jpg differ diff --git a/files/Wallpapers/1708470532817406.jpg b/files/Wallpapers/1708470532817406.jpg new file mode 100644 index 0000000..4a4f2f0 Binary files /dev/null and b/files/Wallpapers/1708470532817406.jpg differ diff --git a/files/Wallpapers/1720750738377603.jpg b/files/Wallpapers/1720750738377603.jpg new file mode 100644 index 0000000..f8dd9cd Binary files /dev/null and b/files/Wallpapers/1720750738377603.jpg differ diff --git a/files/Wallpapers/1720751011150282.png b/files/Wallpapers/1720751011150282.png new file mode 100644 index 0000000..dbd3e38 Binary files /dev/null and b/files/Wallpapers/1720751011150282.png differ diff --git a/files/Wallpapers/1723625710776950.jpg b/files/Wallpapers/1723625710776950.jpg new file mode 100644 index 0000000..71608ff Binary files /dev/null and b/files/Wallpapers/1723625710776950.jpg differ diff --git a/files/Wallpapers/1723626275390685.jpg b/files/Wallpapers/1723626275390685.jpg new file mode 100644 index 0000000..aa8c8c2 Binary files /dev/null and b/files/Wallpapers/1723626275390685.jpg differ diff --git a/files/Wallpapers/1728661127589872.jpg b/files/Wallpapers/1728661127589872.jpg new file mode 100644 index 0000000..b5dcbeb Binary files /dev/null and b/files/Wallpapers/1728661127589872.jpg differ diff --git a/files/Wallpapers/4yglzy4rkh4d1.jpeg b/files/Wallpapers/4yglzy4rkh4d1.jpeg new file mode 100644 index 0000000..0ef50ad Binary files /dev/null and b/files/Wallpapers/4yglzy4rkh4d1.jpeg differ diff --git a/files/Wallpapers/7xosa7um3ohd1.jpg b/files/Wallpapers/7xosa7um3ohd1.jpg new file mode 100644 index 0000000..3bb615e Binary files /dev/null and b/files/Wallpapers/7xosa7um3ohd1.jpg differ diff --git a/files/Wallpapers/83juiltm3ohd1.jpg b/files/Wallpapers/83juiltm3ohd1.jpg new file mode 100644 index 0000000..15aff05 Binary files /dev/null and b/files/Wallpapers/83juiltm3ohd1.jpg differ diff --git a/files/Wallpapers/CN62QXJ.jpg b/files/Wallpapers/CN62QXJ.jpg new file mode 100644 index 0000000..c49c449 Binary files /dev/null and b/files/Wallpapers/CN62QXJ.jpg differ diff --git a/files/Wallpapers/above-clouds.jpg b/files/Wallpapers/above-clouds.jpg new file mode 100644 index 0000000..a525ee8 Binary files /dev/null and b/files/Wallpapers/above-clouds.jpg differ diff --git a/files/Wallpapers/alena-aenami-bluehour-1k.jpg b/files/Wallpapers/alena-aenami-bluehour-1k.jpg new file mode 100644 index 0000000..ade3472 Binary files /dev/null and b/files/Wallpapers/alena-aenami-bluehour-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-budapest.jpg b/files/Wallpapers/alena-aenami-budapest.jpg new file mode 100644 index 0000000..a01b60b Binary files /dev/null and b/files/Wallpapers/alena-aenami-budapest.jpg differ diff --git a/files/Wallpapers/alena-aenami-cave-1k.jpg b/files/Wallpapers/alena-aenami-cave-1k.jpg new file mode 100644 index 0000000..048b4c1 Binary files /dev/null and b/files/Wallpapers/alena-aenami-cave-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-close-to-the-sun-1920.jpg b/files/Wallpapers/alena-aenami-close-to-the-sun-1920.jpg new file mode 100644 index 0000000..853ff56 Binary files /dev/null and b/files/Wallpapers/alena-aenami-close-to-the-sun-1920.jpg differ diff --git a/files/Wallpapers/alena-aenami-cold-1k.jpg b/files/Wallpapers/alena-aenami-cold-1k.jpg new file mode 100644 index 0000000..5152b02 Binary files /dev/null and b/files/Wallpapers/alena-aenami-cold-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-cosmo-1k.jpg b/files/Wallpapers/alena-aenami-cosmo-1k.jpg new file mode 100644 index 0000000..78f50a9 Binary files /dev/null and b/files/Wallpapers/alena-aenami-cosmo-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-downtown-1k.jpg b/files/Wallpapers/alena-aenami-downtown-1k.jpg new file mode 100644 index 0000000..870813b Binary files /dev/null and b/files/Wallpapers/alena-aenami-downtown-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-dreamy-1k.jpg b/files/Wallpapers/alena-aenami-dreamy-1k.jpg new file mode 100644 index 0000000..3931833 Binary files /dev/null and b/files/Wallpapers/alena-aenami-dreamy-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-eclipse-1k.jpg b/files/Wallpapers/alena-aenami-eclipse-1k.jpg new file mode 100644 index 0000000..acf008e Binary files /dev/null and b/files/Wallpapers/alena-aenami-eclipse-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-end-1k.jpg b/files/Wallpapers/alena-aenami-end-1k.jpg new file mode 100644 index 0000000..5b8d249 Binary files /dev/null and b/files/Wallpapers/alena-aenami-end-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-eternity-1080px.jpg b/files/Wallpapers/alena-aenami-eternity-1080px.jpg new file mode 100644 index 0000000..f8a50f8 Binary files /dev/null and b/files/Wallpapers/alena-aenami-eternity-1080px.jpg differ diff --git a/files/Wallpapers/alena-aenami-kosmos19001.jpg b/files/Wallpapers/alena-aenami-kosmos19001.jpg new file mode 100644 index 0000000..e3ce36a Binary files /dev/null and b/files/Wallpapers/alena-aenami-kosmos19001.jpg differ diff --git a/files/Wallpapers/alena-aenami-light-at-the-end-hd.jpg b/files/Wallpapers/alena-aenami-light-at-the-end-hd.jpg new file mode 100644 index 0000000..00cbcb1 Binary files /dev/null and b/files/Wallpapers/alena-aenami-light-at-the-end-hd.jpg differ diff --git a/files/Wallpapers/alena-aenami-lights-1k.jpg b/files/Wallpapers/alena-aenami-lights-1k.jpg new file mode 100644 index 0000000..b3038ec Binary files /dev/null and b/files/Wallpapers/alena-aenami-lights-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-lines1k.jpg b/files/Wallpapers/alena-aenami-lines1k.jpg new file mode 100644 index 0000000..73688eb Binary files /dev/null and b/files/Wallpapers/alena-aenami-lines1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-mountains1k.jpg b/files/Wallpapers/alena-aenami-mountains1k.jpg new file mode 100644 index 0000000..7448ab1 Binary files /dev/null and b/files/Wallpapers/alena-aenami-mountains1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-new-year1k.jpg b/files/Wallpapers/alena-aenami-new-year1k.jpg new file mode 100644 index 0000000..816a884 Binary files /dev/null and b/files/Wallpapers/alena-aenami-new-year1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-orangemoon1900p.jpg b/files/Wallpapers/alena-aenami-orangemoon1900p.jpg new file mode 100644 index 0000000..08e56c0 Binary files /dev/null and b/files/Wallpapers/alena-aenami-orangemoon1900p.jpg differ diff --git a/files/Wallpapers/alena-aenami-portal-1k.jpg b/files/Wallpapers/alena-aenami-portal-1k.jpg new file mode 100644 index 0000000..24311ff Binary files /dev/null and b/files/Wallpapers/alena-aenami-portal-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-reflect1k.jpg b/files/Wallpapers/alena-aenami-reflect1k.jpg new file mode 100644 index 0000000..49ab145 Binary files /dev/null and b/files/Wallpapers/alena-aenami-reflect1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-serenity-1k.jpg b/files/Wallpapers/alena-aenami-serenity-1k.jpg new file mode 100644 index 0000000..7164548 Binary files /dev/null and b/files/Wallpapers/alena-aenami-serenity-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-sky1k.jpg b/files/Wallpapers/alena-aenami-sky1k.jpg new file mode 100644 index 0000000..84b9739 Binary files /dev/null and b/files/Wallpapers/alena-aenami-sky1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-solar-1k.jpg b/files/Wallpapers/alena-aenami-solar-1k.jpg new file mode 100644 index 0000000..cb71169 Binary files /dev/null and b/files/Wallpapers/alena-aenami-solar-1k.jpg differ diff --git a/files/Wallpapers/alena-aenami-tl-002-1k.png b/files/Wallpapers/alena-aenami-tl-002-1k.png new file mode 100644 index 0000000..b6f450f Binary files /dev/null and b/files/Wallpapers/alena-aenami-tl-002-1k.png differ diff --git a/files/Wallpapers/alena-aenami-wait.jpg b/files/Wallpapers/alena-aenami-wait.jpg new file mode 100644 index 0000000..2dc72ac Binary files /dev/null and b/files/Wallpapers/alena-aenami-wait.jpg differ diff --git a/files/Wallpapers/alena-aenami-wings-hd.jpg b/files/Wallpapers/alena-aenami-wings-hd.jpg new file mode 100644 index 0000000..89b1378 Binary files /dev/null and b/files/Wallpapers/alena-aenami-wings-hd.jpg differ diff --git a/files/Wallpapers/alena-aenami-you-1k-2.jpg b/files/Wallpapers/alena-aenami-you-1k-2.jpg new file mode 100644 index 0000000..5057667 Binary files /dev/null and b/files/Wallpapers/alena-aenami-you-1k-2.jpg differ diff --git a/files/Wallpapers/autumn1.jpg b/files/Wallpapers/autumn1.jpg new file mode 100644 index 0000000..1f06edd Binary files /dev/null and b/files/Wallpapers/autumn1.jpg differ diff --git a/files/Wallpapers/autumn1.png b/files/Wallpapers/autumn1.png new file mode 100644 index 0000000..72cac31 Binary files /dev/null and b/files/Wallpapers/autumn1.png differ diff --git a/files/Wallpapers/dawn-mountains-vibrant.jpg b/files/Wallpapers/dawn-mountains-vibrant.jpg new file mode 100644 index 0000000..c678fec Binary files /dev/null and b/files/Wallpapers/dawn-mountains-vibrant.jpg differ diff --git a/files/Wallpapers/lake-winter.jpg b/files/Wallpapers/lake-winter.jpg new file mode 100644 index 0000000..b47a8c9 Binary files /dev/null and b/files/Wallpapers/lake-winter.jpg differ diff --git a/files/Wallpapers/miku.png b/files/Wallpapers/miku.png new file mode 100644 index 0000000..f88f2eb Binary files /dev/null and b/files/Wallpapers/miku.png differ diff --git a/files/Wallpapers/mountains.jpg b/files/Wallpapers/mountains.jpg new file mode 100644 index 0000000..f51a09b Binary files /dev/null and b/files/Wallpapers/mountains.jpg differ diff --git a/files/Wallpapers/northern-lights-2.jpg b/files/Wallpapers/northern-lights-2.jpg new file mode 100644 index 0000000..cb2a7f4 Binary files /dev/null and b/files/Wallpapers/northern-lights-2.jpg differ diff --git a/files/Wallpapers/northern-lights-bridge.jpg b/files/Wallpapers/northern-lights-bridge.jpg new file mode 100644 index 0000000..8fa7b28 Binary files /dev/null and b/files/Wallpapers/northern-lights-bridge.jpg differ diff --git a/files/Wallpapers/ooglygoo.png b/files/Wallpapers/ooglygoo.png new file mode 100644 index 0000000..f3503ca Binary files /dev/null and b/files/Wallpapers/ooglygoo.png differ diff --git a/files/Wallpapers/purple-grass.jpg b/files/Wallpapers/purple-grass.jpg new file mode 100644 index 0000000..2a81c54 Binary files /dev/null and b/files/Wallpapers/purple-grass.jpg differ diff --git a/files/Wallpapers/purple-intersection.jpg b/files/Wallpapers/purple-intersection.jpg new file mode 100644 index 0000000..cf75de4 Binary files /dev/null and b/files/Wallpapers/purple-intersection.jpg differ diff --git a/files/Wallpapers/purple-lakescape.jpg b/files/Wallpapers/purple-lakescape.jpg new file mode 100644 index 0000000..23d28e2 Binary files /dev/null and b/files/Wallpapers/purple-lakescape.jpg differ diff --git a/files/Wallpapers/sah1k8tm3ohd1.jpg b/files/Wallpapers/sah1k8tm3ohd1.jpg new file mode 100644 index 0000000..a21261b Binary files /dev/null and b/files/Wallpapers/sah1k8tm3ohd1.jpg differ diff --git a/files/Wallpapers/scarecrow.jpg b/files/Wallpapers/scarecrow.jpg new file mode 100644 index 0000000..f095d15 Binary files /dev/null and b/files/Wallpapers/scarecrow.jpg differ diff --git a/files/Wallpapers/snow-1.jpg b/files/Wallpapers/snow-1.jpg new file mode 100644 index 0000000..d00fcd1 Binary files /dev/null and b/files/Wallpapers/snow-1.jpg differ diff --git a/files/Wallpapers/snow-2.jpg b/files/Wallpapers/snow-2.jpg new file mode 100644 index 0000000..5343822 Binary files /dev/null and b/files/Wallpapers/snow-2.jpg differ diff --git a/files/Wallpapers/spong.jpg b/files/Wallpapers/spong.jpg new file mode 100644 index 0000000..7adf257 Binary files /dev/null and b/files/Wallpapers/spong.jpg differ diff --git a/files/Wallpapers/vfcfyfyehhi31.png b/files/Wallpapers/vfcfyfyehhi31.png new file mode 100644 index 0000000..adb7f37 Binary files /dev/null and b/files/Wallpapers/vfcfyfyehhi31.png differ diff --git a/files/Wallpapers/w7ufw5eb3cuz.jpg b/files/Wallpapers/w7ufw5eb3cuz.jpg new file mode 100644 index 0000000..e59d184 Binary files /dev/null and b/files/Wallpapers/w7ufw5eb3cuz.jpg differ diff --git a/files/Wallpapers/wallhaven-832y1o.jpg b/files/Wallpapers/wallhaven-832y1o.jpg new file mode 100644 index 0000000..60f67f2 Binary files /dev/null and b/files/Wallpapers/wallhaven-832y1o.jpg differ diff --git a/files/Wallpapers/wallhaven-gwwkql.jpg b/files/Wallpapers/wallhaven-gwwkql.jpg new file mode 100644 index 0000000..adb1889 Binary files /dev/null and b/files/Wallpapers/wallhaven-gwwkql.jpg differ diff --git a/files/Wallpapers/wallhaven-k81776.jpg b/files/Wallpapers/wallhaven-k81776.jpg new file mode 100644 index 0000000..a09ffcd Binary files /dev/null and b/files/Wallpapers/wallhaven-k81776.jpg differ diff --git a/files/Wallpapers/wallhaven-lywpjl.jpg b/files/Wallpapers/wallhaven-lywpjl.jpg new file mode 100644 index 0000000..dc9bb13 Binary files /dev/null and b/files/Wallpapers/wallhaven-lywpjl.jpg differ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..5c684b1 --- /dev/null +++ b/flake.lock @@ -0,0 +1,312 @@ +{ + "nodes": { + "brew-src": { + "flake": false, + "locked": { + "lastModified": 1785146564, + "narHash": "sha256-Sa7/HrfB04H32OJ7/ofxXjiZEbkWtCNOriONYYTL1OA=", + "owner": "Homebrew", + "repo": "brew", + "rev": "b2cfc03346d482f79886de108fee5dc49a6efc10", + "type": "github" + }, + "original": { + "owner": "Homebrew", + "ref": "6.0.13", + "repo": "brew", + "type": "github" + } + }, + "clipboard-sync": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1759253700, + "narHash": "sha256-pDsDzWEBaZlT9lHsBZMGm8aBJGncMxqerKwkzjEM/EI=", + "owner": "dnut", + "repo": "clipboard-sync", + "rev": "138a59b8f3044dd9e7dcccd9607bbbb48c14bae6", + "type": "github" + }, + "original": { + "owner": "dnut", + "repo": "clipboard-sync", + "type": "github" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1785389976, + "narHash": "sha256-0tLW8Ff5yt8AH97jw4ZpFJ0OCJ122zIlgWGDmOfU/VU=", + "owner": "nix-darwin", + "repo": "nix-darwin", + "rev": "15abb8c98f336cd8bd840d71059adebabe60bf04", + "type": "github" + }, + "original": { + "owner": "nix-darwin", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1785531816, + "narHash": "sha256-vkMnV0JIyw+g/NmcfoajlGaAO+9a0ezia+FZohQJrik=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "bf9ce9fec78f95f374e8dd3b503863a3ec128ebe", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "homebrew-cask": { + "flake": false, + "locked": { + "lastModified": 1785732563, + "narHash": "sha256-g96wDRb5AZOFjmdMDWMHB/00N/cXAdqh3sB/TYJDwaU=", + "owner": "homebrew", + "repo": "homebrew-cask", + "rev": "bee069693a0d8407ea8e2bd746a5109a6930a5d0", + "type": "github" + }, + "original": { + "owner": "homebrew", + "repo": "homebrew-cask", + "type": "github" + } + }, + "homebrew-core": { + "flake": false, + "locked": { + "lastModified": 1785729508, + "narHash": "sha256-u40Hmtr6mLTyydI+JKHCzyzIemIk8tYEZbaCe1OfvZA=", + "owner": "homebrew", + "repo": "homebrew-core", + "rev": "5ec2eaf8b84b6f3bdc4872f74014c050bb4b439d", + "type": "github" + }, + "original": { + "owner": "homebrew", + "repo": "homebrew-core", + "type": "github" + } + }, + "homebrew-felixkratz": { + "flake": false, + "locked": { + "lastModified": 1780547371, + "narHash": "sha256-QGCVV5N1QC56GQK3ck2YJ6J6/S8SQ6rTElz69y58078=", + "owner": "FelixKratz", + "repo": "homebrew-formulae", + "rev": "70b2071488b61c14f773ce9e1bf6626ee851981a", + "type": "github" + }, + "original": { + "owner": "FelixKratz", + "repo": "homebrew-formulae", + "type": "github" + } + }, + "homebrew-netbird": { + "flake": false, + "locked": { + "lastModified": 1785527306, + "narHash": "sha256-EODXrWyUFqBmWJn0tFJ9AmRmqYPfA8eveuBuLW+/6Ds=", + "owner": "netbirdio", + "repo": "homebrew-tap", + "rev": "9ad629107a808a37e5770854ab96574d1e96a8f0", + "type": "github" + }, + "original": { + "owner": "netbirdio", + "repo": "homebrew-tap", + "type": "github" + } + }, + "netbird-tui": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1784513029, + "narHash": "sha256-m9sIguYjsuHz3IWwmNOlvuVTT0Cspe61Y9UyjM3pRVk=", + "ref": "refs/heads/main", + "rev": "efa74d02ad42ee7aeaf5c97240929063118c6252", + "revCount": 1, + "type": "git", + "url": "https://git.rschanz.org/netbird-tui-flake" + }, + "original": { + "type": "git", + "url": "https://git.rschanz.org/netbird-tui-flake" + } + }, + "nix-homebrew": { + "inputs": { + "brew-src": "brew-src" + }, + "locked": { + "lastModified": 1785544760, + "narHash": "sha256-qV6OoNuly4ntqpCg7esIeJjUboxSnQNlLPxz+y5h9/o=", + "owner": "zhaofengli", + "repo": "nix-homebrew", + "rev": "937ce52c7d046310571f3a070713804ead496843", + "type": "github" + }, + "original": { + "owner": "zhaofengli", + "repo": "nix-homebrew", + "type": "github" + } + }, + "nixgl": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1736159088, + "narHash": "sha256-WDBc35XdHCdmgVYbPOtd2IeUtUHCYwNyEpIr5vLZMng=", + "owner": "ryan77627", + "repo": "nixGL", + "rev": "3865170cbc23b32ec7cc8df1ec811fd44b6c2a58", + "type": "github" + }, + "original": { + "owner": "ryan77627", + "repo": "nixGL", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1785602060, + "narHash": "sha256-z7D96eESRM4CPV/XtwpwFn8IDdfLAmxz6lVWrGYXvR4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "a5cbcfe954791221bfffe2307f7d1a1bf61a871e", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1782821651, + "narHash": "sha256-D5jO0ME1lA9bDHnd5kVawBwItG/N4oZr3FlXmMzLec8=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "e52c192be9d7b2c4bd4aed326c8731b35f8bb75c", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "clipboard-sync": "clipboard-sync", + "darwin": "darwin", + "home-manager": "home-manager", + "homebrew-cask": "homebrew-cask", + "homebrew-core": "homebrew-core", + "homebrew-felixkratz": "homebrew-felixkratz", + "homebrew-netbird": "homebrew-netbird", + "netbird-tui": "netbird-tui", + "nix-homebrew": "nix-homebrew", + "nixgl": "nixgl", + "nixpkgs": "nixpkgs", + "virby": "virby", + "zen-browser": "zen-browser" + } + }, + "virby": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1782970342, + "narHash": "sha256-5oVThXJjEFPiCTm6jzAmSCVRuDRi4AG3HgLLjpgLYXA=", + "owner": "quinneden", + "repo": "virby-nix-darwin", + "rev": "a52216470a97ef5970939acf697a00ec61beb0c6", + "type": "github" + }, + "original": { + "owner": "quinneden", + "repo": "virby-nix-darwin", + "type": "github" + } + }, + "zen-browser": { + "inputs": { + "home-manager": [ + "home-manager" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1785652409, + "narHash": "sha256-0273OvIPfkJcdv0+Z3iPL8+eSRavAwGRCnr+Y6tRjYY=", + "owner": "0xc000022070", + "repo": "zen-browser-flake", + "rev": "12224626d0d1cead79603f19601666360c715379", + "type": "github" + }, + "original": { + "owner": "0xc000022070", + "repo": "zen-browser-flake", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..c5f593f --- /dev/null +++ b/flake.nix @@ -0,0 +1,99 @@ +{ + description = "Combined nix flake: darwin system (RyanMac) + standalone home-manager for Guix (ryan@linux)"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + + darwin = { + url = "github:nix-darwin/nix-darwin/master"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # Shared between darwin and linux + zen-browser = { + url = "github:0xc000022070/zen-browser-flake"; + inputs = { + nixpkgs.follows = "nixpkgs"; + home-manager.follows = "home-manager"; + }; + }; + + # Darwin-only + netbird-tui = { + url = "git+https://git.rschanz.org/netbird-tui-flake"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nix-homebrew.url = "github:zhaofengli/nix-homebrew"; + homebrew-core = { + url = "github:homebrew/homebrew-core"; + flake = false; + }; + homebrew-cask = { + url = "github:homebrew/homebrew-cask"; + flake = false; + }; + virby.url = "github:quinneden/virby-nix-darwin"; + homebrew-netbird = { + url = "github:netbirdio/homebrew-tap"; + flake = false; + }; + homebrew-felixkratz = { + url = "github:FelixKratz/homebrew-formulae"; + flake = false; + }; + + # Linux-only. hyprland/hyprlock/hypridle/hyprpicker/wpaperd/kanshi/pyprland + # all now ship in nixpkgs itself, so only the pieces nixpkgs doesn't carry + # need their own flake input: + nixgl = { + # Ryan's fork exists to patch Guix's mesa/OpenGL mismatch, unrelated to + # nixpkgs version - keep tracking it regardless of the nixpkgs bump. + url = "github:ryan77627/nixGL"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + clipboard-sync = { + url = "github:dnut/clipboard-sync"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { nixpkgs, home-manager, ... }@inputs: { + darwinConfigurations."RyanMac" = inputs.darwin.lib.darwinSystem { + system = "aarch64-darwin"; + specialArgs = { inherit inputs; }; + modules = [ + { nixpkgs.config.allowUnfree = true; + nixpkgs.overlays = [ inputs.netbird-tui.overlays.default ]; } + inputs.virby.darwinModules.default + ./hosts/RyanMac/configuration.nix + home-manager.darwinModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.users.ryan = { + imports = [ + inputs.zen-browser.homeModules.beta + ./users/ryan/common.nix + ./users/ryan/darwin.nix + ]; + }; + } + ]; + }; + + homeConfigurations."ryan" = home-manager.lib.homeManagerConfiguration { + pkgs = nixpkgs.legacyPackages.x86_64-linux; + extraSpecialArgs = { inherit inputs; }; + modules = [ + { nixpkgs.config.allowUnfree = true; } + inputs.zen-browser.homeModules.beta + ./users/ryan/common.nix + ./users/ryan/linux.nix + ]; + }; + }; +} diff --git a/hosts/RyanMac/configuration.nix b/hosts/RyanMac/configuration.nix new file mode 100644 index 0000000..e19490d --- /dev/null +++ b/hosts/RyanMac/configuration.nix @@ -0,0 +1,438 @@ +{ config, pkgs, inputs, lib, ... }: +let + username = "ryan"; + + defaultBrowser = "zen"; + + thirdPartyTaps = { + "netbirdio/homebrew-tap" = inputs.homebrew-netbird; + "FelixKratz/homebrew-formulae" = inputs.homebrew-felixkratz; + }; + + pinnedNixpkgs = pkgs.writeText "flake-registry.json" (builtins.toJSON { + version = 2; + flakes = [ + { + from = { type = "indirect"; id = "nixpkgs"; }; + to = { + type = "path"; + path = inputs.nixpkgs.outPath; + lastModified = inputs.nixpkgs.lastModified; + narHash = inputs.nixpkgs.narHash; + }; + } + ]; + }); + + mkSpace = i: { + name = toString (117+i); + value = { + enabled = true; + value = { + type = "standard"; + parameters = [ (48 + i) (builtins.elemAt [ 18 19 20 21 22 23 25 26 28 ] (i - 1)) 524288 ]; # opt + num + #parameters = [ (48 + i) (builtins.elemAt [ 18 19 20 21 22 23 25 26 28 ] (i - 1)) 1048576 ]; # cmd + num + }; + }; + }; + + spaceHotkeys = builtins.listToAttrs (map mkSpace (lib.range 1 9)); + + manualHotkeys = { + "64" = { + enabled = true; + }; + }; + +in { + # Modules + imports = [ + inputs.nix-homebrew.darwinModules.nix-homebrew + ../../modules/darwin/random-wallpaper + ]; + + # Define the system's user and home dir location + users.users."${username}" = { + name = "${username}"; + home = "/Users/${username}"; + }; + + system.primaryUser = "${username}"; + + # Set the hostname for this machine + networking.hostName = "RyanMac"; + + # Install the wallpaper engine + local.randomWallpaper = { + enable = true; + directory = "${../../files/Wallpapers}"; + }; + + # Configure yabai + services.yabai = { + enable = true; + enableScriptingAddition = false; + config = { + mouse_follows_focus = "on"; + layout = "bsp"; + window_placement = "second_child"; + top_padding = "10"; + bottom_padding = "10"; + left_padding = "10"; + right_padding = "10"; + window_gap = "10"; + mouse_modifier = "alt"; + mouse_drop_action = "swap"; + mouse_action1 = "move"; + mouse_action2 = "resize"; + focus_follows_mouse = "autofocus"; + }; + extraConfig = '' + yabai -m rule --add app='System Settings' manage=off + yabai -m rule --add app="^Zen$" title="^Picture-in-Picture$" manage=off + '' + # Add simple-bar signals if enabled + + lib.optionalString config.home-manager.users.${username}.ryan.simple-bar.enable '' + yabai -m signal --add event=window_focused action="curl http://localhost:7776/yabai/spaces/refresh && curl http://localhost:7776/yabai/windows/refresh" label="Refresh simple-bar spaces & windows when focused application changes" + yabai -m signal --add event=window_resized action="curl http://localhost:7776/yabai/spaces/refresh && curl http://localhost:7776/yabai/windows/refresh" label="Refresh simple-bar spaces & windows when a window is resized" + yabai -m signal --add event=window_destroyed action="curl http://localhost:7776/yabai/spaces/refresh && curl http://localhost:7776/yabai/windows/refresh" label="Refresh simple-ba spaces & windows when an application window is closed" + yabai -m signal --add event=space_changed action="curl http://localhost:7776/yabai/spaces/refresh && curl http://localhost:7776/yabai/windows/refresh" label="Refresh simple-bar spaces & windows on space change" + yabai -m signal --add event=display_changed action="curl http://localhost:7776/yabai/spaces/refresh && curl http://localhost:7776/yabai/windows/refresh" label="Refresh simple-bar spaces & windows on display focus change" + yabai -m signal --add event=window_title_changed action="curl http://localhost:7776/yabai/spaces/refresh && curl http://localhost:7776/yabai/windows/refresh" label="Refresh simple-bar spaces & windows when current window title changes" + yabai -m signal --add event=space_destroyed action="curl http://localhost:7776/yabai/spaces/refresh && curl http://localhost:7776/yabai/windows/refresh" label="Refresh simple-bar spaces & windows on space removal" + yabai -m signal --add event=space_created action="curl http://localhost:7776/yabai/spaces/refresh && curl http://localhost:7776/yabai/windows/refresh" label="Refresh simple-bar spaces & windows on space creation" + yabai -m signal --add event=application_activated action="curl http://localhost:7776/yabai/spaces/refresh && curl http://localhost:7776/yabai/windows/refresh" label="Refresh simple-bar spaces & windows when application is activated" + yabai -m signal --add event=display_added action="curl http://localhost:7776/yabai/displays/refresh" label="Refresh simple-bar displays when a new dispay is added" + yabai -m signal --add event=display_removed action="curl http://localhost:7776/yabai/displays/refresh" label="Refresh simple-bar displays when a dispay is removed" + yabai -m signal --add event=display_moved action="curl http://localhost:7776/yabai/displays/refresh" label="Refresh simple-bar displays when a dispay is moved" + ''; + }; + + # Configure JankyBorders + services.jankyborders = { + enable = true; + style = "round"; + width = 6.0; + hidpi = true; + ax_focus = true; + active_color = "gradient(top_left=0xee33ccff,bottom_right=0xee00ff99)"; + inactive_color = "0xaa595959"; + }; + + # Install the /etc/nix/flake-registry.json file we made above + environment.etc."nix/flake-registry.json".source = pinnedNixpkgs; + + # Install RyanCA Root + security.pki.certificateFiles = [ + ../../files/CACerts/RyanCA.crt + ]; + + # Virby linux builder + services.virby = { + enable = true; + cores = 4; + diskSize = "50GiB"; + onDemand = { + enable = true; + ttl = 30; + }; + rosetta = true; + }; + + nix = { + enable = true; + settings = { + flake-registry = "/etc/nix/flake-registry.json"; + extra-substituters = [ + "https://virby-nix-darwin.cachix.org" + ]; + extra-trusted-public-keys = [ + "virby-nix-darwin.cachix.org-1:z9GiEZeBU5bEeoDQjyfHPMGPBaIQJOOvYOOjGMKIlLo=" + ]; + "extra-experimental-features" = [ "nix-command" "flakes" ]; + }; + }; + + # Determines the nix-darwin release compatibility + system.stateVersion = 6; + + # System profile programs + programs = { + zsh.enable = true; + }; + + # Install homebrew itself + nix-homebrew = { + enable = true; + enableRosetta = true; + user = "${username}"; + mutableTaps = false; + taps = { + "homebrew/homebrew-core" = inputs.homebrew-core; + "homebrew/homebrew-cask" = inputs.homebrew-cask; + } // thirdPartyTaps; + trust.taps = builtins.attrNames thirdPartyTaps; + }; + + # Install homebrew casks/apps + homebrew = { + enable = true; + + onActivation = { + cleanup = "zap"; + }; + + global.brewfile = true; + + taps = builtins.attrNames config.nix-homebrew.taps; + + brews = [ ]; + + casks = [ + "utm" + "ghostty" + "zen" + "ungoogled-chromium" + "tailscale-app" + "netbird-ui" + "ubersicht" + "hammerspoon" + ]; + }; + + # Keyboard shortcuts using skhd + services.skhd = { + enable = true; + skhdConfig = '' + alt - d : osascript -e 'tell application "System Events" to key code 49 using {command down}' + alt - return : osascript -e 'tell application "Ghostty"' -e 'new window' -e 'activate' -e 'end tell' + + shift + alt - q : ${pkgs.yabai}/bin/yabai -m window --close + + alt - up : ${pkgs.yabai}/bin/yabai -m window --focus north || ${pkgs.yabai}/bin/yabai -m display --focus north + shift + alt - up : ${pkgs.yabai}/bin/yabai -m window --swap north || ${pkgs.yabai}/bin/yabai -m window --display north + alt - down : ${pkgs.yabai}/bin/yabai -m window --focus south || ${pkgs.yabai}/bin/yabai -m display --focus south + shift + alt - down : ${pkgs.yabai}/bin/yabai -m window --swap south || ${pkgs.yabai}/bin/yabai -m window --display south + alt - right : ${pkgs.yabai}/bin/yabai -m window --focus east || ${pkgs.yabai}/bin/yabai -m display --focus east + shift + alt - right : ${pkgs.yabai}/bin/yabai -m window --swap east || ${pkgs.yabai}/bin/yabai -m window --display east + alt - left : ${pkgs.yabai}/bin/yabai -m window --focus west || ${pkgs.yabai}/bin/yabai -m display --focus west + shift + alt - left: ${pkgs.yabai}/bin/yabai -m window --swap west || ${pkgs.yabai}/bin/yabai -m window --display west + + shift + alt - space: ${pkgs.yabai}/bin/yabai -m window --toggle float + + shift + alt - return: ${pkgs.yabai}/bin/yabai -m window --toggle sticky + + alt - f : ${pkgs.yabai}/bin/yabai -m window --toggle zoom-fullscreen + + shift + alt - f: ${pkgs.yabai}/bin/yabai -m window --toggle native-fullscreen + + shift + alt - 1 : ${pkgs.yabai}/bin/yabai -m window --space 1 + shift + alt - 2 : ${pkgs.yabai}/bin/yabai -m window --space 2 + shift + alt - 3 : ${pkgs.yabai}/bin/yabai -m window --space 3 + shift + alt - 4 : ${pkgs.yabai}/bin/yabai -m window --space 4 + shift + alt - 5 : ${pkgs.yabai}/bin/yabai -m window --space 5 + shift + alt - 6 : ${pkgs.yabai}/bin/yabai -m window --space 6 + shift + alt - 7 : ${pkgs.yabai}/bin/yabai -m window --space 7 + shift + alt - 8 : ${pkgs.yabai}/bin/yabai -m window --space 8 + shift + alt - 9 : ${pkgs.yabai}/bin/yabai -m window --space 9 + ''; + }; + + # System configuration + time.timeZone = "America/New_York"; + + power.sleep = { + display = 10; + computer = 30; + }; + + system.defaults = { + WindowManager = { + EnableTilingOptionAccelerator = false; + }; + NSGlobalDomain = { + # 24 hour time + AppleICUForce24HourTime = true; + + # Dark Mode + AppleInterfaceStyle = "Dark"; + + # Key repeat rate + KeyRepeat = 2; + InitialKeyRepeat = 35; + + # Swap F1-12 to be default + "com.apple.keyboard.fnState" = true; + + # Disable Keyboard bullcrap + NSAutomaticCapitalizationEnabled = false; + NSAutomaticDashSubstitutionEnabled = false; + NSAutomaticPeriodSubstitutionEnabled = false; + NSAutomaticQuoteSubstitutionEnabled = false; + NSAutomaticSpellingCorrectionEnabled = false; + ApplePressAndHoldEnabled = false; + }; + + # screensaver/power settings + screensaver = { + askForPassword = true; + askForPasswordDelay = 0; + }; + + # Control center stuff + controlcenter = { + BatteryShowPercentage = true; + Bluetooth = true; + }; + + # Clock settings + menuExtraClock = { + Show24Hour = true; + ShowDate = 1; # Always + ShowDayOfWeek = true; + ShowSeconds = true; + }; + + # Screen capture settings + screencapture = { + target = "clipboard"; + type = "png"; + }; + + # finder good settings + finder = { + AppleShowAllExtensions = true; + AppleShowAllFiles = true; + ShowPathbar = true; + FXEnableExtensionChangeWarning = false; + _FXShowPosixPathInTitle = true; + NewWindowTarget = "Home"; + ShowExternalHardDrivesOnDesktop = false; + ShowHardDrivesOnDesktop = false; + ShowMountedServersOnDesktop = false; + ShowRemovableMediaOnDesktop = false; + ShowStatusBar = true; + }; + + spaces = { + "spans-displays" = false; # independent spaces per display + }; + + # Login Window Settings + loginwindow = { + GuestEnabled = false; + DisableConsoleAccess = true; + }; + + # dock settings + dock = { + magnification = true; + largesize = 96; + tilesize = 32; + minimize-to-application = false; + orientation = "bottom"; + autohide = true; + mru-spaces = false; # Disable auto-rearrange spaces + persistent-apps = [ + { app = "/Applications/Zen.app"; } + #{ app = "/System/Applications/Launchpad.app"; } + { app = "/System/Applications/Messages.app"; } + { app = "/System/Applications/Facetime.app"; } + { app = "/System/Applications/Calendar.app"; } + { app = "/System/Applications/App Store.app"; } + { app = "/System/Applications/System Settings.app"; } + { app = "/Applications/Ghostty.app"; } + { app = "/Applications/UTM.app"; } + ]; + persistent-others = [ + { folder = { path = "/Users/${username}/Downloads"; showas = "grid"; arrangement = "date-created"; }; } + { folder = { path = "/Users/${username}/Applications"; showas = "grid"; arrangement = "name"; }; } + ]; + show-recents = false; + }; + + # Custom preferences + CustomUserPreferences = { + NSGlobalDomain = { + # Always show menu bar + AppleMenuBarVisibleInFullscreen = true; + + # Hide the menubar by default + "_HIHideMenuBar" = true; + + # Option + L lock + NSUserKeyEquivalents = { + "Lock Screen" = "~l"; + }; + }; + + "com.apple.desktopservices" = { + DSDontWriteNetworkStores = true; + DSDontWriteUSBStores = true; + }; + + "com.apple.WindowManager" = { + EnableStandardClickToShowDesktop = false; + StandardHideDesktopIcons = false; + }; + + "com.apple.screensaver" = { + askForPassword = true; + askForPasswordDelay = 2; + }; + + "com.apple.AdLib" = { + allowApplePersonalizedAdvertising = false; + }; + + "com.apple.Accessibility" = { + ReduceMotionEnabled = 1; + }; + + "com.apple.symbolichotkeys" = { + AppleSymbolicHotKeys = manualHotkeys // spaceHotkeys; + }; + }; + universalaccess.reduceMotion = true; + }; + + # Post-Activation scripts + system.activationScripts.postActivation.text = '' + echo "Configuring NTP servers..." + systemsetup -setnetworktimeserver pool.ntp.org > /dev/null 2>&1 || true + systemsetup -setusingnetworktime on > /dev/null 2>&1 || true + + ryancasum="$(${pkgs.openssl}/bin/openssl x509 -in "${../../files/CACerts/RyanCA.crt}" -noout -fingerprint -sha1 | sed 's/.*=//; s/://g')" + if ! /usr/bin/security find-certificate -a -Z "/Library/Keychains/System.keychain" | tr -d ':' | grep -iq "$ryancasum"; then + echo "Installing RyanCA Certificate..." + /usr/bin/security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${../../files/CACerts/RyanCA.crt} + fi + + echo "Reloading Preferences DB..." + sudo -iu ${username} /System/Library/PrivateFrameworks/SystemAdministration.framework/Resources/activateSettings -u + + echo "Setting default browser" + ${pkgs.defaultbrowser}/bin/defaultbrowser ${defaultBrowser} + + echo "Adding Keyboard brightness controls to Control Center..." + sudo -iu ${username} defaults -currentHost write com.apple.controlcenter KeyboardBrightness -int 25 + + # this is fragile so it goes at the bottom + echo "Reloading skhd..." + sudo -iu ${username} ${pkgs.skhd}/bin/skhd -r + + # Notes if we are running for the first time and writes a message for actions that may need to be done on macOS or linux + MARK="/opt/.nix-complete" + if [ ! -f "$MARK" ]; then + echo "o0o0o0o0o0o MacOS Initial Deploy Notes o0o0o0o0o0o" + echo "--------------------------------------------------" + echo "The following actions must be taken since they are not configurable by Nix. This must be done only ONCE." + echo "" + echo "1. Create 9 spaces." + echo "2. Set keyboard autofill settings" + echo "--------------------------------------------------" + fi + touch "$MARK" + ''; + +} diff --git a/modules/darwin/random-wallpaper/default.nix b/modules/darwin/random-wallpaper/default.nix new file mode 100644 index 0000000..b20ce88 --- /dev/null +++ b/modules/darwin/random-wallpaper/default.nix @@ -0,0 +1,29 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.local.randomWallpaper; + wallpaper-agent-src = ./wallpaper-daemon.swift; +in +{ + options.local.randomWallpaper = { + enable = lib.mkEnableOption "Random Rotating Wallpaper"; + directory = lib.mkOption { + type = lib.types.str; + description = "Folder containing images"; + }; + interval = lib.mkOption { + type = lib.types.int; + default = 1800; + description = "Seconds between wallpaper changes"; + }; + }; + + config = lib.mkIf cfg.enable { + launchd.user.agents.random-wallpaper.serviceConfig = { + Label = "org.rschanz.wallpaperDaemon"; + ProgramArguments = [ "/usr/bin/swift" "${wallpaper-agent-src}" "${cfg.directory}" "${builtins.toString cfg.interval}" ]; + RunAtLoad = true; + KeepAlive = true; + ProcessType = "Background"; + }; + }; +} diff --git a/modules/darwin/random-wallpaper/wallpaper-daemon.swift b/modules/darwin/random-wallpaper/wallpaper-daemon.swift new file mode 100644 index 0000000..72f52ef --- /dev/null +++ b/modules/darwin/random-wallpaper/wallpaper-daemon.swift @@ -0,0 +1,51 @@ +import AppKit +import Foundation + +if CommandLine.arguments.count != 3 { + print("Must have 2 args") + exit(1) +} + +let wallpaperDir = CommandLine.arguments[1] +let interval: TimeInterval = Double(CommandLine.arguments[2]) ?? 30.0 + +let workspace = NSWorkspace.shared +let imageExtensions: Set = ["jpg", "jpeg", "png", "heic", "tiff", "gif", "bmp"] + +func images() -> [URL] { + let dir = URL(fileURLWithPath: wallpaperDir, isDirectory: true) + let entries = (try? FileManager.default.contentsOfDirectory( + at: dir, includingPropertiesForKeys: nil)) ?? [] + return entries.filter { imageExtensions.contains($0.pathExtension.lowercased()) } +} + +var current: URL? + +// setDesktopImageURL only touches the current Space (all displays). +func apply(_ url: URL?) { + guard let url else { return } + for screen in NSScreen.screens { + try? workspace.setDesktopImageURL(url, for: screen, options: [:]) + } +} + +func advance() { + let imgs = images() + guard !imgs.isEmpty else { return } + let pool = imgs.count > 1 ? imgs.filter { $0 != current } : imgs + current = pool.randomElement() + apply(current) +} + +// Whenever you switch Space, repaint it to the current image. +workspace.notificationCenter.addObserver( + forName: NSWorkspace.activeSpaceDidChangeNotification, + object: nil, queue: .main +) { _ in apply(current) } + +advance() +Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in advance() } + +let app = NSApplication.shared +app.setActivationPolicy(.accessory) // no Dock icon +app.run() diff --git a/users/ryan/aerc/accounts.conf b/users/ryan/aerc/accounts.conf new file mode 100644 index 0000000..b140dbd --- /dev/null +++ b/users/ryan/aerc/accounts.conf @@ -0,0 +1,24 @@ +[Personal] +source = jmap://ryan%40rschanz.org@mail.rschanz.org/jmap/session +source-cred-cmd = pass emails/personal 2>/dev/null | tr -d '\n' +outgoing = jmap:// +default = Inbox +from = Ryan Schanzenbacher +copy-to = Sent +signature-file = ~/.config/aerc/signature_personal +#check-mail = 5m +aliases = Ryan S , Ryan Schanzenbacher +pgp-self-encrypt = true + +[School] +source = imaps+oauthbearer://rjs1877%40rit.edu@imap.gmail.com:993?token_endpoint=https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Ftoken&client_id=667738788924-0rdfvaq9ijfo1vk4474eb3quf8206h2t.apps.googleusercontent.com&client_secret=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 +source-cred-cmd = pass emails/rit_personal 2>/dev/null | tr -d '\n' +outgoing = smtps+oauthbearer://rjs1877%40rit.edu@imap.gmail.com:465?token_endpoint=https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Ftoken&client_id=667738788924-0rdfvaq9ijfo1vk4474eb3quf8206h2t.apps.googleusercontent.com&client_secret=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 +outgoing-cred-cmd = pass emails/rit_personal 2>/dev/null | tr -d '\n' +from = Ryan Schanzenbacher +signature-file = ~/.config/aerc/signature_rit_personal +check-mail = 5m +default = INBOX +copy-to = [Gmail]/Sent Mail +pgp-self-encrypt = true + diff --git a/users/ryan/aerc/aerc.conf b/users/ryan/aerc/aerc.conf new file mode 100644 index 0000000..ad54cf7 --- /dev/null +++ b/users/ryan/aerc/aerc.conf @@ -0,0 +1,569 @@ +# +# aerc main configuration + +[general] +# +# Used as a default path for save operations if no other path is specified. +# ~ is expanded to the current user home dir. +# +default-save-path=~/Downloads/ + +# If set to "gpg", aerc will use system gpg binary and keystore for all crypto +# operations. If set to "internal", the internal openpgp keyring will be used. +# If set to "auto", the system gpg will be preferred unless the internal +# keyring already exists, in which case the latter will be used. +# +# Default: auto +pgp-provider=gpg + +# By default, the file permissions of accounts.conf must be restrictive and +# only allow reading by the file owner (0600). Set this option to true to +# ignore this permission check. Use this with care as it may expose your +# credentials. +# +# Default: false +unsafe-accounts-conf=true # I don't store my creds in this + +# Output log messages to specified file. A path starting with ~/ is expanded to +# the user home dir. When redirecting aerc's output to a file using > shell +# redirection, this setting is ignored and log messages are printed to stdout. +# +#log-file=~/aerc_log + +# Only log messages above the specified level to log-file. Supported levels +# are: trace, debug, info, warn and error. When redirecting aerc's output to +# a file using > shell redirection, this setting is ignored and the log level +# is forced to trace. +# +# Default: info +log-level=trace + +# Set the $TERM environment variable used for the embedded terminal. +# +# Default: xterm-256color +#term=xterm-256color + +# Display OSC8 strings in the embedded terminal +# +# Default: false +#enable-osc8=false + +[ui] +# +# Describes the format for each row in a mailbox view. This is a comma +# separated list of column names with an optional align and width suffix. After +# the column name, one of the '<' (left), ':' (center) or '>' (right) alignment +# characters can be added (by default, left) followed by an optional width +# specifier. The width is either an integer representing a fixed number of +# characters, or a percentage between 1% and 99% representing a fraction of the +# terminal width. It can also be one of the '*' (auto) or '=' (fit) special +# width specifiers. Auto width columns will be equally attributed the remaining +# terminal width. Fit width columns take the width of their contents. If no +# width specifier is set, '*' is used by default. +# +# Default: date<20,name<17,flags>4,subject<* +#index-columns=date<20,name<17,flags>4,subject<* + +spinner = '/,-,\,|' + +# +# Each name in index-columns must have a corresponding column-$name setting. +# All column-$name settings accept golang text/template syntax. See +# aerc-templates(7) for available template attributes and functions. +# +# Default settings +#column-date={{.DateAutoFormat .Date.Local}} +#column-name={{index (.From | names) 0}} +#column-flags={{.Flags | join ""}} +#column-subject={{.ThreadPrefix}}{{.Subject}} + +# +# String separator inserted between columns. When the column width specifier is +# an exact number of characters, the separator is added to it (i.e. the exact +# width will be fully available for the column contents). +# +# Default: " " +#column-separator=" " + +# +# See time.Time#Format at https://godoc.org/time#Time.Format +# +# Default: 2006-01-02 03:04 PM (ISO 8601 + 12 hour time) +#timestamp-format=2006-01-02 03:04 PM + +# +# Index-only time format for messages that were received/sent today. +# If this is not specified, timestamp-format is used instead. +# +#this-day-time-format= + +# +# Index-only time format for messages that were received/sent within the last +# 7 days. If this is not specified, timestamp-format is used instead. +# +#this-week-time-format= + +# +# Index-only time format for messages that were received/sent this year. +# If this is not specified, timestamp-format is used instead. +# +#this-year-time-format= + +# +# Width of the sidebar, including the border. +# +# Default: 20 +#sidebar-width=20 + +# +# Message to display when viewing an empty folder. +# +# Default: (no messages) +#empty-message=(no messages) + +# Message to display when no folders exists or are all filtered +# +# Default: (no folders) +#empty-dirlist=(no folders) + +# Enable mouse events in the ui, e.g. clicking and scrolling with the mousewheel +# +# Default: false +#mouse-enabled=false + +# +# Ring the bell when new messages are received +# +# Default: true +#new-message-bell=true + +# +# Template to use for Account tab titles +# +# Default: {{.Account}} +#tab-title-account={{.Account}} + +# Marker to show before a pinned tab's name. +# +# Default: ` +#pinned-tab-marker='`' + +# Template for the left side of the directory list. +# See aerc-templates(7) for all available fields and functions. +# +# Default: {{.Folder}} +#dirlist-left={{.Folder}} + +# Template for the right side of the directory list. +# See aerc-templates(7) for all available fields and functions. +# +# Default: {{if .Unread}}{{humanReadable .Unread}}/{{end}}{{if .Exists}}{{humanReadable .Exists}}{{end}} +#dirlist-right={{if .Unread}}{{humanReadable .Unread}}/{{end}}{{if .Exists}}{{humanReadable .Exists}}{{end}} + +# Delay after which the messages are actually listed when entering a directory. +# This avoids loading messages when skipping over folders and makes the UI more +# responsive. If you do not want that, set it to 0s. +# +# Default: 200ms +#dirlist-delay=200ms + +# Display the directory list as a foldable tree that allows to collapse and +# expand the folders. +# +# Default: false +#dirlist-tree=false + +# If dirlist-tree is enabled, set level at which folders are collapsed by +# default. Set to 0 to disable. +# +# Default: 0 +#dirlist-collapse=0 + +# List of space-separated criteria to sort the messages by, see *sort* +# command in *aerc*(1) for reference. Prefixing a criterion with "-r " +# reverses that criterion. +# +# Example: "from -r date" +# +#sort= + +# Moves to next message when the current message is deleted +# +# Default: true +#next-message-on-delete=true + +# Automatically set the "seen" flag when a message is opened in the message +# viewer. +# +# Default: true +#auto-mark-read=true + +# The directories where the stylesets are stored. It takes a colon-separated +# list of directories. If this is unset or if a styleset cannot be found, the +# following paths will be used as a fallback in that order: +# +# ${XDG_CONFIG_HOME:-~/.config}/aerc/stylesets +# ${XDG_DATA_HOME:-~/.local/share}/aerc/stylesets +# /usr/local/share/aerc/stylesets +# /usr/share/aerc/stylesets +# +#stylesets-dirs= + +# Uncomment to use box-drawing characters for vertical and horizontal borders. +# +# Default: " " +#border-char-vertical=" " +#border-char-horizontal=" " + +# Sets the styleset to use for the aerc ui elements. +# +# Default: default +#styleset-name=default + +# Activates fuzzy search in commands and their arguments: the typed string is +# searched in the command or option in any position, and need not be +# consecutive characters in the command or option. +# +# Default: false +#fuzzy-complete=false + +# How long to wait after the last input before auto-completion is triggered. +# +# Default: 250ms +#completion-delay=250ms + +# The minimum required characters to allow auto-completion to be triggered after +# completion-delay. +# +# Default: 1 +#completion-min-chars=1 + +# +# Global switch for completion popovers +# +# Default: true +#completion-popovers=true + +# Uncomment to use UTF-8 symbols to indicate PGP status of messages +# +# Default: ASCII +#icon-unencrypted= +#icon-encrypted=✔ +#icon-signed=✔ +#icon-signed-encrypted=✔ +#icon-unknown=✘ +#icon-invalid=⚠ + +# Reverses the order of the message list. By default, the message list is +# ordered with the newest (highest UID) message on top. Reversing the order +# will put the oldest (lowest UID) message on top. This can be useful in cases +# where the backend does not support sorting. +# +# Default: false +#reverse-msglist-order = false + +# Reverse display of the mesage threads. Default order is the the intial +# message is on the top with all the replies being displayed below. The +# reverse option will put the initial message at the bottom with the +# replies on top. +# +# Default: false +#reverse-thread-order=false + +# Sort the thread siblings according to the sort criteria for the messages. If +# sort-thread-siblings is false, the thread siblings will be sorted based on +# the message UID in ascending order. This option is only applicable for +# client-side threading with a backend that enables sorting. Note that there's +# a performance impact when sorting is activated. +# +# Default: false +#sort-thread-siblings=false + +#[ui:account=Personal] +# +# Enable a threaded view of messages. If this is not supported by the backend +# (IMAP server or notmuch), threads will be built by the client. +# +# Default: false +threading-enabled=true + +# Force client-side thread building +# +# Default: false +#force-client-threads=false + +# Debounce client-side thread building +# +# Default: 50ms +#client-threads-delay=50ms + +[statusline] +# +# Describes the format for the status line. This is a comma separated list of +# column names with an optional align and width suffix. See [ui].index-columns +# for more details. To completely mute the status line except for push +# notifications, explicitly set status-columns to an empty string. +# +# Default: left<*,center:=,right>* +#status-columns=left<*,center:=,right>* + +# +# Each name in status-columns must have a corresponding column-$name setting. +# All column-$name settings accept golang text/template syntax. See +# aerc-templates(7) for available template attributes and functions. +# +# Default settings +#column-left=[{{.Account}}] {{.StatusInfo}} +#column-center={{.PendingKeys}} +#column-right={{.TrayInfo}} + +# +# String separator inserted between columns. +# See [ui].column-separator for more details. +# +#column-separator=" " + +# Specifies the separator between grouped statusline elements. +# +# Default: " | " +#separator=" | " + +# Defines the mode for displaying the status elements. +# Options: text, icon +# +# Default: text +#display-mode=text + +[viewer] +# +# Specifies the pager to use when displaying emails. Note that some filters +# may add ANSI codes to add color to rendered emails, so you may want to use a +# pager which supports ANSI codes. +# +# Default: less -R +#pager=less -R + +# +# If an email offers several versions (multipart), you can configure which +# mimetype to prefer. For example, this can be used to prefer plaintext over +# html emails. +# +# Default: text/plain,text/html +#alternatives=text/plain,text/html + +# +# Default setting to determine whether to show full headers or only parsed +# ones in message viewer. +# +# Default: false +#show-headers=false + +# +# Layout of headers when viewing a message. To display multiple headers in the +# same row, separate them with a pipe, e.g. "From|To". Rows will be hidden if +# none of their specified headers are present in the message. +# +# Default: From|To,Cc|Bcc,Date,Subject +#header-layout=From|To,Cc|Bcc,Date,Subject + +# Whether to always show the mimetype of an email, even when it is just a single part +# +# Default: false +#always-show-mime=false + +# Parses and extracts http links when viewing a message. Links can then be +# accessed with the open-link command. +# +# Default: true +#parse-http-links=true + +[compose] +# +# Specifies the command to run the editor with. It will be shown in an embedded +# terminal, though it may also launch a graphical window if the environment +# supports it. Defaults to $EDITOR, or vi. +#editor= + +# Address book command +address-book-cmd = sh -c 'abook --mutt-query "%s" | tail -n +2' + +# +# Default header fields to display when composing a message. To display +# multiple headers in the same row, separate them with a pipe, e.g. "To|From". +# +# Default: To|From,Subject +#header-layout=To|From,Subject + +# +# Specifies the command to be used to tab-complete email addresses. Any +# occurrence of "%s" in the address-book-cmd will be replaced with what the +# user has typed so far. +# +# The command must output the completions to standard output, one completion +# per line. Each line must be tab-delimited, with an email address occurring as +# the first field. Only the email address field is required. The second field, +# if present, will be treated as the contact name. Additional fields are +# ignored. +# +# This parameter can also be set per account in accounts.conf. +#address-book-cmd= + +# Specifies the command to be used to select attachments. Any occurence of '%s' +# in the file-picker-cmd will be replaced the argument to :attach -m +# . +# +# The command must output the selected files to standard output, one file per +# line. +file-picker-cmd=fzf --multi --query=%s + +# +# Allow to address yourself when replying +# +# Default: true +#reply-to-self=true + +# +# Warn before sending an email that matches the specified regexp but does not +# have any attachments. Leave empty to disable this feature. +# +# Uses Go's regexp syntax, documented at https://golang.org/s/re2syntax. The +# "(?im)" flags are set by default (case-insensitive and multi-line). +# +# Example: +# no-attachment-warning=^[^>]*attach(ed|ment) +# +#no-attachment-warning= + +# +# When set, aerc will generate "format=flowed" bodies with a content type of +# "text/plain; format=flowed" as described in RFC3676. This format is easier to +# handle for some mailing software, and generally just looks like ordinary +# text. To actually make use of this format's features, you'll need support in +# your editor. +# +format-flowed=true + +[multipart-converters] +# +# Converters allow to generate multipart/alternative messages by converting the +# main text/plain part into any other MIME type. Only exact MIME types are +# accepted. The commands are invoked with sh -c and are expected to output +# valid UTF-8 text. +# +# Example (obviously, this requires that you write your main text/plain body +# using the markdown syntax): +text/html=pandoc --wrap=preserve -f gfm+hard_line_breaks -t html --standalone + +[filters] +# +# Filters allow you to pipe an email body through a shell command to render +# certain emails differently, e.g. highlighting them with ANSI escape codes. +# +# The commands are invoked with sh -c. The following folders are appended to +# the system $PATH to allow referencing filters from their name only: +# +# ${XDG_CONFIG_HOME:-~/.config}/aerc/filters +# ${XDG_DATA_HOME:-~/.local/share}/aerc/filters +# $PREFIX/share/aerc/filters +# /usr/share/aerc/filters +# +# The following variables are defined in the filter command environment: +# +# AERC_MIME_TYPE the part MIME type/subtype +# AERC_FORMAT the part content type format= parameter +# AERC_FILENAME the attachment filename (if any) +# AERC_SUBJECT the message Subject header value +# AERC_FROM the message From header value +# +# The first filter which matches the email's mimetype will be used, so order +# them from most to least specific. +# +# You can also match on non-mimetypes, by prefixing with the header to match +# against (non-case-sensitive) and a comma, e.g. subject,text will match a +# subject which contains "text". Use header,~regex to match against a regex. +# +#text/plain=colorize +#text/calendar=calendar +message/delivery-status=bat -fn +message/rfc822=bat -fn +text/html=pandoc -f html -t plain | bat -fn +#text/html=html | colorize +text/*=bat -fn +application/x-sh=bat -fn -l sh +#image/*=catimg -w $(tput cols) - +#subject,~Git(hub|lab)=lolcat -f +#from,thatguywhodoesnothardwraphismessages=wrap -w 100 | colorize + +# This special filter is only used to post-process email headers when +# [viewer].show-headers=true +# By default, headers are piped directly into the pager. +# +#.headers=bat -fp + +[openers] +# +# Openers allow you to specify the command to use for the :open and :open-link +# actions on a per-MIME-type basis. The :open-link URL scheme is used to +# determine the MIME type as follows: x-scheme-handler/. +# +# {} is expanded as the temporary filename to be opened. If it is not +# encountered in the command, the temporary filename will be appened to the end +# of the command. +# +# Like [filters], openers support basic shell globbing. The first opener which +# matches the part's MIME type (or URL scheme handler MIME type) will be used, +# so order them from most to least specific. +# +# Examples: +# x-scheme-handler/irc=hexchat +# x-scheme-handler/http*=firefox +# text/html=surf -dfgms +# text/plain=gvim {} +125 +# message/rfc822=thunderbird + +[hooks] +# +# Hooks are triggered whenever the associated event occurs. + +# +# Executed when a new email arrives in the selected folder +mail-received=notify-send "$AERC_FROM_NAME" "$AERC_SUBJECT" + +# +# Executed when aerc starts +#aerc-startup=aerc :terminal calcurse && aerc :next-tab + +# +# Executed when aerc shuts down. +#aerc-shutdown= + +[templates] +# Templates are used to populate email bodies automatically. +# + +# The directories where the templates are stored. It takes a colon-separated +# list of directories. If this is unset or if a template cannot be found, the +# following paths will be used as a fallback in that order: +# +# ${XDG_CONFIG_HOME:-~/.config}/aerc/templates +# ${XDG_DATA_HOME:-~/.local/share}/aerc/templates +# /usr/local/share/aerc/templates +# /usr/share/aerc/templates +# +#template-dirs= + +# The default template to be used for new messages. +# +# default: new_message +#new-message=new_message + +# The default template to be used for quoted replies. +# +# default: quoted_reply +#quoted-reply=quoted_reply + +# The default template to be used for forward as body. +# +# default: forward_as_body +#forwards=forward_as_body + diff --git a/users/ryan/aerc/binds.conf b/users/ryan/aerc/binds.conf new file mode 100644 index 0000000..3c1e2d2 --- /dev/null +++ b/users/ryan/aerc/binds.conf @@ -0,0 +1,150 @@ +# Binds are of the form = +# To use '=' in a key sequence, substitute it with "Eq": "" +# If you wish to bind #, you can wrap the key sequence in quotes: "#" = quit + = :prev-tab + = :next-tab + = :term +? = :help keys + +[messages] +q = :quit + +j = :next + = :next + = :next 50% + = :next 100% + = :next 100% + +k = :prev + = :prev + = :prev 50% + = :prev 100% + = :prev 100% +g = :select 0 +G = :select -1 + = :read + = :unread + +J = :next-folder +K = :prev-folder +H = :collapse-folder +L = :expand-folder + +v = :mark -t +V = :mark -v + +T = :toggle-threads + + = :view +dd = :mv Trash +dg = :mv [Gmail]/Trash +D = :delete +A = :archive year + +C = :compose + +rr = :reply -a +rq = :reply -aq +Rr = :reply +Rq = :reply -q +f = :forward -A + +# Git custom stuff ala Drew Devault +ga = :pipe -mb git am -3 +gp = :term git push +rt = :reply -aTthanks + +c = :cf +$ = :term +! = :term +| = :pipe + +/ = :search +\ = :filter +n = :next-result +N = :prev-result + = :clear + +[messages:folder=Drafts] + = :recall + +[view] +/ = :toggle-key-passthrough/ +q = :close +O = :open +S = :save +| = :pipe +D = :delete +dd = :mv Trash +dg = :mv [Gmail]/Trash +A = :archive year + + = :open-link + +f = :forward -A +rr = :reply -a +rq = :reply -aq +Rr = :reply +Rq = :reply -q + +H = :toggle-headers + = :prev-part + = :next-part +J = :next +K = :prev + +[view::passthrough] +$noinherit = true +$ex = + = :toggle-key-passthrough + +[compose] +# Keybindings used when the embedded terminal is not selected in the compose +# view +$noinherit = true +$ex = + = :prev-field + = :next-field + = :switch-account -p + = :switch-account -n + = :next-field + = :prev-field + = :prev-tab + = :next-tab + = :cc + = :bcc + = :abort + +[compose::editor] +# Keybindings used when the embedded terminal is selected in the compose view +$noinherit = true +$ex = + = :prev-field + = :next-field + = :prev-tab + = :next-tab + = :abort + +[compose::review] +# Keybindings used when reviewing a message to be sent +y = :send +n = :abort +v = :preview +p = :postpone +q = :choose -o d discard abort -o p postpone postpone +e = :edit +a = :attach +d = :detach +S = :sign +E = :encrypt +A = :attach-key +C = :multipart text/html + +[terminal] +$noinherit = true +$ex = + = :close + + = :prev-tab + = :next-tab + diff --git a/users/ryan/aerc/signature_personal b/users/ryan/aerc/signature_personal new file mode 100644 index 0000000..d9a8de7 --- /dev/null +++ b/users/ryan/aerc/signature_personal @@ -0,0 +1,3 @@ +-- +Best, +Ryan Schanzenbacher diff --git a/users/ryan/aerc/signature_rit_personal b/users/ryan/aerc/signature_rit_personal new file mode 100644 index 0000000..efe4ceb --- /dev/null +++ b/users/ryan/aerc/signature_rit_personal @@ -0,0 +1,5 @@ +-- +Best, +Ryan Schanzenbacher +Rochester Institute of Technology +Cybersecurity BS/MS Student diff --git a/users/ryan/aerc/templates/quoted_reply b/users/ryan/aerc/templates/quoted_reply new file mode 100644 index 0000000..402515f --- /dev/null +++ b/users/ryan/aerc/templates/quoted_reply @@ -0,0 +1,6 @@ +X-Mailer: aerc {{version}} + +{{.Signature}} + +On {{dateFormat (.OriginalDate | toLocal) "Mon Jan 2, 2006 at 3:04 PM MST"}}, {{(index .OriginalFrom 0).Name}} wrote: +{{trimSignature .OriginalText | quote}} diff --git a/users/ryan/aerc/templates/thanks b/users/ryan/aerc/templates/thanks new file mode 100644 index 0000000..bc920a6 --- /dev/null +++ b/users/ryan/aerc/templates/thanks @@ -0,0 +1,7 @@ +X-Mailer: aerc {{version}} + +Thanks! + +{{exec "{ git remote get-url --push origin; git reflog -2 origin/main --pretty=format:%h; } | xargs printf 'To %s\n %s..%s main -> main\n'" ""}} + +{{.Signature}} diff --git a/users/ryan/common.nix b/users/ryan/common.nix new file mode 100644 index 0000000..2e7505f --- /dev/null +++ b/users/ryan/common.nix @@ -0,0 +1,180 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ ./modules/nvim ]; + + news.display = "silent"; + + # My own modules + ryan.neovim.enable = true; + + programs.starship = { + enable = true; + settings = { + add_newline = false; + character = { + success_symbol = "[➜](bold green)"; + error_symbol = "[➜](bold red)"; + }; + time = { + disabled = false; + format = "\[ $time \]($style)"; + time_format = "%T"; + }; + }; + }; + + # Package/platform overrides (darwinDefaultsId, package = null for homebrew, + # etc.) live in darwin.nix/linux.nix. Policies/profile are shared. + programs.zen-browser = { + enable = true; + policies = import ./zen/zenPolicies.nix; + profiles.default = import ./zen/zenProfile.nix; + }; + + programs.eza = { + enable = true; + enableZshIntegration = true; + }; + + programs.gpg.enable = true; + + programs.git = { + enable = true; + signing.signByDefault = true; + settings = { + user = { + name = "Ryan Schanzenbacher"; + email = "ryan@rschanz.org"; + }; + core.pager = "${pkgs.delta}/bin/delta"; + init.defaultBranch = "main"; + merge.conflictStyle = "zdiff3"; + interactive.diffFilter = "${pkgs.delta}/bin/delta --color-only"; + delta = { + navigate = true; + side-by-side = true; + }; + # Merged from guix-dotfiles' ~/.gitconfig - git-lfs filter and + # git send-email settings, missing from the darwin config until now. + filter.lfs = { + clean = "git-lfs clean -- %f"; + smudge = "git-lfs smudge -- %f"; + process = "git-lfs filter-process"; + required = true; + }; + sendemail = { + smtpserver = "mail.rschanz.org"; + smtpuser = "ryan@rschanz.org"; + smtpencryption = "ssl"; + smtpserverport = 465; + }; + }; + }; + + programs.ssh = { + enable = true; + package = null; # installed by default + + enableDefaultConfig = false; + + settings = { + "rocApex" = { + hostname = "129.158.232.104"; + user = "root"; + }; + "hetzner" = { + hostname = "5.161.207.21"; + user = "root"; + }; + "rncorepub" = { + hostname = "5.161.89.186"; + user = "root"; + }; + # Merged from guix-dotfiles' ~/.ssh/config - hosts and quirks missing + # from the darwin config until now. + "linode" = { + hostname = "97.107.142.58"; + user = "root"; + }; + # `settings` has a freeform type, so upstream ssh_config directive + # names can be set directly - `programs.ssh.settings.*.extraOptions` + # is explicitly unsupported (hard assertion failure) in this HM version. + "192.168.216.1" = { + HostKeyAlgorithms = "+ssh-rsa"; + PubkeyAcceptedAlgorithms = "+ssh-rsa"; + }; + "*" = { + KexAlgorithms = "-sntrup761x25519-sha512@openssh.com"; + }; + }; + + # HM always renders the "*" block last regardless of dag order, so this + # trailing exec-only Match block (no directives of its own - position + # relative to the Host blocks above doesn't matter) is safe to append here. + # `settings."*"` above satisfies the assertion that gates using extraConfig. + extraConfig = '' + Match host * exec "gpg-connect-agent UPDATESTARTUPTTY /bye" + ''; + }; + + services.gpg-agent = { + enable = pkgs.stdenv.isLinux; + enableSshSupport = true; + }; + + programs.zsh = { + enable = true; + initContent = let + brewPath = if pkgs.stdenv.isDarwin && pkgs.stdenv.isAarch64 then '' + eval "$(/opt/homebrew/bin/brew shellenv)" + '' else ""; + in '' + export GPG_TTY="$(tty)" + export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" + gpgconf --launch gpg-agent + gpg-connect-agent updatestartuptty /bye > /dev/null + ${brewPath} + ''; + shellAliases = { + cat = "bat --paging=never"; + diff = "delta"; + # Merged from guix-dotfiles' bash aliases (home-bash-service-type) - + # bash is being retired there in favor of this zsh config. `ls`/`spt`/ + # `python` are Linux-only (BSD ls on darwin doesn't take --color/-p, + # spotify_player and python3 aren't darwin things) - see linux.nix. + grep = "grep --color=auto"; + ll = "ls -l"; + rebuild = + if pkgs.stdenv.isDarwin + then "sudo darwin-rebuild switch --flake ~/.config/nix/." + else "home-manager switch --flake ~/.config/home-manager/#ryan"; + }; + }; + + # Shared across darwin and linux; the guix side already deferred these + # packages to nix (all commented out of home-configuration.scm's package + # list), same as the darwin config always has. + home.packages = with pkgs; [ + yt-dlp + aerc + gdu + taskwarrior3 + delta + kubectl + talhelper + talosctl + ]; + + xdg.configFile."aerc" = { + source = ./aerc; + recursive = true; + }; + + home.sessionVariables = { + XDG_CONFIG_HOME = "${config.home.homeDirectory}/.config"; + EDITOR = "${pkgs.neovim}/bin/nvim"; + }; + + programs.home-manager.enable = true; +} diff --git a/users/ryan/darwin.nix b/users/ryan/darwin.nix new file mode 100644 index 0000000..72467ee --- /dev/null +++ b/users/ryan/darwin.nix @@ -0,0 +1,68 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ + ./modules/sketchybar + ./modules/simple-bar + ./modules/taskwarrior-ubersicht + ./modules/ubersicht + ]; + + home.stateVersion = "26.05"; # Please read the comment before changing. + + ryan.sketchybar.enable = true; + + programs.zen-browser = { + package = null; # managed via homebrew + darwinDefaultsId = "app.zen-browser.zen"; + }; + + # Need special config for gpg-agent on macOS + home.file.".gnupg/gpg-agent.conf".text = '' + pinentry-program ${pkgs.pinentry_mac}/Applications/pinentry-mac.app/Contents/MacOS/pinentry-mac + enable-ssh-support + ''; + + # Add hammerspoon + home.file.".hammerspoon".source = ./hammerspoon; + + home.packages = with pkgs; [ + bat + pass + pandoc + iina # Media player (frontend to mpv essentially) + audacity + ffmpeg + blender + nerd-fonts.anonymice + jujutsu + netbird-tui + # common.nix's programs.git.settings now sets filter.lfs (merged from + # guix-dotfiles' .gitconfig) - Guix's package list already has git-lfs, + # darwin needs its own copy or LFS checkouts hard-fail. + git-lfs + ]; + + # Install User apps to subdir for dock stuff + targets.darwin.linkApps.directory = "Applications/User Apps"; + + # Symlink System apps into the user apps "system" dir + home.activation.linkSystemApps = lib.hm.dag.entryAfter ["writeBoundary"] '' + if [[ -z "$HOME" ]]; then + echo "ERROR: HOME was not defined. This should not happen. Bailing! ">&2 + exit 1 + fi + + $DRY_RUN_CMD mkdir -p "$HOME/Applications/System Apps" + + $DRY_RUN_CMD rm -rf "$HOME/Applications/System Apps/"*.app + + $DRY_RUN_CMD find /Applications /System/Applications -maxdepth 2 -name "*.app" \ + -prune -exec ln -sf {} "$HOME/Applications/System Apps/" \; + ''; + + # Restart gpg-agent + home.activation.restartGpgAgent = lib.hm.dag.entryAfter ["writeBoundary"] '' + $DRY_RUN_CMD ${pkgs.gnupg}/bin/gpgconf --kill gpg-agent || true + ''; +} diff --git a/users/ryan/hammerspoon/init.lua b/users/ryan/hammerspoon/init.lua new file mode 100644 index 0000000..1245a09 --- /dev/null +++ b/users/ryan/hammerspoon/init.lua @@ -0,0 +1,35 @@ +-- ~/.hammerspoon/init.lua + +local function refreshWidget() + hs.http.asyncGet("http://127.0.0.1:7776/widget/sound/refresh", nil, function(status, body, headers) + -- optional: log failures + if status ~= 200 then + print("Widget refresh failed with status: " .. tostring(status)) + end + end) +end + +local function audioWatcherCallback(uid, eventName, scope, element) + -- "vmvc" = volume changed, "mute" = mute toggled + if eventName == "vmvc" or eventName == "mute" then + refreshWidget() + end +end + +local function setupAudioWatcher() + local device = hs.audiodevice.defaultOutputDevice() + if device then + device:watcherCallback(audioWatcherCallback) + device:watcherStart() + end +end + +setupAudioWatcher() + +-- Re-attach the watcher if the default output device changes (e.g. plugging in headphones) +hs.audiodevice.watcher.setCallback(function(event) + if event == "dOut " then -- note: the trailing space is intentional, it's part of the event name + setupAudioWatcher() + end +end) +hs.audiodevice.watcher.start() diff --git a/users/ryan/linux.nix b/users/ryan/linux.nix new file mode 100644 index 0000000..a86cad1 --- /dev/null +++ b/users/ryan/linux.nix @@ -0,0 +1,162 @@ +{ config, pkgs, lib, inputs, ... }: + +{ + imports = [ + ./linux/firefox-nightly + ]; + + home.username = "ryan"; + home.homeDirectory = "/home/ryan"; + home.stateVersion = "23.11"; # Please read the comment before changing. + + nixpkgs.config.allowUnfree = true; + + programs.zsh.shellAliases = { + ls = "ls -p --color=auto"; + spt = "spotify_player"; + python = "python3"; + }; + + # `nix shell nixpkgs#...`/`nix run nixpkgs#...` etc. resolve `nixpkgs` to + # this flake's own pinned input instead of fetching latest nixpkgs-unstable. + # This is the standalone-HM equivalent of RyanMac's /etc/nix/flake-registry.json. + # HM owns the whole ~/.config/nix directory (including nix.conf) so this + # doesn't end up writing through guix-dotfiles' `nix-config` symlink - see + # MIGRATION.md. + xdg.configFile."nix/nix.conf".text = "experimental-features = nix-command flakes\n"; + xdg.configFile."nix/registry.json".text = builtins.toJSON { + version = 2; + flakes = [ + { + from = { type = "indirect"; id = "nixpkgs"; }; + to = { + type = "path"; + path = inputs.nixpkgs.outPath; + lastModified = inputs.nixpkgs.lastModified; + narHash = inputs.nixpkgs.narHash; + }; + } + ]; + }; + + # Non-NixOS (Guix), so HM has to write its own fontconfig instead of + # relying on a system module. + fonts.fontconfig.enable = true; + fonts.fontconfig.defaultFonts = { + monospace = [ "DejaVu Sans Mono" ]; + sansSerif = [ "DejaVu Sans" ]; + serif = [ "DejaVu Serif" ]; + }; + + # Cursor theme. Replaces the previously hand-vendored Bibata asset (which + # embedded oddly-versioned theme names) with nixpkgs' own build - see the + # comment in linux/hypr/hyprland.conf for the corresponding env var change. + home.pointerCursor = { + enable = true; + package = pkgs.bibata-cursors; + name = "Bibata-Modern-Classic"; + size = 24; + gtk.enable = true; + x11.enable = true; + }; + + # gpg-agent itself is enabled in common.nix; nixpkgs' pinentry here instead + # of depending on Guix's system profile path. + services.gpg-agent.pinentry.package = pkgs.pinentry-qt; + + wayland.windowManager.hyprland = { + enable = true; + package = pkgs.hyprland; + portalPackage = pkgs.xdg-desktop-portal-hyprland; + extraConfig = builtins.readFile ./linux/hypr/hyprland.conf; + }; + + xdg.configFile = { + "hypr/monitors.conf".source = ./linux/hypr/monitors.conf; + "hypr/kanshi.conf".source = ./linux/hypr/kanshi.conf; + "hypr/pyprland.toml".source = ./linux/hypr/pyprland.toml; + "hypr/hypridle.conf".source = ./linux/hypr/hypridle.conf; + "hypr/hyprlock.conf".source = ./linux/hypr/hyprlock.conf; + "hypr/scripts" = { source = ./linux/hypr/scripts; recursive = true; }; + "hypr/family_guy.mp4".source = ./linux/hypr/family_guy.mp4; + "hypr/subwaysurfer.webm".source = ./linux/hypr/subwaysurfer.webm; + + "waybar" = { source = ./linux/waybar; recursive = true; }; + "alacritty" = { source = ./linux/alacritty; recursive = true; }; + "foot" = { source = ./linux/foot; recursive = true; }; + "wpaperd" = { source = ./linux/wpaperd; recursive = true; }; + "mpv" = { source = ./linux/mpv; recursive = true; }; + + "pulse/client.conf".source = ./linux/pulseaudio/client.conf; + "spotify-player/app.toml".source = ./linux/spotify-player/app.toml; + }; + + home.file = { + ".local/share/mailvelope" = { source = ./linux/mailvelope; recursive = true; }; + ".local/share/tridactyl" = { source = ./linux/tridactyl; recursive = true; }; + ".mozilla/native-messaging-hosts/tridactyl.json".source = ./linux/tridactyl/tridactyl.json; + }; + + home.packages = with pkgs; [ + rustup + zoxide + pnpm + gcc + pkg-config + wttrbar + wl-clip-persist + gifski + waypaper + spotify-player + xwayland + xdg-desktop-portal + xdg-desktop-portal-gtk + mpv + imv + libva + libvdpau + hypridle + hyprpicker + wpaperd + wl-mirror + pyprland + satty + fluxcd + sops + restic + kdePackages.kdenlive + bluetui + supercell-wx + chromium + + # foot is Guix system-packaged and is the terminal actually wired into + # the WM; alacritty's config was carried over from guix-dotfiles but + # nothing provided its binary there either - see MIGRATION.md. + alacritty + + # Nerd Fonts, replacing the hand-vendored ttf files that used to live in + # guix-dotfiles/home-config/fonts (Fira Code and "Monofur For Powerline" + # dropped - superseded by these, unreferenced anywhere) + nerd-fonts.anonymice + nerd-fonts.monofur + nerd-fonts.lilex + nerd-fonts.fira-code + noto-fonts + dejavu_fonts + liberation_ttf + noto-fonts-cjk-sans + noto-fonts-color-emoji + + # hyprlock built by nix needs Guix's PAM/fontconfig libs preloaded to run + # under the Guix system profile - same interop hack as before. + (pkgs.writeScriptBin "hyprlock" '' + #! ${pkgs.bash}/bin/bash + export LD_PRELOAD="/run/current-system/profile/lib/libpam.so.0:/run/current-system/profile/lib/libfontconfig.so:$LD_PRELOAD" + exec ${pkgs.hyprlock}/bin/hyprlock "$@" + '') + + # Guix's mesa doesn't match nixpkgs', so GL apps built by nix need nixGL. + inputs.nixgl.packages.${pkgs.system}.nixGLIntel + inputs.clipboard-sync.packages.${pkgs.system}.default + ]; +} diff --git a/users/ryan/linux/alacritty/alacritty.yml b/users/ryan/linux/alacritty/alacritty.yml new file mode 100644 index 0000000..4fbd991 --- /dev/null +++ b/users/ryan/linux/alacritty/alacritty.yml @@ -0,0 +1,15 @@ +window: + opacity: 0.70 +font: + size: 15 + normal: + family: "Monofur Nerd Font Mono" + style: Regular + + bold: + family: "Monofur Nerd Font Mono" + style: Bold + + italic: + family: "Monofur Nerd Font Mono" + style: Italic diff --git a/users/ryan/linux/firefox-nightly/default.nix b/users/ryan/linux/firefox-nightly/default.nix new file mode 100644 index 0000000..5c3fce7 --- /dev/null +++ b/users/ryan/linux/firefox-nightly/default.nix @@ -0,0 +1,193 @@ +{ config, pkgs, ... }: + +{ + programs.firefox = { + enable = true; + policies = import ./policies.nix; + #package = zen-browser.packages.${pkgs.system}.default.unwrapped; + + profiles.${config.home.username} = { + name = "${config.home.username}"; + isDefault = true; + containersForce = true; + containers = { + rit = { + name = "RIT"; + color = "orange"; + icon = "dollar"; + id = 1; + }; + ritwork = { + name = "RIT Work"; + color = "green"; + icon = "briefcase"; + id = 2; + }; + other = { + name = "Other"; + color = "blue"; + icon = "fingerprint"; + id = 3; + }; + }; + search = { + force = true; + default = "ddg"; + order = ["ddg" "google"]; + engines = { + "Nix Packages" = { + urls = [ + { + template = "https://search.nixos.org/packages"; + params = [ + { + name = "type"; + value = "packages"; + } + { + name = "channel"; + value = "unstable"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + } + ]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = ["@np"]; + }; + }; + }; + userChrome = " +#main-window .toolbar-items { +overflow: hidden; +transition: height 0.3s 0.3s !important; +} +/* Default state: Set initial height to enable animation */ +#main-window .toolbar-items { height: 3em !important; } +#main-window .titlebar-button { height: 3em !important; } +#main-window[uidensity=\"touch\"] .toolbar-items { height: 3.35em !important; } +#main-window[uidensity=\"compact\"] .toolbar-items { height: 2.7em !important; } +/* Hidden state: Hide native tabs strip */ +#main-window[titlepreface*=\"\"] .toolbar-items { height: 0 !important; } +#main-window[titlepreface*=\"\"] .titlebar-button { height: 0 !important; } +/* Hidden state: Fix z-index of active pinned tabs */ +#main-window[titlepreface*=\"\"] #tabbrowser-tabs { z-index: 0 !important; } + +/* Sidebery expand on mouse-over and hide otherwise */ + +/* Source file https://github.com/MrOtherGuy/firefox-csshacks/tree/master/chrome/autohide_sidebar.css made available under Mozilla Public License v. 2.0 +See the above repository for updates as well as full license text. */ + +/* Show sidebar only when the cursor is over it */ +/* The border controlling sidebar width will be removed so you'll need to modify these values to change width */ + +#sidebar-box{ +--uc-sidebar-width: 60px; +--uc-sidebar-hover-width: 230px; +--uc-autohide-sidebar-delay: 200ms; /* Wait 0.2s before hiding sidebar */ +--uc-autohide-transition-duration: 115ms; +--uc-autohide-transition-type: linear; +--browser-area-z-index-sidebar: 3; +position: relative; + min-width: var(--uc-sidebar-width) !important; +width: var(--uc-sidebar-width) !important; + max-width: var(--uc-sidebar-width) !important; + z-index: var(--browser-area-z-index-sidebar,3); +} +#sidebar-box[positionend]{ direction: rtl } +#sidebar-box[positionend] > *{ direction: ltr } + +#sidebar-box[positionend]:-moz-locale-dir(rtl){ direction: ltr } +#sidebar-box[positionend]:-moz-locale-dir(rtl) > *{ direction: rtl } + +#main-window[sizemode=\"fullscreen\"] #sidebar-box{ --uc-sidebar-width: 1px; } + +#sidebar-splitter{ display: none } + +#sidebar-header{ +overflow: hidden; +color: var(--chrome-color, inherit) !important; + padding-inline: 0 !important; +} + +#sidebar-header::before, +#sidebar-header::after{ +content: \"\"; +display: flex; + padding-left: 8px; +} + +#sidebar-header, +#sidebar{ +transition: min-width var(--uc-autohide-transition-duration) var(--uc-autohide-transition-type) var(--uc-autohide-sidebar-delay) !important; + min-width: var(--uc-sidebar-width) !important; + will-change: min-width; +} +#sidebar-box:hover > #sidebar-header, +#sidebar-box:hover > #sidebar{ +min-width: var(--uc-sidebar-hover-width) !important; +transition-delay: 0ms !important; +} + +.sidebar-panel{ +background-color: transparent !important; +color: var(--newtab-text-primary-color) !important; +} + +.sidebar-panel #search-box{ +-moz-appearance: none !important; +background-color: rgba(249,249,250,0.1) !important; +color: inherit !important; +} + +/* Add sidebar divider and give it background */ + +#sidebar, +#sidebar-header{ +background-color: inherit !important; +border-inline: 1px solid rgb(80,80,80); +border-inline-width: 0px 1px; +} + +#sidebar-box:not([positionend]) > :-moz-locale-dir(rtl), +#sidebar-box[positionend] > *{ +border-inline-width: 1px 0px; +} + +/* Move statuspanel to the other side when sidebar is hovered so it doesn't get covered by sidebar */ + +#sidebar-box:not([positionend]):hover ~ #appcontent #statuspanel{ +inset-inline: auto 0px !important; +} +#sidebar-box:not([positionend]):hover ~ #appcontent #statuspanel-label{ +margin-inline: 0px !important; +border-left-style: solid !important; +} + +/* Remove the tabs label and move the Sidebary icon to the center of the box */ +#sidebar-box:hover [id=\"sidebar-icon\"] { +transform: translateX(0px) !important; + transition-delay: 0ms !important; +} + +#sidebar-box [id=\"sidebar-icon\"] { +transform: translateX(9px); +transition: transform var(--uc-autohide-transition-duration) var(--uc-autohide-transition-type) var(--uc-autohide-sidebar-delay) !important; +} + +#sidebar-box [id=\"sidebar-title\"] { +visibility: hidden !important; +transition: visibility var(--uc-autohide-transition-duration) var(--uc-autohide-transition-type) var(--uc-autohide-sidebar-delay) !important; +} + +#sidebar-box:hover [id=\"sidebar-title\"] { +visibility: visible !important; + transition-delay: 0ms !important; +} +"; +}; +}; +} diff --git a/users/ryan/linux/firefox-nightly/policies.nix b/users/ryan/linux/firefox-nightly/policies.nix new file mode 100644 index 0000000..136b8b9 --- /dev/null +++ b/users/ryan/linux/firefox-nightly/policies.nix @@ -0,0 +1,130 @@ +let + lock-false = { + Value = false; + Status = "locked"; + }; + lock-true = { + Value = true; + Status = "locked"; + }; +in +{ + +EnableTrackingProtection = { + Value = true; + Locked = true; + Cryptomining = true; + Fingerprinting = true; + EmailTracking = true; +}; +UserMessaging = { + WhatsNew = false; + ExtensionRecommendations = false; + FeatureRecommendations = false; + UrlbarInterventions = false; + SkipOnboarding = true; + MoreFromMozilla = false; + Labs = false; + Locked = true; +}; +DisableAppUpdate = true; +DisableAccounts = true; +DisableFirefoxAccounts = true; +DisableFirefoxStudies = true; +DisablePocket = true; +DisableTelemetry = true; +AutofillAddressEnabled = false; +AutofillCreditCardEnabled = false; +DisableMasterPasswordCreation = true; +PasswordManagerEnabled = false; +PrimaryPassword = false; +OfferToSaveLogins = false; +NoDefaultBookmarks = true; +OverrideFirstRunPage = ""; +OverridePostUpdatePage = ""; +FirefoxHome = { + Search = true; + TopSites = true; + SponsoredTopSites = false; + Highlights = false; + Pocket = false; + SponsoredPocket = false; + Snippets = false; + Locked = true; +}; +SearchSuggestEnabled = true; +FirefoxSuggest = { + WebSuggestions = true; + SponsoredSuggestions = false; + ImproveSuggest = false; + Locked = true; +}; +PictureInPicture = lock-true; +HardwareAcceleration = true; +Certificates = { + ImportEnterpriseRoots = true; +}; +ExtensionSettings = { +#"*".installation_mode = "blocked"; +# uBlock Origin + "uBlock0@raymondhill.net" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi"; + installation_mode = "force_installed"; + }; +# Bitwarden + "{446900e4-71c2-419f-a6a7-df9c091e268b}" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi"; + installation_mode = "normal_installed"; + }; +# SponsorBlock + "sponsorBlocker@ajay.app" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/sponsorblock/latest.xpi"; + installation_mode = "force_installed"; + }; +# DeArrow + "deArrow@ajay.app" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/dearrow/latest.xpi"; + installation_mode = "force_installed"; + }; +# Return Youtube Dislike + "{762f9885-5a13-4abd-9c77-433dcd38b8fd}" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/return-youtube-dislikes/latest.xpi"; + installation_mode = "force_installed"; + }; +# Youtube Nonstop + "{0d7cafdd-501c-49ca-8ebb-e3341caaa55e}" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/youtube-nonstop/latest.xpi"; + installation_mode = "force_installed"; + }; +# Sidebery + "{3c078156-979c-498b-8990-85f7987dd929}" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/sidebery/latest.xpi"; + installation_mode = "normal_installed"; + }; +# TamperMonkey + "firefox@tampermonkey.net" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/tampermonkey/latest.xpi"; + installation_mode = "force_installed"; + }; +# Floccus + "floccus@handmadeideas.org" = { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/floccus/latest.xpi"; + installation_mode = "force_installed"; + }; +}; +Preferences = { + "browser.startup.homepage" = "https://d.in.rschanz.org"; + "extensions.activeThemeID" = { + Value = "firefox-compact-dark@mozilla.org"; + Status = "locked"; + }; + "toolkit.legacyUserProfileCustomizations.stylesheets" = lock-true; + "xpinstall.whitelist.required" = lock-true; + "dom.webgpu.enabled" = lock-true; + "media.eme.enabled" = lock-true; + "general.autoScroll" = lock-true; + "general.smoothScroll" = lock-true; + "browser.crashReports.unsubmittedCheck.autoSubmit2" = lock-false; + "browser.aboutConfig.showWarning" = lock-false; +}; +} diff --git a/users/ryan/linux/foot/foot.ini b/users/ryan/linux/foot/foot.ini new file mode 100644 index 0000000..50cb3fa --- /dev/null +++ b/users/ryan/linux/foot/foot.ini @@ -0,0 +1,7 @@ +font=Lilex Nerd Font Mono:size=14,FiraCode Nerd Font Mono:size=14 + +[desktop-notifications] +command=notify-send -a ${app-id} -i ${app-id} ${title} ${body} + +[colors-dark] +alpha=0.75 diff --git a/users/ryan/linux/hypr/family_guy.mp4 b/users/ryan/linux/hypr/family_guy.mp4 new file mode 100644 index 0000000..077fe49 Binary files /dev/null and b/users/ryan/linux/hypr/family_guy.mp4 differ diff --git a/users/ryan/linux/hypr/hypridle.conf b/users/ryan/linux/hypr/hypridle.conf new file mode 100644 index 0000000..72688da --- /dev/null +++ b/users/ryan/linux/hypr/hypridle.conf @@ -0,0 +1,16 @@ +general { + lock_cmd = pidof hyprlock || hyprlock + before_sleep_cmd = loginctl lock-session + after_sleep_cmd = hyprctl dispatch dpms on +} + +listener { + timeout = 300 + on-timeout = loginctl lock-session +} + +listener { + timeout = 600 + on-timeout = hyprctl dispatch dpms off + on-resume = hyprctl dispatch dpms on +} diff --git a/users/ryan/linux/hypr/hyprland.conf b/users/ryan/linux/hypr/hyprland.conf new file mode 100644 index 0000000..e51b54c --- /dev/null +++ b/users/ryan/linux/hypr/hyprland.conf @@ -0,0 +1,336 @@ +exec-once = dbus-update-activation-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP=Hyprland + +# +# Please note not all available settings / options are set here. +# For a full list, see the wiki +# + +# See https://wiki.hyprland.org/Configuring/Monitors/ +monitor=,preferred,auto,1 + +# Cursor theme is set via home.pointerCursor in linux.nix (pkgs.bibata-cursors, +# theme "Bibata-Modern-Classic"). The old vendored theme used +# hyprcursor/daed9-versioned names that only existed in the manually-packaged +# asset; nixpkgs' build uses the plain name below for both HYPRCURSOR_THEME +# and XCURSOR_THEME. +env = HYPRCURSOR_THEME,Bibata-Modern-Classic +env = HYPRCURSOR_SIZE,24 +env = XCURSOR_THEME,Bibata-Modern-Classic +env = XCURSOR_SIZE,24 + +env = AQ_NO_MODIFIERS,1 + +render { + expand_undersized_textures = false +} + +ecosystem { + no_update_news = true +} + + +# See https://wiki.hyprland.org/Configuring/Keywords/ for more + +# Execute your favorite apps at launch +# exec-once = waybar & hyprpaper & firefox + +# Source a file (multi-file configs) +source = ~/.config/hypr/monitors.conf + +# Some default env vars. +env = XCURSOR_SIZE,24 + +debug { + disable_logs = false + enable_stdout_logs = true +} + +# For all categories, see https://wiki.hyprland.org/Configuring/Variables/ +input { + kb_layout = us + kb_variant = + kb_model = + kb_options = + kb_rules = + numlock_by_default = true + + follow_mouse = 1 + + touchpad { + natural_scroll = no + middle_button_emulation = true + clickfinger_behavior = true + } + + sensitivity = 0 # -1.0 - 1.0, 0 means no modification. +} + +general { + # See https://wiki.hyprland.org/Configuring/Variables/ for more + + gaps_in = 5 + gaps_out = 10 + border_size = 2 + col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg + col.inactive_border = rgba(595959aa) + + layout = dwindle +} + +decoration { + # See https://wiki.hyprland.org/Configuring/Variables/ for more + + rounding = 5 + blur { + enabled = yes + size = 3 + passes = 1 + new_optimizations = on + } + + shadow { + enabled = true + range = 4 + render_power = 3 + color = rgba(1a1a1aee) + } +} + +animations { + enabled = yes + + # Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more + + bezier = myBezier, 0.05, 0.9, 0.1, 1.05 + + animation = windows, 1, 7, myBezier + animation = windowsOut, 1, 7, default, popin 80% + animation = border, 1, 10, default + animation = borderangle, 1, 8, default + animation = fade, 1, 7, default + animation = workspaces, 1, 6, default +} + +dwindle { + # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more + pseudotile = yes # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below + preserve_split = yes # you probably want this +} + +#master { +# # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more +# new_is_master = true +#} + +# Example per-device config +# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more +device { + name = epic-mouse-v1 + sensitivity = -0.5 +} + +# Example windowrule v1 +# windowrule = float, ^(kitty)$ +# Example windowrule v2 +# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ +# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more + + +# See https://wiki.hyprland.org/Configuring/Keywords/ for more +$mainMod = SUPER + +# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more +bind = $mainMod, Return, exec, foot +bind = $mainMod CTRL, Return, exec, foot -a float-foot +bind = $mainMod SHIFT, Q, killactive +bind = $mainMod SHIFT, E, exit +bind = $mainMod SHIFT, Space, togglefloating +bind = $mainMod SHIFT, Return, pin, active +bind = $mainMod, D, exec, fuzzel --width=35 --font='Hack:weight=bold:size=12' --background-color='282a36fa' --selection-color='3d4460fa' --line-height=20 --border-radius=20 +bind = $mainMod, P, pseudo, # dwindle +bind = $mainMod, J, togglesplit, # dwindle +bind = $mainMod, F, fullscreen, 1 +bind = $mainMod SHIFT, F, fullscreen +bind = ,XF86MonBrightnessUp, exec, light -A 10 +bind = ,XF86MonBrightnessDown, exec, light -U 10 +bind = ,XF86AudioRaiseVolume, exec, pamixer -i 5 +bind = ,XF86AudioLowerVolume, exec, pamixer -d 5 +bind = ,XF86AudioMute, exec, pamixer -t +bind = ,XF86AudioPlay, exec, playerctl play-pause +bind = ,XF86AudioPause, exec, playerctl play-pause +bind = ,XF86AudioNext, exec, playerctl next +bind = ,XF86AudioPrev, exec, playerctl previous +bind = ,XF86AudioStop, exec, playerctl stop + +# "Auto-connect headphones" +bind = $mainMod, H, exec, bluetoothctl connect AC:80:0A:1C:D6:C7 + +# Move workspace between monitors +bind = $mainMod CTRL SHIFT, left, movecurrentworkspacetomonitor, l +bind = $mainMod CTRL SHIFT, right, movecurrentworkspacetomonitor, r +bind = $mainMod CTRL SHIFT, up, movecurrentworkspacetomonitor, u +bind = $mainMod CTRL SHIFT, down, movecurrentworkspacetomonitor, d + +# Move focus with mainMod + arrow keys +bind = $mainMod, left, movefocus, l +bind = $mainMod, right, movefocus, r +bind = $mainMod, up, movefocus, u +bind = $mainMod, down, movefocus, d + +# Move window with mainMod + SHIFT + arrow keys +bind = $mainMod SHIFT, left, movewindow, l +bind = $mainMod SHIFT, right, movewindow, r +bind = $mainMod SHIFT, up, movewindow, u +bind = $mainMod SHIFT, down, movewindow, d + +# Switch workspaces with mainMod + [0-9] +bind = $mainMod, 1, workspace, 1 +bind = $mainMod, 2, workspace, 2 +bind = $mainMod, 3, workspace, 3 +bind = $mainMod, 4, workspace, 4 +bind = $mainMod, 5, workspace, 5 +bind = $mainMod, 6, workspace, 6 +bind = $mainMod, 7, workspace, 7 +bind = $mainMod, 8, workspace, 8 +bind = $mainMod, 9, workspace, 9 +bind = $mainMod, 0, workspace, 10 + +# Move active window to a workspace with mainMod + SHIFT + [0-9] +bind = $mainMod SHIFT, 1, movetoworkspace, 1 +bind = $mainMod SHIFT, 2, movetoworkspace, 2 +bind = $mainMod SHIFT, 3, movetoworkspace, 3 +bind = $mainMod SHIFT, 4, movetoworkspace, 4 +bind = $mainMod SHIFT, 5, movetoworkspace, 5 +bind = $mainMod SHIFT, 6, movetoworkspace, 6 +bind = $mainMod SHIFT, 7, movetoworkspace, 7 +bind = $mainMod SHIFT, 8, movetoworkspace, 8 +bind = $mainMod SHIFT, 9, movetoworkspace, 9 +bind = $mainMod SHIFT, 0, movetoworkspace, 10 + +# Scroll through existing workspaces with mainMod + scroll +bind = $mainMod, mouse_down, workspace, e+1 +bind = $mainMod, mouse_up, workspace, e-1 + +# Move/resize windows with mainMod + LMB/RMB and dragging +bindm = $mainMod, mouse:272, movewindow +bindm = $mainMod, mouse:273, resizewindow + +# Bind mainMod + L to screenlocker +bind = $mainMod, L, exec, hyprlock +bind = $mainMod SHIFT, L, exec, loginctl suspend + +# Keybind to toggle "performance mode" (toggles GPU intensive things) +bind = $mainMod, F1, exec, ~/.config/hypr/scripts/perf_mode.sh + +bind = $mainMod SHIFT, Z, exec, pypr zoom + +# Keybind for screenshot (satty) +bind = $mainMod SHIFT, S, exec, grimblast save output - | satty --fullscreen --copy-command 'wl-copy' --filename - +bind = $mainMod, S, exec, grimblast copy area +bind = $mainMod, Print, exec, export TEMP=$(mktemp) && grimblast copy area && wl-paste > $TEMP && imv $TEMP && rm $TEMP + +# Keybind for screenshot (old) +# bind = $mainMod SHIFT, S, exec, grimblast copy area +# bind = $mainMod SHIFT, Print, exec, grimblast edit area +# bind = $mainMod, S, exec, imv <(grimblast save area -) + +# Keybind for screenshot (flameshot) +#bind = $mainMod SHIFT, S, exec, flameshot gui --raw | wl-copy +#bind = $mainMod SHIFT CTRL, S, exec, flameshot gui --raw -d $(( 1000 * $(fuzzel -l0 --dmenu -p"Delay> ") )) | wl-copy +#bind = $mainMod, S, exec, flameshot gui + +# Notifications keybinds +bind = $mainMod, N, exec, makoctl dismiss +bind = $mainMod SHIFT, N, exec, makoctl dismiss -a + +# Color picker +bind = $mainMod SHIFT, C, exec, hyprpicker -a + +# LinkedIn Joke (very serious) +bind = $mainMod SHIFT CTRL ALT, L, exec, xdg-open https://linkedin.com + +# Window Rules + +# Firefox PiP +windowrulev2 = float, class:^(zen-beta)$, title:^(Picture-in-Picture)$ +windowrulev2 = pin, class:^(zen-beta)$, title:^(Picture-in-Picture)$ +windowrulev2 = size 22% 22%, class:^(zen-beta)$, title:^(Picture-in-Picture)$ +windowrulev2 = move 76% 8%, class:^(zen-beta)$, title:^(Picture-in-Picture)$ + +# Firefox Sharing Indicator +windowrulev2 = float, class:^(firefox)$, title:^(Firefox — Sharing Indicator)$ +windowrulev2 = size 56 31, class:^(firefox)$, title:^(Firefox — Sharing Indicator)$ +windowrulev2 = move 50% 0, class:^(firefox)$, title:^(Firefox — Sharing Indicator)$ +windowrulev2 = suppressevent fullscreen maximize, class:^(firefox)$, title:^(Firefox — Sharing Indicator)$ + +# Weather +windowrulev2 = float,class:^(ala-wttr)$ +windowrulev2 = size 822 1026, class:^(ala-wttr)$ + +# Floating terminal +windowrulev2 = float,class:^(float-foot)$ +windowrulev2 = size 930 680,class:^(float-foot)$ +windowrulev2 = center,class:^(float-foot)$ + +# Change color of pinned windows +windowrulev2 = bordercolor rgba(bf0000ee) rgba(ab00adee) 45deg,pinned:1 + +# Fun Keybinds +# Subway surfer +bind = $mainMod CTRL SHIFT, S, exec, mpv ~/.config/hypr/subwaysurfer.webm +windowrulev2 = float,class:^(mpv)$, title:^(subwaysurfer.webm - mpv)$ +windowrulev2 = size 310 554,class:^(mpv)$, title:^(subwaysurfer.webm - mpv)$ +windowrulev2 = move 81% 46% ,class:^(mpv)$, title:^(subwaysurfer.webm - mpv)$ +windowrulev2 = pin,class:^(mpv)$, title:^(subwaysurfer.webm - mpv)$ + +# Family guy funny moments +bind = $mainMod CTRL SHIFT, F, exec, mpv ~/.config/hypr/family_guy.mp4 +windowrulev2 = float,class:^(mpv)$, title:^(family_guy.mp4 - mpv)$ +windowrulev2 = size 595 336,class:^(mpv)$, title:^(family_guy.mp4 - mpv)$ +windowrulev2 = move 67% 5% ,class:^(mpv)$, title:^(family_guy.mp4 - mpv)$ +windowrulev2 = pin,class:^(mpv)$, title:^(family_guy.mp4 - mpv)$ + +# Satty windowrules +windowrulev2 = fullscreen,class:^(com.gabm.satty)$ + +exec-once = ~/.config/hypr/scripts/autostart.sh + +misc { + disable_hyprland_logo = true + force_default_wallpaper = 0 +} + +# Cursors! +plugin:dynamic-cursors { + enabled = true + mode = tilt + threshold = 2 + tilt { + limit = 5000 + function = negative_quadratic + } + + shake { + enabled = true + nearest = true + threshold = 6.0 + base = 4.0 + speed = 4.0 + influence = 0.0 + + limit = 0.0 + + timeout = 2000 + + effects = true + + ipc = false + } + + hyprcursor { + nearest = true + enabled = true + resolution = -1 + fallback = clientside + } +} diff --git a/users/ryan/linux/hypr/hyprlock.conf b/users/ryan/linux/hypr/hyprlock.conf new file mode 100644 index 0000000..5c63fad --- /dev/null +++ b/users/ryan/linux/hypr/hyprlock.conf @@ -0,0 +1,57 @@ +background { + monitor = + #path = /home/ryan/.config/hypr/Wallpapers/static/autumn1.png + path = screenshot + + # all these options are taken from hyprland, see https://wiki.hyprland.org/Configuring/Variables/#blur for explanations + blur_passes = 2 # 0 disables blurring + blur_size = 7 + noise = 0.2 + contrast = 0.8916 + brightness = 0.8172 + vibrancy = 0.1696 + vibrancy_darkness = 0.0 +} + +input-field { + monitor = + size = 200, 50 + outline_thickness = 3 + dots_size = 0.33 # Scale of input-field height, 0.2 - 0.8 + dots_spacing = 0.15 # Scale of dots' absolute size, 0.0 - 1.0 + dots_center = false + dots_rounding = -1 # -1 default circle, -2 follow input-field rounding + outer_color = rgb(151515) + inner_color = rgb(200, 200, 200) + font_color = rgb(10, 10, 10) + fade_on_empty = true + fade_timeout = 1000 # Milliseconds before fade_on_empty is triggered. + placeholder_text = Input Password... # Text rendered in the input box when it's empty. + hide_input = false + rounding = -1 # -1 means complete rounding (circle/oval) + check_color = rgb(204, 136, 34) + fail_color = rgb(204, 34, 34) # if authentication failed, changes outer_color and fail message color + fail_text = $FAIL ($ATTEMPTS) # can be set to empty + fail_timeout = 2000 # milliseconds before fail_text and fail_color disappears + fail_transition = 300 # transition time in ms between normal outer_color and fail_color + capslock_color = -1 + numlock_color = -1 + bothlock_color = -1 # when both locks are active. -1 means don't change outer color (same for above) + invert_numlock = false # change color if numlock is off + swap_font_color = false # see below + + position = 0, -20 + halign = center + valign = center +} + +label { + monitor = + text = cmd[update:1000] echo "$(date +"%-H:%M:%S")" + #color = rgba(255, 255, 255, 0.6) + font_size = 80 + position = 0, 300 + halign = center + valign = center + font_family = Lilex Nerd Font +} diff --git a/users/ryan/linux/hypr/kanshi.conf b/users/ryan/linux/hypr/kanshi.conf new file mode 100644 index 0000000..52c3c0f --- /dev/null +++ b/users/ryan/linux/hypr/kanshi.conf @@ -0,0 +1,22 @@ +profile { + output "AU Optronics 0x103D Unknown" enable +} + +profile emilydesk { + output "AU Optronics 0x103D Unknown" disable + output "Dell Inc. DELL U2422H JN4SF83" position 0,0 mode 1920x1080 + output "Dell Inc. DELL U2414H R9F1P5C59WDL" position 1920,0 mode 1920x1080 + output "Dell Inc. DELL U2422H 5S9SF83" position 3840,0 mode 1920x1080 +} + +profile justindesk { + output "AU Optronics 0x103D Unknown" position 0,0 mode 1920x1080 + output "Dell Inc. DELL U2417H XVNNT7CDC80L" position 1920,0 mode 1920x1080 + output "Dell Inc. DELL U2417H XVNNT82M978L" position 3840,0 mode 1920x1080 +} + +profile homedesk { + output "AU Optronics 0x103D Unknown" disable + output "Samsung Electric Company C27F390 H1AK500000" position 0,0 mode 1920x1080 + output "Samsung Electric Company S22R35x H4TNA01683" position 1920,0 mode 1920x1080 +} diff --git a/users/ryan/linux/hypr/monitors.conf b/users/ryan/linux/hypr/monitors.conf new file mode 100644 index 0000000..7b3b503 --- /dev/null +++ b/users/ryan/linux/hypr/monitors.conf @@ -0,0 +1,2 @@ +monitor=eDP-1,1920x1080, 0x0, 1 +monitor=HDMI-A-1,1920x1080, 1920x0, 1 diff --git a/users/ryan/linux/hypr/pyprland.toml b/users/ryan/linux/hypr/pyprland.toml new file mode 100644 index 0000000..cd081fe --- /dev/null +++ b/users/ryan/linux/hypr/pyprland.toml @@ -0,0 +1,5 @@ +[pyprland] +plugins = ["magnify"] + +[magnify] +factor = 2.5 diff --git a/users/ryan/linux/hypr/scripts/autostart.sh b/users/ryan/linux/hypr/scripts/autostart.sh new file mode 100755 index 0000000..706f82f --- /dev/null +++ b/users/ryan/linux/hypr/scripts/autostart.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +waybar & + +mako & + +#swaybg -i ~/.config/hypr/Wallpapers/above-clouds.jpg & + +nice -n13 swww init & + +#~/.config/hypr/wallpaper-daemon.sh & +wpaperd -d & + +pypr & + +#swayidle -w timeout 300 'swaylock --screenshots --clock --indicator --grace 3 --fade-in 1 --effect-blur 7x5 --effect-greyscale' timeout 600 'hyprctl dispatch dpms off' resume 'hyprctl dispatch dpms on' before-sleep 'swaylock -f -c 000000' & + +hypridle & + +syncthing serve --no-browser & + +# Kill any orphans of this +killall wl-clip-persist +wl-clip-persist -c regular --reconnect-tries 5 & + +kanshi -c ~/.config/hypr/kanshi.conf & + +# Start the portals + +sleep 0.5 +killall -e xdg-desktop-portal-hyprland +killall xdg-desktop-portal-gtk +killall xdk-desktop-portal + +~/.nix-profile/libexec/xdg-desktop-portal-hyprland & +~/.nix-profile/libexec/xdg-desktop-portal-gtk & +sleep 2 +XDG_DESKTOP_PORTAL_DIR="/home/ryan/.nix-profile/share/xdg-desktop-portal/portals" ~/.nix-profile/libexec/xdg-desktop-portal & + +#flameshot & diff --git a/users/ryan/linux/hypr/scripts/perf_mode.sh b/users/ryan/linux/hypr/scripts/perf_mode.sh new file mode 100755 index 0000000..c195688 --- /dev/null +++ b/users/ryan/linux/hypr/scripts/perf_mode.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +HYPRGAMEMODE=$(hyprctl getoption animations:enabled | awk 'NR==1{print $2}') +if [ "$HYPRGAMEMODE" = 1 ] ; then + hyprctl --batch "\ + keyword animations:enabled 0;\ + keyword decoration:drop_shadow 0;\ + keyword decoration:blur:enabled 0;\ + keyword general:gaps_in 0;\ + keyword general:gaps_out 0;\ + keyword general:border_size 1;\ + keyword decoration:rounding 0" + exit +fi +hyprctl reload diff --git a/users/ryan/linux/hypr/subwaysurfer.webm b/users/ryan/linux/hypr/subwaysurfer.webm new file mode 100644 index 0000000..594e1c0 Binary files /dev/null and b/users/ryan/linux/hypr/subwaysurfer.webm differ diff --git a/users/ryan/linux/mailvelope/gpgmejson.json b/users/ryan/linux/mailvelope/gpgmejson.json new file mode 100644 index 0000000..7ad8586 --- /dev/null +++ b/users/ryan/linux/mailvelope/gpgmejson.json @@ -0,0 +1,7 @@ +{ + "name": "gpgmejson", + "description": "JavaScript binding for GnuPG", + "path": "/home/ryan/.local/share/mailvelope/start.sh", + "type": "stdio", + "allowed_extensions": ["jid1-AQqSMBYb0a8ADg@jetpack"] +} diff --git a/users/ryan/linux/mailvelope/start.sh b/users/ryan/linux/mailvelope/start.sh new file mode 100755 index 0000000..01b3ee2 --- /dev/null +++ b/users/ryan/linux/mailvelope/start.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Wrap for gpgme-json so firefox can use it +exec gpgme-json $@ diff --git a/users/ryan/linux/mpv/scripts/easycrop.lua b/users/ryan/linux/mpv/scripts/easycrop.lua new file mode 100644 index 0000000..415fce5 --- /dev/null +++ b/users/ryan/linux/mpv/scripts/easycrop.lua @@ -0,0 +1,254 @@ +local msg = require('mp.msg') +local assdraw = require('mp.assdraw') + +local script_name = "easycrop" + +-- Number of crop points currently chosen (0 to 2) +local points = {} +-- True if in cropping selection mode +local cropping = false +-- Original value of osc property +local osc_prop = false + +-- Helper that converts two points to top-left and bottom-right +local swizzle_points = function (p1, p2) + if p1.x > p2.x then p1.x, p2.x = p2.x, p1.x end + if p1.y > p2.y then p1.y, p2.y = p2.y, p1.y end +end + +local clamp = function (val, min, max) + assert(min <= max) + if val < min then return min end + if val > max then return max end + return val +end + +local video_space_from_screen_space = function (ssp) + -- Video native dimensions and screen size + local vid_w = mp.get_property("width") + local vid_h = mp.get_property("height") + local osd_w = mp.get_property("osd-width") + local osd_h = mp.get_property("osd-height") + + -- Factor by which the video is scaled to fit the screen + local scale = math.min(osd_w/vid_w, osd_h/vid_h) + + -- Size video takes up in screen + local vid_sw, vid_sh = scale*vid_w, scale*vid_h + + -- Video offset within screen + local off_x = math.floor((osd_w - vid_sw)/2) + local off_y = math.floor((osd_h - vid_sh)/2) + + local vsp = {} + + -- Move the point to within the video + vsp.x = clamp(ssp.x, off_x, off_x + vid_sw) + vsp.y = clamp(ssp.y, off_y, off_y + vid_sh) + + -- Convert screen-space to video-space + vsp.x = math.floor((vsp.x - off_x) / scale) + vsp.y = math.floor((vsp.y - off_y) / scale) + + return vsp +end + +local screen_space_from_video_space = function (vsp) + -- Video native dimensions and screen size + local vid_w = mp.get_property("width") + local vid_h = mp.get_property("height") + local osd_w = mp.get_property("osd-width") + local osd_h = mp.get_property("osd-height") + + -- Factor by which the video is scaled to fit the screen + local scale = math.min(osd_w/vid_w, osd_h/vid_h) + + -- Size video takes up in screen + local vid_sw, vid_sh = scale*vid_w, scale*vid_h + + -- Video offset within screen + local off_x = math.floor((osd_w - vid_sw)/2) + local off_y = math.floor((osd_h - vid_sh)/2) + + local ssp = {} + ssp.x = vsp.x * scale + off_x + ssp.y = vsp.y * scale + off_y + return ssp +end + +-- Wrapper that converts RRGGBB / RRGGBBAA to ASS format +local ass_set_color = function (idx, color) + assert(color:len() == 8 or color:len() == 6) + local ass = "" + + -- Set alpha value (if present) + if color:len() == 8 then + local alpha = 0xff - tonumber(color:sub(7, 8), 16) + ass = ass .. string.format("\\%da&H%X&", idx, alpha) + end + + -- Swizzle RGB to BGR and build ASS string + color = color:sub(5, 6) .. color:sub(3, 4) .. color:sub(1, 2) + return "{" .. ass .. string.format("\\%dc&H%s&", idx, color) .. "}" +end + +local draw_rect = function (p1, p2) + local osd_w, osd_h = mp.get_property("osd-width"), mp.get_property("osd-height") + + ass = assdraw.ass_new() + + -- Draw overlay over surrounding unselected region + + ass:draw_start() + ass:pos(0, 0) + + ass:append(ass_set_color(1, "000000aa")) + ass:append(ass_set_color(3, "00000000")) + + local l = math.min(p1.x, p2.x) + local r = math.max(p1.x, p2.x) + local u = math.min(p1.y, p2.y) + local d = math.max(p1.y, p2.y) + + ass:rect_cw(0, 0, l, osd_h) + ass:rect_cw(r, 0, osd_w, osd_h) + ass:rect_cw(l, 0, r, u) + ass:rect_cw(l, d, r, osd_h) + + ass:draw_stop() + + -- Draw border around selected region + + ass:new_event() + ass:draw_start() + ass:pos(0, 0) + + ass:append(ass_set_color(1, "00000000")) + ass:append(ass_set_color(3, "000000ff")) + ass:append("{\\bord2}") + + ass:rect_cw(p1.x, p1.y, p2.x, p2.y) + + ass:draw_stop() + + mp.set_osd_ass(osd_w, osd_h, ass.text) +end + +local draw_fill = function () + local osd_w, osd_h = mp.get_property("osd-width"), mp.get_property("osd-height") + + ass = assdraw.ass_new() + ass:draw_start() + ass:pos(0, 0) + + ass:append(ass_set_color(1, "000000aa")) + ass:append(ass_set_color(3, "00000000")) + ass:rect_cw(0, 0, osd_w, osd_h) + + ass:draw_stop() + mp.set_osd_ass(osd_w, osd_h, ass.text) +end + +local draw_clear = function () + local osd_w, osd_h = mp.get_property("osd-width"), mp.get_property("osd-height") + mp.set_osd_ass(osd_w, osd_h, "") +end + +local draw_cropper = function () + if #points == 1 then + local p1 = screen_space_from_video_space(points[1]) + local p2 = {} + p2.x, p2.y = mp.get_mouse_pos() + draw_rect(p1, p2) + end +end + +local uncrop = function () + mp.command("no-osd vf del @" .. script_name .. ":crop") +end + +local crop = function(p1, p2) + swizzle_points(p1, p2) + + local w = p2.x - p1.x + local h = p2.y - p1.y + local ok, err = mp.command(string.format( + "no-osd vf add @%s:crop=%s:%s:%s:%s", script_name, w, h, p1.x, p1.y)) + + if not ok then + mp.osd_message("Cropping failed") + points = {} + end +end + +local easycrop_stop = function () + mp.set_property("osc", osc_prop) + cropping = false + mp.remove_key_binding("easycrop_mouse_btn0") + draw_clear() +end + +local mouse_btn0_cb = function () + if not cropping then + return + end + + local mx, my = mp.get_mouse_pos() + table.insert(points, video_space_from_screen_space({ x = mx, y = my })) + + if #points == 2 then + crop(points[1], points[2]) + easycrop_stop() + end +end + +local easycrop_start = function () + -- Cropping requires swdec or hwdec with copy-back + local hwdec = mp.get_property("hwdec-current") + if hwdec == nil then + return mp.msg.error("Cannot determine current hardware decoder mode") + end + -- Check whitelist of ok values + local valid_hwdec = { + ["no"] = true, -- software decoding + -- Taken from mpv manual + ["videotoolbox-co"] = true, + ["vaapi-copy"] = true, + ["dxva2-copy"] = true, + ["d3d11va-copy"] = true, + ["mediacodec"] = true + } + if not valid_hwdec[hwdec] then + return mp.osd_message("Cropping requires swdec or hwdec with copy-back (see mpv manual)") + end + + -- Just clear the current crop and return, if there is one + if #points ~= 0 then + uncrop() + points = {} + return + end + + -- Hide OSC + osc_prop = mp.get_property("osc") + mp.set_property("osc", "no") + + cropping = true + mp.add_forced_key_binding("mouse_btn0", "easycrop_mouse_btn0", mouse_btn0_cb) + draw_fill() +end + +local easycrop_activate = function () + if cropping then + easycrop_stop() + else + easycrop_start() + end +end + +mp.add_key_binding("mouse_move", draw_cropper) +mp.observe_property("osd-width", "native", draw_cropper) +mp.observe_property("osd-height", "native", draw_cropper) + +mp.add_key_binding("c", "easy_crop", easycrop_activate) + diff --git a/users/ryan/linux/pulseaudio/client.conf b/users/ryan/linux/pulseaudio/client.conf new file mode 100644 index 0000000..207e152 --- /dev/null +++ b/users/ryan/linux/pulseaudio/client.conf @@ -0,0 +1 @@ +autospawn = no diff --git a/users/ryan/linux/spotify-player/app.toml b/users/ryan/linux/spotify-player/app.toml new file mode 100644 index 0000000..4eac5e4 --- /dev/null +++ b/users/ryan/linux/spotify-player/app.toml @@ -0,0 +1,34 @@ +theme = "dracula" +client_id = "4b1219bdc29945bc8ca914f80a8a6a47" +client_port = 8888 +playback_format = """ +{track} • {artists} +{album} +{metadata}""" +tracks_playback_limit = 50 +app_refresh_duration_in_ms = 32 +playback_refresh_duration_in_ms = 0 +cover_image_refresh_duration_in_ms = 2000 +page_size_in_rows = 20 +play_icon = "▶" +pause_icon = "▌▌" +liked_icon = "♥" +border_type = "Plain" +progress_bar_type = "Rectangle" +playback_window_position = "Top" +cover_img_length = 9 +cover_img_width = 5 +cover_img_scale = 1.0 +playback_window_width = 6 +enable_media_control = true +enable_streaming = "DaemonOnly" +enable_cover_image_cache = true +default_device = "RyanThinkpad" + +[copy_command] +command = "wlcopy" +args = [] + +[notify_format] +summary = "{track} • {artists}" +body = "{album}" diff --git a/users/ryan/linux/tridactyl/native_main b/users/ryan/linux/tridactyl/native_main new file mode 100755 index 0000000..2104875 Binary files /dev/null and b/users/ryan/linux/tridactyl/native_main differ diff --git a/users/ryan/linux/tridactyl/tridactyl.json b/users/ryan/linux/tridactyl/tridactyl.json new file mode 100644 index 0000000..0764f98 --- /dev/null +++ b/users/ryan/linux/tridactyl/tridactyl.json @@ -0,0 +1,7 @@ +{ + "name": "tridactyl", + "description": "Tridactyl native command handler", + "path": "/home/ryan/.local/share/tridactyl/native_main", + "type": "stdio", + "allowed_extensions": [ "tridactyl.vim@cmcaine.co.uk","tridactyl.vim.betas@cmcaine.co.uk", "tridactyl.vim.betas.nonewtab@cmcaine.co.uk" ] +} diff --git a/users/ryan/linux/waybar/config b/users/ryan/linux/waybar/config new file mode 100644 index 0000000..62e6b20 --- /dev/null +++ b/users/ryan/linux/waybar/config @@ -0,0 +1,167 @@ +{ + "layer": "top", + "position": "top", + "height": 30, + + "modules-left": ["hyprland/workspaces", "hyprland/submap"], + "modules-center": ["hyprland/window"], + "modules-right": ["tray", "custom/spotify", "privacy", "custom/weather", "custom/mail", "custom/storage", "backlight", "bluetooth", "pulseaudio", "network", "idle_inhibitor", "battery", "battery#num2", "clock"], + "hyprland/submap": { + "format": " {}" + }, + "hyprland/workspaces": { + "format": "{id}", + "all-outputs": false, + "disable-scroll": true + }, + "hyprland/window": { + "max-length": 80, + "tooltip": false, + "separate-outputs": true + }, + "clock": { + "format": "{:%a %d %b %H:%M}", + "tooltip": false + }, + "battery": { + "format": "{capacity}% {icon}", + "format-alt": "{time} {icon}", + "format-icons": ["", "", "", "", ""], + "format-charging": "{capacity}% ", + "interval": 30, + "states": { + "warning": 25, + "critical": 10 + }, + "tooltip": false, + "bat":"BAT0" + }, + "battery#num2": { + "format": "{capacity}% {icon}", + "format-alt": "{time} {icon}", + "format-icons": ["", "", "", "", ""], + "format-charging": "{capacity}% ", + "interval": 30, + "states": { + "warning": 25, + "critical": 10 + }, + "tooltip": false, + "bat":"BAT1" + }, + "bluetooth": { + "format": "󰂯", + "format-disabled": "󰂲", + "format-connected": "󰂯", + "format-connected-battery": "󰂱 {device_battery_percentage}%", + "on-click": "foot bluetui", + "tooltip-format": "{controller_alias}\t{controller_address}\n\n{num_connections} connected", + "tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}", + "tooltip-format-enumerate-connected": "{device_alias}\t{device_address}", + "tooltip-format-enumerate-connected-battery": "{device_alias}\t{device_address}\t{device_battery_percentage}%" + }, + "network": { + "format-alt": "{ipaddr}/{cidr} {icon} {bandwidthTotalBytes}󰹹", + "format": "{ipaddr}/{cidr} {icon}", + "format-alt-click": "click-right", + "format-icons": { + "wifi": ["󰤟", "󰤢" ,"󰤥", "󰤨"], + "ethernet": [""], + "disconnected": ["󰤭"] + }, + "on-click": "foot -t alacritty doas nmtui", + "tooltip": false + }, + "privacy": { + "icon-spacing":4, + "icon-size":18, + "transition-duration":250, + "modules": [ + { + "type":"screenshare", + "tooltip":true, + "tooltip-icon-size":24 + }, + { + "type":"audio-in", + "tooltip":true, + "tooltip-icon-size":24 + } + ] + }, + "pulseaudio": { + "format-alt": "{icon}", + "format": "{volume} {icon}", + "format-alt-click": "click-right", + "format-muted": "", + "format-icons": { + "phone": [" ", " ", " ", " "], + "default": ["", "", "", ""] + }, + "scroll-step": 1, + "on-click": "pavucontrol", + "tooltip": false + }, + "custom/spotify": { + "interval": 2, + "return-type": "json", + "exec": "~/.config/waybar/modules/spotify.sh", + "exec-if": "~/.config/waybar/modules/check-for-music.sh", + "escape": true, + "on-click": "playerctl play-pause" + }, + "custom/storage": { + "format-alt": "{} ", + "format": "{percentage}% ", + "format-alt-click": "click-right", + "return-type": "json", + "interval": 60, + "exec": "~/.config/waybar/modules/storage.sh" + }, + "backlight": { + "format-alt": "{icon}", + "format": "{percent}% {icon}", + "format-alt-click": "click-right", + "format-icons": ["", ""], + "on-scroll-up": "light -A 1", + "on-scroll-down": "light -U 1" + }, + "custom/weather_OLD": { + "format-alt": "{}", + "format": "{alt}: {}", + "format-alt-click": "click-right", + "interval": 1800, + "return-type": "json", + "on-click": "foot -a ala-wttr -H curl https://v2.wttr.in", + "exec": "~/.config/waybar/modules/weather.sh", + "exec-if": "ping wttr.in -c1" + }, + "custom/weather": { + "format": "{} °F", + "tooltip": true, + "interval": 3600, + "exec": "exit=101; while [ $exit = 101 ]; do wttrbar --main-indicator temp_F --fahrenheit; exit=$(echo $?); sleep 1; done", + "on-click": "foot -a ala-wttr -H curl https://v2.wttr.in", + "return-type": "json" + }, + "idle_inhibitor": { + "format": "{icon}", + "format-icons": { + "activated": "", + "deactivated": "" + }, + "tooltip": false + }, + "custom/mail": { + "format": "", + "format-alt": "{alt} ", + "format-alt-click": "click-right", + "interval": 60, + "return-type": "json", + "exec": "~/.config/waybar/modules/mail.py", + "tooltip": false + }, + "tray": { + "icon-size": 18 + } +} diff --git a/users/ryan/linux/waybar/modules/check-for-music.sh b/users/ryan/linux/waybar/modules/check-for-music.sh new file mode 100755 index 0000000..3b735a2 --- /dev/null +++ b/users/ryan/linux/waybar/modules/check-for-music.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +if [[ $(playerctl metadata --format '{{lc(status)}}' | grep playing) -eq 0 ]]; then + exit 0 +else + exit 1 +fi diff --git a/users/ryan/linux/waybar/modules/spotify.sh b/users/ryan/linux/waybar/modules/spotify.sh new file mode 100755 index 0000000..fc732a1 --- /dev/null +++ b/users/ryan/linux/waybar/modules/spotify.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +class=$(playerctl metadata --format '{{lc(status)}}') +icon="󰎆" + +if [[ $class == "playing" ]]; then + info=$(playerctl metadata --format '{{artist}} - {{title}}') + if [[ ${#info} > 40 ]]; then + info=$(playerctl metadata --format '{{title}}' | cut -c1-40)"..." + fi + text=$info" "$icon +elif [[ $class == "paused" ]]; then + text=$icon +elif [[ $class == "stopped" ]]; then + text="" +fi + +echo -e "{\"text\":\""$text"\", \"class\":\""$class"\"}" + diff --git a/users/ryan/linux/waybar/modules/storage.sh b/users/ryan/linux/waybar/modules/storage.sh new file mode 100755 index 0000000..90cc3dc --- /dev/null +++ b/users/ryan/linux/waybar/modules/storage.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +mount="/" +warning=20 +critical=10 + +df -h -P -l "$mount" | awk -v warning=$warning -v critical=$critical ' +/\/.*/ { + text=$4 + tooltip="Filesystem: "$1"\rSize: "$2"\rUsed: "$3"\rAvail: "$4"\rUse%: "$5"\rMounted on: "$6 + use=$5 + exit 0 +} +END { + class="" + gsub(/%$/,"",use) + if ((100 - use) < critical) { + class="critical" + } else if ((100 - use) < warning) { + class="warning" + } + print "{\"text\":\""text"\", \"percentage\":"use",\"tooltip\":\""tooltip"\", \"class\":\""class"\"}" +} +' + diff --git a/users/ryan/linux/waybar/modules/weather.sh b/users/ryan/linux/waybar/modules/weather.sh new file mode 100755 index 0000000..01faffc --- /dev/null +++ b/users/ryan/linux/waybar/modules/weather.sh @@ -0,0 +1,77 @@ +cachedir=~/.cache/rbn +cachefile=${0##*/}-$1 + +if [ ! -d $cachedir ]; then + mkdir -p $cachedir +fi + +if [ ! -f $cachedir/$cachefile ]; then + touch $cachedir/$cachefile +fi + +# Save current IFS +SAVEIFS=$IFS +# Change IFS to new line. +IFS=$'\n' + +cacheage=$(($(date +%s) - $(stat -c '%Y' "$cachedir/$cachefile"))) +if [ $cacheage -gt 1740 ] || [ ! -s $cachedir/$cachefile ]; then + data=($(curl -s https://en.wttr.in/$1\?0qnT 2>&1)) + echo ${data[0]} | cut -f1 -d, > $cachedir/$cachefile + echo ${data[1]} | sed -E 's/^.{15}//' >> $cachedir/$cachefile + echo ${data[2]} | sed -E 's/^.{15}//' >> $cachedir/$cachefile +fi + +weather=($(cat $cachedir/$cachefile)) + +# Restore IFSClear +IFS=$SAVEIFS + +temperature=$(echo ${weather[2]} | sed -E 's/([[:digit:]]+)\.\./\1 to /g') + +#echo ${weather[1]##*,} + +# https://fontawesome.com/icons?s=solid&c=weather +case $(echo ${weather[1]##*,} | tr '[:upper:]' '[:lower:]') in +"clear" | "sunny") + condition="" + ;; +"partly cloudy") + condition="" + ;; +"cloudy") + condition="" + ;; +"overcast") + condition="" + ;; +"mist" | "fog" | "freezing fog") + condition="敖" + ;; +"patchy rain possible" | "patchy light drizzle" | "light drizzle" | "patchy light rain" | "light rain" | "light rain shower" | "rain") + condition="殺" + ;; +"moderate rain at times" | "moderate rain" | "heavy rain at times" | "heavy rain" | "moderate or heavy rain shower" | "torrential rain shower" | "rain shower") + condition="" + ;; +"patchy snow possible" | "patchy sleet possible" | "patchy freezing drizzle possible" | "freezing drizzle" | "heavy freezing drizzle" | "light freezing rain" | "moderate or heavy freezing rain" | "light sleet" | "ice pellets" | "light sleet showers" | "moderate or heavy sleet showers") + condition="流" + ;; +"blowing snow" | "moderate or heavy sleet" | "patchy light snow" | "light snow" | "light snow showers") + condition="ﰕ" + ;; +"blizzard" | "patchy moderate snow" | "moderate snow" | "patchy heavy snow" | "heavy snow" | "moderate or heavy snow with thunder" | "moderate or heavy snow showers") + condition="" + ;; +"thundery outbreaks possible" | "patchy light rain with thunder" | "moderate or heavy rain with thunder" | "patchy light snow with thunder") + condition="" + ;; +*) + condition="" + echo -e "{\"text\":\""$condition"\", \"alt\":\""${weather[0]}"\", \"tooltip\":\""${weather[0]}: $temperature ${weather[1]}"\"}" + ;; +esac + +#echo $temp $condition + +echo -e "{\"text\":\""$temperature $condition"\", \"alt\":\""${weather[0]}"\", \"tooltip\":\""${weather[0]}: $temperature ${weather[1]}"\"}" diff --git a/users/ryan/linux/waybar/style.css b/users/ryan/linux/waybar/style.css new file mode 100644 index 0000000..682a14e --- /dev/null +++ b/users/ryan/linux/waybar/style.css @@ -0,0 +1,77 @@ +* { + border: none; + border-radius: 0; + font-family: AnonymicePro Nerd Font; + font-size: 15px; + box-shadow: none; + text-shadow: none; + transition-duration: 0s; + color: white; +} + +#waybar { + background-color:rgba(0,0,0,0.25); + color: white; +} + +window { + color: rgba(217, 216, 216, 1); + background: rgba(35, 31, 32, 0.00); +} + +window#waybar.solo { + color: rgba(217, 216, 216, 1); + background: rgba(35, 31, 32, 0.85); +} + +#workspaces { + margin: 0 5px; +} + +#workspaces button { + padding: 0 5px; + color: rgba(217, 216, 216, 0.4); +} + +#workspaces button.visible { + color: rgba(217, 216, 216, 1); +} + +#workspaces button.active { + border-top: 3px solid rgba(217, 216, 216, 1); + border-bottom: 3px solid rgba(217, 216, 216, 0); +} + +#workspaces button.urgent { + color: rgba(238, 46, 36, 1); +} + +#mode, #battery, #cpu, #memory, #network, #bluetooth, #pulseaudio, #idle_inhibitor, #backlight, #custom-storage, #custom-spotify, #custom-weather, #custom-mail { + margin: 0px 6px 0px 10px; + min-width: 25px; +} + +#clock { + margin: 0px 16px 0px 10px; + min-width: 140px; +} + +#battery.warning #battery.num2.warning { + color: rgba(255, 210, 4, 1); +} + +#battery.critical #battery.bat2.critical { + color: rgba(238, 46, 36, 1); +} + +#battery.charging #battery.bat2.charging { + color: rgba(217, 216, 216, 1); +} + +#custom-storage.warning { + color: rgba(255, 210, 4, 1); +} + +#custom-storage.critical { + color: rgba(238, 46, 36, 1); +} diff --git a/users/ryan/linux/wpaperd/config.toml b/users/ryan/linux/wpaperd/config.toml new file mode 100644 index 0000000..9947370 --- /dev/null +++ b/users/ryan/linux/wpaperd/config.toml @@ -0,0 +1,4 @@ +[default] +duration = "30m" +path = "~/.config/hypr/Wallpapers/static/" +transition-time = 2000 diff --git a/users/ryan/modules/nvim/default.nix b/users/ryan/modules/nvim/default.nix new file mode 100644 index 0000000..83c9e1f --- /dev/null +++ b/users/ryan/modules/nvim/default.nix @@ -0,0 +1,53 @@ +{config, lib, pkgs, ...}: + +with lib; + +let + cfg = config.ryan.neovim; +in +{ + options.ryan.neovim.enable = mkEnableOption "Neovim"; + + config = mkIf cfg.enable { + programs.neovim = { + enable = true; + + extraConfig = builtins.readFile ./init.vim; + + initLua = builtins.readFile ./init.lua; + + plugins = with pkgs.vimPlugins; [ + vim-pandoc + vim-pandoc-syntax + vim-table-mode + + tokyonight-nvim + lualine-nvim + nvim-web-devicons + + coq_nvim + #coq-artifacts + + (nvim-treesitter.withPlugins (p: [ + p.zig + p.go + p.python + p.vim + ])) + + #transparent-nvim + marks-nvim + leap-nvim + ]; + + extraPackages = with pkgs; [ + pyright + gopls + zls + ]; + + }; + + xdg.configFile."nvim/after".source = ./extraConfigs/after; + }; +} diff --git a/users/ryan/modules/nvim/extraConfigs/after/ftplugin/mail/custom.vim b/users/ryan/modules/nvim/extraConfigs/after/ftplugin/mail/custom.vim new file mode 100644 index 0000000..75078e5 --- /dev/null +++ b/users/ryan/modules/nvim/extraConfigs/after/ftplugin/mail/custom.vim @@ -0,0 +1,2 @@ +setlocal tw=0 wm=0 +setlocal wrap linebreak diff --git a/users/ryan/modules/nvim/extraConfigs/after/ftplugin/markdown/custom.vim b/users/ryan/modules/nvim/extraConfigs/after/ftplugin/markdown/custom.vim new file mode 100644 index 0000000..96aac6e --- /dev/null +++ b/users/ryan/modules/nvim/extraConfigs/after/ftplugin/markdown/custom.vim @@ -0,0 +1,2 @@ +"Used to overwrite table behavior in markdown files +let b:table_mode_corner='+' diff --git a/users/ryan/modules/nvim/init.lua b/users/ryan/modules/nvim/init.lua new file mode 100644 index 0000000..2686f15 --- /dev/null +++ b/users/ryan/modules/nvim/init.lua @@ -0,0 +1,26 @@ +require('lualine').setup() +local coq = require 'coq' +--require("transparent") +--require("mason").setup() +--require("mason-lspconfig").setup { +-- ensure_installed = { "pyright" }, +-- } + +-- nvim marks +require'marks'.setup { + default_mappings = true +} + +-- Leap keybinds +config = function(_, opts) + vim.keymap.set({'n', 'x', 'o'}, 's', '(leap-forward)') + vim.keymap.set({'n', 'x', 'o'}, 'S', '(leap-backward)') + vim.keymap.set({'n', 'x', 'o'}, 'gs', '(leap-from-window)') +end + +--require'nvim-treesitter'.install { 'zig','go','python','vim' } + +vim.opt.conceallevel = 2 +vim.opt.concealcursor = nc + +--local lspconfig = require('lspconfig') diff --git a/users/ryan/modules/nvim/init.vim b/users/ryan/modules/nvim/init.vim new file mode 100644 index 0000000..8a4d54e --- /dev/null +++ b/users/ryan/modules/nvim/init.vim @@ -0,0 +1,27 @@ +set nu rnu +imap kj +set ts=4 +set sw=4 +set sts=4 +set et +set mouse= +set cursorline +set cc=79 + +"Load Theme +colorscheme tokyonight-night + +"vim-pandoc config +let g:pandoc#modules#disabled = ['spell', 'folding'] + +"vim-table-mode config +let g:table_mode_corner_corner='+' +let g:table_mode_header_fillchar='=' + +"pandoc render and open preview +command Pv AsyncRun zathura '%:r.pdf' +command Rd silent exec "!pandoc -t pdf -o %:r.pdf --from=markdown+escaped_line_breaks -V geometry:margin=1in %" +command Rr exec "!pandoc -t pdf -o %:r.pdf --from=markdown+escaped_line_breaks -V geometry:margin=1in %" + +"Auto-rerender markdown files to pdf +autocmd BufWritePost *.mkd :Rd diff --git a/users/ryan/modules/simple-bar/default.nix b/users/ryan/modules/simple-bar/default.nix new file mode 100644 index 0000000..e05fe08 --- /dev/null +++ b/users/ryan/modules/simple-bar/default.nix @@ -0,0 +1,30 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.ryan.simple-bar; + "simple-bar-upstream" = ./simple-bar-source; +in +{ + options.ryan.simple-bar.enable = mkEnableOption "simple-bar"; + + config = mkIf cfg.enable { + home.file."Library/Application Support/Übersicht/widgets/simple-bar" = { + source = simple-bar-upstream; + recursive = false; + }; + home.file.".simplebarrc".source = ./simplebarrc; + + # Install the LaunchD services + launchd.agents.simple-bar-server = import ./server.nix { inherit config lib pkgs; }; + + launchd.agents.ubersicht = { + enable = true; + config = { + ProgramArguments = [ "/usr/bin/open" "-a" "Übersicht" ]; + RunAtLoad = true; + }; + }; + }; +} diff --git a/users/ryan/modules/simple-bar/server.nix b/users/ryan/modules/simple-bar/server.nix new file mode 100644 index 0000000..f9b636c --- /dev/null +++ b/users/ryan/modules/simple-bar/server.nix @@ -0,0 +1,34 @@ +{ pkgs, lib, ... }: +let + src = builtins.fetchGit { + url = "https://github.com/Jean-Tinland/simple-bar-server.git"; + rev = "0c99921d023b459e44bbba8cca6d8947262359b6"; + shallow = true; + }; + + simple-bar-server = pkgs.buildNpmPackage { + pname = "simple-bar-server"; + version = "0-unstable"; + inherit src; + + npmDepsHash = "sha256-JKUiOqAAoE/TJriErvaaT03uKtX8t1gFh+JzG4GcriI="; + dontNpmBuild = true; # no build script, it's just a server + + installPhase = '' + runHook preInstall + mkdir -p $out/lib/simple-bar-server + cp -r . $out/lib/simple-bar-server/ + runHook postInstall + ''; + }; +in +{ + enable = true; + config = { + ProgramArguments = [ "${pkgs.nodejs}/bin/node" "${simple-bar-server}/lib/simple-bar-server/index.js" ]; + KeepAlive = true; + RunAtLoad = true; + StandardOutPath = "/tmp/simple-bar-server.out.log"; + StandardErrorPath = "/tmp/simple-bar-server.err.log"; + }; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/.github/FUNDING.yml b/users/ryan/modules/simple-bar/simple-bar-source/.github/FUNDING.yml new file mode 100755 index 0000000..0067695 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [Jean-Tinland] diff --git a/users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/bug_report.md b/users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100755 index 0000000..07e7338 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "" +labels: bug +assignees: "" +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Information (please complete the following information):** + +- OS version [e.g. Sonoma 14.1.1] +- yabai or AeroSpace version [e.g. yabai-v6.0.1] +- Übersicht version [e.g. Version 1.6 (82)] + +**Additional context** +Add any other context about the problem here. diff --git a/users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/documentation_error.md b/users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/documentation_error.md new file mode 100755 index 0000000..d0d287b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/documentation_error.md @@ -0,0 +1,21 @@ +--- +name: Documentation error +about: Create a report to help us improve +title: "" +labels: documentation +assignees: "" +--- + +**Describe the bug** +A clear and concise description of what the error is. + +**Where is located the error** + +Link to the documentation page where the error is located. + +**Expected content** + +What should be the correct content. + +**Additional context** +Add any other context about the problem here. diff --git a/users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/feature_request.md b/users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100755 index 0000000..d883b8f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "" +labels: enhancement +assignees: "" +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/users/ryan/modules/simple-bar/simple-bar-source/.github/pull_request_template.md b/users/ryan/modules/simple-bar/simple-bar-source/.github/pull_request_template.md new file mode 100755 index 0000000..d012be7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/.github/pull_request_template.md @@ -0,0 +1,38 @@ +# Description + +Please include a summary of the changes and the related issue. Please also include relevant motivation and context. List any dependencies that are required for this change. + +Fixes # (issue) + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +# How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration + +- [ ] Test A +- [ ] Test B + +**Test Configuration**: + +- OS version [e.g. Sonoma 14.1.1] +- yabai version [e.g. yabai-v6.0.1] (output of `yabai --version`) +- Übersicht version [e.g. Version 1.6 (82)] + +# Checklist: + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my code +- [ ] I have commented my code, particularly in hard-to-understand areas (make use of JSDoc if necessary) +- [ ] My changes generate no new warnings + +# Changes to make to the documentation + +Please list any changes to the documentation that are required to reflect your changes. diff --git a/users/ryan/modules/simple-bar/simple-bar-source/.gitignore b/users/ryan/modules/simple-bar/simple-bar-source/.gitignore new file mode 100755 index 0000000..7839ca3 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +.idea +/node_modules +yarn.lock diff --git a/users/ryan/modules/simple-bar/simple-bar-source/.prettierrc b/users/ryan/modules/simple-bar/simple-bar-source/.prettierrc new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/CODE_OF_CONDUCT.md b/users/ryan/modules/simple-bar/simple-bar-source/CODE_OF_CONDUCT.md new file mode 100755 index 0000000..f9218d4 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or + advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email + address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +https://www.jeantinland.com/contact/. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/users/ryan/modules/simple-bar/simple-bar-source/CONTRIBUTING.md b/users/ryan/modules/simple-bar/simple-bar-source/CONTRIBUTING.md new file mode 100755 index 0000000..13ec1f9 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/CONTRIBUTING.md @@ -0,0 +1,47 @@ +# Contributor guidelines + +## What do I need to know to help? + +If you are looking to help to with a code contribution our project uses **React** in a mac os application names **Übersicht**. It is build on top of **yabai**. If you don't feel ready to make a code contribution yet, no problem! You can also check out the [documentation issues](https://github.com/Jean-Tinland/simple-bar/issues). + +If you are interested in making a code contribution and would like to learn more about the technologies that we use, check out the list below. + +- [React documentation](https://react.dev/learn) +- [Übersicht documentation](https://github.com/felixhageloh/uebersicht#%C3%BCbersicht) +- [yabai documentation](https://github.com/koekeishiya/yabai) + +## Coding style conventions + +Your PR should: + +- Be formatted with prettier +- Pass the linter (run `yarn lint` to check) + +## How do I make a contribution? + +Never made an open source contribution before? Wondering how contributions work in the in our project? Here's a quick rundown! + +1. Find an issue that you are interested in addressing or a feature that you would like to add. +2. Fork the repository associated with the issue to your local GitHub organization. This means that you will have a copy of the repository under `your-GitHub-username/simple-bar`. +3. Clone the repository to your local machine using `git clone https://github.com/Jean-Tinland/simple-bar.git`. +4. Create a new branch for your fix using `git checkout -b branch-name-here`. +5. Make the appropriate changes for the issue you are trying to address or the feature that you want to add. +6. Use `git add insert-paths-of-changed-files-here` to add the file contents of the changed files to the "snapshot" git uses to manage the state of the project, also known as the index. +7. Use `git commit -m "Insert a short message of the changes made here"` to store the contents of the index with a descriptive message. +8. Push the changes to the remote repository using `git push origin branch-name-here`. +9. Submit a pull request to the upstream repository. +10. Title the pull request with a short description of the changes made and the issue or bug number associated with your change. For example, you can title an issue like so "Added more log outputting to resolve #4352". +11. In the description of the pull request, explain the changes that you made, any issues you think exist with the pull request you made, and any questions you have for the maintainer. It's OK if your pull request is not perfect (no pull request is), the reviewer will be able to help you fix any problems and improve it! +12. Wait for the pull request to be reviewed by a maintainer. +13. Make changes to the pull request if the reviewing maintainer recommends them. +14. Celebrate your success after your pull request is merged! + +## Where can I go for help? + +If you need help, you can ask questions on simple-bar's issue section on GitHub or with the contact form on [my website](https://www.jeantinland.com/en/contact/). + +## What does the Code of Conduct mean for me? + +Our Code of Conduct means that you are responsible for treating everyone on the project with respect and courtesy regardless of their identity. If you are the victim of any inappropriate behavior or comments as described in our Code of Conduct, we are here for you and will do the best to ensure that the abuser is reprimanded appropriately, per our code. + +> This contributor guide is adapted from the [opensource.com guide available here](https://opensource.com/life/16/3/contributor-guidelines-template-and-tips). diff --git a/users/ryan/modules/simple-bar/simple-bar-source/LICENSE b/users/ryan/modules/simple-bar/simple-bar-source/LICENSE new file mode 100755 index 0000000..bb64387 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Jean Tinland (https://www.jeantinland.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/users/ryan/modules/simple-bar/simple-bar-source/README.md b/users/ryan/modules/simple-bar/simple-bar-source/README.md new file mode 100755 index 0000000..e3523b9 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/README.md @@ -0,0 +1,73 @@ +# simple-bar + +A [yabai](https://github.com/koekeishiya/yabai) or [AeroSpace](https://github.com/nikitabobko/AeroSpace) status bar widget for [Übersicht](https://github.com/felixhageloh/uebersicht) inspired by [nibar](https://github.com/kkga/nibar), [yabar](https://github.com/AlexNaga/yabar) and [this reddit post](https://www.reddit.com/r/unixporn/comments/chwk89/yabai_yabai_and_gruvbox_with_custom_ubersicht_bar/). + +[Website](https://www.jeantinland.com/toolbox/simple-bar) • [Documentation](https://www.jeantinland.com/toolbox/simple-bar/documentation) + +[`simple-bar-server`](https://github.com/Jean-Tinland/simple-bar-server) is available to trigger refresh and toggle widgets more efficiently with `curl` commands. + +A more "lite" & basic version is available [here](https://github.com/Jean-Tinland/simple-bar-lite). + +**Notice: As I am working simultaneously on a lot of projects, things here may seem to move slowly but they are still in progress. I'm always monitoring my notifications and messages, so if you have any questions or want to chat about anything, feel free [to reach out](https://www.jeantinland.com/contact/)!** + +## Features + +Among the principal features of `simple-bar`, you'll find: + +- **Show all opened apps** in every space +- **Show all opened windows** on the current space and its current layout mode (bsp, stack, float) +- Interactions: **focus window** on click, launch scripts, toggle states +- **Multi-monitor support**: enable individual widget on specific displays +- Add your own custom widgets in settings (it displays scripts outputs) +- **Refresh and toggle parts of simple-bar on the fly** with `curl` commands by installing [simple-bar-server](https://www.jeantinland.com/toolbox/simple-bar-server/documentation/introduction/) and enabling the server in settings. See [widgets](https://www.jeantinland.com/toolbox/simple-bar-server/documentation/widgets/), [yabai](https://www.jeantinland.com/toolbox/simple-bar-server/documentation/yabai/) or [AeroSpace](https://www.jeantinland.com/toolbox/simple-bar-server/documentation/aerospace/) options in its documentation +- **Extensible** themes system with 3 theme behaviors: **dark**, **light**, or **system** +- Numerous customization options, try them out in settings! +- A handfull selection of widgets +- Other features available only with SIP disabled and yabai scripting addition installed (**navigate to workspace**, **create new workspace on "+" click**, **move or destroy workspace on space hover**) + +[See all features in documentation](https://www.jeantinland.com/toolbox/simple-bar/documentation/features/). + +## Preview + +![image](./images/preview.png) + + + +## Installation + +Simply clone this repo in your Übersicht widgets directory with the following command. + +```bash +git clone --depth 1 https://github.com/Jean-Tinland/simple-bar $HOME/Library/Application\ Support/Übersicht/widgets/simple-bar +``` + +You'll find the full installation guide in the [documentation](https://www.jeantinland.com/toolbox/simple-bar/documentation/installation/). + +> [!WARNING]\ +> If you encounter this error: "simple-bar-index.jsx: Something went wrong…", it may be simply due to the fact that the default value for yabai or AeroSpace path is wrong in simple-bar. You can set this path in the settings module.\ +> The default paths are `$(which yabai)` and `$(which aerospace)`. + +> [!NOTE]\ +> `simple-bar` is trying to use yabai by default. If you want to switch to AeroSpace, you'll need to open the settings module (simply click on `simple-bar` then press `cmd` + `,`). You'll find the window manager choice in the "Global" tab. + +> [!TIP]\ +> If you experience some freezing issues with Übersicht or if you simply want to improve `simple-bar` responsiveness & energy consumption, please try to switch to `simple-bar-server` in order to trigger refresh with `curl` commands. You'll find more information about it in the repo [here](https://github.com/Jean-Tinland/simple-bar-server). + +## Roadmap + +Here are the features I'm planning to add in the future: + +- A timer widget ([#474](https://github.com/Jean-Tinland/simple-bar/issues/474)) +- Bars configurator (spawn multiple bars, place widgets anywhere…) [#380](https://github.com/Jean-Tinland/simple-bar/issues/380) +- More accessibility settings like reading direction (LTR or RTL) +- More default themes + +Feel free to open an issue if you have any feature request or if you want me to prioritize one of these features. + +## Special thanks + +I started this project with a simple idea and inspired by similar projects but over the year it has become a real community project. I want to thank everyone who contributed to this project, whether it's by opening issues, suggesting features, or even making pull requests. Furthermore, I also want to thank everyone who is using this project, I'm glad to see that it can be useful to others. + +So thank you, [@Amar1729](https://github.com/Amar1729), [@yorhodes](https://github.com/yorhodes), [@ZhongXiLu](https://github.com/ZhongXiLu), [@jamieweavis](https://github.com/jamieweavis), [@kvndrsslr](https://github.com/kvndrsslr), [@rosenpin](https://github.com/rosenpin), [@MikoMagni](https://github.com/MikoMagni), [@anujc4](https://github.com/anujc4), [@SijanC147](https://github.com/SijanC147), [@donaldguy](https://github.com/donaldguy), [@d-miketa](https://github.com/d-miketa), [@izifortune](https://github.com/izifortune), [@theshortcut](https://github.com/theshortcut), [@jming422](https://github.com/jming422), [@s00500](https://github.com/s00500), [@spwx](https://github.com/spwx), [@basbebe](https://github.com/basbebe), [@is0n](https://github.com/is0n), [@Joroovb](https://github.com/Joroovb), [@Sylenss](https://github.com/Sylenss), [@mrzone64](https://github.com/mrzone64), [@devinbhatt](https://github.com/devinbhatt), [@mdwitr0](https://github.com/mdwitr0), [@wr1159](https://github.com/wr1159), [@ardnep](https://github.com/ardnep), [@kntng](https://github.com/kntng) and every other that are helping me improve this little project by adding icons, fixing what they can, and more… + +I tried to keep track of everyone who contributed to this project in every page of the documentation. If you think I forgot you, please let me know. :) diff --git a/users/ryan/modules/simple-bar/simple-bar-source/SECURITY.md b/users/ryan/modules/simple-bar/simple-bar-source/SECURITY.md new file mode 100755 index 0000000..1779c21 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/SECURITY.md @@ -0,0 +1,9 @@ +# Security Policy + +## Supported Versions + +Only `simple-bar` latest version is supported (latest commit on master branch). + +## Reporting a Vulnerability + +If you think you have detected a vulnerability, please open a new issue in `simple-bar`'s repo, [here](https://github.com/Jean-Tinland/simple-bar/issues). diff --git a/users/ryan/modules/simple-bar/simple-bar-source/eslint.config.mjs b/users/ryan/modules/simple-bar/simple-bar-source/eslint.config.mjs new file mode 100755 index 0000000..378720e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/eslint.config.mjs @@ -0,0 +1,52 @@ +// eslint.config.js +import js from "@eslint/js"; +import globals from "globals"; +import reactPlugin from "eslint-plugin-react"; +import reactHooks from "eslint-plugin-react-hooks"; + +export default [ + { + files: ["**/*.{js,jsx}"], + languageOptions: { + ecmaVersion: 12, + sourceType: "module", + globals: { + ...globals.browser, + }, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + plugins: { + react: reactPlugin, + "react-hooks": reactHooks, + }, + rules: { + // Base ESLint recommended rules + ...js.configs.recommended.rules, + + // React recommended rules + ...reactPlugin.configs.recommended.rules, + + // React hooks recommended rules + ...reactHooks.configs.recommended.rules, + + // Your custom rules + "no-console": "warn", + "react/prop-types": "off", + "react/react-in-jsx-scope": "off", + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", + "react-hooks/preserve-manual-memoization": "off", + "react-hooks/immutability": "off", + "react/no-unescaped-entities": "off", + }, + settings: { + react: { + version: "18.0", + }, + }, + }, +]; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/images/logo-simple-bar.png b/users/ryan/modules/simple-bar/simple-bar-source/images/logo-simple-bar.png new file mode 100755 index 0000000..4d1f5e4 Binary files /dev/null and b/users/ryan/modules/simple-bar/simple-bar-source/images/logo-simple-bar.png differ diff --git a/users/ryan/modules/simple-bar/simple-bar-source/images/preview.png b/users/ryan/modules/simple-bar/simple-bar-source/images/preview.png new file mode 100755 index 0000000..4c68dae Binary files /dev/null and b/users/ryan/modules/simple-bar/simple-bar-source/images/preview.png differ diff --git a/users/ryan/modules/simple-bar/simple-bar-source/index.jsx b/users/ryan/modules/simple-bar/simple-bar-source/index.jsx new file mode 100755 index 0000000..bc817ab --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/index.jsx @@ -0,0 +1,267 @@ +import * as Uebersicht from "uebersicht"; +import * as Error from "./lib/components/error.jsx"; +import SimpleBarContextProvider from "./lib/components/simple-bar-context.jsx"; +import UserWidgets from "./lib/components/data/user-widgets.jsx"; +// Each simple-bar widgets exports both a "Component" or "Widget" render function +// and a "styles" string containing its own CSS +import * as Variables from "./lib/styles/core/variables"; +import * as Base from "./lib/styles/core/base"; +import * as Spaces from "./lib/styles/components/spaces/spaces"; +import * as Process from "./lib/styles/components/process"; +import * as Zoom from "./lib/components/data/zoom.jsx"; +import * as Time from "./lib/components/data/time.jsx"; +import * as DateDisplay from "./lib/components/data/date-display.jsx"; +import * as GitHub from "./lib/components/data/github.jsx"; +import * as Weather from "./lib/components/data/weather.jsx"; +import * as Netstats from "./lib/components/data/netstats.jsx"; +import * as Cpu from "./lib/components/data/cpu.jsx"; +import * as Gpu from "./lib/components/data/gpu.jsx"; +import * as Memory from "./lib/components/data/memory.jsx"; +import * as Battery from "./lib/components/data/battery.jsx"; +import * as Sound from "./lib/components/data/sound.jsx"; +import * as Mic from "./lib/components/data/mic.jsx"; +import * as Wifi from "./lib/components/data/wifi.jsx"; +import * as ViscosityVPN from "./lib/components/data/viscosity-vpn.jsx"; +import * as Keyboard from "./lib/components/data/keyboard.jsx"; +import * as Spotify from "./lib/components/data/spotify.jsx"; +import * as YouTubeMusic from "./lib/components/data/youtube-music.jsx"; +import * as Crypto from "./lib/components/data/crypto.jsx"; +import * as Stock from "./lib/components/data/stock.jsx"; +import * as Music from "./lib/components/data/music.jsx"; +import * as Mpd from "./lib/components/data/mpd.jsx"; +import * as BrowserTrack from "./lib/components/data/browser-track.jsx"; +import * as Notifications from "./lib/components/data/notifications.jsx"; +import * as NextMeeting from "./lib/components/data/next-meeting.jsx"; +import * as Specter from "./lib/components/data/specter.jsx"; +import * as Graph from "./lib/components/data/graph.jsx"; +import * as DataWidgetLoader from "./lib/components/data/data-widget-loader.jsx"; +import * as DataWidget from "./lib/components/data/data-widget.jsx"; +import * as SideIcon from "./lib/components/side-icon.jsx"; +import * as Missives from "./lib/components/missives/missives.jsx"; +import * as Utils from "./lib/utils"; +import * as Settings from "./lib/settings"; + +// Destructure React from Uebersicht in order to make eslint catch hook rules for example +const { React } = Uebersicht; + +// Spaces & process components are lazy loaded to avoid loading them when not needed +const YabaiContextProvider = React.lazy( + () => import("./lib/components/yabai-context.jsx"), +); +const AerospaceContextProvider = React.lazy( + () => import("./lib/components/aerospace-context.jsx"), +); +const YabaiSpaces = React.lazy( + () => import("./lib/components/yabai/spaces.jsx"), +); +const YabaiProcess = React.lazy( + () => import("./lib/components/yabai/process.jsx"), +); +const AerospaceSpaces = React.lazy( + () => import("./lib/components/aerospace/spaces.jsx"), +); +const AerospaceProcess = React.lazy( + () => import("./lib/components/aerospace/process.jsx"), +); + +// Set refresh frequency to false +// Übersicht auto-refresh system is not required as simple-bar works in sync with +// yabai or AeroSpaces for spaces & process widgets and data widgets are refreshed with +// their local refresh functions +const refreshFrequency = false; + +// Init settings from file if existing +Settings.init(); + +// Get settings from the Settings module +const settings = Settings.get(); +const { + // Do not edit the yabaiPath or aerospacePath lines, theses values are simply + // a default value used if nothing is defined in settings. + // You can setup your custom yabai or AeroSpace path in the settings module (Global tab) : + // while on an empty workspace, click on simple-bar then press cmd + , to open it. + yabaiPath = "/opt/homebrew/bin/yabai", + aerospacePath = "/opt/homebrew/bin/aerospace", + windowManager, // Window manager type (yabai or aerospace) + shell, // Shell to use for commands + enableServer, // Enable server mode + yabaiServerRefresh, // Refresh rate for yabai server +} = settings.global; +const { hideWindowTitle, displayOnlyIcon, displaySkhdMode } = settings.process; + +// Determine if signals should be disabled based on settings +const disableSignals = enableServer && yabaiServerRefresh; +const enableTitleChangedSignal = !hideWindowTitle && !displayOnlyIcon; + +// Construct command arguments based on window manager type +const yabaiArgs = `${yabaiPath} ${displaySkhdMode} ${disableSignals} ${enableTitleChangedSignal}`; +const aerospaceArgs = `${aerospacePath}`; +const args = getArguments(windowManager, yabaiArgs, aerospaceArgs); +const command = `${shell} simple-bar/lib/scripts/init-${windowManager}.sh ${args}`; + +// Inject global styles into the document +// I prefer using native CSS instead of Emotion bundled by default in Übersicht +Utils.injectStyles("simple-bar-index-styles", [ + Variables.styles, + Base.styles, + Spaces.styles, + Process.styles, + Settings.styles, + DataWidget.styles, + DateDisplay.styles, + Zoom.styles, + Time.styles, + GitHub.styles, + Weather.styles, + Netstats.styles, + Cpu.styles, + Gpu.styles, + Memory.styles, + Crypto.styles, + Stock.styles, + Battery.styles, + Wifi.styles, + ViscosityVPN.styles, + Keyboard.styles, + Mic.styles, + Sound.styles, + Spotify.styles, + YouTubeMusic.styles, + Music.styles, + Mpd.styles, + BrowserTrack.styles, + Notifications.styles, + NextMeeting.styles, + Specter.styles, + Graph.styles, + DataWidgetLoader.styles, + settings.customStyles.styles, + SideIcon.styles, + Missives.styles, +]); + +// Render function to display the bar +function render({ output, error }) { + // Define base classes for the bar based on settings + const baseClasses = Utils.classNames("simple-bar", { + "simple-bar--floating": settings.global.floatingBar, + "simple-bar--no-bar-background": settings.global.noBarBg, + "simple-bar--no-color-in-data": settings.global.noColorInData, + "simple-bar--on-bottom": settings.global.bottomBar, + "simple-bar--inline-spaces-options": settings.global.inlineSpacesOptions, + "simple-bar--animations-disabled": settings.global.disableAnimations, + "simple-bar--spaces-background-color-as-foreground": + settings.global.spacesBackgroundColorAsForeground, + "simple-bar--widgets-background-color-as-foreground": + settings.global.widgetsBackgroundColorAsForeground, + "simple-bar--process-aligned-to-left": !settings.global.centered, + }); + + // Handle errors + if (error) { + // eslint-disable-next-line no-console + console.error("Error in index.jsx", error); + return ; + } + if (!output) { + return ; + } + + // Cleanup the output data + const cleanedUpOutput = Utils.cleanupOutput(output); + + // Handle specific errors related to yabai or AeroSpace + const errors = ["yabaiError", "aerospaceError"]; + if (errors.includes(cleanedUpOutput)) { + return ; + } + + // Parse the output data + const data = Utils.parseJson(cleanedUpOutput); + if (!data) return ; + + const { displays, shadow, skhdMode, SIP, spaces, windows } = data; + + // Check if SIP (System Integrity Protection) is disabled + const SIPDisabled = SIP !== "System Integrity Protection status: enabled."; + + // Define additional classes based on data + const classes = Utils.classNames(baseClasses, { + "simple-bar--no-shadow": shadow !== "on", + }); + + // Handle bar focus ring on click + Utils.handleBarFocus(); + + // Render the bar with appropriate components and data + return ( + +
+ + }> + {windowManager === "yabai" && ( + + + + + )} + {windowManager === "aerospace" && ( + + + + + )} + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ ); +} + +export { command, refreshFrequency, render }; + +function getArguments(windowManager, yabaiArgs, aerospaceArgs) { + if (windowManager === "yabai") { + return yabaiArgs; + } + if (windowManager === "aerospace") { + return aerospaceArgs; + } + return ""; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/aerospace.js b/users/ryan/modules/simple-bar/simple-bar-source/lib/aerospace.js new file mode 100755 index 0000000..5b403b1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/aerospace.js @@ -0,0 +1,102 @@ +import * as Uebersicht from "uebersicht"; +import * as Settings from "./settings"; +import * as Utils from "./utils"; + +/** + * Switches to the specified workspace. + * @param {number} index - The index of the workspace to switch to. + */ +export async function goToSpace(index) { + const settings = Settings.get(); + const { aerospacePath = "/opt/homebrew/bin/aerospace" } = settings.global; + await Uebersicht.run(`${aerospacePath} workspace ${index}`); +} + +/** + * Focuses the window with the specified ID. + * @param {number} id - The ID of the window to focus. + */ +export async function focusWindow(id) { + const settings = Settings.get(); + const { aerospacePath = "/opt/homebrew/bin/aerospace" } = settings.global; + await Uebersicht.run(`${aerospacePath} focus --window-id ${id}`); +} + +/** + * Retrieves the list of workspaces for the specified display. + * @param {number} displayId - The ID of the display. + * @returns {Promise} The list of workspaces. + */ +export async function getSpaces(displayId) { + const settings = Settings.get(); + const { aerospacePath = "/opt/homebrew/bin/aerospace" } = settings.global; + const json = await Uebersicht.run( + `${aerospacePath} list-workspaces --monitor ${displayId} --json --format "%{workspace} %{monitor-appkit-nsscreen-screens-id}"` + ); + return Utils.parseJson(json); +} + +/** + * Retrieves the currently focused workspace. + * @returns {Promise} The focused workspace. + */ +export async function getFocusedSpace() { + const settings = Settings.get(); + const { aerospacePath = "/opt/homebrew/bin/aerospace" } = settings.global; + const json = await Uebersicht.run( + `${aerospacePath} list-workspaces --focused --json` + ); + return Utils.parseJson(json); +} + +/** + * Retrieves the list of windows for the specified workspace. + * @param {number} workspaceId - The ID of the workspace. + * @returns {Promise} The list of windows. + */ +export async function getWindows(workspaceId) { + const settings = Settings.get(); + const { aerospacePath = "/opt/homebrew/bin/aerospace" } = settings.global; + const json = await Uebersicht.run( + `${aerospacePath} list-windows --workspace ${workspaceId} --json` + ); + const cleanedJson = json.replace(/\\\n/g, "").replace(/00000/g, "0"); + return Utils.parseJson(cleanedJson); +} + +/** + * Retrieves the currently focused window. + * @returns {Promise} The focused window. + */ +export async function getFocusedWindow() { + const settings = Settings.get(); + const { aerospacePath = "/opt/homebrew/bin/aerospace" } = settings.global; + const json = await Uebersicht.run( + `${aerospacePath} list-windows --focused --json` + ); + return Utils.parseJson(json); +} + +/** + * Retrieves the list of displays. + * @returns {Promise} The list of displays. + */ +export async function getDisplays() { + const settings = Settings.get(); + const { aerospacePath = "/opt/homebrew/bin/aerospace" } = settings.global; + const json = await Uebersicht.run(`${aerospacePath} list-monitors --json`); + return Utils.parseJson(json); +} + +/** + * Retrieves the custom display index for the specified display. + * @param {Object} display - The display object. + * @returns {number} The custom display index. + */ +export function getDisplayIndex(item) { + const settings = Settings.get(); + const { customAeroSpaceDisplayIndexes } = settings.spacesDisplay; + const nativeId = item["monitor-appkit-nsscreen-screens-id"]; + const customId = customAeroSpaceDisplayIndexes[nativeId]; + return customId || nativeId; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/app-icons.js b/users/ryan/modules/simple-bar/simple-bar-source/lib/app-icons.js new file mode 100755 index 0000000..3eef38d --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/app-icons.js @@ -0,0 +1,254 @@ +import * as Icons from "./components/icons/icons.jsx"; + +// List of supported apps and their corresponding icons +export const apps = { + "1Password 7": Icons.OnePassword, + "1Password": Icons.OnePassword, + "Acrobat Reader": Icons.PDF, + "Activity Monitor": Icons.Activity, + "Affinity Designer": Icons.AffinityDesigner, + "Affinity Photo": Icons.AffinityPhoto, + "Affinity Publisher": Icons.AffinityPublisher, + Airmail: Icons.Airmail, + Alacritty: Icons.Terminal, + Alfred: Icons.Alfred, + "Android Messages": Icons.AndroidMessages, + "Android Studio": Icons.AndroidStudio, + Anki: Icons.Anki, + Antigravity: Icons.Antigravity, + Anytype: Icons.Anytype, + "App Store": Icons.AppStore, + Arc: Icons.Arc, + Atom: Icons.Atom, + "Apple Simulator": Icons.AppleSimulator, + Audacity: Icons.Audacity, + Aqua: Icons.Aqua, + "Battle.net": Icons.BattleNet, + "Bambu Studio": Icons.BambuStudio, + Bear: Icons.Bear, + "Beekeeper Studio": Icons.Beekeeper, + Bitwarden: Icons.BitWarden, + Blender: Icons.Blender, + "Brave Browser": Icons.BraveBrowser, + Bruno: Icons.Bruno, + Claude: Icons.Claude, + ClaudeCode: Icons.ClaudeCode, + Cline: Icons.Cline, + CLion: Icons.CLion, + Calendar: Icons.Calendar, + Calibre: Icons.Book, + "Canary Mail": Icons.Mail, + Caprine: Icons.Caprine, + CARROT: Icons.CARROT, + ChatGPT: Icons.ChatGPT, + Chatterino: Icons.Chatterino, + Chromium: Icons.GoogleChrome, + "CleanMyMac X": Icons.Desktop, + ClickUp: Icons.ClickUp, + "Code - Insiders": Icons.Code, + Code: Icons.Code, + Codex: Icons.Codex, + "Color Picker": Icons.ColorPicker, + ComfyUI: Icons.ComfyUI, + Copilot: Icons.Copilot, + Cursor: Icons.Cursor, + DataGrip: Icons.DataGrip, + Deezer: Icons.Deezer, + Default: Icons.Default, + "DEVONthink 3": Icons.DEVONthink3, + "Discord Canary": Icons.Discord, + "Discord PTB": Icons.Discord, + Discord: Icons.Discord, + "Docker Desktop": Icons.Docker, + Drafts: Icons.Drafts, + Dropbox: Icons.Dropbox, + Element: Icons.Element, + Emacs: Icons.Emacs, + "Evernote Legacy": Icons.EvernoteLegacy, + FaceTime: Icons.FaceTime, + Fantastical: Icons.Calendar, + Figma: Icons.Figma, + "Figma Beta": Icons.Figma, + "Final Cut Pro": Icons.FinalCutPro, + "Find My": Icons.Radar, + Finder: Icons.Finder, + "Firefox Developer Edition": Icons.FirefoxDeveloperEdition, + "Firefox Nightly": Icons.FirefoxDeveloperEdition, + Firefox: Icons.Firefox, + Fleet: Icons.Fleet, + Folx: Icons.Folx, + FreeTube: Icons.FreeTube, + Ghostty: Icons.Ghostty, + "GitHub Desktop": Icons.GitHub, + Gnucash: Icons.GnuCash, + GoLand: Icons.GoLand, + GoodNotes: Icons.GoodNotes, + "Google Chrome Canary": Icons.GoogleChrome, + "Google Chrome": Icons.GoogleChrome, + Goose: Icons.Goose, + "Grammarly Editor": Icons.Grammarly, + GrandTotal: Icons.Dollar, + Helium: Icons.Helium, + HEY: Icons.Mail, + "Home Assistant": Icons.HomeAssistant, + HTTPie: Icons.HTTPie, + Hyper: Icons.Terminal, + Insomnia: Icons.Insomnia, + "IntelliJ IDEA": Icons.Idea, + Iris: Icons.Iris, + iTerm2: Icons.Terminal, + Joplin: Icons.Joplin, + Kakoune: Icons.Kakoune, + KeePassXC: Icons.KeePassXC, + "Keyboard Maestro": Icons.KeyboardMaestro, + Keynote: Icons.Keynote, + kitty: Icons.Terminal, + "League of Legends": Icons.LeagueOfLegends, + LibreWolf: Icons.LibreWolf, + Linear: Icons.Linear, + Live: Icons.Ableton, + "LM Studio": Icons.LMStudio, + MacVim: Icons.Vim, + Mail: Icons.Mail, + MailMate: Icons.Mail, + Mailspring: Icons.Mail, + "MAMP PRO": Icons.Mamp, + MAMP: Icons.Mamp, + Maestro: Icons.MaestroAI, + Manus: Icons.Manus, + Matlab: Icons.Matlab, + Mattermost: Icons.Mattermost, + Messages: Icons.Messages, + "Microsoft Edge": Icons.MicrosoftEdge, + "Microsoft Excel": Icons.MicrosoftExcel, + "Microsoft Outlook": Icons.MicrosoftOutlook, + "Microsoft PowerPoint": Icons.MicrosoftPowerPoint, + "Microsoft Teams": Icons.Teams, + "Microsoft To Do": Icons.Things, + "Microsoft Word": Icons.MicrosoftWord, + Mimestream: Icons.Mimestream, + Min: Icons.MinBrowser, + Miro: Icons.Miro, + "Monero GUI": Icons.MoneroGUI, + "MongoDB Compass": Icons.MongoDB, + MoneyMoney: Icons.Bank, + mpv: Icons.Mpv, + Music: Icons.Music, + n8n: Icons.N8n, + Neovide: Icons.Vim, + NetNewsWire: Icons.NetNewsWire, + Notability: Icons.Notability, + NotebookLM: Icons.NotebookLM, + Notes: Icons.Notes, + Notion: Icons.Notion, + Nova: Icons.Nova, + Numbers: Icons.Numbers, + "OBS Studio": Icons.OBSStudio, + OBS: Icons.OBSStudio, + Obsidian: Icons.Obsidian, + Ollama: Icons.Ollama, + OmniFocus: Icons.OmniFocus, + OpenClaw: Icons.OpenClaw, + opencode: Icons.Opencode, + OrbStack: Icons.OrbStack, + Pages: Icons.Pages, + "Parallels Desktop": Icons.Parallels, + Perplexity: Icons.Perplexity, + "Pi-hole Remote": Icons.Pihole, + Pine: Icons.Pine, + Pins: Icons.Pins, + Podcasts: Icons.Podcasts, + "PomoDone App": Icons.Pomodone, + Postman: Icons.Postman, + "Proton Mail": Icons.ProtonMail, + PyCharm: Icons.PyCharm, + Preview: Icons.PDF, + PHPStorm: Icons.PHPStorm, + Plex: Icons.Plex, + Quip: Icons.Quip, + qutebrowser: Icons.QuteBrowser, + Receipts: Icons.Dollar, + "Redis Insight": Icons.Redis, + Reeder: Icons.Reeder5, + Reminders: Icons.Reminders, + Remnote: Icons.Remnote, + "Remote Desktop": Icons.RemoteDesktop, + Replit: Icons.Replit, + Rider: Icons.Rider, + "Rocket.Chat": Icons.RocketChat, + Roon: Icons.Roon, + "Royal TSX": Icons.RoyalTSX, + RubyMine: Icons.RubyMine, + RustRover: Icons.RustRover, + "Safari Technology Preview": Icons.Safari, + Safari: Icons.Safari, + Screens4: Icons.Screens4, + "Sequel Ace": Icons.SequelAce, + "Sequel Pro": Icons.SequelPro, + Setapp: Icons.Setapp, + Signal: Icons.Signal, + sioyek: Icons.PDF, + Sketch: Icons.Sketch, + SketchUp: Icons.SketchUp, + Skim: Icons.PDF, + Skype: Icons.Skype, + Slack: Icons.Slack, + Spark: Icons.Spark, + Spotify: Icons.Spotify, + Spotlight: Icons.Spotlight, + spotube: Icons.Spotube, + Spotube: Icons.Spotube, + "Sublime Text": Icons.SublimeText, + "Super Productivity": Icons.SuperProductivity, + "System Preferences": Icons.Gear, + "System Settings": Icons.Gear, + TablePlus: Icons.TablePlus, + Tailscale: Icons.Tailscale, + "TeamSpeak 3": Icons.TeamSpeak, + Telegram: Icons.Telegram, + Terminal: Icons.Terminal, + Texts: Icons.Messages, + Things: Icons.Things, + Thunderbird: Icons.Thunderbird, + TickTick: Icons.TickTick, + TIDAL: Icons.Tidal, + Todoist: Icons.Todoist, + "Tor Browser": Icons.TorBrowser, + Tower: Icons.Tower, + Transmit: Icons.Transmit, + Trello: Icons.Trello, + Tweetbot: Icons.Twitter, + Twitter: Icons.Twitter, + Typora: Icons.Text, + Vim: Icons.Vim, + VimR: Icons.Vim, + Vivaldi: Icons.Vivaldi, + VLC: Icons.VLC, + "VMware Fusion": Icons.VMwareFusion, + VSCodium: Icons.VSCodium, + Warp: Icons.Warp, + WebStorm: Icons.WebStorm, + WezTerm: Icons.Terminal, + WhatsApp: Icons.WhatsApp, + "Windows App": Icons.Windows, + Xcode: Icons.Xcode, + "YouTube Music": Icons.YoutubeMusic, + zathura: Icons.PDF, + Zed: Icons.Zed, + Zen: Icons.ZenBrowser, + Zeplin: Icons.Zeplin, + "zoom.us": Icons.Zoom, + Zotero: Icons.Zotero, + Zulip: Icons.Zulip, + + // German app names + Musik: Icons.Music, + Kalender: Icons.Calendar, + Nachrichten: Icons.Messages, + + // Chinese app names + 访达: Icons.Finder, + 邮件: Icons.Mail, + 微信: Icons.Wechat, + 网易云音乐: Icons.NeteaseMusic, +}; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace-context.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace-context.jsx new file mode 100755 index 0000000..f780a71 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace-context.jsx @@ -0,0 +1,117 @@ +import * as Uebersicht from "uebersicht"; +import { useSimpleBarContext } from "./simple-bar-context.jsx"; +import useServerSocket from "../hooks/use-server-socket.js"; +import * as Aerospace from "../aerospace.js"; + +const { React } = Uebersicht; + +// Create a context with default values +const AerospaceContext = React.createContext({ + spaces: [], + windows: [], + mode: "", +}); + +/** + * Custom hook to use the AerospaceContext + * @returns {Object} The context value + */ +export function useAerospaceContext() { + return React.useContext(AerospaceContext); +} + +// Memoized AerospaceContextProvider component +export default React.memo(AerospaceContextProvider); + +/** + * AerospaceContextProvider component + * @param {Object} props - The component props + * @param {React.ReactNode} props.children - The child components + * @returns {JSX.Element} The provider component + */ +function AerospaceContextProvider({ children }) { + // Get settings, displayIndex, and displays from SimpleBarContext + const { settings, displayIndex, displays } = useSimpleBarContext(); + const { enableServer, aerospaceServerRefresh } = settings.global; + const serverEnabled = enableServer && aerospaceServerRefresh; + + // State to store aerospace spaces + const [aerospaceSpaces, setAerospaceSpaces] = React.useState([]); + const latestRequestRef = React.useRef(0); + + // Fetches and sets the aerospace spaces + const getSpaces = React.useCallback(async () => { + const requestId = latestRequestRef.current + 1; + latestRequestRef.current = requestId; + + let focusedWindow = {}; + const [focusedSpace] = await Aerospace.getFocusedSpace(); + try { + [focusedWindow] = await Aerospace.getFocusedWindow(); + // eslint-disable-next-line no-empty + } catch {} + const spaces = await Promise.all( + displays.map(async (display) => { + const id = display["monitor-id"]; + const result = await Aerospace.getSpaces(id); + return Promise.all( + result.map(async (space) => { + const focused = space.workspace === focusedSpace.workspace; + const monitor = Aerospace.getDisplayIndex(space); + const windows = await Aerospace.getWindows(space.workspace); + const formatted = windows.map((window) => { + const focused = + window["window-id"] === focusedWindow["window-id"]; + return { + ...window, + focused, + }; + }); + return { ...space, windows: formatted, focused, monitor }; + }) + ); + }) + ); + if (requestId !== latestRequestRef.current) { + return; + } + setAerospaceSpaces(spaces.flat()); + }, [displays]); + + // Refreshes spaces with the data sent by simple-bar-server if it exists + // in order to speed up the process then refreshes everything in background + // else, simply refreshes everything + const refreshSpaces = React.useCallback( + async (data) => { + if (data) { + const { space } = data; + setAerospaceSpaces((current) => { + return current.map((s) => ({ ...s, focused: s.workspace === space })); + }); + getSpaces(); + } else { + await getSpaces(); + } + }, + [getSpaces] + ); + + // Resets the aerospace spaces state + const resetSpaces = () => { + setAerospaceSpaces([]); + }; + + // Use server socket to fetch and reset spaces + useServerSocket("spaces", serverEnabled, refreshSpaces, resetSpaces); + + // Fetch spaces on component mount and when displayIndex changes + React.useEffect(() => { + refreshSpaces(); + }, [refreshSpaces, displayIndex]); + + return ( + + {children} + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/opened-apps.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/opened-apps.jsx new file mode 100755 index 0000000..5b56966 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/opened-apps.jsx @@ -0,0 +1,33 @@ +import * as Uebersicht from "uebersicht"; +import * as AppIcons from "../../app-icons.js"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import * as Utils from "../../utils.js"; + +const { React } = Uebersicht; + +/** + * OpenedApps component to display icons of opened applications. + * @param {Object} props - The component props. + * @param {Array} props.apps - The list of opened applications. + * @returns {JSX.Element|null} The rendered component or null if no apps are opened. + */ +export default function OpenedApps({ apps }) { + if (!apps.length) return null; + + return apps.map((app, i) => { + const { focused } = app; + const appName = Utils.normalizeAppName(app["app-name"]); + const Icon = AppIcons.apps[appName] || AppIcons.apps.Default; + + // Generate class names for the app icon + const classes = Utils.classNames("space__icon", { + "space__icon--focused": focused, + }); + + return ( + + + + ); + }); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/process.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/process.jsx new file mode 100755 index 0000000..0c461cc --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/process.jsx @@ -0,0 +1,72 @@ +import * as Uebersicht from "uebersicht"; +import Window from "./window.jsx"; +import * as Utils from "../../utils"; +import { useAerospaceContext } from "../aerospace-context.jsx"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; + +export { processStyles as styles } from "../../styles/components/process"; + +const { React } = Uebersicht; + +/** + * Process component to display windows in the current space. + * @returns {JSX.Element|null} The rendered component or null if not visible. + */ +const Component = React.memo(() => { + // Get spaces from aerospace context + const { spaces } = useAerospaceContext(); + // Get settings and display index from simple bar context + const { settings, displayIndex } = useSimpleBarContext(); + const { spacesDisplay, process, widgets } = settings; + const { exclusionsAsRegex } = spacesDisplay; + const { processWidget } = widgets; + const { centered, showOnDisplay } = process; + + // Determine if the component should be visible + const visible = + spaces?.length && + processWidget && + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay); + + if (!visible) return null; + + // Find the focused space on the current display + const { windows = [] } = + spaces.find((space) => space.focused && space.monitor === displayIndex) || + {}; + + if (!windows.length) return null; + + // Get exclusions for filtering windows + const exclusions = exclusionsAsRegex + ? spacesDisplay.exclusions + : spacesDisplay.exclusions.split(", "); + + const titleExclusions = exclusionsAsRegex + ? spacesDisplay.titleExclusions + : spacesDisplay.titleExclusions.split(", "); + + // Generate class names for the component + const classes = Utils.classNames("process", { + "process--centered": centered, + }); + + // Filter windows based on exclusions + const filteredWindows = windows.filter((window) => + Utils.filterApps(window, exclusions, titleExclusions, exclusionsAsRegex), + ); + + return ( +
+
+ {filteredWindows.map((window, i) => ( + + ))} +
+
+ ); +}); + +Component.displayName = "Process"; + +export default Component; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/space.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/space.jsx new file mode 100755 index 0000000..ab91bbb --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/space.jsx @@ -0,0 +1,84 @@ +import * as Uebersicht from "uebersicht"; +import OpenedApps from "./opened-apps.jsx"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils.js"; +import * as Aerospace from "../../aerospace.js"; + +const { React } = Uebersicht; + +/** + * Space component to display a single space. + * @param {Object} props - The component props. + * @param {Object} props.space - The space object. + * @param {boolean} props.lastOfSpace - Indicates if this is the last space of the monitor. + * @returns {JSX.Element|null} The rendered component. + */ +export default function Space({ space, lastOfSpace }) { + const { windows } = space; + const { settings } = useSimpleBarContext(); + const { spacesDisplay } = settings; + const { + displayAllSpacesOnAllScreens, + exclusionsAsRegex, + hideDuplicateAppsInSpaces, + } = spacesDisplay; + const { workspace, focused } = space; + + /** + * Handle click event to switch to the clicked space. + * @param {Event} e - The click event. + */ + const onClick = (e) => { + if (focused) return; + Aerospace.goToSpace(workspace); + Utils.clickEffect(e); + }; + + // Determine if the space should be hidden + const hidden = !focused && !windows.length && spacesDisplay.hideEmptySpaces; + + if (hidden) return null; + + // Get exclusions and title exclusions based on settings + const exclusions = exclusionsAsRegex + ? spacesDisplay.exclusions + : spacesDisplay.exclusions.split(", "); + const titleExclusions = exclusionsAsRegex + ? spacesDisplay.titleExclusions + : spacesDisplay.titleExclusions.split(", "); + + // Filter windows based on exclusions + const filteredWindows = windows.filter((window) => + Utils.filterApps(window, exclusions, titleExclusions, exclusionsAsRegex), + ); + + // Remove duplicate apps if the setting is enabled + const displayedWindows = hideDuplicateAppsInSpaces + ? filteredWindows.reduce((acc, window) => { + const isDuplicate = acc.find( + (w) => w["app-name"] === window["app-name"], + ); + return isDuplicate ? acc : [...acc, window]; + }, []) + : filteredWindows; + + // Determine the CSS classes for the space + const classes = Utils.classNames("space", { + "space--focused": focused, + "space--empty": windows.length, + }); + + return ( + + {displayAllSpacesOnAllScreens && lastOfSpace && ( +
+ )} +
+ +
+ + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/spaces.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/spaces.jsx new file mode 100755 index 0000000..d576389 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/spaces.jsx @@ -0,0 +1,67 @@ +import * as Uebersicht from "uebersicht"; +import Space from "./space.jsx"; +import { useAerospaceContext } from "../aerospace-context.jsx"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils.js"; +import * as AeroSpace from "../../aerospace.js"; + +export { spacesStyles as styles } from "../../styles/components/spaces/spaces.js"; + +const { React } = Uebersicht; + +/** + * Spaces component to display spaces on the screen. + * @returns {JSX.Element|null} The rendered component. + */ +const Component = React.memo(() => { + // Get spaces from aerospace context + const { spaces } = useAerospaceContext(); + // Get displays, displayIndex, and settings from simple bar context + const { displays, displayIndex, settings } = useSimpleBarContext(); + const { spacesDisplay, process } = settings; + const { displayAllSpacesOnAllScreens, showOnDisplay } = spacesDisplay; + // Determine if the component should be visible on the current display + const visible = Utils.isVisibleOnDisplay(displayIndex, showOnDisplay); + const isProcessVisible = Utils.isVisibleOnDisplay( + displayIndex, + process.showOnDisplay + ); + + // If not visible, return null + if (!visible) return null; + + // If there are no spaces, return an empty div + if (!spaces?.length) { + return
; + } + + // Map through displays and render spaces for the current display + return displays.map((display) => { + const displayId = AeroSpace.getDisplayIndex(display); + if (displayId !== displayIndex) return null; + + // Filter spaces based on display settings + const filteredSpaces = displayAllSpacesOnAllScreens + ? spaces + : spaces.filter((space) => space.monitor === displayId); + + return ( +
+ {filteredSpaces.map((space, i) => { + const { workspace } = space; + const lastOfSpace = + i !== 0 && space.monitor !== spaces[i - 1].monitor; + + return ( + + ); + })} + {isProcessVisible &&
} +
+ ); + }); +}); + +Component.displayName = "Spaces"; + +export default Component; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/window.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/window.jsx new file mode 100755 index 0000000..04b54d6 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/window.jsx @@ -0,0 +1,99 @@ +import * as Uebersicht from "uebersicht"; +import * as AppIcons from "../../app-icons"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; +import * as Aerospace from "../../aerospace"; + +const { React } = Uebersicht; + +/** + * Window component to display a window in the process bar. + * @param {Object} props - The component props. + * @param {Object} props.window - The window object. + * @returns {JSX.Element|null} The rendered component. + */ +export default function Window({ window }) { + // Get settings from context + const { settings } = useSimpleBarContext(); + // Create a ref for the button element + const ref = React.useRef(); + // Destructure settings + const { + displayOnlyCurrent, + hideWindowTitle, + displayOnlyIcon, + expandAllProcesses, + } = settings.process; + // Destructure window properties + const { + focused, + "app-name": appName, + "window-title": title, + "window-id": id, + } = window; + + // If displayOnlyCurrent is true and the window is not focused, return null + if (displayOnlyCurrent && !focused) { + return null; + } + + // Get the icon for the app or use the default icon + const Icon = AppIcons.apps[appName] || AppIcons.apps.Default; + + /** + * Handle click event on the window button. + * @param {Event} e - The click event. + */ + const onClick = (e) => { + !displayOnlyCurrent && Utils.clickEffect(e); + Aerospace.focusWindow(id); + }; + + /** + * Handle mouse enter event on the window button. + */ + const onMouseEnter = () => { + Utils.startSliding(ref.current, ".process__inner", ".process__name"); + }; + + /** + * Handle mouse leave event on the window button. + */ + const onMouseLeave = () => { + Utils.stopSliding(ref.current, ".process__name"); + }; + + // Generate class names based on settings and window state + const classes = Utils.classNames("process__window", { + "process__window--expanded": expandAllProcesses, + "process__window--focused": !displayOnlyCurrent && focused, + "process__window--only-current": displayOnlyCurrent, + "process__window--only-icon": displayOnlyIcon, + }); + + // Clean up the window title + const cleanedUpName = + appName !== title && title.length ? `${appName} / ${title}` : appName; + const processName = hideWindowTitle ? appName : cleanedUpName; + + // Render the window button + return ( + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx new file mode 100755 index 0000000..a2abffd --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/battery.jsx @@ -0,0 +1,183 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { batteryStyles as styles } from "../../styles/components/data/battery"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 10000; + +/** + * Battery widget component + * @returns {JSX.Element|null} The battery widget component + */ +export const Widget = React.memo(() => { + const { displayIndex, settings, pushMissive } = useSimpleBarContext(); + const { widgets, batteryWidgetOptions } = settings; + const { batteryWidget } = widgets; + const { + refreshFrequency, + toggleCaffeinateOnClick, + caffeinateOption, + disableCaffeinateInvertedBackground, + showOnDisplay, + showIcon, + } = batteryWidgetOptions; + + // Determine if the widget should be visible based on display settings + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && batteryWidget; + + // Calculate the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + // Reset the widget state + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetch battery information and update the state + */ + const getBattery = React.useCallback(async () => { + if (!visible) return; + // Fetch battery information and parse the results + const [system, percentage, status, caffeinate, lowPowerMode] = + await Promise.all([ + Utils.getSystem(), + Utils.cachedRun( + `pmset -g batt | grep -Eo '[0-9]+%' | head -1 | tr -d '%'`, + refresh, + ), + Utils.cachedRun( + `pmset -g batt | head -1 | grep -q 'AC Power' && echo 'AC' || echo 'Batt'`, + refresh, + ), + Uebersicht.run(`pgrep caffeinate`), + Utils.cachedRun( + `pmset -g | awk '/lowpowermode|powermode/ {print $2; exit}'`, + refresh, + ), + ]); + setState({ + system, + percentage: parseInt(percentage, 10), + charging: Utils.cleanupOutput(status) === "AC", + caffeinate: Utils.cleanupOutput(caffeinate), + lowPowerMode: Utils.cleanupOutput(lowPowerMode) === "1", + }); + setLoading(false); + }, [visible, refresh]); + + // Use server socket to fetch battery data + useServerSocket("battery", visible, getBattery, resetWidget, setLoading); + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getBattery, refresh); + + if (loading) return ; + if (!state) return null; + + const { system, percentage, charging, caffeinate, lowPowerMode } = state; + const isLowBattery = !charging && percentage < 20; + + const classes = Utils.classNames("battery", { + "battery--low": isLowBattery, + "battery--low-power-mode": lowPowerMode, + "battery--caffeinate": + !disableCaffeinateInvertedBackground && caffeinate.length > 0, + }); + + const transformValue = getTransform(percentage); + + /** + * Handle click event to toggle caffeinate mode + * @param {React.MouseEvent} e - The click event + */ + const onClick = async (e) => { + Utils.clickEffect(e); + await toggleCaffeinate(system, caffeinate, caffeinateOption, pushMissive); + getBattery(); + }; + + const onClickProp = toggleCaffeinateOnClick ? { onClick } : {}; + + const Icon = () => ( +
+
+
+ {charging && ( + + + + )} +
+
+ ); + + return ( + + {caffeinate.length > 0 && ( + + + + )} + {`${percentage}%`} + + ); +}); + +Widget.displayName = "Battery"; + +/** + * Get the transform value for the battery icon based on the percentage + * @param {number} value - The battery percentage + * @returns {string} The transform value + */ +function getTransform(value) { + let transform = `0.${value}`; + if (value === 100) transform = "1"; + if (value < 10) transform = `0.0${value}`; + return `scaleX(${transform})`; +} + +/** + * Toggle caffeinate mode on or off + * @param {string} system - The system architecture + * @param {string} caffeinate - The current caffeinate state + * @param {string} option - The caffeinate option + * @param {function} pushMissive - Function to push notifications + */ +async function toggleCaffeinate(system, caffeinate, option, pushMissive) { + const command = + system === "x86_64" ? "caffeinate -d" : "arch -arch arm64 caffeinate -d"; + if (caffeinate.length === 0) { + Uebersicht.run(`${command} ${option} &`); + Utils.notification("Enabling caffeinate...", pushMissive); + } else { + await Uebersicht.run("pkill -f caffeinate"); + Utils.notification("Disabling caffeinate...", pushMissive); + } +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/browser-track.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/browser-track.jsx new file mode 100755 index 0000000..d320e4a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/browser-track.jsx @@ -0,0 +1,147 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { browserTrackStyles as styles } from "../../styles/components/data/browser-track"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 10000; + +/** + * BrowserTrack Widget component + * @returns {JSX.Element|null} The BrowserTrack widget + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, browserTrackWidgetOptions } = settings; + const { browserTrackWidget } = widgets; + const { refreshFrequency, showSpecter, showOnDisplay, showIcon } = + browserTrackWidgetOptions; + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && browserTrackWidget; + + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + const ref = React.useRef(); + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + /** + * Resets the widget state + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetches the current browser track information + */ + const getBrowserTrack = React.useCallback(async () => { + if (!visible) return; + const [firefoxStatus, firefoxDevStatus] = await Promise.all([ + Utils.cachedRun( + `pgrep -xq 'Firefox' && echo "true" || echo "false"`, + refresh, + ), + Utils.cachedRun( + `pgrep -xq 'Firefox Developer Edition' && echo "true" || echo "false"`, + refresh, + ), + ]); + const isFirefoxDevRunning = + Utils.cleanupOutput(firefoxDevStatus) === "true"; + const isFirefoxRunning = Utils.cleanupOutput(firefoxStatus) === "true"; + const scriptNamePrefix = isFirefoxDevRunning + ? "firefox-dev" + : isFirefoxRunning + ? "firefox" + : "browser"; + + const [browserTrackOutput, spotifyStatus] = await Promise.all([ + Utils.cachedRun( + `osascript ./simple-bar/lib/scripts/${scriptNamePrefix}-audio.applescript 2>&1`, + refresh, + ), + Utils.cachedRun( + `pgrep -fq '[S]potify Helper' && echo "true" || echo "false"`, + refresh, + ), + ]); + const browserTrack = JSON.parse(browserTrackOutput); + setState({ + ...browserTrack, + isSpotifyRunning: Utils.cleanupOutput(spotifyStatus) === "true", + }); + setLoading(false); + }, [visible, refresh]); + + useServerSocket( + "browser-track", + visible, + getBrowserTrack, + resetWidget, + setLoading, + ); + useWidgetRefresh(visible, getBrowserTrack, refresh); + + if (loading) return ; + if (!state) return null; + const { browser, title, isSpotifyRunning } = state; + + if (!browser?.length || !title?.length || isSpotifyRunning) return null; + + /** + * Icon component for displaying browser and playing icons + * @returns {JSX.Element} The icon component + */ + const Icon = () => { + const BrowserIcon = getIcon(browser); + return ( +
+ + + + +
+ ); + }; + + return ( + + {title} + + ); +}); + +Widget.displayName = "BrowserTrack"; + +/** + * Returns the appropriate icon component based on the browser name + * @param {string} browser - The name of the browser + * @returns {JSX.Element} The icon component for the browser + */ +function getIcon(browser) { + if (browser === "chrome") return Icons.GoogleChrome; + if (browser === "brave") return Icons.BraveBrowser; + if (browser === "safari") return Icons.Safari; + if (browser === "firefox") return Icons.Firefox; + return Icons.Default; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/cpu.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/cpu.jsx new file mode 100755 index 0000000..378b3c9 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/cpu.jsx @@ -0,0 +1,153 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import Graph from "./graph.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { cpuStyles as styles } from "../../styles/components/data/cpu"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 2000; +const GRAPH_LENGTH = 50; + +/** + * CPU Widget component + * @returns {JSX.Element|null} The CPU widget + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, cpuWidgetOptions } = settings; + const { cpuWidget } = widgets; + const { + refreshFrequency, + showOnDisplay, + displayAsGraph, + cpuMonitorApp, + showIcon, + cpuUsageThreshold, + } = cpuWidgetOptions; + + // Determine if the widget should be visible based on display settings + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && cpuWidget; + + // Set the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + const [graph, setGraph] = React.useState([]); + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + /** + * Reset the widget state + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + setGraph([]); + }; + + /** + * Fetch CPU usage data + */ + const getCpu = React.useCallback(async () => { + if (!visible) return; + try { + const usage = await Utils.cachedRun( + `top -l 2 | awk '/CPU usage/ && NR > 10 {gsub(/%/, "", $7); print int(100 - $7); exit}'`, + refresh, + ); + const formattedUsage = { usage: parseInt(usage, 10) }; + setState(formattedUsage); + if (displayAsGraph) { + Utils.addToGraphHistory(formattedUsage, setGraph, GRAPH_LENGTH); + } + setLoading(false); + } catch { + setTimeout(getCpu, 1000); + } + }, [displayAsGraph, setGraph, visible, refresh]); + + // Use server socket to fetch CPU data + useServerSocket("cpu", visible, getCpu, resetWidget, setLoading); + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getCpu, refresh); + + if (loading) return ; + if (!state) return null; + + const { usage } = state; + const threshold = Number(cpuUsageThreshold) || 0; + const usageValue = Number(usage) || 0; + + if (threshold > 0 && usageValue < threshold) return null; + + // Handle click event to open CPU monitor app + const onClick = + cpuMonitorApp === "None" + ? undefined + : (e) => { + Utils.clickEffect(e); + openCpuUsageApp(cpuMonitorApp); + }; + + if (displayAsGraph) { + return ( + + + + ); + } + + return ( + + {usage}% + + ); +}); + +Widget.displayName = "Cpu"; + +/** + * Open the specified CPU usage monitoring application + * @param {string} app - The name of the application to open + */ +function openCpuUsageApp(app) { + switch (app) { + case "Activity Monitor": + Uebersicht.run(`open -a "Activity Monitor"`); + break; + case "Top": + Utils.runInUserTerminal("top"); + break; + } +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/crypto.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/crypto.jsx new file mode 100755 index 0000000..3faf4ea --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/crypto.jsx @@ -0,0 +1,160 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { cryptoStyles as styles } from "../../styles/components/data/crypto"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 5 * 60 * 1000; // Default refresh frequency set to 5 minutes + +/** + * Crypto Widget Component + * @returns {JSX.Element|null} The Crypto Widget component + */ +export const Widget = React.memo(() => { + const { displayIndex, settings, pushMissive } = useSimpleBarContext(); + const { widgets, cryptoWidgetOptions } = settings; + const { cryptoWidget } = widgets; + const { + refreshFrequency, + denomination, + identifiers, + precision, + showOnDisplay, + showIcon, + } = cryptoWidgetOptions; + + // Calculate the refresh frequency using the provided or default value + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible on the current display + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && cryptoWidget; + + const ref = React.useRef(); + const denominatorToken = getDenominatorToken(denomination); + + // Memoize cleanedUpIdentifiers to prevent recreation on every render + const cleanedUpIdentifiers = React.useMemo( + () => identifiers.replace(/ /g, ""), + [identifiers], + ); + + // Memoize enumeratedIdentifiers to prevent recreation on every render + const enumeratedIdentifiers = React.useMemo( + () => cleanedUpIdentifiers.replace(/ /g, "").split(","), + [cleanedUpIdentifiers], + ); + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + // Reset the widget state + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetches cryptocurrency prices from the CoinGecko API + */ + const getCrypto = React.useCallback(async () => { + if (!visible) return; + const response = await fetch( + `https://api.coingecko.com/api/v3/simple/price?ids=${cleanedUpIdentifiers}&vs_currencies=${denomination}`, + ); + const result = await response.json(); + + const prices = enumeratedIdentifiers.map((id) => { + const value = parseFloat(result[id][denomination]).toFixed(precision); + return `${denominatorToken}${value}`; + }); + setState(prices); + setLoading(false); + }, [ + visible, + cleanedUpIdentifiers, + denomination, + enumeratedIdentifiers, + precision, + denominatorToken, + ]); + + useServerSocket("crypto", visible, getCrypto, resetWidget, setLoading); + useWidgetRefresh(visible, getCrypto, refresh); + + /** + * Refreshes the cryptocurrency prices + * @param {Event} e - The event object + */ + const refreshCrypto = (e) => { + Utils.clickEffect(e); + setLoading(true); + getCrypto(); + Utils.notification("Refreshing price from coingecko.com...", pushMissive); + }; + + if (loading) return ; + if (!state) return null; + + const classes = Utils.classNames("crypto"); + + return enumeratedIdentifiers.map((id, i) => ( + openCrypto(e, pushMissive)} + onRightClick={refreshCrypto} + > + {state[i]} + + )); +}); + +Widget.displayName = "Crypto"; + +/** + * Returns the icon component for a given cryptocurrency identifier + * @param {string} identifier - The cryptocurrency identifier + * @returns {JSX.Element} The icon component + */ +function getIcon(identifier) { + if (identifier === "celo") return Icons.Celo; + if (identifier === "ethereum") return Icons.Ethereum; + if (identifier === "bitcoin") return Icons.Bitcoin; + return Icons.Moon; +} + +/** + * Returns the symbol for a given denomination + * @param {string} denomination - The denomination (e.g., "usd", "eur") + * @returns {string} The symbol for the denomination + */ +function getDenominatorToken(denomination) { + if (denomination === "usd") return "$"; + if (denomination === "eur") return "€"; + return ""; +} + +/** + * Opens the cryptocurrency price chart + * @param {Event} e - The event object + * @param {Function} pushMissive - The function to push a notification + */ +function openCrypto(e, pushMissive) { + Utils.clickEffect(e); + Utils.notification("Opening price chart from coingecko.com...", pushMissive); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/data-widget-loader.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/data-widget-loader.jsx new file mode 100755 index 0000000..4115024 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/data-widget-loader.jsx @@ -0,0 +1,37 @@ +import * as Uebersicht from "uebersicht"; +import * as Utils from "../../utils"; + +export { dataWidgetLoaderStyles as styles } from "../../styles/components/data/data-widget-loader"; + +const { React } = Uebersicht; + +/** + * A memoized React component that renders a data widget loader. + * + * @param {Object} props - The properties object. + * @param {number} [props.width=14] - The width of the loader. + * @param {number} [props.height=14] - The height of the loader. + * @param {string} [props.className] - Additional class names for the loader. + * @param {Object} [props.style] - Additional styles for the loader. + * @returns {JSX.Element} The rendered data widget loader component. + */ +export const Widget = React.memo( + ({ width = 14, height = 14, className, style }) => { + // Generate class names using the Utils.classNames function + const classes = Utils.classNames("data-widget-loader", "data-widget", { + [className]: className, + }); + + // Return the JSX for the data widget loader + return ( +
+
+
+ ); + }, +); + +Widget.displayName = "DataWidgetLoader"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/data-widget.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/data-widget.jsx new file mode 100755 index 0000000..f5555a1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/data-widget.jsx @@ -0,0 +1,136 @@ +import * as Uebersicht from "uebersicht"; +import * as Specter from "./specter.jsx"; +import * as Utils from "../../utils"; +import { SuspenseIcon } from "../icons/icon.jsx"; +export { dataWidgetStyles as styles } from "../../styles/components/data/data-widget"; + +const { React } = Uebersicht; + +/** + * Widget component that renders a clickable data widget with optional icon and specter. + * @param {Object} props - The properties object. + * @param {React.Component} props.Icon - The icon component to display. + * @param {string} props.classes - Additional classes for the widget. + * @param {string} props.href - The URL to link to. + * @param {function} props.onClick - The click event handler. + * @param {function} props.onRightClick - The right-click event handler. + * @param {function} props.onMiddleClick - The middle-click event handler. + * @param {Object} props.style - The style object. + * @param {boolean} props.disableSlider - Flag to disable the slider effect. + * @param {boolean} props.showSpecter - Flag to show the specter widget. + * @param {boolean} props.useDivForClick - Render a div for click handling instead of a button. + * @param {React.ReactNode} props.children - The child elements to render inside the widget. + * @returns {React.ReactElement} The rendered widget component. + */ +export function Widget({ + Icon, + classes, + href, + onClick, + onRightClick, + onMiddleClick, + style, + disableSlider, + showSpecter, + useDivForClick, + children, +}) { + const ref = React.useRef(); + + let Tag = "div"; + if (href) Tag = "a"; + if (onClick && !href && !useDivForClick) Tag = "button"; + + const renderDivButton = Tag === "div" && Boolean(onClick); + + const dataWidgetClasses = Utils.classNames("data-widget", classes, { + "data-widget--clickable": href || onClick, + }); + + /** + * Handles the click event, determining the appropriate action based on the event. + * @param {MouseEvent} e - The mouse event. + */ + const onClickProp = (e) => { + const { metaKey } = e; + const action = metaKey || isMiddleClick(e) ? onMiddleClick : onClick; + if (action) action(e); + }; + + /** + * Handles the mouse enter event to start the sliding effect. + */ + const onMouseEnter = () => { + Utils.startSliding( + ref.current, + ".data-widget__inner", + ".data-widget__slider", + ); + }; + + /** + * Handles the mouse leave event to stop the sliding effect. + */ + const onMouseLeave = () => { + Utils.stopSliding(ref.current, ".data-widget__slider"); + }; + + /** + * Handles keyboard interaction for div-based clickable widgets. + * @param {KeyboardEvent} e - The keyboard event. + */ + const onKeyDown = (e) => { + if (e.key !== "Enter" && e.key !== " ") return; + e.preventDefault(); + onClickProp(e); + }; + + return ( + + {Icon && ( + + + + )} + {showSpecter && } + {children} + + ); +} + +/** + * Inner component that optionally wraps children with sliding effect elements. + * @param {Object} props - The properties object. + * @param {boolean} props.disableSlider - Flag to disable the slider effect. + * @param {React.ReactNode} props.children - The child elements to render inside the inner component. + * @returns {React.ReactElement} The rendered inner component. + */ +function Inner({ disableSlider, children }) { + if (disableSlider) return children; + return ( +
+
{children}
+
+ ); +} + +/** + * Checks if the event is a middle-click. + * @param {MouseEvent} e - The mouse event. + * @returns {boolean} True if the event is a middle-click, false otherwise. + */ +function isMiddleClick(e) { + return e.button === 1 || e["button&2"] === 1; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/date-display.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/date-display.jsx new file mode 100755 index 0000000..af4c058 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/date-display.jsx @@ -0,0 +1,118 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import * as Utils from "../../utils"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; + +export { dateStyles as styles } from "../../styles/components/data/date-display"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 30000; + +/** + * Date display widget component. + * @returns {JSX.Element} The date display widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, dateWidgetOptions } = settings; + const { dateWidget } = widgets; + const { + refreshFrequency, + shortDateFormat, + locale, + calendarApp, + showOnDisplay, + showIcon, + } = dateWidgetOptions; + + // Determine if the widget should be visible based on display settings + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && dateWidget; + + // Calculate the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + const formatOptions = shortDateFormat ? "short" : "long"; + + // Memoize the date format options + const options = React.useMemo( + () => ({ + weekday: formatOptions, + month: formatOptions, + day: "numeric", + }), + [formatOptions], + ); + + // Ensure locale is valid, default to "en-UK" if not + const _locale = locale.length > 4 ? locale : "en-UK"; + + /** + * Reset the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Get the current date and update the state. + */ + const getDate = React.useCallback(() => { + if (!visible) return; + const now = new Date().toLocaleDateString(_locale, options); + setState({ now }); + setLoading(false); + }, [_locale, options, visible]); + + // Use server socket to get date updates + useServerSocket("date-display", visible, getDate, resetWidget, setLoading); + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getDate, refresh); + + if (loading) return ; + if (!state) return null; + const { now } = state; + + /** + * Handle click event to open the calendar application. + * @param {Event} e - The click event. + */ + const onClick = (e) => { + Utils.clickEffect(e); + openCalendarApp(calendarApp); + }; + + return ( + + {now} + + ); +}); + +Widget.displayName = "DateDisplay"; + +/** + * Open the specified calendar application. + * @param {string} calendarApp - The name of the calendar application to open. + */ +function openCalendarApp(calendarApp) { + const appName = calendarApp || "Calendar"; + Uebersicht.run(`open -a "${appName}"`); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/github.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/github.jsx new file mode 100755 index 0000000..89308b5 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/github.jsx @@ -0,0 +1,105 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh.js"; +import useServerSocket from "../../hooks/use-server-socket.js"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils.js"; + +export { githubStyles as styles } from "../../styles/components/data/github.js"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 1000 * 60 * 10; + +/** + * GitHub notification widget component + * @returns {JSX.Element|null} The GitHub notification widget component + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, githubWidgetOptions } = settings; + const { githubWidget } = widgets; + const { + refreshFrequency, + showOnDisplay, + hideWhenNoNotification, + notificationUrl, + ghBinaryPath, + showIcon, + } = githubWidgetOptions; + + const isDisabled = React.useRef(false); + + // Calculate the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && githubWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + /** + * Reset the widget state + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetch GPU data and update the widget state + */ + const getGitHub = React.useCallback(async () => { + if (!visible) return; + setLoading(true); + const result = await Utils.cachedRun( + `${ghBinaryPath} api notifications`, + refresh, + ); + if (!visible || isDisabled.current) { + return setLoading(false); + } + const json = JSON.parse(result); + const count = json.length; + setState({ count: count > 99 ? "99+" : count }); + setLoading(false); + }, [ghBinaryPath, visible, refresh]); + + // Update the disabled state based on visibility + React.useEffect(() => { + isDisabled.current = !visible; + }, [visible]); + + // Use server socket to fetch GPU data + useServerSocket("github", visible, getGitHub, resetWidget, setLoading); + // Use widget refresh hook to periodically refresh the widget + useWidgetRefresh(visible, getGitHub, refresh); + + if (loading) return ; + if (!state) return null; + + const { count } = state; + + if (hideWhenNoNotification && count === 0) return null; + + return ( + + {count} + + ); +}); + +Widget.displayName = "GitHub"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/gpu.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/gpu.jsx new file mode 100755 index 0000000..6ac1dab --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/gpu.jsx @@ -0,0 +1,128 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import Graph from "./graph.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh.js"; +import useServerSocket from "../../hooks/use-server-socket.js"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils.js"; + +export { gpuStyles as styles } from "../../styles/components/data/gpu.js"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 2000; +const GRAPH_LENGTH = 40; + +/** + * GPU Widget component + * @returns {JSX.Element|null} The GPU widget component + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, gpuWidgetOptions } = settings; + const { gpuWidget } = widgets; + const { + refreshFrequency, + showOnDisplay, + displayAsGraph, + gpuMacmonBinaryPath, + showIcon, + } = gpuWidgetOptions; + + const isDisabled = React.useRef(false); + + // Calculate the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && gpuWidget; + + const [graph, setGraph] = React.useState([]); + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + /** + * Reset the widget state + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + setGraph([]); + }; + + /** + * Fetch GPU data and update the widget state + */ + const getGpu = React.useCallback(async () => { + if (!visible) return; + try { + const result = await Utils.cachedRun( + `${gpuMacmonBinaryPath} pipe -s 1`, + refresh, + ); + if (!visible || isDisabled.current) { + return; + } + const json = JSON.parse(result); + const { gpu_usage } = json; + const formattedUsage = { usage: Math.round(gpu_usage[1] * 100) }; + setState(formattedUsage); + if (displayAsGraph) { + Utils.addToGraphHistory(formattedUsage, setGraph, GRAPH_LENGTH); + } + setLoading(false); + } catch { + setTimeout(getGpu, 1000); + } + }, [displayAsGraph, gpuMacmonBinaryPath, visible, refresh]); + + // Update the disabled state based on visibility + React.useEffect(() => { + isDisabled.current = !visible; + }, [visible]); + + // Use server socket to fetch GPU data + useServerSocket("gpu", visible, getGpu, resetWidget, setLoading); + // Use widget refresh hook to periodically refresh the widget + useWidgetRefresh(visible, getGpu, refresh); + + if (loading) return ; + if (!state) return null; + + const { usage } = state; + + if (displayAsGraph) { + return ( + + + + ); + } + + return ( + + {usage}% + + ); +}); + +Widget.displayName = "Gpu"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/graph.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/graph.jsx new file mode 100755 index 0000000..008e68e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/graph.jsx @@ -0,0 +1,87 @@ +import * as Uebersicht from "uebersicht"; +import * as Utils from "../../utils.js"; +import { SuspenseIcon } from "../icons/icon.jsx"; + +const { React } = Uebersicht; + +export { graphStyles as styles } from "../../styles/components/data/graph"; + +/** + * Graph component to display a bar graph with captions and values. + * + * @param {Object} props - The properties object. + * @param {string} props.className - Additional class names for the graph container. + * @param {Object} props.caption - Caption data containing value, icon, and color for each key. + * @param {Array} props.values - Array of value objects to be displayed as bars. + * @param {number} props.maxLength - Maximum length of the graph. + * @param {number} [props.maxValue] - Maximum value for scaling the bars. + * @returns {JSX.Element|null} The rendered graph component or null if no caption is provided. + */ +export default function Graph({ + className, + caption, + values = [], + maxLength, + maxValue, +}) { + // Return null if no caption is provided + if (!caption) { + return null; + } + + const captionKeys = Object.keys(caption); + + // Calculate maxValue if not provided + if (maxValue === undefined) { + const allValues = values.map((value) => Object.values(value)).flat(); + maxValue = Math.max(...allValues); + } + + const classes = Utils.classNames("graph", className); + + return ( +
+
+ {values.map((value) => { + const keys = Object.keys(value); + return keys.map((key) => { + const height = (value[key] / maxValue) * 100; + const { color: backgroundColor } = caption[key]; + return ( +
+ ); + }); + })} +
+
+ {captionKeys.map((key) => { + const { value, icon: Icon, color } = caption[key]; + return ( +
+ {Icon && ( + + + + )} + +
+ ); + })} +
+
+ ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/keyboard.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/keyboard.jsx new file mode 100755 index 0000000..d6e04f2 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/keyboard.jsx @@ -0,0 +1,108 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { keyboardStyles as styles } from "../../styles/components/data/keyboard"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 20000; + +/** + * Keyboard widget component. + * @returns {JSX.Element|null} The rendered widget or null if not visible. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, keyboardWidgetOptions } = settings; + const { keyboardWidget } = widgets; + const { refreshFrequency, showOnDisplay, showIcon, keyboardMaxLength } = + keyboardWidgetOptions; + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible based on display settings + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && keyboardWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + /** + * Resets the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetches the current keyboard layout or input mode. + */ + const getKeyboard = React.useCallback(async () => { + if (!visible) return; + const keyboard = await Utils.cachedRun( + `defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources | awk '/KeyboardLayout Name/ {$1=$2=$3=""; print $0}'`, + refresh, + ); + const layout = Utils.cleanupOutput(keyboard) + .replace(";", "") + .replaceAll('"', ""); + if (layout.length) { + setState({ keyboard: layout }); + setLoading(false); + return; + } + + const inputMode = await Utils.cachedRun( + `defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources | awk '/"Input Mode" =/ {$1=$2=$3=""; print $0}'`, + refresh, + ); + const cleanedInputMode = Utils.cleanupOutput(inputMode) + .replace(/"com.apple.inputmethod.(.*)"/, "$1") + .replace(";", ""); + + if (!cleanedInputMode.length) return setLoading(false); + + const splitedInputMode = cleanedInputMode.split("."); + const inputModeName = splitedInputMode[splitedInputMode.length - 1]; + setState({ keyboard: inputModeName }); + setLoading(false); + }, [visible, refresh]); + + // Use server socket to listen for keyboard events + useServerSocket("keyboard", visible, getKeyboard, resetWidget, setLoading); + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getKeyboard, refresh); + + if (loading) return ; + if (!state) return null; + const { keyboard } = state; + + const maxLength = Number(keyboardMaxLength) || 0; + const displayKeyboard = + maxLength > 0 ? keyboard.slice(0, maxLength) : keyboard; + + if (!displayKeyboard?.length) return null; + + return ( + + {displayKeyboard} + + ); +}); + +Widget.displayName = "Keyboard"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/memory.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/memory.jsx new file mode 100755 index 0000000..f5dce96 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/memory.jsx @@ -0,0 +1,134 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { memoryStyles as styles } from "../../styles/components/data/memory"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 4000; + +/** + * Memory Widget component + * @returns {JSX.Element|null} The memory widget component + */ +export const Widget = () => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, memoryWidgetOptions } = settings; + const { memoryWidget } = widgets; + const { + refreshFrequency, + showOnDisplay, + memoryMonitorApp, + showIcon, + memoryUsageThreshold, + } = memoryWidgetOptions; + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && memoryWidget; + + const [state, setState] = Uebersicht.React.useState(); + const [loading, setLoading] = Uebersicht.React.useState(visible); + + /** + * Reset the widget state + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetch memory usage data + */ + const getMemory = React.useCallback(async () => { + const output = await Utils.cachedRun( + 'vm_stat | awk \'BEGIN {page_size=4096} /page size of/ {page_size=$8} /Pages free/ {free=$3} /Pages inactive/ {inactive=$3} /Pages speculative/ {spec=$4} /Pages active/ {active=$3} /Pages wired/ {wired=$4} END {gsub(/\\./, "", free); gsub(/\\./, "", inactive); gsub(/\\./, "", spec); gsub(/\\./, "", active); gsub(/\\./, "", wired); available=free+inactive+spec; total=available+active+wired; printf "%.0f", (available/total)*100}\'', + refresh, + ); + const free = parseInt(Utils.cleanupOutput(output), 10); + setState({ free }); + setLoading(false); + }, [setLoading, setState, refresh]); + + // Use server socket to get memory data + useServerSocket("memory", visible, getMemory, resetWidget, setLoading); + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getMemory, refresh); + + if (loading) return ; + if (!state) return null; + + const { free } = state; + const used = 100 - free; + const threshold = Number(memoryUsageThreshold) || 0; + + if (threshold > 0 && used < threshold) return null; + + // Handle click event to open memory usage app + const onClick = + memoryMonitorApp === "None" + ? undefined + : (e) => { + Utils.clickEffect(e); + openMemoryUsageApp(memoryMonitorApp); + }; + + /** + * Pie chart component for memory usage + * @returns {JSX.Element} The pie chart component + */ + const Pie = () => { + return ( +
+ ); + }; + + const classes = Utils.classNames("memory", { + "memory--low": used <= 30, + "memory--medium": used > 30 && used <= 70, + "memory--high": used > 70, + }); + + return ( + +
{`${used}%`}
+
+ ); +}; + +/** + * Open the specified memory usage application + * @param {string} app - The name of the application to open + */ +function openMemoryUsageApp(app) { + switch (app) { + case "Activity Monitor": + Uebersicht.run(`open -a "Activity Monitor"`); + break; + case "Top": + Utils.runInUserTerminal("top"); + break; + } +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/mic.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/mic.jsx new file mode 100755 index 0000000..5c071a8 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/mic.jsx @@ -0,0 +1,152 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import * as Utils from "../../utils"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; + +const { React } = Uebersicht; + +export { micStyles as styles } from "../../styles/components/data/mic"; + +const DEFAULT_REFRESH_FREQUENCY = 20000; + +/** + * Mic widget component. + * @returns {JSX.Element} The rendered mic widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, micWidgetOptions } = settings; + const { micWidget } = widgets; + const { refreshFrequency, showOnDisplay, showIcon } = micWidgetOptions; + + // Determine the refresh frequency for the widget. + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible. + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && micWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + const { volume: _volume } = state || {}; + const [volume, setVolume] = React.useState(_volume && parseInt(_volume, 10)); + const [dragging, setDragging] = React.useState(false); + + /** + * Reset the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetch the current microphone volume. + */ + const getMic = React.useCallback(async () => { + if (!visible) return; + const volume = await Utils.cachedRun( + `osascript -e 'input volume of (get volume settings)'`, + refresh, + ); + setState({ volume: Utils.cleanupOutput(volume) }); + setLoading(false); + }, [visible, refresh]); + + // Use server socket to get mic data. + useServerSocket("mic", visible, getMic, resetWidget, setLoading); + // Refresh the widget periodically. + useWidgetRefresh(visible, getMic, refresh); + + // Update the mic volume when dragging state changes. + React.useEffect(() => { + if (!dragging) setMic(volume); + }, [dragging, volume]); + + // Update the volume state when the fetched volume changes. + React.useEffect(() => { + setVolume((currentVolume) => { + if (_volume && currentVolume !== parseInt(_volume, 10)) { + return parseInt(_volume, 10); + } + return currentVolume; + }); + }, [_volume]); + + if (loading) return ; + if (!state || volume === undefined || _volume === "missing value") + return null; + + const Icon = !volume ? Icons.MicOff : Icons.MicOn; + + /** + * Handle volume change event. + * @param {React.ChangeEvent} e - The change event. + */ + const onChange = (e) => { + const value = parseInt(e.target.value, 10); + setVolume(value); + }; + + /** + * Handle mouse down event on the slider. + */ + const onMouseDown = () => setDragging(true); + + /** + * Handle mouse up event on the slider. + */ + const onMouseUp = () => setDragging(false); + + const formattedVolume = `${volume.toString().padStart(2, "0")}%`; + + const classes = Utils.classNames("mic", { + "mic--dragging": dragging, + }); + + return ( + +
+ {showIcon && ( + + + + )} + {formattedVolume} +
+
+ +
+
+ ); +}); + +Widget.displayName = "Mic"; + +/** + * Set the microphone volume. + * @param {number} volume - The volume level to set. + */ +function setMic(volume) { + if (volume === undefined) return; + Uebersicht.run(`osascript -e 'set volume input volume ${volume}'`); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/mpd.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/mpd.jsx new file mode 100755 index 0000000..53449b1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/mpd.jsx @@ -0,0 +1,228 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { mpdStyles as styles } from "../../styles/components/data/mpd"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 10000; + +/** + * MPD Widget component + * @returns {JSX.Element|null} The MPD widget + */ +export const Widget = React.memo(() => { + const ref = React.useRef(); + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, mpdWidgetOptions } = settings; + const { mpdWidget } = widgets; + const { + refreshFrequency, + showSpecter, + mpdBinaryPath, + mpdHost, + mpdPort, + mpdFormatString, + showOnDisplay, + showIcon, + } = mpdWidgetOptions; + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible on the current display + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && mpdWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + const [isMpdActive, setIsMpdActive] = React.useState(false); + const { volume: _volume } = state || {}; + const defaultVolume = _volume && parseInt(_volume); + const [volume, setVolume] = React.useState(defaultVolume); + const [dragging, setDragging] = React.useState(false); + + /** + * Reset the widget state + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + setIsMpdActive(false); + }; + + /** + * Fetch MPD data + */ + const getMpd = React.useCallback(async () => { + if (!visible) return; + + try { + const mpdProcess = await Utils.cachedRun( + `pgrep -x mpd > /dev/null && echo "true" || echo "false"`, + refresh, + ); + + if (Utils.cleanupOutput(mpdProcess) === "false") { + setLoading(false); + setIsMpdActive(false); + return; + } + + const [playerState, trackInfo, volumeState] = await Promise.all([ + Utils.cachedRun( + `${mpdBinaryPath} --host ${mpdHost} --port ${mpdPort} | head -n 2 | tail -n 1 | awk '{print substr($1,2,length($1)-2)}' 2>/dev/null || echo "stopped"`, + refresh, + ), + Utils.cachedRun( + `${mpdBinaryPath} --host ${mpdHost} --port ${mpdPort} --format "${mpdFormatString}" | head -n 1`, + refresh, + ), + Utils.cachedRun( + `${mpdBinaryPath} --host ${mpdHost} --port ${mpdPort} volume | sed -e 's/volume:[ ]*//g' -e 's/%//g'`, + refresh, + ), + ]); + if (Utils.cleanupOutput(trackInfo) === "") { + setLoading(false); + setIsMpdActive(false); + return; + } + setState({ + playerState: Utils.cleanupOutput(playerState), + trackInfo: Utils.cleanupOutput(trackInfo), + volume: Utils.cleanupOutput(volumeState), + }); + setIsMpdActive(true); + setLoading(false); + } catch { + setLoading(false); + setIsMpdActive(false); + } + }, [visible, mpdBinaryPath, mpdHost, mpdPort, mpdFormatString, refresh]); + + // Update the volume when dragging ends + React.useEffect(() => { + if (!dragging) setSound(mpdBinaryPath, mpdHost, mpdPort, volume); + }, [dragging, mpdBinaryPath, mpdHost, mpdPort, volume]); + + // Set the volume state when dragging ends + React.useEffect(() => { + if (!dragging) setVolume(volume); + }, [dragging, volume]); + + useServerSocket("mpd", visible, getMpd, resetWidget, setLoading); + useWidgetRefresh(visible, getMpd, refresh); + + if (loading) return ; + if (!state || !isMpdActive) return null; + const { playerState, trackInfo } = state; + + if (!trackInfo.length) return null; + + const isPlaying = playerState === "playing"; + const Icon = isPlaying ? Icons.Playing : Icons.Paused; + + /** + * Handle click event to toggle play/pause + * @param {React.MouseEvent} e - The click event + */ + const onClick = async (e) => { + Utils.clickEffect(e); + await togglePlay(mpdBinaryPath, mpdHost, mpdPort); + await getMpd(); + }; + + /** + * Handle volume change event + * @param {React.ChangeEvent} e - The change event + */ + const onChange = (e) => { + const value = parseInt(e.target.value); + setVolume(value); + }; + + const onMouseDown = () => setDragging(true); + + const onMouseUp = () => setDragging(false); + + const stopPropagation = (e) => e.stopPropagation(); + + const onMouseEnter = () => + Utils.startSliding(ref.current, ".mpd__inner", ".mpd__info"); + const onMouseLeave = () => Utils.stopSliding(ref.current, ".mpd__slider"); + + const classes = Utils.classNames("sound", "mpd", { + "mpd--playing": isPlaying, + "mpd--dragging": dragging, + }); + + return ( + +
+
+
{trackInfo}
+
+
+ +
+
+
+ ); +}); + +Widget.displayName = "Mpd"; + +/** + * Toggle play/pause state of MPD + * @param {string} path - The path to the MPD binary + * @param {string} host - The MPD host + * @param {string} port - The MPD port + * @returns {Promise} + */ +async function togglePlay(path, host, port) { + return Uebersicht.run(`${path} --host ${host} --port ${port} toggle`); +} + +/** + * Set the volume of MPD + * @param {string} path - The path to the MPD binary + * @param {string} host - The MPD host + * @param {string} port - The MPD port + * @param {number} volume - The volume level to set + */ +function setSound(path, host, port, volume) { + if (!volume) return; + Uebersicht.run(`${path} --host ${host} --port ${port} volume ${volume}`); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/music.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/music.jsx new file mode 100755 index 0000000..f0fabd6 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/music.jsx @@ -0,0 +1,161 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { musicStyles as styles } from "../../styles/components/data/music"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 10000; + +/** + * Music widget component. + * @returns {JSX.Element|null} The music widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, musicWidgetOptions } = settings; + const { musicWidget } = widgets; + const { refreshFrequency, showSpecter, showOnDisplay, showIcon } = + musicWidgetOptions; + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible on the current display + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && musicWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + const [isMusicActive, setIsMusicActive] = React.useState(false); + + /** + * Resets the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + setIsMusicActive(false); + }; + + /** + * Fetches the current music information. + */ + const getMusic = React.useCallback(async () => { + if (!visible) return; + const osVersion = await Utils.cachedRun(`sw_vers -productVersion`, refresh); + const processName = + Utils.cleanupOutput(osVersion) === "10.15" ? "iTunes" : "Music"; + const isRunning = await Utils.cachedRun( + `pgrep -xq "${processName}" && echo "true" || echo "false"`, + refresh, + ); + if (Utils.cleanupOutput(isRunning) === "false") { + setLoading(false); + setIsMusicActive(false); + return; + } + const output = await Utils.cachedRun( + `osascript -e 'tell application "${processName}"' -e 'set output to (player state as string) & "|" & (name of current track as string) & "|" & (artist of current track as string)' -e 'end tell' 2>/dev/null || echo "stopped|unknown track|unknown artist"`, + refresh, + ); + const [playerState, trackName, artistName] = + Utils.cleanupOutput(output).split("|"); + setState({ + playerState, + trackName, + artistName, + processName: Utils.cleanupOutput(processName), + }); + setIsMusicActive(true); + setLoading(false); + }, [visible, refresh]); + + // Use server socket to listen for music events + useServerSocket("music", visible, getMusic, resetWidget, setLoading); + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getMusic, refresh); + + if (loading) return ; + if (!state || !isMusicActive) return null; + const { processName, playerState, trackName, artistName } = state; + + if (!trackName.length) return null; + + const isPlaying = playerState === "playing"; + const Icon = isPlaying ? Icons.Playing : Icons.Paused; + + /** + * Handles click event to toggle play/pause. + * @param {React.MouseEvent} e - The click event. + */ + const onClick = (e) => { + Utils.clickEffect(e); + togglePlay(!isPlaying, processName); + getMusic(); + }; + + /** + * Handles right-click event to skip to the next track. + * @param {React.MouseEvent} e - The right-click event. + */ + const onRightClick = (e) => { + Utils.clickEffect(e); + Uebersicht.run( + `osascript -e 'tell application "${processName}" to Next Track'`, + ); + getMusic(); + }; + + /** + * Handles middle-click event to open the music application. + * @param {React.MouseEvent} e - The middle-click event. + */ + const onMiddleClick = (e) => { + Utils.clickEffect(e); + Uebersicht.run(`open -a '${processName}'`); + getMusic(); + }; + + const classes = Utils.classNames("music", { + "music--playing": isPlaying, + }); + + return ( + + {trackName} - {artistName} + + ); +}); + +Widget.displayName = "Music"; + +/** + * Toggles play/pause state of the music application. + * @param {boolean} isPaused - Whether the music is paused. + * @param {string} processName - The name of the music application process. + */ +function togglePlay(isPaused, processName) { + if (isPaused) { + Uebersicht.run(`osascript -e 'tell application "${processName}" to play'`); + } else { + Uebersicht.run(`osascript -e 'tell application "${processName}" to pause'`); + } +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/netstats.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/netstats.jsx new file mode 100755 index 0000000..ef3d7be --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/netstats.jsx @@ -0,0 +1,182 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import Graph from "./graph.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh.js"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils.js"; + +export { netstatsStyles as styles } from "../../styles/components/data/netstats"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 2000; +const GRAPH_LENGTH = 30; + +/** + * Netstats widget component. + * @returns {JSX.Element|null} The rendered component. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, netstatsWidgetOptions } = settings; + const { netstatsWidget } = widgets; + const { + refreshFrequency, + showOnDisplay, + displayAsGraph, + showIcon, + netstatsThreshold, + } = netstatsWidgetOptions; + + const isDisabled = React.useRef(false); + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && netstatsWidget; + + const [graph, setGraph] = React.useState([]); + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + /** + * Resets the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + setGraph([]); + }; + + /** + * Fetches network statistics. + */ + const getNetstats = React.useCallback(async () => { + if (!visible) return; + try { + const output = await Utils.cachedRun( + `bash ./simple-bar/lib/scripts/netstats.sh 2>&1`, + refresh, + ); + if (!visible || isDisabled.current) { + return; + } + const data = Utils.cleanupOutput(output); + const json = JSON.parse(data); + setState(json); + if (displayAsGraph) { + Utils.addToGraphHistory(json, setGraph, GRAPH_LENGTH); + } + setLoading(false); + } catch { + setTimeout(getNetstats, 1000); + } + }, [displayAsGraph, setGraph, visible, refresh]); + + // Update the disabled state based on visibility + React.useEffect(() => { + isDisabled.current = !visible; + }, [visible]); + + // Set up server socket and widget refresh hooks + useServerSocket("netstats", visible, getNetstats, resetWidget, setLoading); + useWidgetRefresh(visible, getNetstats, refresh); + + if (loading) + return ( + + + {!displayAsGraph && } + + ); + + if (!state) { + return null; + } + + const { download, upload } = state; + + if (download === undefined || upload === undefined) { + return null; + } + + const threshold = (Number(netstatsThreshold) || 0) * 1024; + const isBelowThreshold = + threshold > 0 && + Math.abs(download) < threshold && + Math.abs(upload) < threshold; + + if (isBelowThreshold) { + return null; + } + + const formattedDownload = Utils.formatBytes(download); + const formattedUpload = Utils.formatBytes(upload); + + if (displayAsGraph) { + return ( + + + + ); + } + + return ( + + +
+ {showIcon && ( + + + + )} + +
+
+ +
+ {showIcon && ( + + + + )} + +
+
+
+ ); +}); + +Widget.displayName = "Netstats"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/next-meeting.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/next-meeting.jsx new file mode 100755 index 0000000..74f6bf8 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/next-meeting.jsx @@ -0,0 +1,310 @@ +/** + * Next Meeting Widget + * + * Displays the next upcoming calendar event with time until start and optional join button. + * Uses icalBuddy for fast calendar access with proper recurring event support. + * + * Requirements: + * - macOS with Calendar.app or compatible calendar + * - icalBuddy installed (brew install ical-buddy) + * - Calendar access permissions granted + * + * @module next-meeting + */ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { nextMeetingStyles as styles } from "../../styles/components/data/next-meeting"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 60000; // 1 minute + +// Timing thresholds (in minutes) +const URGENT_THRESHOLD = 5; // Red pulsing when ≤5 min until meeting +const UPCOMING_THRESHOLD = 15; // Yellow when ≤15 min until meeting + +// Uses icalBuddy for fast calendar access (handles recurring events properly) +// Note: Shell script automatically skips meetings that started more than 15 minutes ago +const BASE_COMMAND = `./simple-bar/lib/scripts/next-meeting.sh`; + +/** + * Builds the shell command with optional custom icalBuddy path and look-ahead hours. + * @param {string} icalBuddyPath - Optional custom path to icalBuddy binary + * @param {number} lookAheadHours - Hours to look ahead for meetings (default: 12) + * @returns {string} Complete shell command + */ +function buildCommand(icalBuddyPath, lookAheadHours) { + const hours = lookAheadHours || 12; + if (icalBuddyPath && icalBuddyPath.trim()) { + // Escape special shell characters to prevent injection + const safePath = icalBuddyPath.replace(/["$`\\]/g, "\\$&"); + return `${BASE_COMMAND} "${safePath}" ${hours}`; + } + return `${BASE_COMMAND} "" ${hours}`; +} + +// Patterns to extract meeting URLs from notes +const MEETING_URL_PATTERNS = [ + /https?:\/\/[\w-]*\.?zoom\.us\/[^\s<>"]+/gi, + /https?:\/\/teams\.microsoft\.com\/l\/meetup-join\/[^\s<>"]+/gi, + /https?:\/\/meet\.google\.com\/[^\s<>"]+/gi, + /https?:\/\/[\w-]*\.?webex\.com\/[^\s<>"]+/gi, +]; + +// SafeLinks pattern (Microsoft Outlook protection wrapper) +const SAFELINKS_PATTERN = + /https?:\/\/[\w.-]*safelinks\.protection\.outlook\.com\/[^\s<>">\]]+/gi; + +/** + * Decode a URL that may be URL-encoded + * @param {string} url - Possibly encoded URL + * @returns {string} Decoded URL + */ +function decodeUrl(url) { + try { + return decodeURIComponent(url); + } catch { + return url; + } +} + +/** + * Extract the real URL from a SafeLink wrapper + * @param {string} safeLink - SafeLink URL + * @returns {string} Extracted real URL or original + */ +function extractFromSafeLink(safeLink) { + const urlParam = safeLink.match(/[?&]url=([^&]+)/i); + if (urlParam && urlParam[1]) { + return decodeUrl(urlParam[1]); + } + return safeLink; +} + +/** + * Extract meeting URL from event URL or notes + * @param {string} url - Event URL + * @param {string} notes - Event notes/description + * @returns {string|null} Meeting URL or null + */ +function extractMeetingUrl(url, notes) { + // First check direct URL + if (url && url.trim() && url !== "missing value") { + for (const pattern of MEETING_URL_PATTERNS) { + pattern.lastIndex = 0; + const match = url.match(pattern); + if (match) return match[0]; + } + if (url.startsWith("http")) return url; + } + + // Check notes for meeting links + if (notes && notes.trim()) { + // First try direct meeting URLs + for (const pattern of MEETING_URL_PATTERNS) { + pattern.lastIndex = 0; + const match = notes.match(pattern); + if (match) return match[0]; + } + + // Check for SafeLinks that contain meeting URLs + SAFELINKS_PATTERN.lastIndex = 0; + const safeLinks = notes.match(SAFELINKS_PATTERN); + if (safeLinks) { + for (const safeLink of safeLinks) { + const realUrl = extractFromSafeLink(safeLink); + for (const pattern of MEETING_URL_PATTERNS) { + pattern.lastIndex = 0; + if (pattern.test(realUrl)) { + return realUrl; + } + } + } + } + } + + return null; +} + +/** + * Format time until meeting + * @param {number} minutes - Minutes until meeting + * @returns {string} Formatted time string + */ +function formatTimeUntil(minutes) { + if (minutes < 0) return "now"; + if (minutes < 1) return "<1m"; + if (minutes < 60) return `${minutes}m`; + const hours = Math.floor(minutes / 60); + const mins = minutes % 60; + if (mins === 0) return `${hours}h`; + return `${hours}h ${mins}m`; +} + +/** + * Parse meeting data from shell script output + * @param {string} output - Raw command output + * @returns {Object|null} Meeting object or null + */ +function parseMeetingData(output) { + if (!output || !output.trim()) return null; + + const parts = output.trim().split("|"); + if (parts.length < 5) return null; + + const [title, startTime, url, notes, minutesUntil] = parts; + if (!title) return null; + + const meetingUrl = extractMeetingUrl(url, notes); + + return { + title: title.trim(), + startTime: startTime, + url: meetingUrl, + minutesUntil: parseInt(minutesUntil, 10) || 0, + }; +} + +/** + * Join button sub-component for meeting URLs. + * @component + * @param {Object} props - Component props + * @param {string} props.url - Meeting URL to open + * @returns {JSX.Element} Join button element + */ +const JoinButton = React.memo(({ url }) => { + /** + * Opens the meeting URL when clicked. + * @param {React.MouseEvent} e - Click event + */ + const handleJoin = async (e) => { + e.stopPropagation(); + Utils.clickEffect(e); + // Escape special shell characters to prevent injection + const safeUrl = url.replace(/["$`\\]/g, "\\$&"); + await Uebersicht.run(`open "${safeUrl}"`); + }; + + return ( + + ); +}); + +JoinButton.displayName = "JoinButton"; + +/** + * Next Meeting widget component + * Shows the next upcoming meeting with optional join button + * @returns {JSX.Element|null} The next meeting widget + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, nextMeetingWidgetOptions, dateWidgetOptions } = settings; + const { nextMeetingWidget } = widgets; + const { + refreshFrequency, + showOnDisplay, + showJoinButton, + showTimeOnly, + icalBuddyPath, + lookAheadHours, + } = nextMeetingWidgetOptions; + + // Calculate the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible based on display settings + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && nextMeetingWidget; + + const [state, setState] = React.useState(null); + const [loading, setLoading] = React.useState(visible); + + /** + * Resets the widget state. + */ + const resetWidget = React.useCallback(() => { + setState(null); + setLoading(false); + }, []); + + /** + * Fetches next meeting and updates the state. + */ + const getMeeting = React.useCallback(async () => { + if (!visible) return; + try { + const command = buildCommand(icalBuddyPath, lookAheadHours); + const output = await Uebersicht.run(command); + const meeting = parseMeetingData(output); + setState(meeting); + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching next meeting:", error); + setState(null); + } + setLoading(false); + }, [visible, icalBuddyPath, lookAheadHours]); + + // Server socket for real-time updates + useServerSocket("next-meeting", visible, getMeeting, resetWidget, setLoading); + + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getMeeting, refresh); + + if (loading) return ; + if (!state) return null; + + const { title, minutesUntil, url } = state; + const timeDisplay = formatTimeUntil(minutesUntil); + const isUrgent = minutesUntil <= URGENT_THRESHOLD; // Red pulsing: ≤5 min or in progress (up to 15 min) + const isUpcoming = minutesUntil <= UPCOMING_THRESHOLD; // Yellow: ≤15 min (but not urgent/in-progress) + + const widgetClasses = Utils.classNames("next-meeting", { + "next-meeting--urgent": isUrgent, + "next-meeting--upcoming": isUpcoming && !isUrgent, + }); + + /** + * Handle click event to open the calendar application + * @param {Event} e - The click event + */ + const openCalendar = async (e) => { + Utils.clickEffect(e); + const calendarApp = dateWidgetOptions?.calendarApp || "Calendar"; + await Uebersicht.run(`open -a "${calendarApp}"`); + }; + + return ( + + {!showTimeOnly && {title}} + {timeDisplay} + {showJoinButton && url && } + + ); +}); + +Widget.displayName = "NextMeeting"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/notifications.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/notifications.jsx new file mode 100755 index 0000000..b55e487 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/notifications.jsx @@ -0,0 +1,189 @@ +/** + * Notifications Widget + * + * Displays badge counts from running applications with active notifications. + * Uses macOS lsappinfo to query app status labels (dock badges). + * + * Requirements: + * - macOS (lsappinfo is macOS-specific) + * - No special permissions required + * + * @module notifications + */ +import * as Uebersicht from "uebersicht"; +import * as AppIcons from "../../app-icons.js"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { notificationsStyles as styles } from "../../styles/components/data/notifications"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 10000; + +// Shell command to get notification badges from running apps +const COMMAND = `lsappinfo -all list 2>/dev/null | perl -0777 -pe 's/---/\\n---\\n/g' | perl -ne ' + if (/"CFBundleName"="([^"]+)"/) { $app = $1; } + if (/"StatusLabel"=\\{ "label"="([^"]*)"/) { $badge = $1; } + if (/"LSBundlePath"="([^"]+)"/) { $path = $1; } + if (/^---$/ || eof) { + print "$app|$badge|$path\\n" if ($app && $badge); + ($app, $badge, $path) = ("", "", ""); + } +'`; + +/** + * Parses shell command output into notification objects. + * @param {string} output - Raw command output from lsappinfo + * @returns {Array<{name: string, badge: string, bundlePath: string}>} Array of notification objects + */ +function parseNotifications(output) { + if (!output || !output.trim()) return []; + + return output + .trim() + .split("\n") + .filter((line) => line.includes("|")) + .map((line) => { + const [name, badge, bundlePath] = line.split("|"); + return { name, badge, bundlePath }; + }) + .filter((item) => item.name && item.badge); +} + +/** + * Single app notification pill component. + * @component + * @param {Object} props - Component props + * @param {Object} props.app - Application notification data + * @param {string} props.app.name - Application name + * @param {string} props.app.badge - Badge count + * @param {string} props.app.bundlePath - Path to application bundle + * @returns {JSX.Element} Notification pill button + */ +const NotificationPill = React.memo(({ app }) => { + /** + * Opens the application when pill is clicked. + * @param {React.MouseEvent} e - Click event + */ + const openApp = async (e) => { + Utils.clickEffect(e); + // Escape special shell characters to prevent injection + const safePath = app.bundlePath.replace(/["$`\\]/g, "\\$&"); + await Uebersicht.run(`open "${safePath}"`); + }; + + // Get the SVG icon for this app, or use Default + const Icon = AppIcons.apps[app.name] || AppIcons.apps.Default; + + return ( + + ); +}); + +NotificationPill.displayName = "NotificationPill"; + +/** + * Notification Badges widget component. + * Shows each app with notifications as an inline pill. + * @component + * @returns {JSX.Element|null} The notifications widget component or null if no notifications + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, notificationsWidgetOptions } = settings; + const { notificationsWidget } = widgets; + const { refreshFrequency, showOnDisplay, excludedApps } = notificationsWidgetOptions; + + // Determine if the widget should be visible based on display settings + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && + notificationsWidget; + + // Calculate the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + const [state, setState] = React.useState([]); + const [loading, setLoading] = React.useState(visible); + + /** + * Resets the widget state. + */ + const resetWidget = React.useCallback(() => { + setState([]); + setLoading(false); + }, []); + + // Build the exclusion list from the comma-separated setting + const exclusionList = React.useMemo( + () => + excludedApps + ? excludedApps + .split(",") + .map((s) => s.trim().toLowerCase()) + .filter(Boolean) + : [], + [excludedApps], + ); + + /** + * Fetches notification badges and updates the state. + */ + const getNotifications = React.useCallback(async () => { + if (!visible) return; + try { + const output = await Utils.cachedRun(COMMAND, refresh); + const notifications = parseNotifications(output).filter( + (item) => !exclusionList.includes(item.name.toLowerCase()), + ); + setState(notifications); + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching notifications:", error); + setState([]); + } + setLoading(false); + }, [visible, refresh, exclusionList]); + + // Server socket for real-time updates + useServerSocket( + "notifications", + visible, + getNotifications, + resetWidget, + setLoading, + ); + + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getNotifications, refresh); + + // Don't render anything if loading or no notifications + if (loading || !state.length) return null; + + return ( +
+ {state.map((app) => ( + + ))} +
+ ); +}); + +Widget.displayName = "Notifications"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/sound.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/sound.jsx new file mode 100755 index 0000000..3b39594 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/sound.jsx @@ -0,0 +1,156 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { soundStyles as styles } from "../../styles/components/data/sound"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 20000; + +/** + * Sound widget component. + * @returns {JSX.Element|null} The sound widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, soundWidgetOptions } = settings; + const { soundWidget } = widgets; + const { refreshFrequency, showOnDisplay, showIcon } = soundWidgetOptions; + + // Determine the refresh frequency for the widget. + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible on the current display. + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && soundWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + const { volume: _volume } = state || {}; + const [volume, setVolume] = React.useState(_volume && parseInt(_volume, 10)); + const [dragging, setDragging] = React.useState(false); + + /** + * Reset the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetch the current sound settings. + */ + const getSound = React.useCallback(async () => { + if (!visible) return; + const output = await Utils.cachedRun( + `osascript -e 'set v to get volume settings' -e 'output volume of v & output muted of v'`, + 500, + ); + const parts = Utils.cleanupOutput(output).split(", "); + setState({ + volume: parts[0], + muted: parts[1], + }); + setLoading(false); + }, [visible, refresh]); + + // Use server socket to listen for sound updates. + useServerSocket("sound", visible, getSound, resetWidget, setLoading); + // Refresh the widget at the specified interval. + useWidgetRefresh(visible, getSound, refresh); + + // Update the volume state when the fetched volume changes. + React.useEffect(() => { + setVolume((currentVolume) => { + if (_volume && currentVolume !== parseInt(_volume, 10)) { + return parseInt(_volume, 10); + } + return currentVolume; + }); + }, [_volume]); + + if (loading) return ; + if (!state || volume === undefined) return null; + + const { muted } = state; + if (_volume === "missing value" || muted === "missing value") return null; + + let Icon = Icons.VolumeHigh; + if (volume < 50) Icon = Icons.VolumeLow; + if (volume < 20) Icon = Icons.NoVolume; + if (muted === "true" || !volume) Icon = Icons.VolumeMuted; + + /** + * Handle volume change event. + * @param {React.ChangeEvent} e - The change event. + */ + const onChange = (e) => { + const value = parseInt(e.target.value, 10); + setVolume(value); + }; + + const onInteractionEnd = (e) => { + setDragging(false); + const finalVolume = parseInt(e.target.value, 10); + setSound(finalVolume); + }; + + // const onMouseDown = () => setDragging(true); + // const onMouseUp = () => setDragging(false); + + const formattedVolume = `${volume.toString().padStart(2, "0")}%`; + + const classes = Utils.classNames("sound", { + "sound--dragging": dragging, + }); + + return ( + +
+ {showIcon && ( + + + + )} + {formattedVolume} +
+
+ setDragging(true)} + onMouseUp={onInteractionEnd} + onKeyUp={onInteractionEnd} + onChange={onChange} + /> +
+
+ ); +}); + +Widget.displayName = "Sound"; + +/** + * Set the system volume. + * @param {number} volume - The volume to set. + */ +function setSound(volume) { + if (volume === undefined) return; + Uebersicht.run(`osascript -e 'set volume output volume ${volume}'`); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/specter.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/specter.jsx new file mode 100755 index 0000000..66b0850 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/specter.jsx @@ -0,0 +1,24 @@ +import * as Uebersicht from "uebersicht"; + +export { specterStyles as styles } from "../../styles/components/data/specter"; + +const { React } = Uebersicht; + +/** + * Specter widget component + * + * This component renders a div with six span elements inside it. These are animated in CSS. + * + * @returns {JSX.Element} The rendered widget component + */ +export const Widget = React.memo(() => { + return ( +
+ {[...new Array(6)].map((_, i) => ( + + ))} +
+ ); +}); + +Widget.displayName = "Specter"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/spotify.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/spotify.jsx new file mode 100755 index 0000000..bc9f6e6 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/spotify.jsx @@ -0,0 +1,189 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Icons from "../icons/icons.jsx"; +import * as Utils from "../../utils"; + +export { spotifyStyles as styles } from "../../styles/components/data/spotify"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 10000; + +/** + * Spotify widget component. + * @returns {JSX.Element|null} The Spotify widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, spotifyWidgetOptions } = settings; + const { spotifyWidget } = widgets; + const { + refreshFrequency, + showSpecter, + showOnDisplay, + showIcon, + showSpotifyMetadata, + } = spotifyWidgetOptions; + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && spotifyWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + const [isSpotifyActive, setIsSpotifyActive] = React.useState(false); + + /** + * Resets the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + setIsSpotifyActive(false); + }; + + /** + * Fetches the current Spotify state. + */ + const getSpotify = React.useCallback(async () => { + if (!visible) return; + const isRunning = await Utils.cachedRun( + `pgrep -fq '[S]potify Helper' && echo "true" || echo "false"`, + refresh, + ); + if (Utils.cleanupOutput(isRunning) === "false") { + setLoading(false); + setIsSpotifyActive(false); + setState({ + playerState: "", + trackName: "", + artistName: "", + }); + return; + } + // if showSpotifyMetadata is enabled, retrieves all information + if (showSpotifyMetadata) { + const output = await Utils.cachedRun( + `osascript -e 'tell application "Spotify"' -e 'set output to (player state as string) & "|" & (name of current track as string) & "|" & (artist of current track as string)' -e 'end tell' 2>/dev/null || echo "stopped||"`, + refresh, + ); + const [playerState, trackName, artistName] = + Utils.cleanupOutput(output).split("|"); + setState({ + playerState, + trackName, + artistName, + }); + // else, only playerState + } else { + const playerState = await Utils.cachedRun( + `osascript -e 'tell application "Spotify" to player state as string' 2>/dev/null || echo "stopped"`, + refresh, + ); + setState({ + playerState: Utils.cleanupOutput(playerState), + trackName: "", + artistName: "", + }); + } + + setIsSpotifyActive(true); + setLoading(false); + }, [visible, showSpotifyMetadata, refresh]); + + // Set up server socket and widget refresh hooks + useServerSocket("spotify", visible, getSpotify, resetWidget, setLoading); + useWidgetRefresh(visible, getSpotify, refresh); + + if (loading) return ; + if (!state || !isSpotifyActive) return null; + const { playerState, trackName, artistName } = state; + + if (!trackName.length && showSpotifyMetadata) return null; + + const label = artistName.length ? `${trackName} - ${artistName}` : trackName; + const isPlaying = playerState === "playing"; + const Icon = getIcon(playerState); + + /** + * Handles click event to toggle play/pause. + * @param {React.MouseEvent} e - The click event. + */ + const onClick = (e) => { + Utils.clickEffect(e); + togglePlay(!isPlaying); + getSpotify(); + }; + + /** + * Handles right-click event to skip to the next track. + * @param {React.MouseEvent} e - The right-click event. + */ + const onRightClick = (e) => { + Utils.clickEffect(e); + Uebersicht.run(`osascript -e 'tell application "Spotify" to Next Track'`); + getSpotify(); + }; + + /** + * Handles middle-click event to open Spotify. + * @param {React.MouseEvent} e - The middle-click event. + */ + const onMiddleClick = (e) => { + Utils.clickEffect(e); + Uebersicht.run(`open -a 'Spotify'`); + getSpotify(); + }; + + const classes = Utils.classNames("spotify", { + "spotify--hidden-metadata": !showSpotifyMetadata, + "spotify--playing": isPlaying, + }); + + return ( + + {showSpotifyMetadata && label} + + ); +}); + +Widget.displayName = "Spotify"; + +/** + * Toggles play/pause state of Spotify. + * @param {boolean} isPaused - Whether the player is paused. + */ +function togglePlay(isPaused) { + const state = isPaused ? "play" : "pause"; + Uebersicht.run(`osascript -e 'tell application "Spotify" to ${state}'`); +} + +/** + * Gets the appropriate icon based on the player state. + * @param {string} playerState - The current state of the player. + * @returns {JSX.Element} The icon component. + */ +function getIcon(playerState) { + if (playerState === "stopped") return Icons.Stopped; + if (playerState === "playing") return Icons.Playing; + return Icons.Paused; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/stock.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/stock.jsx new file mode 100755 index 0000000..4327f1c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/stock.jsx @@ -0,0 +1,211 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { stockStyles as styles } from "../../styles/components/data/stock"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 15 * 60 * 1000; // 15 min + +/** + * Stock widget component + * @returns {JSX.Element|null} The stock widget + */ +export const Widget = React.memo(() => { + const { displayIndex, settings, pushMissive } = useSimpleBarContext(); + const { widgets, stockWidgetOptions } = settings; + const { stockWidget } = widgets; + const { + refreshFrequency, + yahooFinanceApiKey, + symbols, + showSymbol, + showCurrency, + showMarketPrice, + showMarketChange, + showMarketPercent, + showColor, + showOnDisplay, + showIcon, + } = stockWidgetOptions; + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Check if the widget should be visible on the current display + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && stockWidget; + + const ref = React.useRef(); + + // Memoize cleanedUpSymbols to prevent recreation on every render + const cleanedUpSymbols = React.useMemo( + () => symbols.replace(/ /g, ""), + [symbols], + ); + + // Memoize enumeratedSymbols to prevent recreation on every render + const enumeratedSymbols = React.useMemo( + () => cleanedUpSymbols.replace(/ /g, "").split(","), + [cleanedUpSymbols], + ); + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + /** + * Reset the widget state + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetch stock data from Yahoo Finance API + */ + const getStocks = React.useCallback(async () => { + if (!visible) return; + const response = await fetch( + `https://yfapi.net/v6/finance/quote?symbols=${cleanedUpSymbols}`, + { + headers: new Headers({ "x-api-key": yahooFinanceApiKey }), + }, + ); + if (response.status === 429) { + // Exceeded daily quota + } else if (response.status === 403) { + Utils.notification("Invalid Yahoo Finance API key", pushMissive); + } else if (response.status === 200) { + const result = await response.json(); + const symbolQuotes = result.quoteResponse.result; + + if (symbolQuotes.length !== enumeratedSymbols.length) { + // One or more symbols is invalid + const receivedSymbols = symbolQuotes.map((s) => s.symbol.toLowerCase()); + const invalidSymbols = enumeratedSymbols.filter( + (s) => !receivedSymbols.includes(s), + ); + Utils.notification("Invalid stock symbol(s): " + invalidSymbols); + } else { + setState({ symbolQuotes }); + } + } else { + // eslint-disable-next-line no-console + console.error("Unexpected response from Yahoo Finance API: ", response); + } + + setLoading(false); + }, [ + visible, + cleanedUpSymbols, + yahooFinanceApiKey, + pushMissive, + enumeratedSymbols, + ]); + + // Use server socket to fetch stock data + useServerSocket("stock", visible, getStocks, resetWidget, setLoading); + // Refresh widget data periodically + useWidgetRefresh(visible, getStocks, refresh); + + /** + * Refresh stock data on user interaction + * @param {Event} e - The event object + */ + const refreshStocks = (e) => { + Utils.clickEffect(e); + setLoading(true); + getStocks(); + }; + + if (loading) return ; + if (!state || !state.symbolQuotes) return null; + + return enumeratedSymbols.map((symbolName, i) => { + const symbolQuote = state.symbolQuotes[i]; + const symbol = symbolQuote.symbol; + const currencySymbol = getCurrencySymbol(symbolQuote.currency); + const marketPrice = Number(symbolQuote.regularMarketPrice).toFixed(2); + const marketChange = Number(symbolQuote.regularMarketChange).toFixed(2); + const marketPercentChange = Number( + symbolQuote.regularMarketChangePercent, + ).toFixed(2); + const stockUp = !marketChange.startsWith("-"); + + return ( + + + {showSymbol && symbol} + {(showCurrency || showMarketPrice) && showSymbol && ( +   + )} + {showCurrency && currencySymbol} + {showMarketPrice && marketPrice} + + + {(showMarketChange || showMarketPercent) &&  } + {showMarketChange && formatPriceChange(marketChange)} + {showMarketPercent && + showMarketChange && + ` (${formatPriceChange(marketPercentChange)}%)`} + {showMarketPercent && + !showMarketChange && + `${formatPriceChange(marketPercentChange)}%`} + + + ); + }); +}); + +Widget.displayName = "Stock"; + +/** + * Handle click event to open stock details + * @param {Event} e - The event object + */ +function openStock(e) { + Utils.clickEffect(e); +} + +/** + * Get the currency symbol for a given currency code + * @param {string} currency - The currency code + * @returns {string} The currency symbol + */ +function getCurrencySymbol(currency) { + if (currency === "EUR") return "€"; + if (currency === "USD") return "$"; + if (currency === "GBP") return "£"; + if (currency === "CNY") return "¥"; + if (currency === "JPY") return "¥"; + return `${currency} `; +} + +/** + * Format the price change with a '+' for positive changes + * @param {string} priceChange - The price change + * @returns {string} The formatted price change + */ +function formatPriceChange(priceChange) { + // Add a '+' for positive changes + return (priceChange.startsWith("-") ? "" : "+") + priceChange; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/time.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/time.jsx new file mode 100755 index 0000000..6890ffb --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/time.jsx @@ -0,0 +1,144 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { timeStyles as styles } from "../../styles/components/data/time"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 1000; + +/** + * Time widget component. + * @returns {JSX.Element|null} The rendered widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, timeWidgetOptions } = settings; + const { timeWidget } = widgets; + const { + refreshFrequency, + hour12, + dayProgress, + showSeconds, + showOnDisplay, + showIcon, + } = timeWidgetOptions; + + // Determine if the widget should be visible on the current display + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && timeWidget; + + // Calculate the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + // Options for formatting the time string + const options = React.useMemo( + () => ({ + hour: "numeric", + minute: "numeric", + second: showSeconds ? "numeric" : undefined, + hour12, + }), + [hour12, showSeconds], + ); + + /** + * Resets the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetches the current time and updates the widget state. + */ + const getTime = React.useCallback(() => { + if (!visible) return; + const time = new Date().toLocaleString("en-UK", options); + setState({ time }); + setLoading(false); + }, [visible, options]); + + // Use server socket to get time updates + useServerSocket("time", visible, getTime, resetWidget, setLoading); + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getTime, refresh); + + if (loading) return ; + if (!state) return null; + const { time } = state; + + // Calculate the progress of the current day + const [dayStart, dayEnd] = [new Date(), new Date()]; + dayStart.setHours(0, 0, 0); + dayEnd.setHours(0, 0, 0); + dayEnd.setDate(dayEnd.getDate() + 1); + const range = dayEnd - dayStart; + const diff = Math.max(0, dayEnd - new Date()); + const fillerWidth = (100 - (100 * diff) / range) / 100; + + /** + * Icon component for the time widget. + * @returns {JSX.Element} The rendered icon. + */ + const TimeIcon = () => { + return ; + }; + + return ( + + {time} + {dayProgress && ( +
+ )} + + ); +}); + +Widget.displayName = "Time"; + +/** + * Icon component for displaying the time as a clock. + * @param {Object} props - The component props. + * @param {string} props.time - The current time string. + * @returns {JSX.Element} The rendered icon. + */ +function Icon({ time }) { + const [hours, minutes] = time.split(":"); + + const hoursInDegree = ((parseInt(hours, 10) % 12) / 12) * 360; + const minutesInDegree = (parseInt(minutes, 10) / 60) * 360; + + return ( +
+
+
+
+ ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/user-widgets.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/user-widgets.jsx new file mode 100755 index 0000000..efa9876 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/user-widgets.jsx @@ -0,0 +1,181 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Settings from "../../settings"; +import * as Utils from "../../utils"; + +const { React } = Uebersicht; + +export default React.memo(UserWidgets); + +/** + * UserWidgets component that renders a list of user-defined widgets. + * @returns {JSX.Element[]} Array of UserWidget components. + */ +function UserWidgets() { + const { settings } = useSimpleBarContext(); + const { userWidgetsList } = settings.userWidgets; + + // Get the keys of the userWidgetsList object + const keys = Object.keys(userWidgetsList); + + // Map over the keys and render a UserWidget for each key + return keys.map((key) => ( + + )); +} + +UserWidgets.displayName = "UserWidgets"; + +/** + * UserWidget component that renders an individual user-defined widget. + * @param {Object} props - The component props. + * @param {string} props.index - The index of the widget. + * @param {Object} props.widget - The widget configuration object. + * @returns {JSX.Element|null} The rendered UserWidget component or null if not visible. + */ +const UserWidget = React.memo(({ index, widget }) => { + const { displayIndex, settings } = useSimpleBarContext(); + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(true); + const [isWidgetActive, setIsWidgetActive] = React.useState(true); + const { + icon, + backgroundColor, + output, + onClickAction, + onRightClickAction, + onMiddleClickAction, + refreshFrequency, + active, + noIcon, + hideWhenNoOutput = true, + showOnDisplay = "", + } = widget; + + // Determine if the widget should be visible based on display settings and active status + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && active; + + /** + * Resets the widget state and loading status. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + setIsWidgetActive(true); + }; + + /** + * Fetches the widget output and updates the state. + */ + const getUserWidget = React.useCallback(async () => { + if (!visible) return; + const widgetOutput = await Utils.cachedRun(output, refreshFrequency); + const cleanedOutput = Utils.cleanupOutput(widgetOutput); + + // Hide widget if script returns empty output and hideWhenNoOutput is enabled + if ( + hideWhenNoOutput && + (!cleanedOutput.length || cleanedOutput.trim() === "") + ) { + setLoading(false); + setIsWidgetActive(false); + setState(undefined); + return; + } + + setState(widgetOutput); + setIsWidgetActive(true); + setLoading(false); + }, [visible, output, hideWhenNoOutput, refreshFrequency]); + + // Use server socket to listen for widget updates + useServerSocket( + "user-widget", + visible, + getUserWidget, + resetWidget, + setLoading, + index, + ); + + // Refresh the widget at the specified frequency + useWidgetRefresh(visible, getUserWidget, refreshFrequency); + + // Hide widget if not visible or if script indicates it should be inactive (only when hideWhenNoOutput is enabled) + if (!visible || (hideWhenNoOutput && !isWidgetActive)) return null; + + const isCustomColor = !Settings.userWidgetColors.includes(backgroundColor); + + const property = settings.global.widgetsBackgroundColorAsForeground + ? "color" + : "backgroundColor"; + + const style = settings.global.noColorInData + ? undefined + : { + [property]: isCustomColor ? backgroundColor : `var(${backgroundColor})`, + }; + + if (loading) return ; + + const Icon = !noIcon ? Icons[icon] : null; + + const hasOnClickAction = onClickAction?.trim().length > 0; + const hasRightClickAction = onRightClickAction?.trim().length > 0; + const hasMiddleClickAction = onMiddleClickAction?.trim().length > 0; + + /** + * Handles the click event for the widget. + * @param {Event} e - The click event. + */ + const onClick = async (e) => { + Utils.clickEffect(e); + await Uebersicht.run(onClickAction); + getUserWidget(); + }; + + /** + * Handles the right-click event for the widget. + * @param {Event} e - The right-click event. + */ + const onRightClick = async (e) => { + Utils.clickEffect(e); + await Uebersicht.run(onRightClickAction); + getUserWidget(); + }; + + /** + * Handles the middle-click event for the widget. + * @param {Event} e - The middle-click event. + */ + const onMiddleClick = async (e) => { + Utils.clickEffect(e); + await Uebersicht.run(onMiddleClickAction); + getUserWidget(); + }; + + const onClickProps = { + onClick: hasOnClickAction ? onClick : undefined, + onRightClick: hasRightClickAction ? onRightClick : undefined, + onMiddleClick: hasMiddleClickAction ? onMiddleClick : undefined, + }; + + return ( + + {state} + + ); +}); + +UserWidget.displayName = "UserWidget"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx new file mode 100755 index 0000000..340c59b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/viscosity-vpn.jsx @@ -0,0 +1,144 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { viscosityVPNStyles as styles } from "../../styles/components/data/viscosity-vpn"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 8000; + +/** + * Viscosity VPN Widget component. + * @returns {JSX.Element|null} The Viscosity VPN widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings, pushMissive } = useSimpleBarContext(); + const { widgets, vpnWidgetOptions } = settings; + const { vpnWidget } = widgets; + const { + refreshFrequency, + vpnConnectionName, + vpnShowConnectionName, + showOnDisplay, + showIcon, + } = vpnWidgetOptions; + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && vpnWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + const [isViscosityActive, setIsViscosityActive] = React.useState(false); + + /** + * Reset the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + setIsViscosityActive(false); + }; + + /** + * Fetch the current VPN status. + */ + const getVPN = React.useCallback(async () => { + if (!visible) return; + const isRunning = await Utils.cachedRun( + `pgrep -xq 'Viscosity' && echo "true" || echo "false"`, + refresh, + ); + if (Utils.cleanupOutput(isRunning) === "false") { + setLoading(false); + setIsViscosityActive(false); + return; + } + const status = await Utils.cachedRun( + `osascript -e "tell application \\"Viscosity\\" to return state of the first connection where name is equal to \\"${vpnConnectionName}\\"" 2>/dev/null`, + refresh, + ); + if (!status.length) return; + setState({ status: Utils.cleanupOutput(status) }); + setIsViscosityActive(true); + setLoading(false); + }, [visible, vpnConnectionName, refresh]); + + // Use server socket to listen for VPN status updates + useServerSocket("viscosity-vpn", visible, getVPN, resetWidget, setLoading); + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getVPN, refresh); + + if (loading) return ; + if (!state || !vpnConnectionName.length || !isViscosityActive) return null; + + const { status } = state; + const isConnected = status === "Connected"; + + const classes = Utils.classNames("viscosity-vpn", { + "viscosity-vpn--disconnected": !isConnected, + }); + + const Icon = isConnected ? Icons.VPN : Icons.VPNOff; + + /** + * Handle click event to toggle VPN connection. + * @param {Event} e - The click event. + */ + const clicked = (e) => { + Utils.clickEffect(e); + toggleVPN(isConnected, vpnConnectionName, pushMissive); + setTimeout(getVPN, refreshFrequency / 2); + }; + + return ( + + {vpnShowConnectionName ? vpnConnectionName : status} + + ); +}); + +Widget.displayName = "ViscosityVPN"; + +/** + * Toggle the VPN connection. + * @param {boolean} isConnected - Whether the VPN is currently connected. + * @param {string} vpnConnectionName - The name of the VPN connection. + * @param {function} pushMissive - Function to push notifications. + */ +function toggleVPN(isConnected, vpnConnectionName, pushMissive) { + if (isConnected) { + Uebersicht.run( + `osascript -e 'tell application "Viscosity" to disconnect "${vpnConnectionName}"'`, + ); + Utils.notification( + `Disabling Viscosity ${vpnConnectionName} network...`, + pushMissive, + ); + } else { + Uebersicht.run( + `osascript -e 'tell application "Viscosity" to connect "${vpnConnectionName}"'`, + ); + Utils.notification( + `Enabling Viscosity ${vpnConnectionName} network...`, + pushMissive, + ); + } +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/weather.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/weather.jsx new file mode 100755 index 0000000..946fda1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/weather.jsx @@ -0,0 +1,214 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import * as Utils from "../../utils"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; + +export { weatherStyles as styles } from "../../styles/components/data/weather"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 1000 * 60 * 30; // Default refresh frequency set to 30 minutes + +/** + * Weather widget component + */ +export const Widget = React.memo(() => { + const { displayIndex, settings, pushMissive } = useSimpleBarContext(); + const { widgets, weatherWidgetOptions } = settings; + const { weatherWidget } = widgets; + const { + refreshFrequency, + customLocation, + unit, + hideLocation, + hideGradient, + showOnDisplay, + showIcon, + } = weatherWidgetOptions; + + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && weatherWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + const location = React.useRef( + visible && customLocation.length ? customLocation : undefined, + ); + + /** + * Resets the widget state and loading status + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetches weather data from wttr.in + */ + const getWeather = React.useCallback(async () => { + if (!visible) return; + if (!location.current) { + const position = await Promise.race([getPosition(), Utils.timeout(5000)]); + if (!position) await getWeather(); + const { city, zip } = position?.address || {}; + location.current = zip || city; + if (!location.current) return setLoading(false); + } + try { + const result = await fetch( + `https://wttr.in/${location.current}?format=j1`, + ); + const data = await result.json(); + setState({ location: location.current, data }); + } catch { + // eslint-disable-next-line no-console + console.error("Error while fetching weather") + } + setLoading(false); + }, [visible, location]); + + useServerSocket("weather", visible, getWeather, resetWidget, setLoading); + useWidgetRefresh(visible, getWeather, refresh); + + if (loading) return ; + if (!state || !state.data.current_condition) return null; + + const { + temp_C: tempC, + temp_F: tempF, + weatherDesc, + } = state.data.current_condition[0]; + const temperature = unit === "C" ? tempC : tempF; + const wttrUnitParam = unit === "C" ? "?m" : "?u"; + + const description = weatherDesc[0].value; + + const { astronomy } = state.data.weather[0]; + const sunriseData = astronomy[0].sunrise.replace(" AM", "").split(":"); + const sunsetData = astronomy[0].sunset.replace(" PM", "").split(":"); + + const now = new Date(); + const nowIntervalStart = new Date(); + nowIntervalStart.setHours(nowIntervalStart.getHours() - 1); + const nowIntervalStop = new Date(); + nowIntervalStop.setHours(nowIntervalStop.getHours() + 1); + const sunriseTime = new Date(); + sunriseTime.setHours( + parseInt(sunriseData[0], 10), + parseInt(sunriseData[1], 10), + 0, + 0, + ); + const sunsetTime = new Date(); + sunsetTime.setHours( + parseInt(sunsetData[0], 10) + 12, + parseInt(sunsetData[1], 10), + 0, + 0, + ); + + const atNight = sunriseTime >= now || now >= sunsetTime; + + const Icon = getIcon(description, atNight); + const label = getLabel(state.location, temperature, unit, hideLocation); + + const sunRising = + sunriseTime >= nowIntervalStart && sunriseTime <= nowIntervalStop; + const sunSetting = + sunsetTime >= nowIntervalStart && sunsetTime <= nowIntervalStop; + + /** + * Handles right-click event to refresh weather data + * @param {Event} e - The event object + */ + const onRightClick = (e) => { + Utils.clickEffect(e); + setLoading(true); + getWeather(); + Utils.notification("Refreshing forecast from wttr.in...", pushMissive); + }; + + const classes = Utils.classNames("weather", { + "weather--sunrise": sunRising, + "weather--sunset": sunSetting, + }); + + return ( + openWeather(e, pushMissive)} + onRightClick={onRightClick} + disableSlider + > + {!hideGradient &&
} + {label} + + ); +}); + +Widget.displayName = "Weather"; + +/** + * Returns the appropriate weather icon based on the description and time of day + * @param {string} description - Weather description + * @param {boolean} atNight - Whether it is currently night time + * @returns {JSX.Element} - The weather icon component + */ +function getIcon(description, atNight) { + if (description.includes("fog") || description.includes("mist")) { + return Icons.Fog; + } + if (description.includes("storm")) return Icons.Storm; + if (description.includes("snow")) return Icons.Snow; + if (description.includes("rain")) return Icons.Rain; + if (description.includes("cloud")) return Icons.Cloud; + if (atNight) return Icons.Moon; + return Icons.Sun; +} + +/** + * Returns the label for the weather widget + * @param {string} location - The location name + * @param {string} temperature - The temperature value + * @param {string} unit - The temperature unit (C or F) + * @param {boolean} hideLocation - Whether to hide the location name + * @returns {string} - The label text + */ +function getLabel(location, temperature, unit, hideLocation) { + if (!location) return "Fetching..."; + if (hideLocation) return `${temperature}°${unit}`; + return `${location}, ${temperature}°${unit}`; +} + +/** + * Opens the weather forecast in a new tab + * @param {Event} e - The event object + * @param {Function} pushMissive - Function to push notifications + */ +function openWeather(e, pushMissive) { + Utils.clickEffect(e); + Utils.notification("Opening forecast from wttr.in...", pushMissive); +} + +/** + * Gets the current geographical position of the user + * @returns {Promise} - The position object + */ +async function getPosition() { + return new Promise((resolve) => + navigator.geolocation.getCurrentPosition(resolve), + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/wifi.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/wifi.jsx new file mode 100755 index 0000000..c7bedcd --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/wifi.jsx @@ -0,0 +1,154 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { wifiStyles as styles } from "../../styles/components/data/wifi"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 20000; + +/** + * Wifi widget component. + * @returns {JSX.Element|null} The Wifi widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings, pushMissive } = useSimpleBarContext(); + const { widgets, networkWidgetOptions } = settings; + const { wifiWidget } = widgets; + const { + refreshFrequency, + hideWifiIfDisabled, + toggleWifiOnClick, + networkDevice, + hideNetworkName, + showOnDisplay, + showIcon, + } = networkWidgetOptions; + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && wifiWidget; + + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + /** + * Resets the widget state. + */ + const resetWidget = () => { + setState(undefined); + setLoading(false); + }; + + /** + * Fetches the wifi status and SSID. + */ + const getWifi = React.useCallback(async () => { + if (!visible) return; + const [status, ssid] = await Promise.all([ + Utils.cachedRun( + `ifconfig ${networkDevice} | grep status | cut -c 10-`, + refresh, + ), + Utils.cachedRun( + `system_profiler SPAirPortDataType | awk '/Current Network/ {getline;$1=$1;print $0 | "tr -d ':'";exit}'`, + refresh, + ), + ]); + setState({ + status: Utils.cleanupOutput(status), + ssid: Utils.cleanupOutput(ssid), + }); + setLoading(false); + }, [networkDevice, visible, refresh]); + + useServerSocket("wifi", visible, getWifi, resetWidget, setLoading); + useWidgetRefresh(visible, getWifi, refresh); + + if (loading) return ; + if (!state) return null; + + const { status, ssid } = state; + const isActive = status === "active"; + const name = renderName(ssid, hideNetworkName); + + if (hideWifiIfDisabled && !isActive) return null; + + const classes = Utils.classNames("wifi", { + "wifi--hidden-name": !name, + "wifi--inactive": !isActive, + }); + + const Icon = isActive ? Icons.Wifi : Icons.WifiOff; + + /** + * Handles the click event to toggle wifi. + * @param {React.MouseEvent} e - The click event. + */ + const onClick = async (e) => { + Utils.clickEffect(e); + await toggleWifi(isActive, networkDevice, pushMissive); + getWifi(); + }; + + return ( + + {name} + + ); +}); + +Widget.displayName = "Wifi"; + +/** + * Toggles the wifi on or off. + * @param {boolean} isActive - Whether the wifi is currently active. + * @param {string} networkDevice - The network device name. + * @param {function} pushMissive - Function to push notifications. + */ +async function toggleWifi(isActive, networkDevice, pushMissive) { + if (isActive) { + await Uebersicht.run(`networksetup -setairportpower ${networkDevice} off`); + Utils.notification("Disabling network...", pushMissive); + } else { + await Uebersicht.run(`networksetup -setairportpower ${networkDevice} on`); + Utils.notification("Enabling network...", pushMissive); + } +} + +/** + * Opens the wifi preferences pane. + * @param {React.MouseEvent} e - The click event. + */ +function openWifiPreferences(e) { + Utils.clickEffect(e); + Uebersicht.run(`open /System/Library/PreferencePanes/Network.prefPane/`); +} + +/** + * Renders the wifi network name. + * @param {string} name - The network name. + * @param {boolean} hideNetworkName - Whether to hide the network name. + * @returns {string} The rendered network name. + */ +function renderName(name, hideNetworkName) { + if (!name || hideNetworkName) return ""; + if (name === "with an AirPort network.y off.") return "Disabled"; + if (name === "with an AirPort network.") return "Searching..."; + return name; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/youtube-music.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/youtube-music.jsx new file mode 100755 index 0000000..bf586b1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/youtube-music.jsx @@ -0,0 +1,191 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Icons from "../icons/icons.jsx"; +import * as Utils from "../../utils"; + +export { youtubeMusicStyles as styles } from "../../styles/components/data/youtube-music"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 10000; + +/** + * YouTube Music Widget component. + * @returns {JSX.Element} The YouTube Music widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { + widgets: { youtubeMusicWidget }, + youtubeMusicWidgetOptions: { + refreshFrequency, + showSpecter, + showOnDisplay, + youtubeMusicPort, + showIcon, + }, + } = settings; + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible on the current display + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && youtubeMusicWidget; + + const [state, setState] = React.useState(); + const [cachedAccessToken, setCachedAccessToken] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + const apiUrl = `http://localhost:${youtubeMusicPort}`; + + /** + * Resets the widget state. + */ + const resetWidget = () => { + setState(undefined); + setCachedAccessToken(undefined); + setLoading(false); + }; + + /** + * Fetches the access token for the YouTube Music API. + * @returns {Promise} The access token. + */ + const getAccessToken = React.useCallback(async () => { + // As of 2024/12/01, the generated access tokens don't expire + if (cachedAccessToken) return cachedAccessToken; + + const response = await fetch(`${apiUrl}/auth/simple-bar`, { + method: "POST", + }); + const json = await response.json(); + setCachedAccessToken(json.accessToken); + return json.accessToken; + }, [apiUrl, cachedAccessToken]); + + /** + * Fetches data from a specified route. + * @param {string} route - The API route to fetch data from. + * @param {string} [method="POST"] - The HTTP method to use. + * @returns {Promise} The fetch response. + */ + const fetchRoute = React.useCallback( + async (route, method = "POST") => { + const headers = {}; + const url = new URL(route, apiUrl); + + // All routes under /api are protected + const needsAuthentication = url.pathname.startsWith("/api"); + if (needsAuthentication) { + const accessToken = await getAccessToken(); + if (!accessToken) { + throw new Error("Failed to get access token"); + } + headers.Authorization = `Bearer ${accessToken}`; + } + + return await fetch(url, { method, headers }); + }, + [apiUrl, getAccessToken], + ); + + /** + * Refreshes the widget state by fetching the current song info. + */ + const refreshState = React.useCallback(async () => { + if (!visible) return; + + try { + const response = await fetchRoute("/api/v1/song-info", "GET"); + const json = await response.json(); + setState(json); + } catch { + // most likely due to offline server, reset state + resetWidget(); + } + }, [visible, fetchRoute]); + + // Use server socket to listen for updates + useServerSocket( + "youtube-music", + visible, + refreshState, + resetWidget, + setLoading, + ); + // Use widget refresh hook to periodically refresh the state + useWidgetRefresh(visible, refreshState, refresh); + + if (loading) return ; + + /** + * Handles click event to toggle play/pause. + * @param {React.MouseEvent} e - The click event. + */ + const onClick = async (e) => { + Utils.clickEffect(e); + await fetchRoute("/api/v1/toggle-play"); + await refreshState(); + }; + + /** + * Handles right-click event to skip to the next song. + * @param {React.MouseEvent} e - The right-click event. + */ + const onRightClick = async (e) => { + Utils.clickEffect(e); + await fetchRoute("/api/v1/next"); + await refreshState(); + }; + + /** + * Handles middle-click event to open YouTube Music app. + * @param {React.MouseEvent} e - The middle-click event. + */ + const onMiddleClick = async (e) => { + Utils.clickEffect(e); + Uebersicht.run(`open -a 'YouTube Music'`); + await refreshState(); + }; + + const classes = Utils.classNames("youtube-music", {}); + if (!state) return null; + const { title, artist, isPaused } = state; + if (!title) return null; + + const label = artist.length ? `${title} - ${artist}` : title; + const Icon = getIcon(isPaused); + + return ( + + {label} + + ); +}); + +Widget.displayName = "YouTube Music"; + +/** + * Returns the appropriate icon based on the play/pause state. + * @param {boolean} isPaused - Whether the music is paused. + * @returns {JSX.Element} The icon component. + */ +function getIcon(isPaused) { + return isPaused ? Icons.Paused : Icons.Playing; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/zoom.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/zoom.jsx new file mode 100755 index 0000000..2c123e9 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/data/zoom.jsx @@ -0,0 +1,107 @@ +import * as Uebersicht from "uebersicht"; +import * as DataWidget from "./data-widget.jsx"; +import * as DataWidgetLoader from "./data-widget-loader.jsx"; +import * as Icons from "../icons/icons.jsx"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import useWidgetRefresh from "../../hooks/use-widget-refresh"; +import useServerSocket from "../../hooks/use-server-socket"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils"; + +export { zoomStyles as styles } from "../../styles/components/data/zoom"; + +const { React } = Uebersicht; + +const DEFAULT_REFRESH_FREQUENCY = 5000; + +/** + * Zoom widget component. + * @returns {JSX.Element|null} The Zoom widget. + */ +export const Widget = React.memo(() => { + const { displayIndex, settings } = useSimpleBarContext(); + const { widgets, zoomWidgetOptions } = settings; + const { zoomWidget } = widgets; + const { refreshFrequency, showVideo, showMic, showOnDisplay } = + zoomWidgetOptions; + + // Determine the refresh frequency for the widget + const refresh = React.useMemo( + () => + Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), + [refreshFrequency], + ); + + // Determine if the widget should be visible + const visible = + Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && zoomWidget; + + const [state, setState] = React.useState(); + const [loading, setLoading] = React.useState(visible); + + /** + * Reset the widget state. + */ + const resetWidget = React.useCallback(() => { + setState(undefined); + setLoading(false); + }, []); + + /** + * Fetch the Zoom status for mic and video. + */ + const getZoom = React.useCallback(async () => { + if (!visible) return; + try { + const [mic, video] = await Promise.all([ + Utils.cachedRun( + `osascript ./simple-bar/lib/scripts/zoom-mute-status.applescript`, + refresh, + ), + Utils.cachedRun( + `osascript ./simple-bar/lib/scripts/zoom-video-status.applescript`, + refresh, + ), + ]); + setState({ + mic: Utils.cleanupOutput(mic), + video: Utils.cleanupOutput(video), + }); + setLoading(false); + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error fetching Zoom status:", error); + setLoading(false); + } + }, [visible, refresh]); + + // Use server socket to listen for Zoom events + useServerSocket("zoom", visible, getZoom, resetWidget, setLoading); + // Refresh the widget at the specified interval + useWidgetRefresh(visible, getZoom, refresh); + + if (loading) return ; + if (!state || (!state.mic.length && !state.video.length)) return null; + + const { mic, video } = state; + + const VideoIcon = video === "off" ? Icons.CameraOff : Icons.Camera; + const MicIcon = mic === "off" ? Icons.MicOff : Icons.MicOn; + + return ( + + {showVideo && ( + + + + )} + {showMic && ( + + + + )} + + ); +}); + +Widget.displayName = "Zoom"; diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/error.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/error.jsx new file mode 100755 index 0000000..135cb29 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/error.jsx @@ -0,0 +1,42 @@ +import * as Settings from "./settings/settings.jsx"; +import * as Utils from "../utils"; + +// Error messages for different types of errors +const message = { + error: "Something went wrong…", + yabaiError: "yabai is not running", + aerospaceError: "AeroSpace is either not running or outdated", + noOutput: "Loading…", + noData: "JSON error…", +}; + +/** + * Component to display error messages based on the type of error. + * @param {Object} props - The properties object. + * @param {string} props.type - The type of error. + * @param {string} props.classes - Additional CSS classes. + * @returns {JSX.Element} The error component. + */ +export function Component({ type, classes }) { + // Combine base class with additional classes and conditional loading class + const errorClasses = Utils.classNames("simple-bar--empty", classes, { + "simple-bar--loading": type === "noOutput", + }); + + // Refresh the component after 2 seconds for general errors and JSON errors + if (type === "error" || type === "noData") { + setTimeout(Utils.softRefresh, 2000); + } + + // Refresh the component after 15 seconds for yabai and aerospace errors + if (type === "yabaiError" || type === "aerospaceError") { + setTimeout(Utils.softRefresh, 15000); + } + + return ( +
+ simple-bar-index.jsx: {message[type]} + +
+ ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/icon.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/icon.jsx new file mode 100755 index 0000000..c46f60c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/icon.jsx @@ -0,0 +1,40 @@ +import * as Uebersicht from "uebersicht"; + +const { React } = Uebersicht; + +/** + * Icon component renders an SVG element. + * + * @param {Object} props - The properties object. + * @param {number} [props.width=24] - The width of the SVG. + * @param {number} [props.height=24] - The height of the SVG. + * @param {React.ReactNode} props.children - The children elements to be rendered inside the SVG. + * @returns {JSX.Element} The SVG element. + */ +export default function Icon({ width = 24, height = 24, children, ...props }) { + return ( + + {children} + + ); +} + +/** + * SuspenseIcon component renders its children within a React.Suspense component. + * + * @param {Object} props - The properties object. + * @param {React.ReactNode} props.children - The children elements to be rendered inside the Suspense component. + * @returns {JSX.Element} The Suspense component with a fallback SVG loader. + */ +export function SuspenseIcon({ children }) { + return ( + }> + {children} + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/icons.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/icons.jsx new file mode 100755 index 0000000..514a2f1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/icons.jsx @@ -0,0 +1,337 @@ +import * as Uebersicht from "uebersicht"; + +const { React } = Uebersicht; + +export const Default = React.lazy(() => import("./library/default.jsx")); +export const Ableton = React.lazy(() => import("./library/ableton.jsx")); +export const Activity = React.lazy(() => import("./library/activity.jsx")); +export const Add = React.lazy(() => import("./library/add.jsx")); +export const AffinityDesigner = React.lazy( + () => import("./library/affinity-designer.jsx"), +); +export const AffinityPhoto = React.lazy( + () => import("./library/affinity-photo.jsx"), +); +export const AffinityPublisher = React.lazy( + () => import("./library/affinity-publisher.jsx"), +); +export const Airmail = React.lazy(() => import("./library/airmail.jsx")); +export const Alfred = React.lazy(() => import("./library/alfred.jsx")); +export const AndroidMessages = React.lazy( + () => import("./library/android-messages.jsx"), +); +export const AndroidStudio = React.lazy( + () => import("./library/android-studio.jsx"), +); +export const Anki = React.lazy(() => import("./library/anki.jsx")); +export const Antigravity = React.lazy( + () => import("./library/antigravity.jsx"), +); +export const Anytype = React.lazy(() => import("./library/anytype.jsx")); +export const AppleSimulator = React.lazy( + () => import("./library/apple-simulator.jsx"), +); +export const AppStore = React.lazy(() => import("./library/app-store.jsx")); +export const Apple = React.lazy(() => import("./library/apple.jsx")); +export const Arc = React.lazy(() => import("./library/arc.jsx")); +export const Atom = React.lazy(() => import("./library/atom.jsx")); +export const Audacity = React.lazy(() => import("./library/audacity.jsx")); +export const Aqua = React.lazy(() => import("./library/aqua.jsx")); +export const Bank = React.lazy(() => import("./library/bank.jsx")); +export const BattleNet = React.lazy(() => import("./library/battle-net.jsx")); +export const BambuStudio = React.lazy( + () => import("./library/bambu-studio.jsx"), +); +export const Bear = React.lazy(() => import("./library/bear.jsx")); +export const Beekeeper = React.lazy(() => import("./library/beekeeper.jsx")); +export const Bell = React.lazy(() => import("./library/bell.jsx")); +export const BellOff = React.lazy(() => import("./library/bell-off.jsx")); +export const Bitcoin = React.lazy(() => import("./library/bitcoin.jsx")); +export const BitWarden = React.lazy(() => import("./library/bit-warden.jsx")); +export const Blender = React.lazy(() => import("./library/blender.jsx")); +export const Book = React.lazy(() => import("./library/book.jsx")); +export const BraveBrowser = React.lazy( + () => import("./library/brave-browser.jsx"), +); +export const Bruno = React.lazy(() => import("./library/bruno.jsx")); +export const CLion = React.lazy(() => import("./library/c-lion.jsx")); +export const Calendar = React.lazy(() => import("./library/calendar.jsx")); +export const Camera = React.lazy(() => import("./library/camera.jsx")); +export const CameraOff = React.lazy(() => import("./library/camera-off.jsx")); +export const Cancel = React.lazy(() => import("./library/cancel.jsx")); +export const Caprine = React.lazy(() => import("./library/caprine.jsx")); +export const CARROT = React.lazy(() => import("./library/ca-r-r-o-t.jsx")); +export const Celo = React.lazy(() => import("./library/celo.jsx")); +export const Charging = React.lazy(() => import("./library/charging.jsx")); +export const ChatGPT = React.lazy(() => import("./library/chat-gpt.jsx")); +export const Chatterino = React.lazy(() => import("./library/chatterino.jsx")); +export const ChevronBottom = React.lazy( + () => import("./library/chevron-bottom.jsx"), +); +export const ChevronLeft = React.lazy( + () => import("./library/chevron-left.jsx"), +); +export const ChevronRight = React.lazy( + () => import("./library/chevron-right.jsx"), +); +export const ChevronTop = React.lazy(() => import("./library/chevron-top.jsx")); +export const CheckBox = React.lazy(() => import("./library/check-box.jsx")); +export const ClickUp = React.lazy(() => import("./library/click-up.jsx")); +export const Claude = React.lazy(() => import("./library/claude.jsx")); +export const ClaudeCode = React.lazy(() => import("./library/claude-code.jsx")); +export const Cline = React.lazy(() => import("./library/cline.jsx")); +export const Clock = React.lazy(() => import("./library/clock.jsx")); +export const Close = React.lazy(() => import("./library/close.jsx")); +export const Cloud = React.lazy(() => import("./library/cloud.jsx")); +export const Codex = React.lazy(() => import("./library/codex.jsx")); +export const Code = React.lazy(() => import("./library/code.jsx")); +export const Coffee = React.lazy(() => import("./library/coffee.jsx")); +export const ColorPicker = React.lazy( + () => import("./library/color-picker.jsx"), +); +export const ComfyUI = React.lazy(() => import("./library/comfy-ui.jsx")); +export const Copilot = React.lazy(() => import("./library/copilot.jsx")); +export const CPU = React.lazy(() => import("./library/cp-u.jsx")); +export const Cursor = React.lazy(() => import("./library/cursor.jsx")); +export const DataGrip = React.lazy(() => import("./library/data-grip.jsx")); +export const Date = React.lazy(() => import("./library/date.jsx")); +export const Deezer = React.lazy(() => import("./library/deezer.jsx")); +export const Desktop = React.lazy(() => import("./library/desktop.jsx")); +export const DEVONthink3 = React.lazy( + () => import("./library/de-v-o-nthink3.jsx"), +); +export const Discord = React.lazy(() => import("./library/discord.jsx")); +export const Docker = React.lazy(() => import("./library/docker.jsx")); +export const Dollar = React.lazy(() => import("./library/dollar.jsx")); +export const DownArrow = React.lazy(() => import("./library/down-arrow.jsx")); +export const Download = React.lazy(() => import("./library/download.jsx")); +export const Drafts = React.lazy(() => import("./library/drafts.jsx")); +export const Dropbox = React.lazy(() => import("./library/dropbox.jsx")); +export const Element = React.lazy(() => import("./library/element.jsx")); +export const Emacs = React.lazy(() => import("./library/emacs.jsx")); +export const Ethereum = React.lazy(() => import("./library/ethereum.jsx")); +export const EvernoteLegacy = React.lazy( + () => import("./library/evernote-legacy.jsx"), +); +export const FaceTime = React.lazy(() => import("./library/face-time.jsx")); +export const Figma = React.lazy(() => import("./library/figma.jsx")); +export const FinalCutPro = React.lazy( + () => import("./library/final-cut-pro.jsx"), +); +export const Finder = React.lazy(() => import("./library/finder.jsx")); +export const Firefox = React.lazy(() => import("./library/firefox.jsx")); +export const FirefoxDeveloperEdition = React.lazy( + () => import("./library/firefox-developer-edition.jsx"), +); +export const Fleet = React.lazy(() => import("./library/fleet.jsx")); +export const Fog = React.lazy(() => import("./library/fog.jsx")); +export const Folx = React.lazy(() => import("./library/folx.jsx")); +export const FreeTube = React.lazy(() => import("./library/free-tube.jsx")); +export const Gear = React.lazy(() => import("./library/gear.jsx")); +export const Ghostty = React.lazy(() => import("./library/ghostty.jsx")); +export const GitHub = React.lazy(() => import("./library/git-hub.jsx")); +export const GoodNotes = React.lazy(() => import("./library/good-notes.jsx")); +export const GoogleChrome = React.lazy( + () => import("./library/google-chrome.jsx"), +); +export const GnuCash = React.lazy(() => import("./library/gnu-cash.jsx")); +export const GoLand = React.lazy(() => import("./library/go-land.jsx")); +export const Goose = React.lazy(() => import("./library/goose.jsx")); +export const Grammarly = React.lazy(() => import("./library/grammarly.jsx")); +export const Helium = React.lazy(() => import("./library/helium.jsx")); +export const HomeAssistant = React.lazy( + () => import("./library/home-assistant.jsx"), +); +export const HTTPie = React.lazy(() => import("./library/ht-t-pie.jsx")); +export const Idea = React.lazy(() => import("./library/idea.jsx")); +export const Insomnia = React.lazy(() => import("./library/insomnia.jsx")); +export const Iris = React.lazy(() => import("./library/iris.jsx")); +export const Italic = React.lazy(() => import("./library/italic.jsx")); +export const Joplin = React.lazy(() => import("./library/joplin.jsx")); +export const Kakoune = React.lazy(() => import("./library/kakoune.jsx")); +export const KeePassXC = React.lazy(() => import("./library/kee-pass-x-c.jsx")); +export const Keyboard = React.lazy(() => import("./library/keyboard.jsx")); +export const KeyboardMaestro = React.lazy( + () => import("./library/keyboard-maestro.jsx"), +); +export const Keynote = React.lazy(() => import("./library/keynote.jsx")); +export const LeagueOfLegends = React.lazy( + () => import("./library/league-of-legends.jsx"), +); +export const LibreWolf = React.lazy(() => import("./library/libre-wolf.jsx")); +export const Linear = React.lazy(() => import("./library/linear.jsx")); +export const LMStudio = React.lazy(() => import("./library/lm-studio.jsx")); +export const MaestroAI = React.lazy(() => import("./library/maestro-ai.jsx")); +export const Mail = React.lazy(() => import("./library/mail.jsx")); +export const Mamp = React.lazy(() => import("./library/mamp.jsx")); +export const Manus = React.lazy(() => import("./library/manus.jsx")); +export const Matlab = React.lazy(() => import("./library/matlab.jsx")); +export const Mattermost = React.lazy(() => import("./library/mattermost.jsx")); +export const Messages = React.lazy(() => import("./library/messages.jsx")); +export const MicOff = React.lazy(() => import("./library/mic-off.jsx")); +export const MicOn = React.lazy(() => import("./library/mic-on.jsx")); +export const MicrosoftEdge = React.lazy( + () => import("./library/microsoft-edge.jsx"), +); +export const MicrosoftExcel = React.lazy( + () => import("./library/microsoft-excel.jsx"), +); +export const MicrosoftOutlook = React.lazy( + () => import("./library/microsoft-outlook.jsx"), +); +export const MicrosoftPowerPoint = React.lazy( + () => import("./library/microsoft-power-point.jsx"), +); +export const MicrosoftWord = React.lazy( + () => import("./library/microsoft-word.jsx"), +); +export const Mimestream = React.lazy(() => import("./library/mimestream.jsx")); +export const MinBrowser = React.lazy(() => import("./library/min-browser.jsx")); +export const Miro = React.lazy(() => import("./library/miro.jsx")); +export const MoneroGUI = React.lazy(() => import("./library/monero-gui.jsx")); +export const MongoDB = React.lazy(() => import("./library/mongo-db.jsx")); +export const Moon = React.lazy(() => import("./library/moon.jsx")); +export const Mpv = React.lazy(() => import("./library/mpv.jsx")); +export const Music = React.lazy(() => import("./library/music.jsx")); +export const N8n = React.lazy(() => import("./library/n8n.jsx")); +export const NeteaseMusic = React.lazy( + () => import("./library/netease-music.jsx"), +); +export const NetNewsWire = React.lazy( + () => import("./library/net-news-wire.jsx"), +); +export const Notability = React.lazy(() => import("./library/notability.jsx")); +export const NotebookLM = React.lazy(() => import("./library/notebook-lm.jsx")); +export const Notes = React.lazy(() => import("./library/notes.jsx")); +export const Notion = React.lazy(() => import("./library/notion.jsx")); +export const Nova = React.lazy(() => import("./library/nova.jsx")); +export const NoVolume = React.lazy(() => import("./library/no-volume.jsx")); +export const Numbers = React.lazy(() => import("./library/numbers.jsx")); +export const Obsidian = React.lazy(() => import("./library/obsidian.jsx")); +export const OBSStudio = React.lazy(() => import("./library/ob-s-studio.jsx")); +export const Ollama = React.lazy(() => import("./library/ollama.jsx")); +export const OmniFocus = React.lazy(() => import("./library/omni-focus.jsx")); +export const OnePassword = React.lazy( + () => import("./library/one-password.jsx"), +); +export const OpenBook = React.lazy(() => import("./library/open-book.jsx")); +export const OpenClaw = React.lazy(() => import("./library/open-claw.jsx")); +export const Opencode = React.lazy(() => import("./library/opencode.jsx")); +export const OrbStack = React.lazy(() => import("./library/orb-stack.jsx")); +export const Pages = React.lazy(() => import("./library/pages.jsx")); +export const Parallels = React.lazy(() => import("./library/parallels.jsx")); +export const Paused = React.lazy(() => import("./library/paused.jsx")); +export const Perplexity = React.lazy(() => import("./library/perplexity.jsx")); +export const PDF = React.lazy(() => import("./library/pdf.jsx")); +export const PHPStorm = React.lazy(() => import("./library/php-storm.jsx")); +export const Pihole = React.lazy(() => import("./library/pihole.jsx")); +export const Pine = React.lazy(() => import("./library/pine.jsx")); +export const Pins = React.lazy(() => import("./library/pins.jsx")); +export const Playing = React.lazy(() => import("./library/playing.jsx")); +export const Plex = React.lazy(() => import("./library/plex.jsx")); +export const Podcasts = React.lazy(() => import("./library/podcasts.jsx")); +export const Pomodone = React.lazy(() => import("./library/pomodone.jsx")); +export const Postman = React.lazy(() => import("./library/postman.jsx")); +export const ProtonMail = React.lazy(() => import("./library/proton-mail.jsx")); +export const PyCharm = React.lazy(() => import("./library/py-charm.jsx")); +export const Quip = React.lazy(() => import("./library/quip.jsx")); +export const QuteBrowser = React.lazy( + () => import("./library/qute-browser.jsx"), +); +export const Radar = React.lazy(() => import("./library/radar.jsx")); +export const Rain = React.lazy(() => import("./library/rain.jsx")); +export const Ram = React.lazy(() => import("./library/ram.jsx")); +export const Redis = React.lazy(() => import("./library/redis.jsx")); +export const Reeder5 = React.lazy(() => import("./library/reeder5.jsx")); +export const Reminders = React.lazy(() => import("./library/reminders.jsx")); +export const Remnote = React.lazy(() => import("./library/remnote.jsx")); +export const RemoteDesktop = React.lazy( + () => import("./library/remote-desktop.jsx"), +); +export const Remove = React.lazy(() => import("./library/remove.jsx")); +export const Replit = React.lazy(() => import("./library/replit.jsx")); +export const Rider = React.lazy(() => import("./library/rider.jsx")); +export const RocketChat = React.lazy(() => import("./library/rocket-chat.jsx")); +export const Roon = React.lazy(() => import("./library/roon.jsx")); +export const RoyalTSX = React.lazy(() => import("./library/royal-tsx.jsx")); +export const RubyMine = React.lazy(() => import("./library/ruby-mine.jsx")); +export const RustRover = React.lazy(() => import("./library/rust-rover.jsx")); +export const Safari = React.lazy(() => import("./library/safari.jsx")); +export const Screens4 = React.lazy(() => import("./library/screens4.jsx")); +export const SequelAce = React.lazy(() => import("./library/sequel-ace.jsx")); +export const SequelPro = React.lazy(() => import("./library/sequel-pro.jsx")); +export const Setapp = React.lazy(() => import("./library/setapp.jsx")); +export const Signal = React.lazy(() => import("./library/signal.jsx")); +export const Sketch = React.lazy(() => import("./library/sketch.jsx")); +export const SketchUp = React.lazy(() => import("./library/sketch-up.jsx")); +export const Skype = React.lazy(() => import("./library/skype.jsx")); +export const Slack = React.lazy(() => import("./library/slack.jsx")); +export const Snow = React.lazy(() => import("./library/snow.jsx")); +export const Spark = React.lazy(() => import("./library/spark.jsx")); +export const Spotify = React.lazy(() => import("./library/spotify.jsx")); +export const Spotlight = React.lazy(() => import("./library/spotlight.jsx")); +export const Spotube = React.lazy(() => import("./library/spotube.jsx")); +export const Statistics = React.lazy(() => import("./library/statistics.jsx")); +export const Stopped = React.lazy(() => import("./library/stopped.jsx")); +export const Storm = React.lazy(() => import("./library/storm.jsx")); +export const SublimeText = React.lazy( + () => import("./library/sublime-text.jsx"), +); +export const Sun = React.lazy(() => import("./library/sun.jsx")); +export const SuperProductivity = React.lazy( + () => import("./library/super-productivity.jsx"), +); +export const TablePlus = React.lazy(() => import("./library/table-plus.jsx")); +export const Tailscale = React.lazy(() => import("./library/tailscale.jsx")); +export const Teams = React.lazy(() => import("./library/teams.jsx")); +export const TeamSpeak = React.lazy(() => import("./library/team-speak.jsx")); +export const Telegram = React.lazy(() => import("./library/telegram.jsx")); +export const Terminal = React.lazy(() => import("./library/terminal.jsx")); +export const Text = React.lazy(() => import("./library/text.jsx")); +export const Thermostat = React.lazy(() => import("./library/thermostat.jsx")); +export const Things = React.lazy(() => import("./library/things.jsx")); +export const Thunderbird = React.lazy( + () => import("./library/thunderbird.jsx"), +); +export const TickTick = React.lazy(() => import("./library/tick-tick.jsx")); +export const Tidal = React.lazy(() => import("./library/tidal.jsx")); +export const Todoist = React.lazy(() => import("./library/todoist.jsx")); +export const TorBrowser = React.lazy(() => import("./library/tor-browser.jsx")); +export const Tower = React.lazy(() => import("./library/tower.jsx")); +export const Transmit = React.lazy(() => import("./library/transmit.jsx")); +export const Trello = React.lazy(() => import("./library/trello.jsx")); +export const Twitter = React.lazy(() => import("./library/twitter.jsx")); +export const UpArrow = React.lazy(() => import("./library/up-arrow.jsx")); +export const Upload = React.lazy(() => import("./library/upload.jsx")); +export const Vim = React.lazy(() => import("./library/vim.jsx")); +export const Vivaldi = React.lazy(() => import("./library/vivaldi.jsx")); +export const VLC = React.lazy(() => import("./library/vl-c.jsx")); +export const VMwareFusion = React.lazy( + () => import("./library/vmware-fusion.jsx"), +); +export const VolumeHigh = React.lazy(() => import("./library/volume-high.jsx")); +export const VolumeLow = React.lazy(() => import("./library/volume-low.jsx")); +export const VolumeMuted = React.lazy( + () => import("./library/volume-muted.jsx"), +); +export const VPN = React.lazy(() => import("./library/vp-n.jsx")); +export const VPNOff = React.lazy(() => import("./library/vp-n-off.jsx")); +export const VSCodium = React.lazy(() => import("./library/vs-codium.jsx")); +export const Warp = React.lazy(() => import("./library/warp.jsx")); +export const WebStorm = React.lazy(() => import("./library/web-storm.jsx")); +export const Wechat = React.lazy(() => import("./library/wechat.jsx")); +export const WhatsApp = React.lazy(() => import("./library/whats-app.jsx")); +export const Widget = React.lazy(() => import("./library/widget.jsx")); +export const Wifi = React.lazy(() => import("./library/wifi.jsx")); +export const WifiOff = React.lazy(() => import("./library/wifi-off.jsx")); +export const Windows = React.lazy(() => import("./library/windows.jsx")); +export const Xcode = React.lazy(() => import("./library/xcode.jsx")); +export const YoutubeMusic = React.lazy( + () => import("./library/youtube-music.jsx"), +); +export const Zed = React.lazy(() => import("./library/zed.jsx")); +export const ZenBrowser = React.lazy(() => import("./library/zen-browser.jsx")); +export const Zeplin = React.lazy(() => import("./library/zeplin.jsx")); +export const Zoom = React.lazy(() => import("./library/zoom.jsx")); +export const Zotero = React.lazy(() => import("./library/zotero.jsx")); +export const Zulip = React.lazy(() => import("./library/zulip.jsx")); diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ableton.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ableton.jsx new file mode 100755 index 0000000..c57cf32 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ableton.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Ableton(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/activity.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/activity.jsx new file mode 100755 index 0000000..502cbc7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/activity.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Activity(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/add.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/add.jsx new file mode 100755 index 0000000..fb2663d --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/add.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Add(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-designer.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-designer.jsx new file mode 100755 index 0000000..4840d80 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-designer.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function AffinityDesigner(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-photo.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-photo.jsx new file mode 100755 index 0000000..d4eb1a0 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-photo.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function AffinityPhoto(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-publisher.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-publisher.jsx new file mode 100755 index 0000000..127ed96 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/affinity-publisher.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function AffinityPublisher(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/airmail.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/airmail.jsx new file mode 100755 index 0000000..bad0d1f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/airmail.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function Airmail(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/alfred.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/alfred.jsx new file mode 100755 index 0000000..909dccf --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/alfred.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Alfred(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/android-messages.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/android-messages.jsx new file mode 100755 index 0000000..a074703 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/android-messages.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function AndroidMessages(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/android-studio.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/android-studio.jsx new file mode 100755 index 0000000..25fb85d --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/android-studio.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function AndroidStudio(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/anki.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/anki.jsx new file mode 100755 index 0000000..6a177aa --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/anki.jsx @@ -0,0 +1,16 @@ +import Icon from "../icon.jsx"; + +export default function Anki(props) { + return ( + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/antigravity.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/antigravity.jsx new file mode 100755 index 0000000..0c71174 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/antigravity.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Antigravity(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/anytype.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/anytype.jsx new file mode 100755 index 0000000..a585ecd --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/anytype.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Anytype(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/app-store.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/app-store.jsx new file mode 100755 index 0000000..91ebdc9 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/app-store.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function AppStore(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/apple-simulator.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/apple-simulator.jsx new file mode 100755 index 0000000..13abc8f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/apple-simulator.jsx @@ -0,0 +1,16 @@ +import Icon from "../icon.jsx"; + +export default function Ableton(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/apple.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/apple.jsx new file mode 100755 index 0000000..dc8ffe8 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/apple.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Apple(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/aqua.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/aqua.jsx new file mode 100755 index 0000000..8267772 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/aqua.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Aqua(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/arc.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/arc.jsx new file mode 100755 index 0000000..dd7a339 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/arc.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function Arc(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/atom.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/atom.jsx new file mode 100755 index 0000000..104203e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/atom.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function Atom(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/audacity.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/audacity.jsx new file mode 100755 index 0000000..c5b72ea --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/audacity.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Audacity(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bambu-studio.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bambu-studio.jsx new file mode 100755 index 0000000..66c60d0 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bambu-studio.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function BambuStudio(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bank.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bank.jsx new file mode 100755 index 0000000..a777b0a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bank.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Bank(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/battle-net.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/battle-net.jsx new file mode 100755 index 0000000..120d215 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/battle-net.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function BattleNet(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bear.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bear.jsx new file mode 100755 index 0000000..249f1d5 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bear.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Bear(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/beekeeper.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/beekeeper.jsx new file mode 100755 index 0000000..121e00b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/beekeeper.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Beekeeper(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bell-off.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bell-off.jsx new file mode 100755 index 0000000..170e05f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bell-off.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function BellOff(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bell.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bell.jsx new file mode 100755 index 0000000..db84ce4 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bell.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Bell(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bit-warden.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bit-warden.jsx new file mode 100755 index 0000000..88ae754 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bit-warden.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function BitWarden(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bitcoin.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bitcoin.jsx new file mode 100755 index 0000000..116e1af --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bitcoin.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function Bitcoin(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/blender.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/blender.jsx new file mode 100755 index 0000000..5fcb14e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/blender.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Blender(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/book.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/book.jsx new file mode 100755 index 0000000..59c53a5 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/book.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Book(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/brave-browser.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/brave-browser.jsx new file mode 100755 index 0000000..66e72a9 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/brave-browser.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function BraveBrowser(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bruno.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bruno.jsx new file mode 100755 index 0000000..a36f8b5 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/bruno.jsx @@ -0,0 +1,11 @@ +import Icon from "../icon.jsx"; + +export default function Bruno(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/c-lion.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/c-lion.jsx new file mode 100755 index 0000000..fb7ff5d --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/c-lion.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function CLion(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ca-r-r-o-t.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ca-r-r-o-t.jsx new file mode 100755 index 0000000..94339d1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ca-r-r-o-t.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function CARROT(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/calendar.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/calendar.jsx new file mode 100755 index 0000000..613f1b0 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/calendar.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Calendar(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/camera-off.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/camera-off.jsx new file mode 100755 index 0000000..a0f3891 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/camera-off.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function CameraOff(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/camera.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/camera.jsx new file mode 100755 index 0000000..e18b0da --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/camera.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Camera(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cancel.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cancel.jsx new file mode 100755 index 0000000..f96294f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cancel.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Cancel(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/caprine.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/caprine.jsx new file mode 100755 index 0000000..6e3c3f2 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/caprine.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Caprine(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/celo.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/celo.jsx new file mode 100755 index 0000000..155c73d --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/celo.jsx @@ -0,0 +1,20 @@ +import Icon from "../icon.jsx"; + +export default function Celo(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/charging.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/charging.jsx new file mode 100755 index 0000000..808f939 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/charging.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Charging(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chat-gpt.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chat-gpt.jsx new file mode 100755 index 0000000..8efbe29 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chat-gpt.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function ChatGPT(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chatterino.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chatterino.jsx new file mode 100755 index 0000000..6970765 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chatterino.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Chatterino(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/check-box.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/check-box.jsx new file mode 100755 index 0000000..cf80ac0 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/check-box.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function CheckBox(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-bottom.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-bottom.jsx new file mode 100755 index 0000000..1ed7678 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-bottom.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function ChevronBottom(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-left.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-left.jsx new file mode 100755 index 0000000..f9da786 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-left.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function ChevronLeft(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-right.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-right.jsx new file mode 100755 index 0000000..028c8b1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-right.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function ChevronRight(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-top.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-top.jsx new file mode 100755 index 0000000..37f5dfc --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/chevron-top.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function ChevronTop(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/claude-code.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/claude-code.jsx new file mode 100755 index 0000000..65babc9 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/claude-code.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function ClaudeCode(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/claude.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/claude.jsx new file mode 100755 index 0000000..53f843b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/claude.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Claude(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/click-up.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/click-up.jsx new file mode 100755 index 0000000..467588e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/click-up.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function ClickUp(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cline.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cline.jsx new file mode 100755 index 0000000..11caeb8 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cline.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Cline(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/clock.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/clock.jsx new file mode 100755 index 0000000..ce01a6c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/clock.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Clock(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/close.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/close.jsx new file mode 100755 index 0000000..627ff65 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/close.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Close(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cloud.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cloud.jsx new file mode 100755 index 0000000..4b5b44a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cloud.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; +import * as Utils from "../../../utils"; + +export default function Cloud(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/code.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/code.jsx new file mode 100755 index 0000000..d0bd4cb --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/code.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Code(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/codex.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/codex.jsx new file mode 100755 index 0000000..332ea52 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/codex.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function Codex(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/coffee.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/coffee.jsx new file mode 100755 index 0000000..e168da6 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/coffee.jsx @@ -0,0 +1,15 @@ +import Icon from "../icon.jsx"; + +export default function Coffee(props) { + return ( + + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/color-picker.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/color-picker.jsx new file mode 100755 index 0000000..c02fd7a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/color-picker.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function ColorPicker(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/comfy-ui.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/comfy-ui.jsx new file mode 100755 index 0000000..5afa497 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/comfy-ui.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function ComfyUI(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/copilot.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/copilot.jsx new file mode 100755 index 0000000..151595c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/copilot.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Copilot(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cp-u.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cp-u.jsx new file mode 100755 index 0000000..7705607 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cp-u.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function CPU(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cursor.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cursor.jsx new file mode 100755 index 0000000..1b40ec3 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/cursor.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Cursor(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/data-grip.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/data-grip.jsx new file mode 100755 index 0000000..6203fe3 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/data-grip.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function DataGrip(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/date.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/date.jsx new file mode 100755 index 0000000..9e59c84 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/date.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Date(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/de-v-o-nthink3.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/de-v-o-nthink3.jsx new file mode 100755 index 0000000..5f5acd1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/de-v-o-nthink3.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function DEVONthink3(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/deezer.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/deezer.jsx new file mode 100755 index 0000000..ec0b2ae --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/deezer.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Deezer(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/default.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/default.jsx new file mode 100755 index 0000000..6a0902c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/default.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Default(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/desktop.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/desktop.jsx new file mode 100755 index 0000000..c7fae7b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/desktop.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Desktop(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/discord.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/discord.jsx new file mode 100755 index 0000000..7b1a27b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/discord.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Discord(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/docker.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/docker.jsx new file mode 100755 index 0000000..2ed8850 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/docker.jsx @@ -0,0 +1,11 @@ +import Icon from "../icon.jsx"; + +export default function Windows(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/dollar.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/dollar.jsx new file mode 100755 index 0000000..5a24b9f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/dollar.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Dollar(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/down-arrow.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/down-arrow.jsx new file mode 100755 index 0000000..4cfd2e1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/down-arrow.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function DownArrow(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/download.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/download.jsx new file mode 100755 index 0000000..e612225 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/download.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function Download(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/drafts.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/drafts.jsx new file mode 100755 index 0000000..7c4c114 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/drafts.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Drafts(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/dropbox.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/dropbox.jsx new file mode 100755 index 0000000..159fac3 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/dropbox.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Dropbox(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/element.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/element.jsx new file mode 100755 index 0000000..03de2a2 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/element.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Element(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/emacs.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/emacs.jsx new file mode 100755 index 0000000..59dd511 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/emacs.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Emacs(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ethereum.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ethereum.jsx new file mode 100755 index 0000000..7c29401 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ethereum.jsx @@ -0,0 +1,34 @@ +import Icon from "../icon.jsx"; + +export default function Ethereum(props) { + return ( + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/evernote-legacy.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/evernote-legacy.jsx new file mode 100755 index 0000000..fcda973 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/evernote-legacy.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function EvernoteLegacy(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/face-time.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/face-time.jsx new file mode 100755 index 0000000..df94f94 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/face-time.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function FaceTime(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/figma.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/figma.jsx new file mode 100755 index 0000000..af80266 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/figma.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Figma(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/final-cut-pro.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/final-cut-pro.jsx new file mode 100755 index 0000000..6d9800b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/final-cut-pro.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function FinalCutPro(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/finder.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/finder.jsx new file mode 100755 index 0000000..e71536c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/finder.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Finder(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/firefox-developer-edition.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/firefox-developer-edition.jsx new file mode 100755 index 0000000..afd96d2 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/firefox-developer-edition.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function FirefoxDeveloperEdition(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/firefox.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/firefox.jsx new file mode 100755 index 0000000..fca522e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/firefox.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Firefox(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/fleet.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/fleet.jsx new file mode 100755 index 0000000..474d739 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/fleet.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Fleet(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/fog.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/fog.jsx new file mode 100755 index 0000000..f1d9556 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/fog.jsx @@ -0,0 +1,20 @@ +import Icon from "../icon.jsx"; +import * as Utils from "../../../utils"; + +export default function Fog(props) { + return ( + + + + + + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/folx.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/folx.jsx new file mode 100755 index 0000000..4fc7f48 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/folx.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Folx(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/free-tube.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/free-tube.jsx new file mode 100755 index 0000000..849131e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/free-tube.jsx @@ -0,0 +1,16 @@ +import Icon from "../icon.jsx"; + +export default function FreeTube(props) { + return ( + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/gear.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/gear.jsx new file mode 100755 index 0000000..faba81b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/gear.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Gear(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ghostty.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ghostty.jsx new file mode 100755 index 0000000..2a63aa0 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ghostty.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Ghostty(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/git-hub.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/git-hub.jsx new file mode 100755 index 0000000..b2df650 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/git-hub.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function GitHub(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/gnu-cash.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/gnu-cash.jsx new file mode 100755 index 0000000..9059b9a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/gnu-cash.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function GnuCash(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/go-land.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/go-land.jsx new file mode 100755 index 0000000..9f37eed --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/go-land.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function GoLand(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/good-notes.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/good-notes.jsx new file mode 100755 index 0000000..857c7ac --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/good-notes.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function GoodNotes(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/google-chrome.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/google-chrome.jsx new file mode 100755 index 0000000..90cb83f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/google-chrome.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function GoogleChrome(props) { + return ( + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/goose.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/goose.jsx new file mode 100755 index 0000000..740916a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/goose.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function Goose(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/grammarly.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/grammarly.jsx new file mode 100755 index 0000000..574fc84 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/grammarly.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Grammarly(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/helium.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/helium.jsx new file mode 100755 index 0000000..141b2ff --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/helium.jsx @@ -0,0 +1,11 @@ +import Icon from "../icon.jsx"; + +export default function Helium(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/home-assistant.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/home-assistant.jsx new file mode 100755 index 0000000..3d94dc2 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/home-assistant.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function HomeAssistant(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ht-t-pie.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ht-t-pie.jsx new file mode 100755 index 0000000..20d99d7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ht-t-pie.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function HTTPie(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/idea.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/idea.jsx new file mode 100755 index 0000000..bdd92cf --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/idea.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Idea(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/insomnia.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/insomnia.jsx new file mode 100755 index 0000000..5d1fc12 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/insomnia.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Insomnia(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/iris.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/iris.jsx new file mode 100755 index 0000000..cb35f76 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/iris.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Iris(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/italic.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/italic.jsx new file mode 100755 index 0000000..cf19e23 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/italic.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Italic(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/joplin.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/joplin.jsx new file mode 100755 index 0000000..980784f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/joplin.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Joplin(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/kakoune.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/kakoune.jsx new file mode 100755 index 0000000..9d8d2ab --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/kakoune.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Kakoune(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/kee-pass-x-c.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/kee-pass-x-c.jsx new file mode 100755 index 0000000..1b73f58 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/kee-pass-x-c.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function KeePassXC(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keyboard-maestro.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keyboard-maestro.jsx new file mode 100755 index 0000000..f171ac7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keyboard-maestro.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function KeyboardMaestro(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keyboard.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keyboard.jsx new file mode 100755 index 0000000..1b5afc8 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keyboard.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Keyboard(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keynote.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keynote.jsx new file mode 100755 index 0000000..73dcd0c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/keynote.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Keynote(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/league-of-legends.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/league-of-legends.jsx new file mode 100755 index 0000000..808cfac --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/league-of-legends.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function LeagueOfLegends(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/libre-wolf.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/libre-wolf.jsx new file mode 100755 index 0000000..b1e856a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/libre-wolf.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function LibreWolf(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/linear.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/linear.jsx new file mode 100755 index 0000000..a71356c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/linear.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Linear(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/lm-studio.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/lm-studio.jsx new file mode 100755 index 0000000..ad2f9be --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/lm-studio.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function LMStudio(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/maestro-ai.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/maestro-ai.jsx new file mode 100755 index 0000000..8ae6ab1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/maestro-ai.jsx @@ -0,0 +1,11 @@ +import Icon from "../icon.jsx"; + +export default function MaestroAI(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mail.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mail.jsx new file mode 100755 index 0000000..5f331f2 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mail.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Mail(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mamp.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mamp.jsx new file mode 100755 index 0000000..bdfadca --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mamp.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Mamp(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/manus.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/manus.jsx new file mode 100755 index 0000000..041df0d --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/manus.jsx @@ -0,0 +1,17 @@ +import Icon from "../icon.jsx"; + +export default function Manus(props) { + return ( + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/matlab.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/matlab.jsx new file mode 100755 index 0000000..7208923 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/matlab.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Matlab(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mattermost.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mattermost.jsx new file mode 100755 index 0000000..eea42a9 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mattermost.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Mattermost(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/messages.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/messages.jsx new file mode 100755 index 0000000..afa1565 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/messages.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Messages(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mic-off.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mic-off.jsx new file mode 100755 index 0000000..f71ff3e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mic-off.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function MicOff(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mic-on.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mic-on.jsx new file mode 100755 index 0000000..76524ad --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mic-on.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function MicOn(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-edge.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-edge.jsx new file mode 100755 index 0000000..48e6caf --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-edge.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function MicrosoftEdge(props) { + return ( + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-excel.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-excel.jsx new file mode 100755 index 0000000..6f4df55 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-excel.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function MicrosoftExcel(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-outlook.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-outlook.jsx new file mode 100755 index 0000000..2de1829 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-outlook.jsx @@ -0,0 +1,11 @@ +import Icon from "../icon.jsx"; + +export default function MicrosoftOutlook(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-power-point.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-power-point.jsx new file mode 100755 index 0000000..2cdab52 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-power-point.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function MicrosoftPowerPoint(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-word.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-word.jsx new file mode 100755 index 0000000..7d3165b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/microsoft-word.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function MicrosoftWord(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mimestream.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mimestream.jsx new file mode 100755 index 0000000..1ed0a2b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mimestream.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Mimestream(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/min-browser.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/min-browser.jsx new file mode 100755 index 0000000..ed6060c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/min-browser.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function MinBrowser(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/miro.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/miro.jsx new file mode 100755 index 0000000..678bc73 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/miro.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Miro(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/monero-gui.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/monero-gui.jsx new file mode 100755 index 0000000..a5d95a7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/monero-gui.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function MoneroGUI(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mongo-db.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mongo-db.jsx new file mode 100755 index 0000000..3d57187 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mongo-db.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function MongoDB(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/moon.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/moon.jsx new file mode 100755 index 0000000..d8a5e15 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/moon.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; +import * as Utils from "../../../utils"; + +export default function Moon(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mpv.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mpv.jsx new file mode 100755 index 0000000..eef4479 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/mpv.jsx @@ -0,0 +1,16 @@ +import Icon from "../icon.jsx"; + +export default function Mpv(props) { + return ( + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/music.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/music.jsx new file mode 100755 index 0000000..6deefcc --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/music.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Music(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/n8n.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/n8n.jsx new file mode 100755 index 0000000..ab86385 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/n8n.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function N8n(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/net-news-wire.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/net-news-wire.jsx new file mode 100755 index 0000000..4db43e7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/net-news-wire.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function NetNewsWire(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/netease-music.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/netease-music.jsx new file mode 100755 index 0000000..0a31527 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/netease-music.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function NeteaseMusic(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/no-volume.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/no-volume.jsx new file mode 100755 index 0000000..0a146d1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/no-volume.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function NoVolume(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notability.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notability.jsx new file mode 100755 index 0000000..8a4c560 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notability.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Notability(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notebook-lm.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notebook-lm.jsx new file mode 100755 index 0000000..2be5095 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notebook-lm.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function NotebookLM(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notes.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notes.jsx new file mode 100755 index 0000000..23e8a43 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notes.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Notes(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notion.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notion.jsx new file mode 100755 index 0000000..ff12f11 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/notion.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Notion(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/nova.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/nova.jsx new file mode 100755 index 0000000..ee0bf11 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/nova.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function Nova(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/numbers.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/numbers.jsx new file mode 100755 index 0000000..0f98a60 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/numbers.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Numbers(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ob-s-studio.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ob-s-studio.jsx new file mode 100755 index 0000000..e62cd93 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ob-s-studio.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function OBSStudio(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/obsidian.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/obsidian.jsx new file mode 100755 index 0000000..f581eab --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/obsidian.jsx @@ -0,0 +1,33 @@ +import Icon from "../icon.jsx"; + +export default function Obsidian(props) { + return ( + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ollama.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ollama.jsx new file mode 100755 index 0000000..afa63f7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ollama.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Ollama(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/omni-focus.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/omni-focus.jsx new file mode 100755 index 0000000..25b414f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/omni-focus.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function OmniFocus(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/one-password.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/one-password.jsx new file mode 100755 index 0000000..4192696 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/one-password.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function OnePassword(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/open-book.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/open-book.jsx new file mode 100755 index 0000000..2381bbc --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/open-book.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function OpenBook(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/open-claw.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/open-claw.jsx new file mode 100755 index 0000000..d314638 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/open-claw.jsx @@ -0,0 +1,16 @@ +import Icon from "../icon.jsx"; + +export default function OpenClaw(props) { + return ( + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/opencode.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/opencode.jsx new file mode 100755 index 0000000..0e407e0 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/opencode.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Opencode(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/orb-stack.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/orb-stack.jsx new file mode 100755 index 0000000..674c20d --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/orb-stack.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function OrbStack(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pages.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pages.jsx new file mode 100755 index 0000000..1e83114 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pages.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Pages(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/parallels.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/parallels.jsx new file mode 100755 index 0000000..cf4063f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/parallels.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Parallels(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/paused.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/paused.jsx new file mode 100755 index 0000000..fe8ed21 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/paused.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Paused(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pdf.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pdf.jsx new file mode 100755 index 0000000..1fc252e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pdf.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function PDF(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/perplexity.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/perplexity.jsx new file mode 100755 index 0000000..9e095a0 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/perplexity.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Perplexity(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/php-storm.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/php-storm.jsx new file mode 100755 index 0000000..628771f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/php-storm.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function PHPStorm(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pihole.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pihole.jsx new file mode 100755 index 0000000..622efe3 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pihole.jsx @@ -0,0 +1,31 @@ +import Icon from "../icon.jsx"; + +export default function Pihole(props) { + return ( + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pine.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pine.jsx new file mode 100755 index 0000000..0e5e2fd --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pine.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Pine(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pins.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pins.jsx new file mode 100755 index 0000000..5b63d82 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pins.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Pins(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/playing.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/playing.jsx new file mode 100755 index 0000000..cc96548 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/playing.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Playing(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/plex.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/plex.jsx new file mode 100755 index 0000000..ab8a1d0 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/plex.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Plex(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/podcasts.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/podcasts.jsx new file mode 100755 index 0000000..767f73e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/podcasts.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Podcasts(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pomodone.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pomodone.jsx new file mode 100755 index 0000000..48c503b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/pomodone.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Pomodone(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/postman.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/postman.jsx new file mode 100755 index 0000000..79d92e1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/postman.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Postman(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/proton-mail.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/proton-mail.jsx new file mode 100755 index 0000000..61cc2ee --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/proton-mail.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function ProtonMail(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/py-charm.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/py-charm.jsx new file mode 100755 index 0000000..8845a8e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/py-charm.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function PyCharm(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/quip.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/quip.jsx new file mode 100755 index 0000000..b489fb4 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/quip.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Quip(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/qute-browser.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/qute-browser.jsx new file mode 100755 index 0000000..9e5a4a8 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/qute-browser.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function QuteBrowser(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/radar.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/radar.jsx new file mode 100755 index 0000000..3dcbaf1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/radar.jsx @@ -0,0 +1,11 @@ +import Icon from "../icon.jsx"; + +export default function Radar(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rain.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rain.jsx new file mode 100755 index 0000000..4518beb --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rain.jsx @@ -0,0 +1,15 @@ +import Icon from "../icon.jsx"; +import * as Utils from "../../../utils"; + +export default function Rain(props) { + return ( + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ram.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ram.jsx new file mode 100755 index 0000000..c37d116 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ram.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Ram(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/redis.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/redis.jsx new file mode 100755 index 0000000..c1ed1cb --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/redis.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Redis(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/reeder5.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/reeder5.jsx new file mode 100755 index 0000000..7775050 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/reeder5.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Reeder5(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/reminders.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/reminders.jsx new file mode 100755 index 0000000..a01348f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/reminders.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Reminders(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remnote.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remnote.jsx new file mode 100755 index 0000000..8783e44 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remnote.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function Remnote(props) { + return ( + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remote-desktop.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remote-desktop.jsx new file mode 100755 index 0000000..11a0758 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remote-desktop.jsx @@ -0,0 +1,15 @@ +import Icon from "../icon.jsx"; + +export default function RemoteDesktop(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remove.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remove.jsx new file mode 100755 index 0000000..d2ea86f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/remove.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Remove(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/replit.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/replit.jsx new file mode 100755 index 0000000..080e608 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/replit.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Replit(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rider.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rider.jsx new file mode 100755 index 0000000..9ad3e3e --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rider.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Rider(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rocket-chat.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rocket-chat.jsx new file mode 100755 index 0000000..0d30073 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rocket-chat.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function RocketChat(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/roon.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/roon.jsx new file mode 100755 index 0000000..a532846 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/roon.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Roon(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/royal-tsx.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/royal-tsx.jsx new file mode 100755 index 0000000..32b051f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/royal-tsx.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function RoyalTSX(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ruby-mine.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ruby-mine.jsx new file mode 100755 index 0000000..7e00335 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/ruby-mine.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function RubyMine(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rust-rover.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rust-rover.jsx new file mode 100755 index 0000000..ea9423b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/rust-rover.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function RustRover(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/safari.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/safari.jsx new file mode 100755 index 0000000..8a238e1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/safari.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Safari(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/screens4.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/screens4.jsx new file mode 100755 index 0000000..a3d028c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/screens4.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function Screens4(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sequel-ace.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sequel-ace.jsx new file mode 100755 index 0000000..e2e5fb7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sequel-ace.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function SequelAce(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sequel-pro.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sequel-pro.jsx new file mode 100755 index 0000000..cc920ae --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sequel-pro.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function SequelPro(props) { + return ( + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/setapp.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/setapp.jsx new file mode 100755 index 0000000..44aad58 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/setapp.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Setapp(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/signal.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/signal.jsx new file mode 100755 index 0000000..c615f9c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/signal.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Signal(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sketch-up.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sketch-up.jsx new file mode 100755 index 0000000..0acb2ed --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sketch-up.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function SketchUp(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sketch.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sketch.jsx new file mode 100755 index 0000000..c35cb07 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sketch.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Sketch(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/skype.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/skype.jsx new file mode 100755 index 0000000..7d7a229 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/skype.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Skype(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/slack.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/slack.jsx new file mode 100755 index 0000000..163fdd9 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/slack.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Slack(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/snow.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/snow.jsx new file mode 100755 index 0000000..1c55afa --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/snow.jsx @@ -0,0 +1,18 @@ +import Icon from "../icon.jsx"; +import * as Utils from "../../../utils"; + +export default function Snow(props) { + return ( + + + + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spark.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spark.jsx new file mode 100755 index 0000000..7655fae --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spark.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Spark(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotify.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotify.jsx new file mode 100755 index 0000000..718a4a8 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotify.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Spotify(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotlight.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotlight.jsx new file mode 100755 index 0000000..4398b47 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotlight.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Spotlight(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotube.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotube.jsx new file mode 100755 index 0000000..f8c0e79 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/spotube.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Spotube(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/statistics.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/statistics.jsx new file mode 100755 index 0000000..5e5911f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/statistics.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Statistics(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/stopped.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/stopped.jsx new file mode 100755 index 0000000..05cb40c --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/stopped.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Stopped(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/storm.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/storm.jsx new file mode 100755 index 0000000..39fb1ad --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/storm.jsx @@ -0,0 +1,18 @@ +import Icon from "../icon.jsx"; +import * as Utils from "../../../utils"; + +export default function Storm(props) { + return ( + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sublime-text.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sublime-text.jsx new file mode 100755 index 0000000..80d2cea --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sublime-text.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function SublimeText(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sun.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sun.jsx new file mode 100755 index 0000000..270a37f --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/sun.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; +import * as Utils from "../../../utils"; + +export default function Sun(props) { + return ( + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/super-productivity.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/super-productivity.jsx new file mode 100755 index 0000000..93ec47a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/super-productivity.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function SuperProductivity(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/table-plus.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/table-plus.jsx new file mode 100755 index 0000000..0083b53 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/table-plus.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function TablePlus(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tailscale.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tailscale.jsx new file mode 100755 index 0000000..98987d7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tailscale.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Tailscale(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/team-speak.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/team-speak.jsx new file mode 100755 index 0000000..7942728 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/team-speak.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function TeamSpeak(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/teams.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/teams.jsx new file mode 100755 index 0000000..c1ea5a4 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/teams.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function Teams(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/telegram.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/telegram.jsx new file mode 100755 index 0000000..798993b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/telegram.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Telegram(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/terminal.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/terminal.jsx new file mode 100755 index 0000000..8a11afd --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/terminal.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Terminal(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/text.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/text.jsx new file mode 100755 index 0000000..6b2054d --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/text.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Text(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/thermostat.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/thermostat.jsx new file mode 100755 index 0000000..77a448a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/thermostat.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Thermostat(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/things.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/things.jsx new file mode 100755 index 0000000..0c8b288 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/things.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function Things(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/thunderbird.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/thunderbird.jsx new file mode 100755 index 0000000..020ace1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/thunderbird.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Thunderbird(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tick-tick.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tick-tick.jsx new file mode 100755 index 0000000..6efffcb --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tick-tick.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function TickTick(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tidal.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tidal.jsx new file mode 100755 index 0000000..ae8b104 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tidal.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Tidal(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/todoist.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/todoist.jsx new file mode 100755 index 0000000..c834873 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/todoist.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Todoist(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tor-browser.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tor-browser.jsx new file mode 100755 index 0000000..93408a6 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tor-browser.jsx @@ -0,0 +1,15 @@ +import Icon from "../icon.jsx"; + +export default function TorBrowser(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tower.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tower.jsx new file mode 100755 index 0000000..9ddfd43 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/tower.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function Tower(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/transmit.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/transmit.jsx new file mode 100755 index 0000000..d9b3c53 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/transmit.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function Transmit(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/trello.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/trello.jsx new file mode 100755 index 0000000..b999e0b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/trello.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Trello(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/twitter.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/twitter.jsx new file mode 100755 index 0000000..6a6e18b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/twitter.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Twitter(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/up-arrow.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/up-arrow.jsx new file mode 100755 index 0000000..f17cb93 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/up-arrow.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function UpArrow(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/upload.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/upload.jsx new file mode 100755 index 0000000..b3b23a1 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/upload.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function Upload(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vim.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vim.jsx new file mode 100755 index 0000000..29b4434 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vim.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Vim(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vivaldi.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vivaldi.jsx new file mode 100755 index 0000000..7baa302 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vivaldi.jsx @@ -0,0 +1,14 @@ +import Icon from "../icon.jsx"; + +export default function Vivaldi(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vl-c.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vl-c.jsx new file mode 100755 index 0000000..08be0f6 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vl-c.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function VLC(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vmware-fusion.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vmware-fusion.jsx new file mode 100755 index 0000000..3ac1b60 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vmware-fusion.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function VMwareFusion(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-high.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-high.jsx new file mode 100755 index 0000000..b11c5e3 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-high.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function VolumeHigh(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-low.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-low.jsx new file mode 100755 index 0000000..7da65d4 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-low.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function VolumeLow(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-muted.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-muted.jsx new file mode 100755 index 0000000..b7ca410 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/volume-muted.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function VolumeMuted(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vp-n-off.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vp-n-off.jsx new file mode 100755 index 0000000..7c2ae8b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vp-n-off.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function VPNOff(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vp-n.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vp-n.jsx new file mode 100755 index 0000000..a73a27a --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vp-n.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function VPN(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vs-codium.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vs-codium.jsx new file mode 100755 index 0000000..26f51b4 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/vs-codium.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function VSCodium(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/warp.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/warp.jsx new file mode 100755 index 0000000..a3e83e5 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/warp.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Warp(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/web-storm.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/web-storm.jsx new file mode 100755 index 0000000..3d75c80 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/web-storm.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function WebStorm(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wechat.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wechat.jsx new file mode 100755 index 0000000..3f814e8 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wechat.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Wechat(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/whats-app.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/whats-app.jsx new file mode 100755 index 0000000..02bd081 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/whats-app.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function WhatsApp(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/widget.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/widget.jsx new file mode 100755 index 0000000..48611f5 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/widget.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Widget(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wifi-off.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wifi-off.jsx new file mode 100755 index 0000000..d2a4690 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wifi-off.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function WifiOff(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wifi.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wifi.jsx new file mode 100755 index 0000000..cbf2610 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/wifi.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Wifi(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/windows.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/windows.jsx new file mode 100755 index 0000000..b81d452 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/windows.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Windows(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/xcode.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/xcode.jsx new file mode 100755 index 0000000..7c6185b --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/xcode.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function Xcode(props) { + return ( + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/youtube-music.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/youtube-music.jsx new file mode 100755 index 0000000..fe7e130 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/youtube-music.jsx @@ -0,0 +1,13 @@ +import Icon from "../icon.jsx"; + +export default function YoutubeMusic(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zed.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zed.jsx new file mode 100755 index 0000000..95e4415 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zed.jsx @@ -0,0 +1,10 @@ +import Icon from "../icon.jsx"; + +export default function Zed(props) { + return ( + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zen-browser.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zen-browser.jsx new file mode 100755 index 0000000..b417df7 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zen-browser.jsx @@ -0,0 +1,11 @@ +import Icon from "../icon.jsx"; + +export default function ZenBrowser(props) { + return ( + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zeplin.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zeplin.jsx new file mode 100755 index 0000000..bf45e51 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zeplin.jsx @@ -0,0 +1,43 @@ +import Icon from "../icon.jsx"; + +export default function Zeplin(props) { + return ( + + + + + + + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zoom.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zoom.jsx new file mode 100755 index 0000000..d0e9610 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zoom.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Zoom(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zotero.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zotero.jsx new file mode 100755 index 0000000..1223d35 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zotero.jsx @@ -0,0 +1,12 @@ +import Icon from "../icon.jsx"; + +export default function Zotero(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zulip.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zulip.jsx new file mode 100755 index 0000000..8b94751 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/icons/library/zulip.jsx @@ -0,0 +1,9 @@ +import Icon from "../icon.jsx"; + +export default function Zulip(props) { + return ( + + + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/missives/missive.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/missives/missive.jsx new file mode 100755 index 0000000..eec0ace --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/missives/missive.jsx @@ -0,0 +1,48 @@ +import * as Uebersicht from "uebersicht"; +import { SuspenseIcon } from "../icons/icon.jsx"; +import * as Icons from "../icons/icons.jsx"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import * as Utils from "../../utils.js"; + +const { React } = Uebersicht; + +/** + * Missive component to display a notification. + * @param {Object} props - The properties object. + * @param {string} props.id - The unique identifier for the missive. + * @param {string} props.side - The side where the missive should appear ('left' or 'right'). + * @param {string} props.content - The content of the missive. + * @param {number} [props.timeout] - The timeout for the missive to auto-close. + * @returns {JSX.Element} The Missive component. + */ +export default function Missive({ id, side, content, timeout }) { + // Get the setMissives function from the context + const { setMissives } = useSimpleBarContext(); + + // Generate class names based on the side prop + const classes = Utils.classNames("missive", { + "missive--left": side === "left", + "missive--right": side === "right", + }); + + // Close the missive by removing it from the context and clearing the timeout. + const closeMissive = () => { + setMissives((current) => { + return current.filter((m) => m.id !== id); + }); + if (timeout) { + clearTimeout(timeout); + } + }; + + return ( +
+
{content}
+ +
+ ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/missives/missives.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/missives/missives.jsx new file mode 100755 index 0000000..3563937 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/missives/missives.jsx @@ -0,0 +1,40 @@ +import * as Uebersicht from "uebersicht"; +import { useSimpleBarContext } from "../simple-bar-context.jsx"; +import Missive from "./missive.jsx"; +import useServerSocket from "../../hooks/use-server-socket.js"; + +export { missivesStyles as styles } from "../../styles/components/missives"; + +const { React } = Uebersicht; + +/** + * Component to display a list of missives. + * It uses the simple-bar context to get settings and missives data. + * It also sets up a server socket to receive new missives. + * + * @returns {JSX.Element} The rendered component. + */ +export function Component() { + // Destructure settings, missives, and pushMissive function from the context + const { settings, missives, pushMissive } = useSimpleBarContext(); + const { enableServer } = settings.global; + + // Set up a server socket to listen for "missive" events and push new missives + useServerSocket("missive", enableServer, pushMissive); + + return ( +
+ {missives.map(({ id, side, content, timeout }) => { + return ( + + ); + })} +
+ ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/aerospace-display-manager.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/aerospace-display-manager.jsx new file mode 100755 index 0000000..8c4fa98 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/aerospace-display-manager.jsx @@ -0,0 +1,83 @@ +import * as Uebersicht from "uebersicht"; +import * as Utils from "../../utils"; +import * as Icons from "../icons/icons.jsx"; + +const { React } = Uebersicht; + +/** + * UserWidgetsCreator component allows users to create and manage custom widgets. + * @param {Object} props - The component props. + * @param {Object} props.defaultValue - The default value for the widgets. + * @param {Function} props.onChange - The function to call when the widgets change. + * @returns {JSX.Element} The UserWidgetsCreator component. + */ +export default function AerospaceDisplayManager({ defaultValue, onChange }) { + const [indexes, setIndexes] = React.useState(defaultValue || {}); + const [displays, setDisplays] = React.useState(Object.keys(defaultValue)); + + const addDisplay = () => { + setDisplays((current) => { + const highest = Math.max(...current, 0); + const newIndex = highest + 1; + setIndexes((current) => { + return { ...current, [newIndex]: Number(current[newIndex]) || 1 }; + }); + return [...current, newIndex]; + }); + }; + + const removeDisplay = (index) => { + setDisplays((current) => { + const newDisplays = current.filter((display) => display !== index); + setIndexes((current) => { + const newIndexes = { ...current }; + delete newIndexes[index]; + return newIndexes; + }); + return newDisplays; + }); + }; + + React.useEffect(() => { + const diffs = Utils.compareObjects(defaultValue, indexes); + const hasDiffs = Object.keys(diffs).length > 0; + if (hasDiffs) onChange({ target: { value: indexes } }); + }, [defaultValue, onChange, indexes]); + + return ( +
+
+ AeroSpace Custom display indexes +
+
+ {displays.map((display) => { + const index = indexes[display] || 1; + + const updateIndex = (e) => { + const value = e.target.value; + setIndexes((current) => { + return { ...current, [display]: Number(value) }; + }); + }; + + return ( +
+ {display}: + + +
+ ); + })} +
+ +
+ ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/color-picker.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/color-picker.jsx new file mode 100755 index 0000000..dbff879 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/color-picker.jsx @@ -0,0 +1,109 @@ +import * as Uebersicht from "uebersicht"; +import * as Settings from "../../settings"; + +const { React } = Uebersicht; + +/** + * ColorPicker component allows users to select a color from predefined options or input a custom color. + * @param {Object} props - The component props. + * @param {Function} props.callback - The callback function to handle color selection. + * @param {number} props.index - The index of the color picker. + * @param {string} props.selectedColor - The initially selected color. + * @returns {JSX.Element} The ColorPicker component. + */ +export default function ColorPicker({ callback, index, selectedColor }) { + // Determine if the selected color is a custom color + const isSelectedCustom = !Settings.userWidgetColors.includes(selectedColor); + // State to manage the open/close status of the color picker + const [open, setOpen] = React.useState(false); + // State to manage the currently selected color + const [selected, setSelected] = React.useState(selectedColor); + // State to manage the custom color input + const [customColor, setCustomColor] = React.useState( + isSelectedCustom ? selectedColor : undefined, + ); + + // Toggle the color picker open/close status + const onClick = () => setOpen(!open); + + /** + * Handle custom color input change. + * @param {Object} e - The event object. + */ + const onCustomColorChange = (e) => { + const value = e.target.value; + setCustomColor(value); + callback?.(index, "backgroundColor", value); + }; + + /** + * Handle custom color submission. + */ + const onCustomColorSubmit = () => { + setSelected(customColor); + setOpen(false); + }; + + return ( +
+ +
+
+ )} +
+ ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/icon-picker.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/icon-picker.jsx new file mode 100755 index 0000000..ca3bdab --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/icon-picker.jsx @@ -0,0 +1,130 @@ +import * as Uebersicht from "uebersicht"; +import * as Icons from "../icons/icons.jsx"; +import { SuspenseIcon } from "../icons/icon.jsx"; + +const { React } = Uebersicht; + +/** + * IconPicker component allows users to select an icon from a list of available icons. + * + * @param {Object} props - The component props. + * @param {Function} props.callback - The callback function to be called when an icon is selected. + * @param {number} props.index - The index of the icon picker. + * @param {string} props.selectedIcon - The initially selected icon. + * @returns {JSX.Element} The IconPicker component. + */ +export default function IconPicker({ callback, index, selectedIcon }) { + // State to manage the open/close state of the icon picker dropdown + const [open, setOpen] = React.useState(false); + // State to manage the currently selected icon + const [selected, setSelected] = React.useState(selectedIcon); + // State to manage the search term for filtering icons + const [searchTerm, setSearchTerm] = React.useState(""); + + // Get the selected icon component + const Icon = Icons[selected]; + // Get the list of all available icon keys + const keys = Object.keys(Icons); + + // Filter icons based on search term + const filteredKeys = React.useMemo(() => { + if (!searchTerm.trim()) { + return keys; + } + return keys.filter((key) => + key.toLowerCase().includes(searchTerm.toLowerCase()), + ); + }, [keys, searchTerm]); + + /** + * Toggles the open state of the icon picker dropdown. + */ + const onClick = () => setOpen(!open); + + /** + * Handles search input changes. + * + * @param {React.ChangeEvent} e - The input change event. + */ + const onSearchChange = (e) => { + setSearchTerm(e.target.value); + }; + + /** + * Clears the search term. + */ + const clearSearch = () => { + setSearchTerm(""); + }; + + return ( +
+ + {open && ( +
+
e.stopPropagation()} + > + + + {searchTerm && ( + + )} +
+
setOpen(false)}> + {filteredKeys.length > 0 ? ( + filteredKeys.map((key) => { + /** + * Handles the icon selection. + * + * @param {React.MouseEvent} e - The click event. + */ + const onClick = (e) => { + e.stopPropagation(); + setSelected(key); + callback?.(index, "icon", key); + setOpen(false); + }; + const Icon = Icons[key]; + return ( + + ); + }) + ) : ( +
+ No icons found for "{searchTerm}" +
+ )} +
+
+ )} +
+ ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-component.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-component.jsx new file mode 100755 index 0000000..8e48b66 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-component.jsx @@ -0,0 +1,159 @@ +import * as Uebersicht from "uebersicht"; +import * as Utils from "../../utils"; +import SettingsInner from "./settings-inner.jsx"; +import SettingsWidgets from "./settings-widgets.jsx"; +import * as Settings from "../../settings"; + +const { React } = Uebersicht; + +const TABS_STORAGE_KEY = "simple-bar-last-current-settings-tab"; +const TABS = [ + "global", + "themes", + "process", + "spacesDisplay", + "widgets", + "customStyles", +]; + +/** + * Main settings component. + * @param {Object} props - Component properties. + * @param {Function} props.closeSettings - Function to close the settings. + */ +export default function Component({ closeSettings }) { + // State to keep track of the current tab + const [currentTab, setCurrentTab] = React.useState(getLastCurrentTab()); + // State to keep track of pending changes + const [pendingChanges, setPendingChanges] = React.useState(0); + // Get current settings + const settings = Settings.get(); + // State to keep track of new settings + const [newSettings, setNewSettings] = React.useState(settings); + + /** + * Update the current tab and store it in session storage. + * @param {number} tab - The index of the tab to switch to. + */ + const updateTab = (tab) => { + setCurrentTab(tab); + window.sessionStorage.setItem(TABS_STORAGE_KEY, tab); + }; + + /** + * Refresh the simple-bar with new settings. + * @param {Event} e - The event object. + */ + const refreshSimpleBar = async (e) => { + Utils.clickEffect(e); + setPendingChanges(0); + await Settings.set(newSettings); + Utils.hardRefresh(); + }; + + // Effect to calculate the number of pending changes + React.useEffect(() => { + const diffs = Utils.compareObjects(settings, newSettings); + const deepDiffs = Object.keys(diffs).reduce( + (acc, key) => [...acc, ...Object.keys(diffs[key])], + [], + ); + setPendingChanges(deepDiffs.length); + }, [newSettings, settings]); + + return ( +
+
+
+
+
+
+ {Object.keys(Settings.defaultSettings).map((key) => { + const setting = Settings.data[key]; + const hideTab = !TABS.includes(key); + + if (!setting || hideTab) return null; + + const { label } = setting; + const i = TABS.indexOf(key); + const classes = Utils.classNames("settings__tab", { + "settings__tab--current": i === currentTab, + }); + return ( + + ); + })} +
+
+ {Object.keys(Settings.defaultSettings).map((key) => { + const setting = Settings.data[key]; + const hideContent = !TABS.includes(key); + + if (!setting || hideContent) return null; + + const isWidgetsTab = key === "widgets"; + + const { label } = setting; + return ( +
+ {isWidgetsTab ? ( + + ) : ( + +
{label}
+ +
+ )} +
+ ); + })} +
+
+ {pendingChanges !== 0 && ( +
+ {pendingChanges} pending change{pendingChanges > 1 && "s"} +
+ )} + +
+
+
+ ); +} + +/** + * Get the last current tab from session storage. + * @returns {number} The index of the last current tab. + */ +function getLastCurrentTab() { + const storedLastCurrentTab = window.sessionStorage.getItem(TABS_STORAGE_KEY); + if (storedLastCurrentTab) return parseInt(storedLastCurrentTab, 10); + return 0; +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-inner.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-inner.jsx new file mode 100755 index 0000000..e318b25 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-inner.jsx @@ -0,0 +1,123 @@ +import * as Uebersicht from "uebersicht"; +import * as Icons from "../icons/icons.jsx"; +import SettingsItem from "./settings-item.jsx"; +import * as Utils from "../../utils"; +import * as Settings from "../../settings"; + +const { React } = Uebersicht; + +/** + * SettingsInner component to render each setting category. + * @param {Object} props - Component properties. + * @param {string} props.settingKey - Key of current setting. + * @param {Object} props.setting - Contains infos & documentation data. + * @param {string[]} props.setting.infos - Current settings information. + * @param {string} props.setting.documentation - Current setting documentation link. + * @param {Object} props.newSettings - Object containing current modified settings. + * @param {Function} props.setNewSettings - Function allowing to save newly modified settings. + */ +export default function SettingsInner({ + settingKey, + setting, + newSettings, + setNewSettings, +}) { + const { infos, documentation } = setting; + return ( + <> + {Object.keys(Settings.defaultSettings[settingKey]).map((subKey) => { + const subSetting = Settings.data[subKey]; + if (!subSetting) return null; + const { + Component, + fullWidth, + label, + options, + placeholder, + title, + type, + minHeight, + } = subSetting; + + const code = settingKey + subKey; + const defaultValue = newSettings[settingKey][subKey]; + + const classes = Utils.classNames("settings__item", { + "settings__item--radio": type === "radio", + "settings__item--text": + type === "text" || type === "number" || type === "color", + "settings__item--textarea": type === "textarea", + "settings__item--color": type === "color", + "settings__item--full-width": fullWidth, + }); + + const onChange = (e) => { + let value = e.target.value; + if (type === "checkbox") { + value = e.target.checked; + } + if (type === "number") { + value = parseFloat(value); + if (isNaN(value)) { + value = 0; + } + } + + const updatedSettings = { + ...newSettings, + [settingKey]: { ...newSettings[settingKey], [subKey]: value }, + }; + setNewSettings(updatedSettings); + }; + + return ( + + {title &&
{title}
} +
+ +
+
+ ); + })} + {documentation && ( +
+ + + You{"'"}ll find all the information about these settings{" "} + + here on the documentation + {" "} + hosted on jeantinland.com. + +
+ )} + {infos && infos.length && ( +
+
Tips
+ {infos.map((info, i) => ( +
+ ))} +
+ )} + + ); +} diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-item.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-item.jsx new file mode 100755 index 0000000..91c6f54 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/settings/settings-item.jsx @@ -0,0 +1,143 @@ +import * as Uebersicht from "uebersicht"; +import * as Utils from "../../utils"; + +const { React } = Uebersicht; + +/** + * Item component to render different types of settings inputs. + * @param {Object} props - Component properties. + * @param {string} props.code - Unique code for the setting. + * @param {React.Component} props.Component - Custom component for the setting. + * @param {any} props.defaultValue - Default value of the setting. + * @param {string} props.label - Label for the setting. + * @param {string} props.type - Type of the setting input. + * @param {Array} [props.options] - Options for select or radio inputs. + * @param {string} [props.placeholder] - Placeholder for text inputs. + * @param {number} [props.minHeight] - Minimum height for textarea inputs. + * @param {Function} props.onChange - Change handler for the setting input. + */ +export default function SettingsItem({ + code, + Component, + defaultValue, + label, + type, + options, + placeholder, + minHeight, + onChange, +}) { + const onClick = (e) => Utils.clickEffect(e); + if (type === "component") { + return ; + } + if (type === "select") { + return ( + + + ); + } + if (type === "radio") { + return options.map((option) => ( +
+ +
+ )); + } + if (type === "text" || type === "color") { + return ( + +