Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d61792433c | ||
|
|
6016efa436 | ||
|
|
ed428e87c4 | ||
|
|
69ecec7ecf | ||
|
|
a90f6eb357 | ||
|
|
c4642919f7 | ||
|
|
c4733e0624 | ||
|
|
e1faaf7a76 | ||
|
|
47f29f9fa9 | ||
|
|
88497826ec | ||
|
|
b319d1a5e1 | ||
|
|
13f3648e4d | ||
|
|
359fb922aa | ||
|
|
b6448c9876 | ||
|
|
15d54b16f6 | ||
|
|
96e4085919 | ||
|
|
6bcc351e07 |
@@ -8,29 +8,57 @@ git clone https://git.gbrown.org/gib/Panama.git ~/.local/share/Panama
|
|||||||
~/.local/share/Panama/install
|
~/.local/share/Panama/install
|
||||||
```
|
```
|
||||||
|
|
||||||
`install` runs everything in `setup/scripts/` in order:
|
`install` asks its questions first and then runs the stages in `setup/scripts/`
|
||||||
|
in order, without stopping again:
|
||||||
|
|
||||||
| Script | Does |
|
| Script | Does |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `install-packages` | Repos (RPM Fusion, Terra, Hyprland COPR), then the four package lists in `setup/packages/` |
|
| `interview` | Every prompt, before anything is installed. Answers last one run and are never written to a durable path |
|
||||||
| `link-dotfiles` | Symlinks `config/dot/<name>` → `~/.config/<name>` |
|
| `install-packages` | Repos (RPM Fusion, Terra, Hyprland COPR), the package lists in `setup/packages/`, then whichever optional categories were chosen |
|
||||||
|
| `link-dotfiles` | Symlinks `config/dot/<name>` → `~/.config/<name>`, and seeds the wallpaper, cursor theme and Firefox chrome |
|
||||||
| `change-settings` | Copies `config/copy/` over `/`, applies gsettings, enables user services |
|
| `change-settings` | Copies `config/copy/` over `/`, applies gsettings, enables user services |
|
||||||
|
| `link-vicinae-scripts` | Publishes the Vicinae script commands |
|
||||||
|
| `setup-identity` | git config, `gh auth login`, an SSH key — whichever were asked for |
|
||||||
|
| `install-hardware` | NVIDIA, Secure Boot enrollment, Fedora's extras, firmware — each only if it was asked for. Last, because enrollment and firmware are consumed at the next boot |
|
||||||
|
|
||||||
|
The run ends with a health summary from `panama-doctor`, which reports what is
|
||||||
|
actually running rather than what was attempted. It never fails the install: on a
|
||||||
|
fresh machine it legitimately reports things as not yet configured.
|
||||||
|
|
||||||
|
### Optional applications
|
||||||
|
|
||||||
|
Every machine gets the lists in `setup/packages/`. The interview also offers the
|
||||||
|
categories in `setup/packages/extras/` as a checklist, so a work laptop need not
|
||||||
|
acquire emulators and a desktop need not skip Steam. Nothing is preselected.
|
||||||
|
|
||||||
|
A category is one file. A bare line is a dnf package and a `flatpak:` line is a
|
||||||
|
Flathub ID, because the applications in a category do not all come from one
|
||||||
|
place. Adding a category is adding a file — the menu is read from the directory,
|
||||||
|
not written down anywhere.
|
||||||
|
|
||||||
Existing configs are moved to `config/old/` rather than overwritten.
|
Existing configs are moved to `config/old/` rather than overwritten.
|
||||||
|
|
||||||
## Desktops
|
## The desktop
|
||||||
|
|
||||||
Panama configures **two** desktops that coexist. Both sessions stay available in
|
Hyprland, with a shell written from scratch. It began as a replacement for a
|
||||||
GDM, so you can switch back and forth while you settle in.
|
GNOME session — Forge for tiling, Dash-to-Dock, Openbar, Vitals — and was built
|
||||||
|
to reproduce it closely enough that muscle memory transferred: same keybinds,
|
||||||
|
same panel contents, same dock, same Tokyo Night Moon palette.
|
||||||
|
|
||||||
### GNOME
|
That is history now rather than a second option. Panama installs and configures
|
||||||
The original setup: Forge for tiling, Dash-to-Dock, Openbar, Vitals,
|
one desktop, and the GNOME session it grew out of is neither installed nor
|
||||||
AppIndicator support. Configured through `config/dot/forge/` and gsettings.
|
configured here. What each piece replaced is recorded in
|
||||||
|
[`config/dot/hypr/DESKTOP-PARITY.md`](config/dot/hypr/DESKTOP-PARITY.md) and in
|
||||||
|
the comments of the components themselves, because knowing what a thing was
|
||||||
|
modelled on explains why it behaves the way it does.
|
||||||
|
|
||||||
### Hyprland
|
GNOME is not gone from the machine: `gnome-control-center` is a declared
|
||||||
A from-scratch replacement built to reproduce the GNOME setup closely enough
|
dependency, and Panama's own Settings hands off to it for the panels it
|
||||||
that muscle memory transfers — same keybinds, same panel contents, same dock,
|
deliberately does not own — Online Accounts, Color, Sound, Network, Keyboard,
|
||||||
same Tokyo Night Moon palette.
|
Privacy, Wellbeing, Accessibility, and System for users, date and time, region
|
||||||
|
and remote desktop. The allow-list in
|
||||||
|
[`services/SystemSettings.qml`](config/dot/quickshell/services/SystemSettings.qml)
|
||||||
|
is what decides; anything not on it is a panel Panama owns itself.
|
||||||
|
|
||||||
| Piece | What it is |
|
| Piece | What it is |
|
||||||
|---|---|
|
|---|---|
|
||||||
@@ -50,13 +78,56 @@ Log in as **"Hyprland (uwsm-managed)"**, not plain "Hyprland".
|
|||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
```
|
```
|
||||||
bin/ Small user-facing commands on PATH
|
bin/ Small user-facing commands on PATH; `panama` is the entry point
|
||||||
config/
|
config/
|
||||||
bash/ .bashrc, aliases, env (env is gitignored)
|
bash/ .bashrc, aliases, env (env is gitignored)
|
||||||
copy/ Files copied verbatim over / (needs sudo)
|
copy/ Files copied verbatim over / (needs sudo)
|
||||||
dot/ Symlinked into ~/.config
|
dot/ Symlinked into ~/.config
|
||||||
|
firefox/ Vendored Firefox chrome, linked into the browser profile
|
||||||
|
local/ Icons and the cursor theme, linked into ~/.local/share
|
||||||
old/ Backups of whatever was replaced (gitignored)
|
old/ Backups of whatever was replaced (gitignored)
|
||||||
|
wallpapers/ Copied into ~/Pictures/Wallpapers when absent
|
||||||
setup/
|
setup/
|
||||||
packages/ One package per line
|
packages/ One package per line; extras/ holds the optional categories
|
||||||
scripts/ Run in order by ./install
|
scripts/ Run in order by ./install
|
||||||
|
tests/ Contracts. See below
|
||||||
|
docs/ Settings reference, and the design specs behind the work
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
121 of them, under `tests/`. Run the lot, or a subset by pattern:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
panama test # everything
|
||||||
|
panama test dock # just the ones matching "dock"
|
||||||
|
tests/setup/interview-contract # or one directly; they are plain executables
|
||||||
|
```
|
||||||
|
|
||||||
|
They are called contracts rather than unit tests because that is what they are:
|
||||||
|
each one pins a decision that was expensive to get right and is cheap to undo by
|
||||||
|
accident. Most read or measure the real thing — launching a shell to measure a
|
||||||
|
surface's geometry, standing stub commands on `PATH` to see what a stage would
|
||||||
|
have installed, running a script against a throwaway `HOME` — rather than
|
||||||
|
asserting things about source text, because the bugs worth catching here have all
|
||||||
|
been ones that source text looked fine for.
|
||||||
|
|
||||||
|
```
|
||||||
|
tests/setup/ The installer: the interview, package lists, hardware, extras
|
||||||
|
tests/quickshell/ The shell and its settings pages
|
||||||
|
tests/hypr/ The compositor config
|
||||||
|
```
|
||||||
|
|
||||||
|
## The `panama` command
|
||||||
|
|
||||||
|
```sh
|
||||||
|
panama update # review, commit and sync this repo
|
||||||
|
panama edit # open it in Neovim
|
||||||
|
panama doctor # what is actually running, not what was installed
|
||||||
|
panama test # every contract, or a subset by pattern
|
||||||
|
panama upgrade # re-run ./install from anywhere
|
||||||
|
```
|
||||||
|
|
||||||
|
None of the scripts in this repository carry a `.sh` extension. A shebang and
|
||||||
|
the executable bit already select the interpreter, and the extension only
|
||||||
|
becomes something to keep in sync — which it did not stay.
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
# Commands:
|
# Commands:
|
||||||
# update Commit & sync local changes (or just pull if clean)
|
# update Commit & sync local changes (or just pull if clean)
|
||||||
# edit Open the Panama repo in Neovim
|
# edit Open the Panama repo in Neovim
|
||||||
|
# doctor Report what is actually running on this machine
|
||||||
|
# test Run every contract under tests/
|
||||||
|
# upgrade Re-run the installer from anywhere
|
||||||
# help Show this help
|
# help Show this help
|
||||||
#
|
#
|
||||||
# Designed to grow: add new subcommands as cmd_<name> functions and
|
# Designed to grow: add new subcommands as cmd_<name> functions and
|
||||||
@@ -62,6 +65,12 @@ ${BOLD}Commands:${RESET}
|
|||||||
${GREEN}update${RESET} Review, commit & sync local changes. If the working tree is
|
${GREEN}update${RESET} Review, commit & sync local changes. If the working tree is
|
||||||
clean it simply runs 'git pull'.
|
clean it simply runs 'git pull'.
|
||||||
${GREEN}edit${RESET} Open the Panama repo in Neovim.
|
${GREEN}edit${RESET} Open the Panama repo in Neovim.
|
||||||
|
${GREEN}doctor${RESET} Report what is actually running on this machine, rather
|
||||||
|
than what was installed. Takes --summary for one line per check.
|
||||||
|
${GREEN}test${RESET} Run every contract under tests/. Give it a pattern to run
|
||||||
|
a subset: 'panama test dock' runs the ones matching 'dock'.
|
||||||
|
${GREEN}upgrade${RESET} Re-run ./install from anywhere. Safe: every stage is
|
||||||
|
idempotent and this is the documented upgrade path.
|
||||||
${GREEN}help${RESET} Show this help (also -h, --help).
|
${GREEN}help${RESET} Show this help (also -h, --help).
|
||||||
|
|
||||||
${BOLD}Options:${RESET}
|
${BOLD}Options:${RESET}
|
||||||
@@ -71,6 +80,9 @@ ${BOLD}Options:${RESET}
|
|||||||
${BOLD}Examples:${RESET}
|
${BOLD}Examples:${RESET}
|
||||||
$PROGRAM update
|
$PROGRAM update
|
||||||
$PROGRAM edit
|
$PROGRAM edit
|
||||||
|
$PROGRAM doctor --summary
|
||||||
|
$PROGRAM test dock
|
||||||
|
$PROGRAM upgrade
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +217,100 @@ cmd_edit() {
|
|||||||
exec nvim .
|
exec nvim .
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Command: doctor
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# The health check already exists and the installer already runs it; what it did
|
||||||
|
# not have was a way to reach it from a terminal. Everything is passed straight
|
||||||
|
# through, so --summary and anything added later work without this knowing about
|
||||||
|
# them.
|
||||||
|
cmd_doctor() {
|
||||||
|
local doctor="$PANAMA_DIR/config/dot/quickshell/scripts/panama-doctor"
|
||||||
|
if [[ ! -x "$doctor" ]]; then
|
||||||
|
err "panama-doctor is missing from $doctor"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
exec "$doctor" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Command: test
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# The contracts are the main safety net in this repository and had no entry
|
||||||
|
# point: 121 executables with no runner and no mention in the README, which is
|
||||||
|
# most of the way to not having them.
|
||||||
|
#
|
||||||
|
# Each runs in its own process and a failure does not stop the rest, because the
|
||||||
|
# useful output is the whole list of what is broken rather than the first thing
|
||||||
|
# that broke. The exit code is what a caller can act on.
|
||||||
|
cmd_test() {
|
||||||
|
local pattern="${1:-}"
|
||||||
|
local -a suite=()
|
||||||
|
|
||||||
|
# Executables, plus the Python suites. Those are unittest files rather than
|
||||||
|
# executables, and collecting only what has the executable bit would skip them
|
||||||
|
# without saying so -- which is how all three came to be run by nothing at all.
|
||||||
|
# A runner with a blind spot is worse than no runner, because it reports PASS.
|
||||||
|
while IFS= read -r path; do
|
||||||
|
[[ -x "$path" || "$path" == *_test.py ]] || continue
|
||||||
|
[[ -z "$pattern" || "$path" == *"$pattern"* ]] && suite+=("$path")
|
||||||
|
done < <(find "$PANAMA_DIR/tests" -type f -not -path '*/fixtures/*' -not -path '*__pycache__*' | sort)
|
||||||
|
|
||||||
|
if (( ${#suite[@]} == 0 )); then
|
||||||
|
err "No contracts match '${pattern}'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
info "Running ${#suite[@]} contract(s)"
|
||||||
|
local -a failed=()
|
||||||
|
local path name
|
||||||
|
local -a runner
|
||||||
|
for path in "${suite[@]}"; do
|
||||||
|
name="${path#"$PANAMA_DIR"/tests/}"
|
||||||
|
if [[ "$path" == *_test.py ]]; then
|
||||||
|
runner=(python3 "$path")
|
||||||
|
else
|
||||||
|
runner=("$path")
|
||||||
|
fi
|
||||||
|
if "${runner[@]}" >/dev/null 2>&1; then
|
||||||
|
ok "$name"
|
||||||
|
else
|
||||||
|
err "$name"
|
||||||
|
failed+=("$name")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
header "Result"
|
||||||
|
if (( ${#failed[@]} == 0 )); then
|
||||||
|
ok "${#suite[@]} contract(s) passed"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
err "${#failed[@]} of ${#suite[@]} failed:"
|
||||||
|
printf ' %s\n' "${failed[@]}" >&2
|
||||||
|
warn "Run one on its own to see why: ${BOLD}${PANAMA_DIR}/tests/<name>${RESET}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Command: upgrade
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# ./install is the upgrade path -- every stage is idempotent and re-running is
|
||||||
|
# the documented way to repair a machine. This only saves remembering where the
|
||||||
|
# repository lives.
|
||||||
|
cmd_upgrade() {
|
||||||
|
local installer="$PANAMA_DIR/install"
|
||||||
|
if [[ ! -x "$installer" ]]; then
|
||||||
|
err "The installer is missing from $installer"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
info "Re-running ${BOLD}${installer}${RESET}"
|
||||||
|
cd "$PANAMA_DIR"
|
||||||
|
exec "$installer" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# Dispatcher
|
# Dispatcher
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
@@ -213,6 +319,9 @@ main() {
|
|||||||
case "$cmd" in
|
case "$cmd" in
|
||||||
update) shift; cmd_update "$@" ;;
|
update) shift; cmd_update "$@" ;;
|
||||||
edit) shift; cmd_edit "$@" ;;
|
edit) shift; cmd_edit "$@" ;;
|
||||||
|
doctor) shift; cmd_doctor "$@" ;;
|
||||||
|
test) shift; cmd_test "$@" ;;
|
||||||
|
upgrade) shift; cmd_upgrade "$@" ;;
|
||||||
help|-h|--help|"") usage ;;
|
help|-h|--help|"") usage ;;
|
||||||
--version) printf '%s %s\n' "$PROGRAM" "$VERSION" ;;
|
--version) printf '%s %s\n' "$PROGRAM" "$VERSION" ;;
|
||||||
*)
|
*)
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ else
|
|||||||
fi
|
fi
|
||||||
export PATH
|
export PATH
|
||||||
fi
|
fi
|
||||||
. "$HOME/.cargo/env"
|
# rustup writes this file, and initial-packages installs rustup rather than
|
||||||
|
# running rustup-init -- so on a fresh machine it does not exist yet and an
|
||||||
# >>> Codex installer >>>
|
# unguarded source made every single shell start with an error.
|
||||||
export PATH="/home/gib/.local/bin:$PATH"
|
[ -f "$HOME/.cargo/env" ] && . "$HOME/.cargo/env"
|
||||||
# <<< Codex installer <<<
|
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"wmClass": "jetbrains-toolbox",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.amezin.ddterm",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.donadigo.eddy",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Conky",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Gnome-initial-setup",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "org.gnome.Calculator",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "gnome-terminal-preferences",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Guake",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "zoom",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "mpv",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Bitwarden",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Hidamari",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.mattjakeman.ExtensionManager",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Cider",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Ulauncher",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.nextcloud.desktopclient.nextcloud",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Emulator",
|
|
||||||
"mode": "float"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"wmClass": "jetbrains-toolbox",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.amezin.ddterm",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.donadigo.eddy",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Conky",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Gnome-initial-setup",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "org.gnome.Calculator",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "gnome-terminal-preferences",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Guake",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "zoom",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "mpv",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Bitwarden",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Hidamari",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.mattjakeman.ExtensionManager",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Cider",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Ulauncher",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.nextcloud.desktopclient.nextcloud",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Emulator",
|
|
||||||
"mode": "float"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"wmClass": "jetbrains-toolbox",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.amezin.ddterm",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.donadigo.eddy",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Conky",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Gnome-initial-setup",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "org.gnome.Calculator",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "gnome-terminal-preferences",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Guake",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "zoom",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "mpv",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Bitwarden",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Hidamari",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.mattjakeman.ExtensionManager",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Cider",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Ulauncher",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.nextcloud.desktopclient.nextcloud",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Emulator",
|
|
||||||
"mode": "float"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"wmClass": "jetbrains-toolbox",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.amezin.ddterm",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.donadigo.eddy",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Conky",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Gnome-initial-setup",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "org.gnome.Calculator",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "gnome-terminal-preferences",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Guake",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "zoom",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "mpv",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Bitwarden",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Hidamari",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.mattjakeman.ExtensionManager",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Cider",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Ulauncher",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.nextcloud.desktopclient.nextcloud",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Emulator",
|
|
||||||
"mode": "float"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"wmClass": "jetbrains-toolbox",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.amezin.ddterm",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.donadigo.eddy",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Conky",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Gnome-initial-setup",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "org.gnome.Calculator",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "gnome-terminal-preferences",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Guake",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "zoom",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "mpv",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Bitwarden",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Hidamari",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.mattjakeman.ExtensionManager",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Cider",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Ulauncher",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.nextcloud.desktopclient.nextcloud",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Emulator",
|
|
||||||
"mode": "float"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"wmClass": "jetbrains-toolbox",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.amezin.ddterm",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.donadigo.eddy",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Conky",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Gnome-initial-setup",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "org.gnome.Calculator",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "gnome-terminal-preferences",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Guake",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "zoom",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "mpv",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Bitwarden",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Hidamari",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.mattjakeman.ExtensionManager",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Cider",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Ulauncher",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.nextcloud.desktopclient.nextcloud",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Emulator",
|
|
||||||
"mode": "float"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
{
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"wmClass": "jetbrains-toolbox",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.amezin.ddterm",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Com.github.donadigo.eddy",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Conky",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Gnome-initial-setup",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "org.gnome.Calculator",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "gnome-terminal-preferences",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Guake",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "zoom",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Bitwarden",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Hidamari",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.mattjakeman.ExtensionManager",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Cider",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Ulauncher",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "com.nextcloud.desktopclient.nextcloud",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "mpv",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "Spotify",
|
|
||||||
"mode": "float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wmClass": "bitwarden",
|
|
||||||
"mode": "float"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
.tiled {
|
|
||||||
color: rgba(236, 94, 94, 1);
|
|
||||||
opacity: 1;
|
|
||||||
border-width: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.split {
|
|
||||||
color: rgba(255, 246, 108, 1);
|
|
||||||
opacity: 1;
|
|
||||||
border-width: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stacked {
|
|
||||||
color: rgba(247, 162, 43, 1);
|
|
||||||
opacity: 1;
|
|
||||||
border-width: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabbed {
|
|
||||||
color: rgba(17, 199, 224, 1);
|
|
||||||
opacity: 1;
|
|
||||||
border-width: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.floated {
|
|
||||||
color: rgba(180, 167, 214, 1);
|
|
||||||
border-width: 3px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tiled-border {
|
|
||||||
border-width: 3px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-split-border {
|
|
||||||
border-width: 3px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* forge-36le: St does not paint an asymmetric (single-side) border when a
|
|
||||||
* border-radius is set, so the directional hint never rendered. Drop the radius
|
|
||||||
* on the one-edge variants; St paints a straight single-side border reliably. */
|
|
||||||
|
|
||||||
.window-split-horizontal {
|
|
||||||
border-left-width: 0;
|
|
||||||
border-top-width: 0;
|
|
||||||
border-bottom-width: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-split-vertical {
|
|
||||||
border-left-width: 0;
|
|
||||||
border-top-width: 0;
|
|
||||||
border-right-width: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-stacked-border {
|
|
||||||
border-width: 3px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-border {
|
|
||||||
border-width: 3px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-bg {
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-tab {
|
|
||||||
background-color: rgba(54, 47, 45, 1);
|
|
||||||
border-color: rgba(98,160,234,0.6);
|
|
||||||
border-width: 1px;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: white;
|
|
||||||
margin: 1px;
|
|
||||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-tab-active {
|
|
||||||
background-color: rgb(98,160,234);
|
|
||||||
color: black;
|
|
||||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-tab-close {
|
|
||||||
padding: 3px;
|
|
||||||
margin: 4px;
|
|
||||||
border-radius: 16px;
|
|
||||||
width: 16px;
|
|
||||||
background-color: #e06666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-tab-icon {
|
|
||||||
margin: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-floated-border {
|
|
||||||
border-width: 3px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tilepreview-tiled {
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: rgba(98,160,234,0.3);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
background-color: rgba(98,160,234,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tilepreview-stacked {
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: rgba(98,160,234,0.3);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
background-color: rgba(98,160,234,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tilepreview-swap {
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: rgba(162, 247, 43, 0.4);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
background-color: rgba(162, 247, 43, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tilepreview-tabbed {
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: rgba(98,160,234,0.3);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
background-color: rgba(98,160,234,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keybindings Cheatsheet Overlay */
|
|
||||||
|
|
||||||
.forge-cheatsheet {
|
|
||||||
background-color: #2d2d2d;
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 24px 32px;
|
|
||||||
border: 1px solid #4d4d4d;
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-title {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #ffffff;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-category {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #78aeed;
|
|
||||||
margin-top: 16px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-row {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #eeeeec;
|
|
||||||
margin: 4px 0;
|
|
||||||
padding: 2px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-key {
|
|
||||||
font-family: monospace;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #f5c211;
|
|
||||||
min-width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-desc {
|
|
||||||
color: #d0cfcc;
|
|
||||||
}
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
.tiled {
|
|
||||||
color: rgba(236, 94, 94, 1);
|
|
||||||
opacity: 1;
|
|
||||||
border-width: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.split {
|
|
||||||
color: rgba(255, 246, 108, 1);
|
|
||||||
opacity: 1;
|
|
||||||
border-width: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stacked {
|
|
||||||
color: rgba(247, 162, 43, 1);
|
|
||||||
opacity: 1;
|
|
||||||
border-width: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabbed {
|
|
||||||
color: rgba(17, 199, 224, 1);
|
|
||||||
opacity: 1;
|
|
||||||
border-width: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.floated {
|
|
||||||
color: rgba(180, 167, 214, 1);
|
|
||||||
border-width: 3px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tiled-border {
|
|
||||||
border-width: 3px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-split-border {
|
|
||||||
border-width: 3px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* forge-36le: St does not paint an asymmetric (single-side) border when a
|
|
||||||
* border-radius is set, so the directional hint never rendered. Drop the radius
|
|
||||||
* on the one-edge variants; St paints a straight single-side border reliably. */
|
|
||||||
|
|
||||||
.window-split-horizontal {
|
|
||||||
border-left-width: 0;
|
|
||||||
border-top-width: 0;
|
|
||||||
border-bottom-width: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-split-vertical {
|
|
||||||
border-left-width: 0;
|
|
||||||
border-top-width: 0;
|
|
||||||
border-right-width: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-stacked-border {
|
|
||||||
border-width: 3px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-border {
|
|
||||||
border-width: 3px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-bg {
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-tab {
|
|
||||||
background-color: rgba(54, 47, 45, 1);
|
|
||||||
border-color: rgba(98,160,234,0.6);
|
|
||||||
border-width: 1px;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: white;
|
|
||||||
margin: 1px;
|
|
||||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-tab-active {
|
|
||||||
background-color: rgb(98,160,234);
|
|
||||||
color: black;
|
|
||||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-tab-close {
|
|
||||||
padding: 3px;
|
|
||||||
margin: 4px;
|
|
||||||
border-radius: 16px;
|
|
||||||
width: 16px;
|
|
||||||
background-color: #e06666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tabbed-tab-icon {
|
|
||||||
margin: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-floated-border {
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: rgb(98,160,234);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tilepreview-tiled {
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: rgba(98,160,234,0.3);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
background-color: rgba(98,160,234,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tilepreview-stacked {
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: rgba(98,160,234,0.3);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
background-color: rgba(98,160,234,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tilepreview-swap {
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: rgba(162, 247, 43, 0.4);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
background-color: rgba(162, 247, 43, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tilepreview-tabbed {
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: rgba(98,160,234,0.3);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 14px;
|
|
||||||
background-color: rgba(98,160,234,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keybindings Cheatsheet Overlay */
|
|
||||||
|
|
||||||
.forge-cheatsheet {
|
|
||||||
background-color: #2d2d2d;
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 24px 32px;
|
|
||||||
border: 1px solid #4d4d4d;
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-title {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #ffffff;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-category {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #78aeed;
|
|
||||||
margin-top: 16px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-row {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #eeeeec;
|
|
||||||
margin: 4px 0;
|
|
||||||
padding: 2px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-key {
|
|
||||||
font-family: monospace;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #f5c211;
|
|
||||||
min-width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.forge-cheatsheet-desc {
|
|
||||||
color: #d0cfcc;
|
|
||||||
}
|
|
||||||
@@ -88,7 +88,7 @@ entry.
|
|||||||
|
|
||||||
`prefs.lua` never raises. A missing, empty, truncated, malformed, or
|
`prefs.lua` never raises. A missing, empty, truncated, malformed, or
|
||||||
wrong-typed settings file costs you your customizations and nothing else;
|
wrong-typed settings file costs you your customizations and nothing else;
|
||||||
`tests/hypr/prefs-fallback-contract.sh` pins that, including that Hyprland still
|
`tests/hypr/prefs-fallback-contract` pins that, including that Hyprland still
|
||||||
accepts the config in each of those states.
|
accepts the config in each of those states.
|
||||||
|
|
||||||
### Adding a keybind: use `bind`, not `hl.bind`
|
### Adding a keybind: use `bind`, not `hl.bind`
|
||||||
@@ -120,7 +120,7 @@ Every `hl.bind` must pass a `description`. Hyprland reports Lua-defined binds
|
|||||||
with dispatcher `__lua` and a bytecode offset as the argument, so a bind without
|
with dispatcher `__lua` and a bytecode offset as the argument, so a bind without
|
||||||
one has nothing readable beside its chord, and the Settings app drops it from the
|
one has nothing readable beside its chord, and the Settings app drops it from the
|
||||||
Input & Shortcuts page rather than showing a mystery row.
|
Input & Shortcuts page rather than showing a mystery row.
|
||||||
`tests/quickshell/keybinds-contract.sh` fails if any bind lacks a description, so
|
`tests/quickshell/keybinds-contract` fails if any bind lacks a description, so
|
||||||
this cannot regress silently.
|
this cannot regress silently.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
import qs.modules.settings
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
ShellRoot {
|
||||||
|
Item {
|
||||||
|
width: 680
|
||||||
|
height: editor.implicitHeight
|
||||||
|
|
||||||
|
AccentEditor {
|
||||||
|
id: editor
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
|
||||||
|
ThemeProfilePicker {
|
||||||
|
width: parent.width
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
AccentPicker {
|
||||||
|
width: parent.width
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
target: "accent-controls-test"
|
||||||
|
|
||||||
|
function status(): string {
|
||||||
|
return JSON.stringify(ThemeProfiles.activeProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
function adjust(target: string, channel: string, ratio: real): string {
|
||||||
|
editor.changeChannel(target, channel, ratio);
|
||||||
|
return status();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -975,6 +975,19 @@ Singleton {
|
|||||||
{ value: "slate", label: "Slate" }
|
{ value: "slate", label: "Slate" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "themeProfileId", type: "string", def: "moon", group: "appearance",
|
||||||
|
pattern: "^[a-z0-9][a-z0-9-]{0,63}$",
|
||||||
|
label: "Selected theme profile",
|
||||||
|
detail: "The shipped or saved theme currently applied to the desktop",
|
||||||
|
internal: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "themeProfiles", type: "json", def: [], group: "appearance",
|
||||||
|
label: "Saved theme profiles",
|
||||||
|
detail: "Named custom colour schemes and accent pairs",
|
||||||
|
internal: true
|
||||||
|
},
|
||||||
|
|
||||||
// ── Application themes ─────────────────────────────────────────────
|
// ── Application themes ─────────────────────────────────────────────
|
||||||
// ColorScheme owns GTK's light/dark theme. These are the two theme
|
// ColorScheme owns GTK's light/dark theme. These are the two theme
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import Quickshell
|
|||||||
// QtQuick is required even though nothing visual is declared here: `color` is a
|
// QtQuick is required even though nothing visual is declared here: `color` is a
|
||||||
// QtQuick value type, and Qt.rgba() lives in its JS namespace.
|
// QtQuick value type, and Qt.rgba() lives in its JS namespace.
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import qs.services
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -60,30 +61,20 @@ Singleton {
|
|||||||
// Blue is the shipped Prism -- blue leading, orchid following -- and stays
|
// Blue is the shipped Prism -- blue leading, orchid following -- and stays
|
||||||
// the default.
|
// the default.
|
||||||
//
|
//
|
||||||
// `gnome` is the nearest member of GNOME's own accent-color enum, which is
|
// The table itself lives in services/ThemeProfileModel.js so a curated
|
||||||
// a fixed list of nine we do not get to extend. It is what libadwaita
|
// accent and a custom profile are the same kind of record. Its `gnome`
|
||||||
|
// member is the nearest name in GNOME's own accent-color enum, which is a
|
||||||
|
// fixed list of nine we do not get to extend; it is what libadwaita
|
||||||
// applications -- Files, Papers, Loupe -- are told to use, so choosing an
|
// applications -- Files, Papers, Loupe -- are told to use, so choosing an
|
||||||
// accent here recolors them too instead of leaving them in GNOME blue.
|
// accent here recolors them too instead of leaving them in GNOME blue.
|
||||||
// Nearest by hue, not by name: "rose" maps to red rather than pink because
|
readonly property var accents: ThemeProfiles.curatedAccents
|
||||||
// it is the red role in this palette.
|
readonly property var activeProfile: ThemeProfiles.activeProfile
|
||||||
readonly property var accents: ({
|
|
||||||
"blue": { dark: "#82aaff", darkSecondary: "#b172b0", light: "#2e7de9", lightSecondary: "#9854f1", label: "Prism blue", gnome: "blue" },
|
|
||||||
"orchid": { dark: "#c099ff", darkSecondary: "#fca7ea", light: "#7847bd", lightSecondary: "#9854f1", label: "Orchid", gnome: "purple" },
|
|
||||||
"teal": { dark: "#86e1fc", darkSecondary: "#82aaff", light: "#007197", lightSecondary: "#2e7de9", label: "Teal", gnome: "teal" },
|
|
||||||
"green": { dark: "#c3e88d", darkSecondary: "#86e1fc", light: "#587539", lightSecondary: "#007197", label: "Green", gnome: "green" },
|
|
||||||
"amber": { dark: "#ffc777", darkSecondary: "#ff966c", light: "#8c6c3e", lightSecondary: "#b15c00", label: "Amber", gnome: "yellow" },
|
|
||||||
"orange": { dark: "#ff966c", darkSecondary: "#ff757f", light: "#b15c00", lightSecondary: "#c64343", label: "Orange", gnome: "orange" },
|
|
||||||
"rose": { dark: "#ff757f", darkSecondary: "#c099ff", light: "#f52a65", lightSecondary: "#9854f1", label: "Rose", gnome: "red" },
|
|
||||||
"slate": { dark: "#828bb8", darkSecondary: "#82aaff", light: "#6172b0", lightSecondary: "#2e7de9", label: "Slate", gnome: "slate" }
|
|
||||||
})
|
|
||||||
|
|
||||||
// Falls back to blue for an unknown name, so a settings file written by a
|
// ThemeProfiles validates every persisted record before it can become
|
||||||
// newer Panama -- or edited by hand -- degrades to the shipped identity
|
// active, so these bindings are both reactive and safe to expose as the
|
||||||
// rather than to an undefined color.
|
// shell-wide colour roles.
|
||||||
readonly property var accentPair: root.accents[DesktopPreferences.get("accentName")] ?? root.accents["blue"]
|
readonly property color accent: root.activeProfile.accent
|
||||||
|
readonly property color accentSecondary: root.activeProfile.secondary
|
||||||
readonly property color accent: root.dark ? root.accentPair.dark : root.accentPair.light
|
|
||||||
readonly property color accentSecondary: root.dark ? root.accentPair.darkSecondary : root.accentPair.lightSecondary
|
|
||||||
readonly property color accentAlt: root.dark ? "#65bcff" : "#007197" // blue1, a lighter blue
|
readonly property color accentAlt: root.dark ? "#65bcff" : "#007197" // blue1, a lighter blue
|
||||||
readonly property color cyan: root.dark ? "#86e1fc" : "#007197"
|
readonly property color cyan: root.dark ? "#86e1fc" : "#007197"
|
||||||
readonly property color teal: root.dark ? "#4fd6be" : "#118c74"
|
readonly property color teal: root.dark ? "#4fd6be" : "#118c74"
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ import qs.config
|
|||||||
import qs.services
|
import qs.services
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
|
// The isolated screen model begins with both fixture outputs so changing
|
||||||
|
// it below exercises the same reactive topology path as a real hotplug.
|
||||||
|
Component.onCompleted: Displays.screenOverride = ["DP-2", "HDMI-A-1"]
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
target: "displays-test"
|
target: "displays-test"
|
||||||
|
|
||||||
@@ -42,6 +46,7 @@ ShellRoot {
|
|||||||
function transactionStatus(): string {
|
function transactionStatus(): string {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
layout: Displays.currentLayout(),
|
layout: Displays.currentLayout(),
|
||||||
|
primaryFirst: Displays.primaryFirstMonitors.map(monitor => monitor.name),
|
||||||
pending: Displays.pendingRequestedLayout,
|
pending: Displays.pendingRequestedLayout,
|
||||||
previous: Displays.pendingPreviousLayout,
|
previous: Displays.pendingPreviousLayout,
|
||||||
reverting: Displays.revertExpectedLayout,
|
reverting: Displays.revertExpectedLayout,
|
||||||
@@ -141,5 +146,8 @@ ShellRoot {
|
|||||||
if (monitor) Displays.forget(monitor.name);
|
if (monitor) Displays.forget(monitor.name);
|
||||||
}
|
}
|
||||||
function refresh(): void { Displays.refresh(); }
|
function refresh(): void { Displays.refresh(); }
|
||||||
|
function setScreenModel(names: string): void {
|
||||||
|
Displays.screenOverride = JSON.parse(names);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Exercises Migrations.applyWith against fixture steps and prints a verdict per
|
// Exercises Migrations.applyWith against fixture steps and prints a verdict per
|
||||||
// case. Run by tests/quickshell/migrations-contract.sh.
|
// case. Run by tests/quickshell/migrations-contract.
|
||||||
//
|
//
|
||||||
// Fixture steps rather than the real list: the real one is empty until the
|
// Fixture steps rather than the real list: the real one is empty until the
|
||||||
// first breaking schema change, and a mechanism that has never been run against
|
// first breaking schema change, and a mechanism that has never been run against
|
||||||
|
|||||||
@@ -177,12 +177,21 @@ PanelWindow {
|
|||||||
x: {
|
x: {
|
||||||
if (!root.revealed)
|
if (!root.revealed)
|
||||||
return root.position === "right" ? surface.width - root.revealStripHeight : 0;
|
return root.position === "right" ? surface.width - root.revealStripHeight : 0;
|
||||||
|
// A horizontal dock is centred on its edge, so the region has
|
||||||
|
// to start where the body starts -- starting at 0 puts it over
|
||||||
|
// the left of the screen while the pointer that summoned the
|
||||||
|
// dock is in the middle, and the hover drops on the very frame
|
||||||
|
// the dock arrives. A vertical dock reaches from the body out
|
||||||
|
// to its own edge, which is x 0 on the left and the body on
|
||||||
|
// the right.
|
||||||
|
if (!root.vertical)
|
||||||
|
return body.x;
|
||||||
return root.position === "right" ? body.x : 0;
|
return root.position === "right" ? body.x : 0;
|
||||||
}
|
}
|
||||||
y: {
|
y: {
|
||||||
if (!root.revealed)
|
if (!root.revealed)
|
||||||
return root.vertical ? 0 : surface.height - root.revealStripHeight;
|
return root.vertical ? 0 : surface.height - root.revealStripHeight;
|
||||||
return root.vertical ? body.y : body.y;
|
return body.y;
|
||||||
}
|
}
|
||||||
width: {
|
width: {
|
||||||
if (!root.revealed)
|
if (!root.revealed)
|
||||||
@@ -201,6 +210,12 @@ PanelWindow {
|
|||||||
DockBody {
|
DockBody {
|
||||||
id: body
|
id: body
|
||||||
|
|
||||||
|
onContextMenuRequested: (anchorItem, entry) => {
|
||||||
|
dockContextMenu.anchorItem = anchorItem;
|
||||||
|
dockContextMenu.entry = entry;
|
||||||
|
dockContextMenu.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
vertical: root.vertical
|
vertical: root.vertical
|
||||||
leftSide: root.position === "left"
|
leftSide: root.position === "left"
|
||||||
|
|
||||||
@@ -251,4 +266,8 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DockContextMenu {
|
||||||
|
id: dockContextMenu
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ Rectangle {
|
|||||||
|
|
||||||
// The item the tooltip is currently describing, or null.
|
// The item the tooltip is currently describing, or null.
|
||||||
property Item hoveredItem: null
|
property Item hoveredItem: null
|
||||||
|
signal contextMenuRequested(Item anchorItem, var entry)
|
||||||
|
|
||||||
// Set by the Dock. A side dock runs the same strip down the screen instead
|
// Set by the Dock. A side dock runs the same strip down the screen instead
|
||||||
// of across it.
|
// of across it.
|
||||||
@@ -170,6 +171,7 @@ Rectangle {
|
|||||||
onEntered: root.hoveredItem = dockItem
|
onEntered: root.hoveredItem = dockItem
|
||||||
onExited: if (root.hoveredItem === dockItem)
|
onExited: if (root.hoveredItem === dockItem)
|
||||||
root.hoveredItem = null
|
root.hoveredItem = null
|
||||||
|
onContextMenuRequested: root.contextMenuRequested(dockItem, dockItem.entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
// The dock's app menu. Desktop-entry actions stay first; the shell-owned
|
||||||
|
// configuration route is deliberately last so it never displaces app actions.
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import qs.config
|
||||||
|
import qs.modules.bar
|
||||||
|
import qs.services
|
||||||
|
import qs.widgets
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property Item anchorItem: null
|
||||||
|
property var entry: null
|
||||||
|
|
||||||
|
anchor.item: root.anchorItem
|
||||||
|
anchor.edges: Edges.Top | Edges.Left
|
||||||
|
anchor.gravity: Edges.Top | Edges.Right
|
||||||
|
anchor.margins.bottom: 8
|
||||||
|
|
||||||
|
implicitWidth: Math.max(menu.implicitWidth + Theme.popoverPadding * 2, 240)
|
||||||
|
implicitHeight: menu.implicitHeight + Theme.popoverPadding * 2
|
||||||
|
color: "transparent"
|
||||||
|
visible: false
|
||||||
|
grabFocus: true
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Theme.popoverRadius
|
||||||
|
color: Theme.alpha(Theme.bgPopover, Theme.popoverAlpha)
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.alpha(Theme.fg, 0.08)
|
||||||
|
|
||||||
|
PrismEdge {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 1
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
inset: parent.radius
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: menu
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.popoverPadding
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: applicationActions
|
||||||
|
model: root.entry ? root.entry.actions : []
|
||||||
|
|
||||||
|
delegate: TrayMenuRow {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
label: modelData.name
|
||||||
|
onActivated: {
|
||||||
|
modelData.execute();
|
||||||
|
root.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
anchors.margins: 3
|
||||||
|
visible: applicationActions.count > 0
|
||||||
|
border.width: 0
|
||||||
|
color: Theme.alpha(Theme.fg, 0.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
TrayMenuRow {
|
||||||
|
width: parent.width
|
||||||
|
label: "Dock settings"
|
||||||
|
onActivated: {
|
||||||
|
ShellState.openSettings("desktop");
|
||||||
|
root.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ Item {
|
|||||||
// Emitted so DockBody can drive the single shared tooltip.
|
// Emitted so DockBody can drive the single shared tooltip.
|
||||||
signal entered
|
signal entered
|
||||||
signal exited
|
signal exited
|
||||||
|
signal contextMenuRequested
|
||||||
|
|
||||||
// The icon may grow past the cell on hover; the cell itself stays a fixed
|
// The icon may grow past the cell on hover; the cell itself stays a fixed
|
||||||
// size so the row doesn't reflow.
|
// size so the row doesn't reflow.
|
||||||
@@ -115,7 +116,7 @@ Item {
|
|||||||
id: mouse
|
id: mouse
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
|
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||||
|
|
||||||
onEntered: root.entered()
|
onEntered: root.entered()
|
||||||
onExited: root.exited()
|
onExited: root.exited()
|
||||||
@@ -126,6 +127,10 @@ Item {
|
|||||||
root.launch();
|
root.launch();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (mev.button === Qt.RightButton) {
|
||||||
|
root.contextMenuRequested();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (root.running)
|
if (root.running)
|
||||||
root.focusNext();
|
root.focusNext();
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import Quickshell.Services.Notifications
|
|||||||
import qs.config
|
import qs.config
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.modules.quicksettings
|
import qs.modules.quicksettings
|
||||||
|
import qs.modules.bar
|
||||||
import qs.widgets
|
import qs.widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -127,11 +128,44 @@ Rectangle {
|
|||||||
onClicked: root.dismissed()
|
onClicked: root.dismissed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
id: settingsMenuButton
|
||||||
|
anchors.right: closeButton.left
|
||||||
|
anchors.rightMargin: 2
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 6
|
||||||
|
size: 24
|
||||||
|
iconSize: 14
|
||||||
|
tint: Theme.fgDim
|
||||||
|
icon: "view-more-symbolic"
|
||||||
|
iconFallback: "open-menu-symbolic"
|
||||||
|
onClicked: settingsMenu.visible = !settingsMenu.visible
|
||||||
|
}
|
||||||
|
|
||||||
|
Popover {
|
||||||
|
id: settingsMenu
|
||||||
|
anchorItem: settingsMenuButton
|
||||||
|
|
||||||
|
// A Column already measures itself from its children, and in Qt 6 both
|
||||||
|
// implicit sizes are read-only on a positioner -- assigning them makes
|
||||||
|
// the whole shell fail to load rather than just this menu.
|
||||||
|
Column {
|
||||||
|
TrayMenuRow {
|
||||||
|
id: notificationSettings
|
||||||
|
label: "Notification settings"
|
||||||
|
onActivated: {
|
||||||
|
ShellState.openSettings("notifications");
|
||||||
|
settingsMenu.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: layout
|
id: layout
|
||||||
anchors.left: appIcon.visible ? appIcon.right : parent.left
|
anchors.left: appIcon.visible ? appIcon.right : parent.left
|
||||||
anchors.leftMargin: appIcon.visible ? 10 : 14
|
anchors.leftMargin: appIcon.visible ? 10 : 14
|
||||||
anchors.right: image.visible ? image.left : closeButton.left
|
anchors.right: image.visible ? image.left : settingsMenuButton.left
|
||||||
anchors.rightMargin: 8
|
anchors.rightMargin: 8
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 12
|
anchors.topMargin: 12
|
||||||
|
|||||||
@@ -34,7 +34,14 @@ PanelWindow {
|
|||||||
implicitWidth: root.desiredWidth
|
implicitWidth: root.desiredWidth
|
||||||
implicitHeight: 64
|
implicitHeight: 64
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
mask: Region {}
|
mask: Region {
|
||||||
|
item: inputMask
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: inputMask
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
WlrLayershell.namespace: "qs-popover-osd"
|
WlrLayershell.namespace: "qs-popover-osd"
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
@@ -145,6 +152,17 @@ PanelWindow {
|
|||||||
font.weight: Font.DemiBold
|
font.weight: Font.DemiBold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
onClicked: event => {
|
||||||
|
if (event.button !== Qt.RightButton)
|
||||||
|
return;
|
||||||
|
ShellState.openSettings("accessibility");
|
||||||
|
OsdState.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextMetrics {
|
TextMetrics {
|
||||||
|
|||||||
@@ -176,33 +176,33 @@ Item {
|
|||||||
height: aspect > 0 ? width / aspect : parent.height
|
height: aspect > 0 ? width / aspect : parent.height
|
||||||
opacity: hasContent ? 1 : 0
|
opacity: hasContent ? 1 : 0
|
||||||
|
|
||||||
// The capture context isn't ready the instant the layer surface is
|
// A ScreencopyView cannot tell us that its recording context is
|
||||||
// told to become visible — it needs the surface to actually map,
|
// ready before a capture. The enclosing overview gets that
|
||||||
// which takes a frame or two. Calling captureFrame() before then
|
// context only after its first rendered frame, so defer the first
|
||||||
// logs "no recording context is ready" and yields nothing, so
|
// one-shot capture to that event. Retrying before then only emits
|
||||||
// retry a few times and then give up quietly (the caption and app
|
// "no recording context is ready" warnings; if a capture later
|
||||||
// icon are still shown, so a missing thumbnail is cosmetic).
|
// cannot produce content, the app icon remains the fallback.
|
||||||
property int captureAttempts: 0
|
property bool recordingReady: false
|
||||||
|
|
||||||
function tryCapture(): void {
|
function tryCapture(): void {
|
||||||
captureAttempts = 0;
|
if (shot.hasContent)
|
||||||
captureRetry.restart();
|
return;
|
||||||
|
if (!shot.recordingReady) {
|
||||||
|
frameReady.restart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
shot.captureFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// `shot`, not `parent`: Timer is a QtObject, so `parent` does not
|
FrameAnimation {
|
||||||
// resolve to the enclosing ScreencopyView.
|
id: frameReady
|
||||||
Timer {
|
|
||||||
id: captureRetry
|
|
||||||
interval: 80
|
|
||||||
repeat: true
|
|
||||||
running: false
|
running: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (shot.hasContent || shot.captureAttempts >= 6) {
|
running = false;
|
||||||
stop();
|
if (shot.hasContent)
|
||||||
return;
|
return;
|
||||||
}
|
shot.recordingReady = true;
|
||||||
shot.captureAttempts++;
|
shot.tryCapture();
|
||||||
shot.captureFrame();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
// Advanced accent editing remains a labelled, keyboard-operable extension of
|
||||||
|
// the named fast path. Hue is always accompanied by saturation, value, a
|
||||||
|
// numeric readout, and the two-colour preview supplied by Appearance.
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import qs.config
|
||||||
|
import qs.services
|
||||||
|
import qs.widgets
|
||||||
|
import "../../services/ThemeProfileModel.js" as ThemeProfileModel
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: editor
|
||||||
|
|
||||||
|
width: parent ? parent.width : 620
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
property string pickerTarget: "primary"
|
||||||
|
property string lastError: ""
|
||||||
|
|
||||||
|
readonly property var primaryHsv: ThemeProfileModel.hexToHsv(
|
||||||
|
ThemeProfiles.activeProfile.accent) || ({ h: 0, s: 0, v: 0 })
|
||||||
|
readonly property var secondaryHsv: ThemeProfileModel.hexToHsv(
|
||||||
|
ThemeProfiles.activeProfile.secondary) || ({ h: 0, s: 0, v: 0 })
|
||||||
|
|
||||||
|
function changeChannel(target: string, channel: string, ratio: real): void {
|
||||||
|
const source = target === "primary" ? editor.primaryHsv : editor.secondaryHsv;
|
||||||
|
const next = { h: source.h, s: source.s, v: source.v };
|
||||||
|
next[channel] = Math.round(Math.max(0, Math.min(1, ratio))
|
||||||
|
* (channel === "h" ? 360 : 100));
|
||||||
|
const changed = ThemeProfileModel.hsvToHex(next.h, next.s, next.v);
|
||||||
|
const primary = target === "primary" ? changed : ThemeProfiles.activeProfile.accent;
|
||||||
|
const secondary = target === "secondary" ? changed : ThemeProfiles.activeProfile.secondary;
|
||||||
|
ThemeProfiles.setAccentPair(primary, secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pick(target: string): void {
|
||||||
|
if (screenPicker.running)
|
||||||
|
return;
|
||||||
|
editor.pickerTarget = target;
|
||||||
|
editor.lastError = "";
|
||||||
|
screenPicker.exec(["hyprpicker", "--format=hex", "--lowercase-hex", "--quiet", "--no-fancy"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function acceptPicked(value: string): void {
|
||||||
|
const picked = String(value).trim().toLowerCase();
|
||||||
|
if (ThemeProfileModel.hexToHsv(picked) === null) {
|
||||||
|
editor.lastError = "The sampled colour was not valid.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const primary = editor.pickerTarget === "primary"
|
||||||
|
? picked : ThemeProfiles.activeProfile.accent;
|
||||||
|
const secondary = editor.pickerTarget === "secondary"
|
||||||
|
? picked : ThemeProfiles.activeProfile.secondary;
|
||||||
|
ThemeProfiles.setAccentPair(primary, secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
component HsvRow: SettingRow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property string target
|
||||||
|
required property string channel
|
||||||
|
required property real channelValue
|
||||||
|
required property real channelMaximum
|
||||||
|
property string suffix: "%"
|
||||||
|
|
||||||
|
controlWidth: 280
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: keyboardSlider
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 270
|
||||||
|
height: 32
|
||||||
|
activeFocusOnTab: true
|
||||||
|
|
||||||
|
Accessible.role: Accessible.Slider
|
||||||
|
Accessible.name: root.label
|
||||||
|
Accessible.description: Math.round(root.channelValue) + root.suffix
|
||||||
|
+ ", range 0 to " + root.channelMaximum
|
||||||
|
Accessible.focusable: true
|
||||||
|
Accessible.focused: activeFocus
|
||||||
|
Accessible.onIncreaseAction: keyboardSlider.step(1)
|
||||||
|
Accessible.onDecreaseAction: keyboardSlider.step(-1)
|
||||||
|
|
||||||
|
function step(direction: int): void {
|
||||||
|
const increment = root.channel === "h" ? 1 : 1;
|
||||||
|
const value = Math.max(0, Math.min(root.channelMaximum,
|
||||||
|
root.channelValue + direction * increment));
|
||||||
|
editor.changeChannel(root.target, root.channel, value / root.channelMaximum);
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Left || event.key === Qt.Key_Down) {
|
||||||
|
keyboardSlider.step(-1);
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Right || event.key === Qt.Key_Up) {
|
||||||
|
keyboardSlider.step(1);
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_Home) {
|
||||||
|
editor.changeChannel(root.target, root.channel, 0);
|
||||||
|
event.accepted = true;
|
||||||
|
} else if (event.key === Qt.Key_End) {
|
||||||
|
editor.changeChannel(root.target, root.channel, 1);
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: readout.left
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
height: 24
|
||||||
|
radius: 9
|
||||||
|
color: "transparent"
|
||||||
|
border.width: keyboardSlider.activeFocus ? 2 : 1
|
||||||
|
border.color: keyboardSlider.activeFocus ? Theme.accentSecondary : Theme.alpha(Theme.fg, 0.08)
|
||||||
|
|
||||||
|
ValueSlider {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 4
|
||||||
|
value: root.channelMaximum > 0 ? root.channelValue / root.channelMaximum : 0
|
||||||
|
onMoved: ratio => editor.changeChannel(root.target, root.channel, ratio)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: readout
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 56
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
text: Math.round(root.channelValue) + root.suffix
|
||||||
|
color: Theme.fgDim
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.features: Theme.tabularFigures
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HsvRow {
|
||||||
|
target: "primary"; channel: "h"; channelValue: editor.primaryHsv.h; channelMaximum: 360
|
||||||
|
suffix: "°"; label: "Primary hue"; detail: "Colour family, measured from 0 to 360 degrees"
|
||||||
|
}
|
||||||
|
HsvRow {
|
||||||
|
target: "primary"; channel: "s"; channelValue: editor.primaryHsv.s; channelMaximum: 100
|
||||||
|
label: "Primary saturation"; detail: "Colour intensity from grey to vivid"
|
||||||
|
}
|
||||||
|
HsvRow {
|
||||||
|
target: "primary"; channel: "v"; channelValue: editor.primaryHsv.v; channelMaximum: 100
|
||||||
|
label: "Primary value"; detail: "Brightness from black to full colour"
|
||||||
|
}
|
||||||
|
HsvRow {
|
||||||
|
target: "secondary"; channel: "h"; channelValue: editor.secondaryHsv.h; channelMaximum: 360
|
||||||
|
suffix: "°"; label: "Secondary hue"; detail: "Colour family at the far end of the Prism gradient"
|
||||||
|
}
|
||||||
|
HsvRow {
|
||||||
|
target: "secondary"; channel: "s"; channelValue: editor.secondaryHsv.s; channelMaximum: 100
|
||||||
|
label: "Secondary saturation"; detail: "Colour intensity from grey to vivid"
|
||||||
|
}
|
||||||
|
HsvRow {
|
||||||
|
target: "secondary"; channel: "v"; channelValue: editor.secondaryHsv.v; channelMaximum: 100
|
||||||
|
label: "Secondary value"; detail: "Brightness from black to full colour"
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingRow {
|
||||||
|
label: "Pick colour from screen"
|
||||||
|
detail: editor.lastError !== ""
|
||||||
|
? editor.lastError
|
||||||
|
: "Sample either end of the accent gradient with hyprpicker"
|
||||||
|
divider: false
|
||||||
|
controlWidth: 330
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 7
|
||||||
|
|
||||||
|
SettingsButton {
|
||||||
|
text: "Pick primary from screen"
|
||||||
|
enabled: !screenPicker.running
|
||||||
|
activeFocusOnTab: enabled
|
||||||
|
border.width: activeFocus ? 2 : 1
|
||||||
|
border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08)
|
||||||
|
onClicked: editor.pick("primary")
|
||||||
|
Keys.onReturnPressed: if (enabled) editor.pick("primary")
|
||||||
|
Keys.onSpacePressed: if (enabled) editor.pick("primary")
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsButton {
|
||||||
|
text: "Pick secondary from screen"
|
||||||
|
enabled: !screenPicker.running
|
||||||
|
activeFocusOnTab: enabled
|
||||||
|
border.width: activeFocus ? 2 : 1
|
||||||
|
border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08)
|
||||||
|
onClicked: editor.pick("secondary")
|
||||||
|
Keys.onReturnPressed: if (enabled) editor.pick("secondary")
|
||||||
|
Keys.onSpacePressed: if (enabled) editor.pick("secondary")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: screenPicker
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: editor.acceptPicked(this.text)
|
||||||
|
}
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
if (exitCode !== 0)
|
||||||
|
editor.lastError = "Screen colour picking was cancelled or unavailable.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ Flow {
|
|||||||
|
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
readonly property string current: DesktopPreferences.get("accentName") || "blue"
|
readonly property string current: ThemeProfiles.activeAccentName
|
||||||
|
|
||||||
// The schema's own option list, not Theme.accents directly -- two lists
|
// The schema's own option list, not Theme.accents directly -- two lists
|
||||||
// hand-kept in sync is how they drift. This is the same pattern
|
// hand-kept in sync is how they drift. This is the same pattern
|
||||||
@@ -60,6 +60,8 @@ Flow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: swatch
|
||||||
|
|
||||||
width: 46
|
width: 46
|
||||||
height: 46
|
height: 46
|
||||||
radius: 23
|
radius: 23
|
||||||
@@ -67,8 +69,25 @@ Flow {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
// The ring sits outside the gradient rather than over it, so a
|
// The ring sits outside the gradient rather than over it, so a
|
||||||
// selected swatch still shows its true colors.
|
// selected swatch still shows its true colors.
|
||||||
border.width: entry.selected ? 2 : 1
|
border.width: swatch.activeFocus || entry.selected ? 2 : 1
|
||||||
border.color: entry.selected ? Theme.fg : Theme.alpha(Theme.fg, 0.14)
|
border.color: swatch.activeFocus
|
||||||
|
? Theme.accentSecondary
|
||||||
|
: (entry.selected ? Theme.fg : Theme.alpha(Theme.fg, 0.14))
|
||||||
|
activeFocusOnTab: true
|
||||||
|
|
||||||
|
Accessible.role: Accessible.Button
|
||||||
|
Accessible.name: entry.pair.label + " accent"
|
||||||
|
Accessible.description: String(entry.start) + " to " + String(entry.end)
|
||||||
|
Accessible.focusable: true
|
||||||
|
Accessible.focused: activeFocus
|
||||||
|
|
||||||
|
function choose(): void {
|
||||||
|
if (!ThemeProfiles.useCuratedAccent(entry.modelData))
|
||||||
|
console.warn("AccentPicker: accent was rejected", entry.modelData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onReturnPressed: swatch.choose()
|
||||||
|
Keys.onSpacePressed: swatch.choose()
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -81,6 +100,9 @@ Flow {
|
|||||||
GradientStop { position: 1.0; color: entry.end }
|
GradientStop { position: 1.0; color: entry.end }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HoverHandler { cursorShape: Qt.PointingHandCursor }
|
||||||
|
TapHandler { onTapped: swatch.choose() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always shown, not a tooltip. Telling swatches apart by color is
|
// Always shown, not a tooltip. Telling swatches apart by color is
|
||||||
|
|||||||
@@ -129,18 +129,26 @@ SettingsPage {
|
|||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
visible: root.tab === "theme"
|
visible: root.tab === "theme"
|
||||||
title: "Color scheme"
|
// Not "Color scheme" any more: the card holds the saved themes as well
|
||||||
|
// as the scheme, and a theme carries both ends of the accent with it.
|
||||||
|
title: "Theme"
|
||||||
subtitle: ColorScheme.lastError !== ""
|
subtitle: ColorScheme.lastError !== ""
|
||||||
? ColorScheme.lastError
|
? ColorScheme.lastError
|
||||||
: "Light is Tokyo Night Day, the official light variant — the same hues at a different lightness, so the blue-into-orchid signature survives the switch. Applications and window borders follow."
|
: "Start with Moon, Moon Rose, or Day; saved themes capture the scheme and both ends of the Prism accent."
|
||||||
|
|
||||||
ChoiceRow { setting: "colorScheme" }
|
ThemeProfilePicker {
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
|
||||||
// Drawn as the gradient each accent produces rather than a flat dot,
|
// Drawn as the gradient each accent produces rather than a flat dot,
|
||||||
// because the gradient is what is being chosen.
|
// because the gradient is what is being chosen.
|
||||||
AccentPicker {
|
AccentPicker {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AccentEditor {
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ SettingsPage {
|
|||||||
|
|
||||||
property string selectedOutput: ""
|
property string selectedOutput: ""
|
||||||
readonly property var monitor: Displays.monitorNamed(root.selectedOutput)
|
readonly property var monitor: Displays.monitorNamed(root.selectedOutput)
|
||||||
?? (Displays.monitors.length > 0 ? Displays.monitors[0] : null)
|
?? (Displays.primaryFirstMonitors.length > 0 ? Displays.primaryFirstMonitors[0] : null)
|
||||||
readonly property string currentMode: root.monitor
|
readonly property string currentMode: root.monitor
|
||||||
? root.monitor.mode
|
? root.monitor.mode
|
||||||
: ""
|
: ""
|
||||||
@@ -38,7 +38,8 @@ SettingsPage {
|
|||||||
|
|
||||||
function syncSelectedOutput(): void {
|
function syncSelectedOutput(): void {
|
||||||
if (!Displays.monitorNamed(root.selectedOutput))
|
if (!Displays.monitorNamed(root.selectedOutput))
|
||||||
root.selectedOutput = Displays.monitors.length > 0 ? Displays.monitors[0].name : "";
|
root.selectedOutput = Displays.primaryFirstMonitors.length > 0
|
||||||
|
? Displays.primaryFirstMonitors[0].name : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Probing I2C for DDC-capable monitors takes on the order of a second, so
|
// Probing I2C for DDC-capable monitors takes on the order of a second, so
|
||||||
@@ -137,7 +138,7 @@ SettingsPage {
|
|||||||
ChoiceGrid {
|
ChoiceGrid {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
label: "Display"
|
label: "Display"
|
||||||
options: Displays.monitors.map(monitor => ({
|
options: Displays.primaryFirstMonitors.map(monitor => ({
|
||||||
value: monitor.name,
|
value: monitor.name,
|
||||||
label: monitor.description || monitor.name
|
label: monitor.description || monitor.name
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ layout.
|
|||||||
|
|
||||||
Mirrors must remain the same schema-backed control, never a second preference
|
Mirrors must remain the same schema-backed control, never a second preference
|
||||||
or a copied default. Additions to this table require a concrete discoverability
|
or a copied default. Additions to this table require a concrete discoverability
|
||||||
reason and an update to `tests/quickshell/settings-ownership-contract.sh`.
|
reason and an update to `tests/quickshell/settings-ownership-contract`.
|
||||||
|
|
||||||
Window border color follows the same ownership rule. The inactive border is a
|
Window border color follows the same ownership rule. The inactive border is a
|
||||||
**scheme-relative role** owned by `ColorScheme.qml`: it changes only to retain
|
**scheme-relative role** owned by `ColorScheme.qml`: it changes only to retain
|
||||||
@@ -127,7 +127,7 @@ store. A row never needs to know which kind it holds.
|
|||||||
the value in a different JSON field per type — `int`, `bool`, `float`, `str`,
|
the value in a different JSON field per type — `int`, `bool`, `float`, `str`,
|
||||||
and `css` for gaps (a four-value box). Declaring the wrong one does not fail
|
and `css` for gaps (a four-value box). Declaring the wrong one does not fail
|
||||||
loudly: it makes every write to that key look *rejected*, and the user sees an
|
loudly: it makes every write to that key look *rejected*, and the user sees an
|
||||||
error for a change that worked. `tests/quickshell/schema-hypr-shape-contract.sh`
|
error for a change that worked. `tests/quickshell/schema-hypr-shape-contract`
|
||||||
asks the compositor for the real shape of every mapped option.
|
asks the compositor for the real shape of every mapped option.
|
||||||
|
|
||||||
**Never trust an exit code from `hyprctl`.** `keyword` refuses to work on a
|
**Never trust an exit code from `hyprctl`.** `keyword` refuses to work on a
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
// Named themes are the first layer of Appearance: shipped profiles stay
|
||||||
|
// immutable, while saved profiles can be selected or removed in place.
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.config
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
width: parent ? parent.width : 620
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: ThemeProfiles.profiles
|
||||||
|
|
||||||
|
SettingRow {
|
||||||
|
id: profileRow
|
||||||
|
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
label: profileRow.modelData.name
|
||||||
|
detail: (profileRow.modelData.scheme === "light" ? "Light" : "Dark")
|
||||||
|
+ " · " + profileRow.modelData.accent + " → " + profileRow.modelData.secondary
|
||||||
|
controlWidth: profileRow.modelData.shipped ? 88 : 170
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
SettingsButton {
|
||||||
|
id: useButton
|
||||||
|
text: profileRow.modelData.id === ThemeProfiles.activeProfile.id ? "Selected" : "Use"
|
||||||
|
enabled: profileRow.modelData.id !== ThemeProfiles.activeProfile.id
|
||||||
|
activeFocusOnTab: enabled
|
||||||
|
border.width: activeFocus ? 2 : (tone === "accent" ? 0 : 1)
|
||||||
|
border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08)
|
||||||
|
onClicked: ThemeProfiles.selectProfile(profileRow.modelData.id)
|
||||||
|
Keys.onReturnPressed: if (enabled) ThemeProfiles.selectProfile(profileRow.modelData.id)
|
||||||
|
Keys.onSpacePressed: if (enabled) ThemeProfiles.selectProfile(profileRow.modelData.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsButton {
|
||||||
|
id: deleteButton
|
||||||
|
visible: !profileRow.modelData.shipped
|
||||||
|
text: "Delete"
|
||||||
|
activeFocusOnTab: visible
|
||||||
|
border.width: activeFocus ? 2 : 1
|
||||||
|
border.color: activeFocus ? Theme.danger : Theme.alpha(Theme.fg, 0.08)
|
||||||
|
onClicked: ThemeProfiles.deleteProfile(profileRow.modelData.id)
|
||||||
|
Keys.onReturnPressed: ThemeProfiles.deleteProfile(profileRow.modelData.id)
|
||||||
|
Keys.onSpacePressed: ThemeProfiles.deleteProfile(profileRow.modelData.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingRow {
|
||||||
|
label: "Save current theme"
|
||||||
|
detail: "Stores this scheme and accent pair under a unique name"
|
||||||
|
divider: false
|
||||||
|
controlWidth: 292
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 7
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 196
|
||||||
|
height: 31
|
||||||
|
radius: 8
|
||||||
|
color: Theme.alpha(Theme.fg, 0.05)
|
||||||
|
border.width: nameInput.activeFocus ? 2 : 1
|
||||||
|
border.color: nameInput.activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.12)
|
||||||
|
|
||||||
|
TextInput {
|
||||||
|
id: nameInput
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
activeFocusOnTab: true
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
maximumLength: 40
|
||||||
|
color: Theme.fg
|
||||||
|
selectionColor: Theme.alpha(Theme.accent, 0.35)
|
||||||
|
font.family: Theme.fontFamily
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
Accessible.name: "Theme profile name"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: nameInput.text === "" && !nameInput.activeFocus
|
||||||
|
text: "Theme name"
|
||||||
|
color: Theme.fgMuted
|
||||||
|
font: nameInput.font
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: saveButton.save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsButton {
|
||||||
|
id: saveButton
|
||||||
|
text: "Save"
|
||||||
|
tone: "accent"
|
||||||
|
activeFocusOnTab: true
|
||||||
|
border.width: activeFocus ? 2 : 0
|
||||||
|
border.color: activeFocus ? Theme.fg : "transparent"
|
||||||
|
|
||||||
|
function save(): void {
|
||||||
|
if (ThemeProfiles.saveProfile(nameInput.text))
|
||||||
|
nameInput.text = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: save()
|
||||||
|
Keys.onReturnPressed: save()
|
||||||
|
Keys.onSpacePressed: save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,13 @@ Column {
|
|||||||
width: parent ? parent.width : 620
|
width: parent ? parent.width : 620
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
|
onOutputsChanged: root.syncSelectedOutput()
|
||||||
|
|
||||||
|
function syncSelectedOutput(): void {
|
||||||
|
if (!root.outputs.includes(root.selectedOutput))
|
||||||
|
root.selectedOutput = root.outputs.length > 0 ? root.outputs[0] : "";
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceGrid {
|
ChoiceGrid {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
label: "Wallpaper mode"
|
label: "Wallpaper mode"
|
||||||
|
|||||||
@@ -80,3 +80,5 @@ SearchPicker 1.0 SearchPicker.qml
|
|||||||
OnlineAccountsPage 1.0 OnlineAccountsPage.qml
|
OnlineAccountsPage 1.0 OnlineAccountsPage.qml
|
||||||
AccentPicker 1.0 AccentPicker.qml
|
AccentPicker 1.0 AccentPicker.qml
|
||||||
TextFieldRow 1.0 TextFieldRow.qml
|
TextFieldRow 1.0 TextFieldRow.qml
|
||||||
|
AccentEditor 1.0 AccentEditor.qml
|
||||||
|
ThemeProfilePicker 1.0 ThemeProfilePicker.qml
|
||||||
|
|||||||
@@ -17,8 +17,10 @@ status_file="$state_dir/hyprlock-status.json"
|
|||||||
fallback="$config_home/hypr/hyprlock.conf"
|
fallback="$config_home/hypr/hyprlock.conf"
|
||||||
temporary="$generated.tmp.$$"
|
temporary="$generated.tmp.$$"
|
||||||
status_temporary="$status_file.tmp.$$"
|
status_temporary="$status_file.tmp.$$"
|
||||||
|
shipped_wallpaper="$HOME/Pictures/Wallpapers/faroe_islands.jpg"
|
||||||
|
|
||||||
settings_valid=false
|
settings_valid=false
|
||||||
|
wallpaper_warning=""
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
rm -f "$temporary" "$status_temporary" 2>/dev/null || true
|
rm -f "$temporary" "$status_temporary" 2>/dev/null || true
|
||||||
@@ -76,7 +78,23 @@ read_object() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
valid_path() {
|
valid_path() {
|
||||||
[[ "$1" == /* && "$1" != *","* && "$1" != *$'\n'* ]]
|
[[ "$1" == /* && "$1" != *","* && "$1" != *$'\n'* && -f "$1" && -r "$1" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_wallpaper_path() {
|
||||||
|
local candidate="$1"
|
||||||
|
if valid_path "$candidate"; then
|
||||||
|
resolved_wallpaper="$candidate"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ -n "$candidate" ]]; then
|
||||||
|
wallpaper_warning="One or more lock-screen wallpapers were unavailable; a safe fallback is in use."
|
||||||
|
fi
|
||||||
|
if valid_path "$shipped_wallpaper"; then
|
||||||
|
resolved_wallpaper="$shipped_wallpaper"
|
||||||
|
else
|
||||||
|
resolved_wallpaper="screenshot"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Same 8 named accents as config/Theme.qml's `accents` map (kept in sync by
|
# Same 8 named accents as config/Theme.qml's `accents` map (kept in sync by
|
||||||
@@ -134,10 +152,9 @@ load_preferences() {
|
|||||||
wallpaper_mode="$(read_string wallpaperMode single)"
|
wallpaper_mode="$(read_string wallpaperMode single)"
|
||||||
[[ "$wallpaper_mode" == single || "$wallpaper_mode" == slideshow || "$wallpaper_mode" == per-monitor ]] \
|
[[ "$wallpaper_mode" == single || "$wallpaper_mode" == slideshow || "$wallpaper_mode" == per-monitor ]] \
|
||||||
|| wallpaper_mode=single
|
|| wallpaper_mode=single
|
||||||
wallpaper_path="$(read_string wallpaperPath '')"
|
wallpaper_warning=""
|
||||||
if ! valid_path "$wallpaper_path"; then
|
resolve_wallpaper_path "$(read_string wallpaperPath '')"
|
||||||
wallpaper_path="$HOME/Pictures/Wallpapers/faroe_islands.jpg"
|
wallpaper_path="$resolved_wallpaper"
|
||||||
fi
|
|
||||||
wallpaper_assignments="$(read_object wallpaperPerMonitor)"
|
wallpaper_assignments="$(read_object wallpaperPerMonitor)"
|
||||||
|
|
||||||
case "$blur_level" in
|
case "$blur_level" in
|
||||||
@@ -218,8 +235,9 @@ emit_backgrounds() {
|
|||||||
candidate="$(jq -r --arg output "$output" \
|
candidate="$(jq -r --arg output "$output" \
|
||||||
'if has($output) and (.[$output] | type) == "string" then .[$output] else "" end' \
|
'if has($output) and (.[$output] | type) == "string" then .[$output] else "" end' \
|
||||||
<<<"$wallpaper_assignments" 2>/dev/null || true)"
|
<<<"$wallpaper_assignments" 2>/dev/null || true)"
|
||||||
if valid_path "$candidate"; then
|
if [[ -n "$candidate" ]]; then
|
||||||
assigned="$candidate"
|
resolve_wallpaper_path "$candidate"
|
||||||
|
assigned="$resolved_wallpaper"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
emit_background "$output" "$assigned"
|
emit_background "$output" "$assigned"
|
||||||
@@ -344,7 +362,7 @@ generate() {
|
|||||||
write_status false "$fallback" true "The lock-screen configuration could not be generated."
|
write_status false "$fallback" true "The lock-screen configuration could not be generated."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
write_status true "$generated" false ""
|
write_status true "$generated" false "$wallpaper_warning"
|
||||||
}
|
}
|
||||||
|
|
||||||
status() {
|
status() {
|
||||||
|
|||||||
@@ -150,12 +150,12 @@ def build() -> dict[Path, str]:
|
|||||||
files: dict[Path, str] = {}
|
files: dict[Path, str] = {}
|
||||||
for page, label in pages():
|
for page, label in pages():
|
||||||
words = keywords_for(page, routing, schema, extras)
|
words = keywords_for(page, routing, schema, extras)
|
||||||
files[OUTPUT_DIR / f"settings-{page}.sh"] = command_for(page, label, words)
|
files[OUTPUT_DIR / f"settings-{page}"] = command_for(page, label, words)
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
||||||
def existing() -> set[Path]:
|
def existing() -> set[Path]:
|
||||||
return {path for path in OUTPUT_DIR.glob("settings-*.sh")}
|
return {path for path in OUTPUT_DIR.glob("settings-*")}
|
||||||
|
|
||||||
|
|
||||||
def main(arguments: list[str]) -> int:
|
def main(arguments: list[str]) -> int:
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Finds wallpaper candidates from fixed roots passed as separate arguments.
|
||||||
|
# Keeping paths as argv values avoids shell interpolation for names containing
|
||||||
|
# quotes, spaces, or other shell syntax.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
find "$@" -maxdepth 2 -type f \
|
||||||
|
\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' \) \
|
||||||
|
-printf '%T@ %p\n' 2>/dev/null \
|
||||||
|
| sort -rn \
|
||||||
|
| cut -d' ' -f2- \
|
||||||
|
| awk 'NR <= 60'
|
||||||
@@ -93,6 +93,14 @@ Singleton {
|
|||||||
function onRevisionChanged(): void { coalesce.restart(); }
|
function onRevisionChanged(): void { coalesce.restart(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Profile selection and custom edits both update preferences, but binding
|
||||||
|
// directly to the effective profile also documents the in-shell ownership
|
||||||
|
// boundary and keeps this propagation reactive if that storage changes.
|
||||||
|
Connections {
|
||||||
|
target: ThemeProfiles
|
||||||
|
function onActiveProfileChanged(): void { coalesce.restart(); }
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: coalesce
|
id: coalesce
|
||||||
interval: 250
|
interval: 250
|
||||||
|
|||||||
@@ -29,8 +29,24 @@ Singleton {
|
|||||||
// [{ name, description, width, height, refreshRate, scale, transform,
|
// [{ name, description, width, height, refreshRate, scale, transform,
|
||||||
// modes: [{ label, mode, width, height, refresh }] }]
|
// modes: [{ label, mode, width, height, refresh }] }]
|
||||||
property var monitors: []
|
property var monitors: []
|
||||||
|
// Quickshell.screens is the topology authority. The override is only the
|
||||||
|
// isolated harness model; normal sessions always observe Quickshell.
|
||||||
|
property var screenOverride: null
|
||||||
property string lastError: ""
|
property string lastError: ""
|
||||||
|
|
||||||
|
readonly property var screenModel: Array.isArray(root.screenOverride)
|
||||||
|
? root.screenOverride : Quickshell.screens
|
||||||
|
readonly property string screenSignature: root.screenModel
|
||||||
|
.map(screen => typeof screen === "string" ? screen : screen.name)
|
||||||
|
.filter(name => !!name)
|
||||||
|
.sort()
|
||||||
|
.join("|")
|
||||||
|
readonly property var primaryFirstMonitors: root.monitors.slice().sort((left, right) => {
|
||||||
|
if (left.primary !== right.primary)
|
||||||
|
return left.primary ? -1 : 1;
|
||||||
|
return left.name.localeCompare(right.name);
|
||||||
|
})
|
||||||
|
|
||||||
// Set while a change is applied but not yet confirmed.
|
// Set while a change is applied but not yet confirmed.
|
||||||
property var pendingPreviousLayout: null
|
property var pendingPreviousLayout: null
|
||||||
property var pendingRequestedLayout: null
|
property var pendingRequestedLayout: null
|
||||||
@@ -113,6 +129,17 @@ Singleton {
|
|||||||
|
|
||||||
Component.onCompleted: root.refresh()
|
Component.onCompleted: root.refresh()
|
||||||
|
|
||||||
|
onScreenSignatureChanged: root.reconcileTopology()
|
||||||
|
|
||||||
|
// A hotplug can invalidate the unconfirmed layout while the confirmation
|
||||||
|
// is visible. Read the current compositor layout first; the normal queued
|
||||||
|
// rollback then filters out any output that has disappeared.
|
||||||
|
function reconcileTopology(): void {
|
||||||
|
root.refresh();
|
||||||
|
if (root.awaitingConfirmation)
|
||||||
|
root.revertWithMessage("A display was connected or disconnected, so Panama restored the previous setting.");
|
||||||
|
}
|
||||||
|
|
||||||
function refresh(): bool {
|
function refresh(): bool {
|
||||||
if (!query.running) {
|
if (!query.running) {
|
||||||
query.generation = root.operationGeneration;
|
query.generation = root.operationGeneration;
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ Singleton {
|
|||||||
// A bind with no description cannot be presented usefully --
|
// A bind with no description cannot be presented usefully --
|
||||||
// the dispatcher is "__lua" and the argument is a bytecode
|
// the dispatcher is "__lua" and the argument is a bytecode
|
||||||
// offset. Showing the chord alone would be worse than omitting
|
// offset. Showing the chord alone would be worse than omitting
|
||||||
// it, and tests/quickshell/keybinds-contract.sh fails the build
|
// it, and tests/quickshell/keybinds-contract fails the build
|
||||||
// if any exist, so this should never be reached in practice.
|
// if any exist, so this should never be reached in practice.
|
||||||
if (description === "")
|
if (description === "")
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -136,7 +136,10 @@ Singleton {
|
|||||||
{ label: "Per-display wallpaper", detail: "Assign a different image to each connected display", page: "appearance" },
|
{ label: "Per-display wallpaper", detail: "Assign a different image to each connected display", page: "appearance" },
|
||||||
{ label: "Arrange displays", detail: "Drag connected displays into their physical positions", page: "displays" },
|
{ label: "Arrange displays", detail: "Drag connected displays into their physical positions", page: "displays" },
|
||||||
{ label: "Monitor position", detail: "Set where each display sits in the desktop", page: "displays" },
|
{ label: "Monitor position", detail: "Set where each display sits in the desktop", page: "displays" },
|
||||||
{ label: "Primary display", detail: "Choose the display that anchors the desktop", page: "displays" }
|
{ label: "Primary display", detail: "Choose the display that anchors the desktop", page: "displays" },
|
||||||
|
{ label: "Theme profiles", detail: "Switch between Moon, Moon Rose, Day, and saved themes", page: "appearance" },
|
||||||
|
{ label: "Advanced accent", detail: "Adjust primary and secondary hue, saturation, and value", page: "appearance" },
|
||||||
|
{ label: "Pick colour from screen", detail: "Sample an accent colour with hyprpicker", page: "appearance" }
|
||||||
]
|
]
|
||||||
|
|
||||||
function pageFor(group: string): string {
|
function pageFor(group: string): string {
|
||||||
|
|||||||
@@ -0,0 +1,419 @@
|
|||||||
|
var MAX_NAME_LENGTH = 40;
|
||||||
|
|
||||||
|
var SHIPPED = [
|
||||||
|
{
|
||||||
|
id: "moon",
|
||||||
|
name: "Moon",
|
||||||
|
scheme: "dark",
|
||||||
|
accent: "#82aaff",
|
||||||
|
secondary: "#b172b0",
|
||||||
|
shipped: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "moon-rose",
|
||||||
|
name: "Moon Rose",
|
||||||
|
scheme: "dark",
|
||||||
|
accent: "#ff757f",
|
||||||
|
secondary: "#c099ff",
|
||||||
|
shipped: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "day",
|
||||||
|
name: "Day",
|
||||||
|
scheme: "light",
|
||||||
|
accent: "#2e7de9",
|
||||||
|
secondary: "#9854f1",
|
||||||
|
shipped: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// The curated accents. `gnome` is the nearest member of GNOME's own
|
||||||
|
// accent-color enum, which is a fixed list of nine we do not get to extend. It
|
||||||
|
// is what libadwaita applications -- Files, Papers, Loupe -- are told to use, so
|
||||||
|
// choosing an accent here recolors them too instead of leaving them in GNOME
|
||||||
|
// blue. Nearest by hue, not by name: "rose" maps to red rather than pink
|
||||||
|
// because it is the red role in this palette. adwaita-accent-contract reads
|
||||||
|
// this table and fails when a member is missing or is not in GNOME's enum.
|
||||||
|
var CURATED = {
|
||||||
|
blue: {
|
||||||
|
dark: "#82aaff", darkSecondary: "#b172b0",
|
||||||
|
light: "#2e7de9", lightSecondary: "#9854f1",
|
||||||
|
label: "Prism blue",
|
||||||
|
gnome: "blue"
|
||||||
|
},
|
||||||
|
orchid: {
|
||||||
|
dark: "#c099ff", darkSecondary: "#fca7ea",
|
||||||
|
light: "#7847bd", lightSecondary: "#9854f1",
|
||||||
|
label: "Orchid",
|
||||||
|
gnome: "purple"
|
||||||
|
},
|
||||||
|
teal: {
|
||||||
|
dark: "#86e1fc", darkSecondary: "#82aaff",
|
||||||
|
light: "#007197", lightSecondary: "#2e7de9",
|
||||||
|
label: "Teal",
|
||||||
|
gnome: "teal"
|
||||||
|
},
|
||||||
|
green: {
|
||||||
|
dark: "#c3e88d", darkSecondary: "#86e1fc",
|
||||||
|
light: "#587539", lightSecondary: "#007197",
|
||||||
|
label: "Green",
|
||||||
|
gnome: "green"
|
||||||
|
},
|
||||||
|
amber: {
|
||||||
|
dark: "#ffc777", darkSecondary: "#ff966c",
|
||||||
|
light: "#8c6c3e", lightSecondary: "#b15c00",
|
||||||
|
label: "Amber",
|
||||||
|
gnome: "yellow"
|
||||||
|
},
|
||||||
|
orange: {
|
||||||
|
dark: "#ff966c", darkSecondary: "#ff757f",
|
||||||
|
light: "#b15c00", lightSecondary: "#c64343",
|
||||||
|
label: "Orange",
|
||||||
|
gnome: "orange"
|
||||||
|
},
|
||||||
|
rose: {
|
||||||
|
dark: "#ff757f", darkSecondary: "#c099ff",
|
||||||
|
light: "#f52a65", lightSecondary: "#9854f1",
|
||||||
|
label: "Rose",
|
||||||
|
gnome: "red"
|
||||||
|
},
|
||||||
|
slate: {
|
||||||
|
dark: "#828bb8", darkSecondary: "#82aaff",
|
||||||
|
light: "#6172b0", lightSecondary: "#2e7de9",
|
||||||
|
label: "Slate",
|
||||||
|
gnome: "slate"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function copyProfile(profile) {
|
||||||
|
return {
|
||||||
|
id: profile.id,
|
||||||
|
name: profile.name,
|
||||||
|
scheme: profile.scheme,
|
||||||
|
accent: profile.accent,
|
||||||
|
secondary: profile.secondary,
|
||||||
|
shipped: profile.shipped === true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function shippedProfiles() {
|
||||||
|
return SHIPPED.map(copyProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
function curatedAccents() {
|
||||||
|
var result = {};
|
||||||
|
Object.keys(CURATED).forEach(function(name) {
|
||||||
|
result[name] = Object.assign({}, CURATED[name]);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isScheme(value) {
|
||||||
|
return value === "dark" || value === "light";
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizedColor(value) {
|
||||||
|
var color = String(value || "").trim().toLowerCase();
|
||||||
|
return /^#[0-9a-f]{6}$/.test(color) ? color : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeStoredProfile(value) {
|
||||||
|
if (!value || typeof value !== "object" || value.shipped === true)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var id = String(value.id || "").trim();
|
||||||
|
var name = String(value.name || "").trim();
|
||||||
|
var accent = normalizedColor(value.accent);
|
||||||
|
var secondary = normalizedColor(value.secondary);
|
||||||
|
if (!/^custom-[a-z0-9][a-z0-9-]{0,56}$/.test(id)
|
||||||
|
|| name.length === 0 || name.length > MAX_NAME_LENGTH
|
||||||
|
|| !isScheme(value.scheme) || !accent || !secondary)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
scheme: value.scheme,
|
||||||
|
accent: accent,
|
||||||
|
secondary: secondary,
|
||||||
|
shipped: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function validCustomProfiles(values) {
|
||||||
|
if (!Array.isArray(values))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
var ids = {};
|
||||||
|
var names = {};
|
||||||
|
SHIPPED.forEach(function(profile) {
|
||||||
|
ids[profile.id] = true;
|
||||||
|
names[profile.name.toLowerCase()] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
var result = [];
|
||||||
|
values.forEach(function(value) {
|
||||||
|
var profile = normalizeStoredProfile(value);
|
||||||
|
if (!profile)
|
||||||
|
return;
|
||||||
|
var foldedName = profile.name.toLowerCase();
|
||||||
|
if (ids[profile.id] || names[foldedName])
|
||||||
|
return;
|
||||||
|
ids[profile.id] = true;
|
||||||
|
names[foldedName] = true;
|
||||||
|
result.push(profile);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function profileCatalog(values) {
|
||||||
|
return shippedProfiles().concat(validCustomProfiles(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
function boundedName(value) {
|
||||||
|
var name = String(value || "").trim();
|
||||||
|
if (!name)
|
||||||
|
name = "Custom theme";
|
||||||
|
return name.slice(0, MAX_NAME_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
function uniqueName(value, profiles) {
|
||||||
|
var requested = boundedName(value);
|
||||||
|
var names = {};
|
||||||
|
profiles.forEach(function(profile) {
|
||||||
|
names[profile.name.toLowerCase()] = true;
|
||||||
|
});
|
||||||
|
if (!names[requested.toLowerCase()])
|
||||||
|
return requested;
|
||||||
|
|
||||||
|
for (var suffix = 2; suffix < 10000; suffix++) {
|
||||||
|
var ending = " " + suffix;
|
||||||
|
var candidate = requested.slice(0, MAX_NAME_LENGTH - ending.length) + ending;
|
||||||
|
if (!names[candidate.toLowerCase()])
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
return requested.slice(0, MAX_NAME_LENGTH - 6) + " 10000";
|
||||||
|
}
|
||||||
|
|
||||||
|
function slug(value) {
|
||||||
|
var result = String(value || "").toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, "-")
|
||||||
|
.replace(/^-+|-+$/g, "")
|
||||||
|
.slice(0, 48)
|
||||||
|
.replace(/-+$/g, "");
|
||||||
|
return result || "theme";
|
||||||
|
}
|
||||||
|
|
||||||
|
function uniqueId(name, profiles) {
|
||||||
|
var base = "custom-" + slug(name);
|
||||||
|
var ids = {};
|
||||||
|
profiles.forEach(function(profile) { ids[profile.id] = true; });
|
||||||
|
if (!ids[base])
|
||||||
|
return base;
|
||||||
|
for (var suffix = 2; suffix < 10000; suffix++) {
|
||||||
|
var candidate = base.slice(0, 57 - String(suffix).length) + "-" + suffix;
|
||||||
|
if (!ids[candidate])
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
return base.slice(0, 52) + "-10000";
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCustomProfile(values, input) {
|
||||||
|
var customs = validCustomProfiles(values);
|
||||||
|
var catalog = shippedProfiles().concat(customs);
|
||||||
|
var scheme = input && input.scheme;
|
||||||
|
var accent = normalizedColor(input && input.accent);
|
||||||
|
var secondary = normalizedColor(input && input.secondary);
|
||||||
|
if (!isScheme(scheme) || !accent || !secondary)
|
||||||
|
return { profiles: customs, profile: null };
|
||||||
|
|
||||||
|
var name = uniqueName(input && input.name, catalog);
|
||||||
|
var profile = {
|
||||||
|
id: uniqueId(name, catalog),
|
||||||
|
name: name,
|
||||||
|
scheme: scheme,
|
||||||
|
accent: accent,
|
||||||
|
secondary: secondary,
|
||||||
|
shipped: false
|
||||||
|
};
|
||||||
|
return { profiles: customs.concat([profile]), profile: profile };
|
||||||
|
}
|
||||||
|
|
||||||
|
function findProfile(values, id) {
|
||||||
|
var catalog = profileCatalog(values);
|
||||||
|
for (var index = 0; index < catalog.length; index++) {
|
||||||
|
if (catalog[index].id === id)
|
||||||
|
return catalog[index];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function editProfile(values, selected, changes) {
|
||||||
|
var customs = validCustomProfiles(values);
|
||||||
|
if (!selected || typeof selected !== "object")
|
||||||
|
return { profiles: customs, profile: null };
|
||||||
|
|
||||||
|
var accent = normalizedColor(changes && changes.accent !== undefined
|
||||||
|
? changes.accent : selected.accent);
|
||||||
|
var secondary = normalizedColor(changes && changes.secondary !== undefined
|
||||||
|
? changes.secondary : selected.secondary);
|
||||||
|
var scheme = changes && changes.scheme !== undefined ? changes.scheme : selected.scheme;
|
||||||
|
if (!isScheme(scheme) || !accent || !secondary)
|
||||||
|
return { profiles: customs, profile: null };
|
||||||
|
|
||||||
|
if (selected.shipped === true) {
|
||||||
|
return createCustomProfile(customs, {
|
||||||
|
name: selected.name + " custom",
|
||||||
|
scheme: scheme,
|
||||||
|
accent: accent,
|
||||||
|
secondary: secondary
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var stored = normalizeStoredProfile(selected);
|
||||||
|
if (!stored)
|
||||||
|
return { profiles: customs, profile: null };
|
||||||
|
|
||||||
|
var updated = Object.assign({}, stored, {
|
||||||
|
scheme: scheme,
|
||||||
|
accent: accent,
|
||||||
|
secondary: secondary
|
||||||
|
});
|
||||||
|
var found = false;
|
||||||
|
var next = customs.map(function(profile) {
|
||||||
|
if (profile.id !== updated.id)
|
||||||
|
return profile;
|
||||||
|
found = true;
|
||||||
|
return updated;
|
||||||
|
});
|
||||||
|
if (!found)
|
||||||
|
next.push(updated);
|
||||||
|
return { profiles: next, profile: updated };
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteProfile(values, id) {
|
||||||
|
var customs = validCustomProfiles(values);
|
||||||
|
for (var shippedIndex = 0; shippedIndex < SHIPPED.length; shippedIndex++) {
|
||||||
|
if (SHIPPED[shippedIndex].id === id)
|
||||||
|
return { profiles: customs, removed: false };
|
||||||
|
}
|
||||||
|
var next = customs.filter(function(profile) { return profile.id !== id; });
|
||||||
|
return { profiles: next, removed: next.length !== customs.length };
|
||||||
|
}
|
||||||
|
|
||||||
|
function curatedPair(name, scheme) {
|
||||||
|
var entry = CURATED[name] || CURATED.blue;
|
||||||
|
if (scheme === "light")
|
||||||
|
return { accent: entry.light, secondary: entry.lightSecondary };
|
||||||
|
return { accent: entry.dark, secondary: entry.darkSecondary };
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchingShippedProfile(scheme, accent, secondary) {
|
||||||
|
var first = normalizedColor(accent);
|
||||||
|
var second = normalizedColor(secondary);
|
||||||
|
for (var index = 0; index < SHIPPED.length; index++) {
|
||||||
|
var profile = SHIPPED[index];
|
||||||
|
if (profile.scheme === scheme && profile.accent === first && profile.secondary === second)
|
||||||
|
return copyProfile(profile);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function curatedNameForProfile(profile) {
|
||||||
|
if (!profile || !isScheme(profile.scheme))
|
||||||
|
return "";
|
||||||
|
var accent = normalizedColor(profile.accent);
|
||||||
|
var secondary = normalizedColor(profile.secondary);
|
||||||
|
var names = Object.keys(CURATED);
|
||||||
|
for (var index = 0; index < names.length; index++) {
|
||||||
|
var name = names[index];
|
||||||
|
var pair = curatedPair(name, profile.scheme);
|
||||||
|
if (pair.accent === accent && pair.secondary === secondary)
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function clamp(value, minimum, maximum) {
|
||||||
|
return Math.max(minimum, Math.min(maximum, Number(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function channelHex(value) {
|
||||||
|
var text = Math.round(value).toString(16);
|
||||||
|
return text.length < 2 ? "0" + text : text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hsvToHex(hue, saturation, value) {
|
||||||
|
var h = Number(hue);
|
||||||
|
var s = Number(saturation);
|
||||||
|
var v = Number(value);
|
||||||
|
if (!isFinite(h) || !isFinite(s) || !isFinite(v))
|
||||||
|
return null;
|
||||||
|
h = ((h % 360) + 360) % 360;
|
||||||
|
s = clamp(s, 0, 100) / 100;
|
||||||
|
v = clamp(v, 0, 100) / 100;
|
||||||
|
|
||||||
|
var chroma = v * s;
|
||||||
|
var section = h / 60;
|
||||||
|
var x = chroma * (1 - Math.abs(section % 2 - 1));
|
||||||
|
var red = 0;
|
||||||
|
var green = 0;
|
||||||
|
var blue = 0;
|
||||||
|
if (section < 1) { red = chroma; green = x; }
|
||||||
|
else if (section < 2) { red = x; green = chroma; }
|
||||||
|
else if (section < 3) { green = chroma; blue = x; }
|
||||||
|
else if (section < 4) { green = x; blue = chroma; }
|
||||||
|
else if (section < 5) { red = x; blue = chroma; }
|
||||||
|
else { red = chroma; blue = x; }
|
||||||
|
var match = v - chroma;
|
||||||
|
return "#" + channelHex((red + match) * 255)
|
||||||
|
+ channelHex((green + match) * 255)
|
||||||
|
+ channelHex((blue + match) * 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexToHsv(value) {
|
||||||
|
var color = normalizedColor(value);
|
||||||
|
if (!color)
|
||||||
|
return null;
|
||||||
|
var red = parseInt(color.slice(1, 3), 16) / 255;
|
||||||
|
var green = parseInt(color.slice(3, 5), 16) / 255;
|
||||||
|
var blue = parseInt(color.slice(5, 7), 16) / 255;
|
||||||
|
var maximum = Math.max(red, green, blue);
|
||||||
|
var minimum = Math.min(red, green, blue);
|
||||||
|
var delta = maximum - minimum;
|
||||||
|
var hue = 0;
|
||||||
|
if (delta !== 0) {
|
||||||
|
if (maximum === red)
|
||||||
|
hue = 60 * (((green - blue) / delta) % 6);
|
||||||
|
else if (maximum === green)
|
||||||
|
hue = 60 * ((blue - red) / delta + 2);
|
||||||
|
else
|
||||||
|
hue = 60 * ((red - green) / delta + 4);
|
||||||
|
}
|
||||||
|
if (hue < 0)
|
||||||
|
hue += 360;
|
||||||
|
return {
|
||||||
|
h: Math.round(hue),
|
||||||
|
s: Math.round((maximum === 0 ? 0 : delta / maximum) * 100),
|
||||||
|
v: Math.round(maximum * 100)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof module !== "undefined") {
|
||||||
|
module.exports = {
|
||||||
|
MAX_NAME_LENGTH: MAX_NAME_LENGTH,
|
||||||
|
shippedProfiles: shippedProfiles,
|
||||||
|
curatedAccents: curatedAccents,
|
||||||
|
validCustomProfiles: validCustomProfiles,
|
||||||
|
profileCatalog: profileCatalog,
|
||||||
|
createCustomProfile: createCustomProfile,
|
||||||
|
findProfile: findProfile,
|
||||||
|
editProfile: editProfile,
|
||||||
|
deleteProfile: deleteProfile,
|
||||||
|
curatedPair: curatedPair,
|
||||||
|
matchingShippedProfile: matchingShippedProfile,
|
||||||
|
curatedNameForProfile: curatedNameForProfile,
|
||||||
|
hsvToHex: hsvToHex,
|
||||||
|
hexToHsv: hexToHsv
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import qs.config
|
||||||
|
import "ThemeProfileModel.js" as ThemeProfileModel
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property var customProfiles: ThemeProfileModel.validCustomProfiles(
|
||||||
|
DesktopPreferences.get("themeProfiles"))
|
||||||
|
readonly property var curatedAccents: ThemeProfileModel.curatedAccents()
|
||||||
|
readonly property var profiles: ThemeProfileModel.profileCatalog(root.customProfiles)
|
||||||
|
readonly property string activeId: DesktopPreferences.get("themeProfileId") || "moon"
|
||||||
|
readonly property var activeProfile: ThemeProfileModel.findProfile(
|
||||||
|
root.customProfiles, root.activeId) || ThemeProfileModel.shippedProfiles()[0]
|
||||||
|
readonly property string activeAccentName: ThemeProfileModel.curatedNameForProfile(
|
||||||
|
root.activeProfile)
|
||||||
|
|
||||||
|
property bool reconciling: false
|
||||||
|
|
||||||
|
function commitActive(profile: var): bool {
|
||||||
|
if (!profile)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Scheme first: if another control changed it, the reconciliation hook
|
||||||
|
// may briefly select Day/Moon before this final stable profile id lands.
|
||||||
|
const schemeAccepted = SystemSettings.commitPreference("colorScheme", profile.scheme);
|
||||||
|
const profileAccepted = SystemSettings.commitPreference("themeProfileId", profile.id);
|
||||||
|
return schemeAccepted && profileAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectProfile(id: string): bool {
|
||||||
|
return root.commitActive(ThemeProfileModel.findProfile(root.customProfiles, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Editing a shipped profile creates a saved custom copy. Editing a custom
|
||||||
|
// profile updates only that record. ThemeProfileModel enforces both rules,
|
||||||
|
// leaving this singleton responsible only for validated preference routing.
|
||||||
|
function setAccentPair(accent: string, secondary: string): bool {
|
||||||
|
const result = ThemeProfileModel.editProfile(root.customProfiles, root.activeProfile, {
|
||||||
|
accent: accent,
|
||||||
|
secondary: secondary
|
||||||
|
});
|
||||||
|
if (!result.profile)
|
||||||
|
return false;
|
||||||
|
if (!SystemSettings.commitPreference("themeProfiles", result.profiles))
|
||||||
|
return false;
|
||||||
|
return SystemSettings.commitPreference("themeProfileId", result.profile.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveProfile(name: string): bool {
|
||||||
|
const result = ThemeProfileModel.createCustomProfile(root.customProfiles, {
|
||||||
|
name: name,
|
||||||
|
scheme: root.activeProfile.scheme,
|
||||||
|
accent: root.activeProfile.accent,
|
||||||
|
secondary: root.activeProfile.secondary
|
||||||
|
});
|
||||||
|
if (!result.profile)
|
||||||
|
return false;
|
||||||
|
if (!SystemSettings.commitPreference("themeProfiles", result.profiles))
|
||||||
|
return false;
|
||||||
|
return SystemSettings.commitPreference("themeProfileId", result.profile.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteProfile(id: string): bool {
|
||||||
|
const result = ThemeProfileModel.deleteProfile(root.customProfiles, id);
|
||||||
|
if (!result.removed)
|
||||||
|
return false;
|
||||||
|
if (!SystemSettings.commitPreference("themeProfiles", result.profiles))
|
||||||
|
return false;
|
||||||
|
if (root.activeId === id)
|
||||||
|
return root.selectProfile(DesktopPreferences.get("colorScheme") === "light" ? "day" : "moon");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useCuratedAccent(name: string): bool {
|
||||||
|
const scheme = DesktopPreferences.get("colorScheme") === "light" ? "light" : "dark";
|
||||||
|
const pair = ThemeProfileModel.curatedPair(name, scheme);
|
||||||
|
const shipped = ThemeProfileModel.matchingShippedProfile(
|
||||||
|
scheme, pair.accent, pair.secondary);
|
||||||
|
const accepted = shipped
|
||||||
|
? root.commitActive(shipped)
|
||||||
|
: root.setAccentPair(pair.accent, pair.secondary);
|
||||||
|
if (accepted)
|
||||||
|
SystemSettings.commitPreference("accentName", name);
|
||||||
|
return accepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reconcileScheme(): void {
|
||||||
|
if (root.reconciling)
|
||||||
|
return;
|
||||||
|
const scheme = DesktopPreferences.get("colorScheme") === "light" ? "light" : "dark";
|
||||||
|
if (root.activeProfile.scheme === scheme)
|
||||||
|
return;
|
||||||
|
root.reconciling = true;
|
||||||
|
SystemSettings.commitPreference("themeProfileId", scheme === "light" ? "day" : "moon");
|
||||||
|
root.reconciling = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: root.reconcileScheme()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: DesktopPreferences
|
||||||
|
function onRevisionChanged(): void { root.reconcileScheme(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,9 +45,10 @@ Singleton {
|
|||||||
readonly property string outputSignature: root.outputNames().slice().sort().join("|")
|
readonly property string outputSignature: root.outputNames().slice().sort().join("|")
|
||||||
|
|
||||||
property var outputNames: function() {
|
property var outputNames: function() {
|
||||||
if (Array.isArray(root.outputOverride))
|
const outputs = Array.isArray(root.outputOverride)
|
||||||
return root.outputOverride.slice();
|
? root.outputOverride.slice()
|
||||||
return Quickshell.screens.map(screen => screen.name).filter(name => !!name);
|
: Quickshell.screens.map(screen => screen.name).filter(name => !!name);
|
||||||
|
return root.primaryFirstOutputs(outputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var searchRoots: [
|
readonly property var searchRoots: [
|
||||||
@@ -59,10 +60,8 @@ Singleton {
|
|||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: scan
|
id: scan
|
||||||
command: ["bash", "-lc",
|
command: [Quickshell.shellDir + "/scripts/panama-wallpaper-scan"]
|
||||||
"find " + root.searchRoots.map(dir => `'${dir}'`).join(" ")
|
.concat(root.searchRoots)
|
||||||
+ " -maxdepth 2 -type f \\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' \\)"
|
|
||||||
+ " -printf '%T@ %p\\n' 2>/dev/null | sort -rn | cut -d' ' -f2- | head -60"]
|
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
onStreamFinished: {
|
onStreamFinished: {
|
||||||
root.available = this.text.split("\n")
|
root.available = this.text.split("\n")
|
||||||
@@ -164,6 +163,18 @@ Singleton {
|
|||||||
activeQuery.running = true;
|
activeQuery.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The saved primary role anchors Panama's per-monitor choices. Keep the
|
||||||
|
// compositor's remaining order stable so a reconnect does not reshuffle
|
||||||
|
// the rest of the picker unnecessarily.
|
||||||
|
function primaryFirstOutputs(outputs: var): var {
|
||||||
|
const stored = DesktopPreferences.get("displays");
|
||||||
|
const layouts = stored && typeof stored === "object" ? stored : {};
|
||||||
|
const primary = outputs.find(output => layouts[output]?.primary === true);
|
||||||
|
return primary === undefined
|
||||||
|
? outputs
|
||||||
|
: [primary].concat(outputs.filter(output => output !== primary));
|
||||||
|
}
|
||||||
|
|
||||||
function candidates(extra: var): var {
|
function candidates(extra: var): var {
|
||||||
const result = [];
|
const result = [];
|
||||||
const discovered = Array.isArray(root.candidateOverride)
|
const discovered = Array.isArray(root.candidateOverride)
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
import qs.config
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
ShellRoot {
|
||||||
|
IpcHandler {
|
||||||
|
target: "theme-profiles-test"
|
||||||
|
|
||||||
|
function status(): string {
|
||||||
|
return JSON.stringify({
|
||||||
|
active: ThemeProfiles.activeProfile,
|
||||||
|
profiles: ThemeProfiles.profiles,
|
||||||
|
stored: DesktopPreferences.get("themeProfiles")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function select(id: string): bool {
|
||||||
|
return ThemeProfiles.selectProfile(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheme(value: string): bool {
|
||||||
|
return SystemSettings.commitPreference("colorScheme", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function edit(accent: string, secondary: string): bool {
|
||||||
|
return ThemeProfiles.setAccentPair(accent, secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
function save(name: string): bool {
|
||||||
|
return ThemeProfiles.saveProfile(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove(id: string): bool {
|
||||||
|
return ThemeProfiles.deleteProfile(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import qs.services
|
|||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Wallpaper.outputOverride = ["DP-2", "HDMI-A-1"];
|
Wallpaper.outputOverride = ["HDMI-A-1", "DP-2"];
|
||||||
Wallpaper.candidateOverride = ["/images/a.jpg", "/images/b.jpg", "/images/c.jpg"];
|
Wallpaper.candidateOverride = ["/images/a.jpg", "/images/b.jpg", "/images/c.jpg"];
|
||||||
Wallpaper.startupRestoreEnabled = false;
|
Wallpaper.startupRestoreEnabled = false;
|
||||||
Wallpaper.slideshowIntervalOverrideMs = 60000;
|
Wallpaper.slideshowIntervalOverrideMs = 60000;
|
||||||
@@ -63,7 +63,9 @@ ShellRoot {
|
|||||||
assignments: DesktopPreferences.get("wallpaperPerMonitor"),
|
assignments: DesktopPreferences.get("wallpaperPerMonitor"),
|
||||||
slideshowPath: Wallpaper.slideshowPath,
|
slideshowPath: Wallpaper.slideshowPath,
|
||||||
shuffleBag: Wallpaper.shuffleBag,
|
shuffleBag: Wallpaper.shuffleBag,
|
||||||
slideshowTimerRunning: Wallpaper.slideshowTimerRunning
|
slideshowTimerRunning: Wallpaper.slideshowTimerRunning,
|
||||||
|
scanning: Wallpaper.scanning,
|
||||||
|
available: Wallpaper.available
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,16 @@ ShellRoot {
|
|||||||
return JSON.stringify(root.calls);
|
return JSON.stringify(root.calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectOutput(output: string): void {
|
||||||
|
controls.selectedOutput = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateOutputs(outputs: string): void {
|
||||||
|
controls.outputs = outputs === "" ? [] : outputs.split("|");
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedOutput(): string { return controls.selectedOutput; }
|
||||||
|
|
||||||
function states(): string {
|
function states(): string {
|
||||||
picker.mode = "single";
|
picker.mode = "single";
|
||||||
const single = {
|
const single = {
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Firefox chrome
|
||||||
|
|
||||||
|
This directory is **not Panama's work**. It is [Edge-Frfox][upstream] — "a
|
||||||
|
Firefox userChrome.css theme that aims to recreate the look and feel of
|
||||||
|
Microsoft Edge" — vendored here, plus two local tweaks.
|
||||||
|
|
||||||
|
- Upstream: <https://github.com/bmFtZQ/edge-frfox>
|
||||||
|
- License: MIT
|
||||||
|
|
||||||
|
`link-dotfiles` places `user.js` and `chrome/` into the Firefox profile. The
|
||||||
|
preferences in `user.js` are what the theme needs to work at all —
|
||||||
|
`toolkit.legacyUserProfileCustomizations.stylesheets` in particular, without
|
||||||
|
which Firefox ignores `chrome/` entirely.
|
||||||
|
|
||||||
|
## Why it is vendored rather than fetched
|
||||||
|
|
||||||
|
The same reason the cursor theme is: downloading it during the install would add
|
||||||
|
a URL that can rot, and this repository is trying to stop installing things that
|
||||||
|
way. 732K in git once, and then the theme is simply there.
|
||||||
|
|
||||||
|
## Two things to know before editing
|
||||||
|
|
||||||
|
`userChrome.css` imports `custom.css` last, deliberately — local changes go
|
||||||
|
there, not into the upstream files, so a future update to the theme is a
|
||||||
|
directory replacement rather than a merge. The imports of
|
||||||
|
`tweaks/hide-tabs-bar.css` and `tweaks/shrink-sideberry.css` are personal
|
||||||
|
choices carried over from sunhat, not upstream defaults.
|
||||||
|
|
||||||
|
`userChrome.css` is unsupported by Mozilla. It breaks on major Firefox releases,
|
||||||
|
and when it does, the fix is upstream's or none. Panama installs Firefox as a
|
||||||
|
second engine to test pages against; if the theme ever costs more than it is
|
||||||
|
worth, deleting this directory and the `link-dotfiles` block that reads it
|
||||||
|
leaves a working browser behind.
|
||||||
|
|
||||||
|
[upstream]: https://github.com/bmFtZQ/edge-frfox
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/* Edge-Frfox - content/common.css */
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Default colours
|
||||||
|
*/
|
||||||
|
@-moz-document url-prefix(about:) {
|
||||||
|
:root {
|
||||||
|
--in-content-page-color: light-dark(#252525, #fff) !important;
|
||||||
|
--in-content-page-background: light-dark(#f7f7f7, #252525) !important;
|
||||||
|
--in-content-deemphasized-text: light-dark(#666, #bbb) !important;
|
||||||
|
--in-content-box-background: light-dark(#fff, #333) !important;
|
||||||
|
--in-content-box-background-odd: light-dark(rgb(0 0 0 / .05), rgb(255 255 255 / .05)) !important;
|
||||||
|
--in-content-box-info-background: light-dark(#f7f7f7, rgb(255 255 255 / 0.15)) !important;
|
||||||
|
--in-content-icon-color: light-dark(#666, #fff) !important;
|
||||||
|
--in-content-accent-color: light-dark(#006CBE, #75B6E8) !important;
|
||||||
|
--in-content-accent-color-active: light-dark(#1683D8, #4C98D1) !important;
|
||||||
|
--in-content-border-hover: light-dark(rgb(0 0 0 / .5), rgb(255 255 255 / .3)) !important;
|
||||||
|
--in-content-border-invalid: var(--red-50) !important;
|
||||||
|
--in-content-border-color: light-dark(#bebebe, rgb(255 255 255 / .2)) !important;
|
||||||
|
--in-content-error-text-color: light-dark(#FF848A, #FF9AA2) !important;
|
||||||
|
--in-content-link-color: light-dark(#0078D4, #75B6E8) !important;
|
||||||
|
--in-content-link-color-hover: light-dark(#006CBE, #63ADE5) !important;
|
||||||
|
--in-content-link-color-active: light-dark(#0749AC, #4C98D1) !important;
|
||||||
|
--in-content-link-color-visited: light-dark(#0078D4, #75B6E8) !important;
|
||||||
|
--link-color: var(--in-content-link-color) !important;
|
||||||
|
--link-color-hover: var(--in-content-link-color-hover) !important;
|
||||||
|
--link-color-active: var(--in-content-link-color-active) !important;
|
||||||
|
--link-color-visited: var(--in-content-link-color-visited) !important;
|
||||||
|
--in-content-button-text-color: var(--in-content-text-color) !important;
|
||||||
|
--in-content-button-text-color-hover: var(--in-content-text-color) !important;
|
||||||
|
--in-content-button-text-color-active: var(--in-content-button-text-color-hover) !important;
|
||||||
|
--in-content-button-background: light-dark(#EDEDED, #3B3B3B) !important;
|
||||||
|
--in-content-button-background-hover: light-dark(#e5e5e5, #545454) !important;
|
||||||
|
--in-content-button-background-active: light-dark(#d5d5d5, #606060) !important;
|
||||||
|
--in-content-primary-button-text-color: light-dark(#fff, #fff) !important;
|
||||||
|
--in-content-primary-button-background: light-dark(#0061e0, #006CBE) !important;
|
||||||
|
--in-content-primary-button-background-hover: light-dark(#0250bb, #0078D4) !important;
|
||||||
|
--in-content-primary-button-background-active: light-dark(#053e94, #005CA3) !important;
|
||||||
|
--color-accent-primary: light-dark(#0078D4, #006CBE) !important;
|
||||||
|
--color-accent-primary-hover: light-dark(#006CBE, #0078D4) !important;
|
||||||
|
--color-accent-primary-active: light-dark(#0749AC, #005CA3) !important;
|
||||||
|
--in-content-danger-button-background: light-dark(#DF4951, #E12424) !important;
|
||||||
|
--in-content-danger-button-background-hover: light-dark(#EA656C, #F94343) !important;
|
||||||
|
--in-content-danger-button-background-active: light-dark(#BB353C, #AA1E1E) !important;
|
||||||
|
--in-content-focus-outline-color: light-dark(rgb(0 85 215 / .5), #63ADE5) !important;
|
||||||
|
--focus-outline-color: var(--in-content-focus-outline-color) !important;
|
||||||
|
--in-content-table-background: light-dark(#f7f7f7, #252525) !important;
|
||||||
|
--in-content-text-color: var(--in-content-page-color) !important;
|
||||||
|
--border-interactive-color: light-dark(#929292, #858585) !important;
|
||||||
|
scrollbar-color:
|
||||||
|
light-dark(rgb(37 37 37 / .4), rgb(255 255 255 / .4))
|
||||||
|
light-dark(#f7f7f7, #252525) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background-color: light-dark(#0078D4, #93B8E7);
|
||||||
|
color: light-dark(#fff, #000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Preferences page
|
||||||
|
*/
|
||||||
|
@-moz-document url-prefix(about:preferences),
|
||||||
|
url-prefix(about:addons) {
|
||||||
|
.category[selected] {
|
||||||
|
position: relative !important;
|
||||||
|
border-radius: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category[selected]:not(:hover, :active) {
|
||||||
|
background-color: var(--in-content-button-background) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category[selected]::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset-block: 0;
|
||||||
|
margin-block: auto;
|
||||||
|
height: 24px;
|
||||||
|
width: 3px;
|
||||||
|
left: 2px;
|
||||||
|
background-color: var(--in-content-accent-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.tab-button:hover {
|
||||||
|
border-block-color: transparent var(--in-content-box-border-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.tab-button[selected],
|
||||||
|
button.tab-button[selected]:hover {
|
||||||
|
border-block-color: transparent currentColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-button {
|
||||||
|
--toggle-dot-margin: 4px !important;
|
||||||
|
--toggle-width: 40px !important;
|
||||||
|
--toggle-height: 20px !important;
|
||||||
|
--toggle-background-color: transparent !important;
|
||||||
|
--toggle-dot-background-color: var(--in-content-page-color) !important;
|
||||||
|
--toggle-dot-background-color-on-pressed: #fff !important;
|
||||||
|
--toggle-dot-transform-x: calc(var(--toggle-width) - 2 * var(--toggle-dot-margin) - 2 * var(--toggle-border-width) - var(--toggle-dot-width)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,415 @@
|
|||||||
|
/* Edge-Frfox - content/newtab.css */
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Default colours
|
||||||
|
*/
|
||||||
|
@-moz-document url-prefix("about:newtab"),
|
||||||
|
url-prefix("about:home"),
|
||||||
|
url-prefix("about:firefoxview") {
|
||||||
|
:root:not([lwt-newtab], [lwt-newtab-brighttext]) {
|
||||||
|
--newtab-background-color: #F7F7F7 !important;
|
||||||
|
--newtab-background-color-secondary: #fff !important;
|
||||||
|
--newtab-text-primary-color: #252525 !important;
|
||||||
|
--newtab-primary-action-background: #0078D4 !important;
|
||||||
|
--newtab-text-secondary-color: color-mix(in srgb, var(--newtab-text-primary-color) 80%, transparent) !important;
|
||||||
|
--newtab-element-hover-color: color-mix(in srgb, var(--newtab-background-color) 95%, #000) !important;
|
||||||
|
--newtab-element-active-color: color-mix(in srgb, var(--newtab-background-color) 90%, #000) !important;
|
||||||
|
--newtab-element-secondary-color: color-mix(in srgb, currentColor 5%, transparent) !important;
|
||||||
|
--newtab-element-secondary-hover-color: color-mix(in srgb, currentColor 12%, transparent) !important;
|
||||||
|
--newtab-element-secondary-active-color: color-mix(in srgb, currentColor 25%, transparent) !important;
|
||||||
|
--newtab-primary-element-hover-color: color-mix(in srgb, var(--newtab-primary-action-background) 90%, #000) !important;
|
||||||
|
--newtab-primary-element-active-color: color-mix(in srgb, var(--newtab-primary-action-background) 80%, #000) !important;
|
||||||
|
--newtab-primary-element-text-color: #fff !important;
|
||||||
|
--newtab-primary-action-background-dimmed: color-mix(in srgb, var(--newtab-primary-action-background) 25%, transparent) !important;
|
||||||
|
--newtab-border-color: color-mix(in srgb, var(--newtab-background-color) 75%, #000) !important;
|
||||||
|
--newtab-wordmark-color: #737373 !important;
|
||||||
|
--newtab-status-success: #50B080 !important;
|
||||||
|
--newtab-status-error: #FF848A !important;
|
||||||
|
--newtab-inner-box-shadow-color: rgb(0 0 0 / .1) !important;
|
||||||
|
--newtab-overlay-color: color-mix(in srgb, var(--newtab-background-color) 85%, transparent) !important;
|
||||||
|
--newtab-text-emphasis-background: #FFED32 !important;
|
||||||
|
--newtab-text-emphasis-text-color: #000 !important;
|
||||||
|
--newtab-textbox-focus-color: var(--newtab-primary-action-background) !important;
|
||||||
|
--newtab-textbox-focus-boxshadow: 0 0 0 1px var(--newtab-primary-action-background), 0 0 0 4px rgba(var(--newtab-primary-action-background), 0.3) !important;
|
||||||
|
--newtab-button-secondary-color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root:not([style*="color"])[lwt-newtab-brighttext] {
|
||||||
|
--newtab-background-color: #252525 !important;
|
||||||
|
--newtab-background-color-secondary: #4A4A4A !important;
|
||||||
|
--newtab-text-primary-color: #fff !important;
|
||||||
|
--newtab-primary-action-background: #75B6E8 !important;
|
||||||
|
--newtab-element-hover-color: color-mix(in srgb, var(--newtab-background-color) 95%, #FFF) !important;
|
||||||
|
--newtab-element-active-color: color-mix(in srgb, var(--newtab-background-color) 90%, #FFF) !important;
|
||||||
|
--newtab-element-secondary-color: color-mix(in srgb, currentColor 10%, transparent) !important;
|
||||||
|
--newtab-element-secondary-hover-color: color-mix(in srgb, currentColor 17%, transparent) !important;
|
||||||
|
--newtab-element-secondary-active-color: color-mix(in srgb, currentColor 30%, transparent) !important;
|
||||||
|
--newtab-border-color: color-mix(in srgb, var(--newtab-background-color) 75%, #FFF) !important;
|
||||||
|
--newtab-primary-element-text-color: #252525 !important;
|
||||||
|
--newtab-wordmark-color: #fff !important;
|
||||||
|
--newtab-status-success: #50B080 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Custom GTK colours
|
||||||
|
*/
|
||||||
|
@media (-moz-gtk-csd-available) {
|
||||||
|
:root:not([lwt-newtab]):not([style*="color"]) {
|
||||||
|
/* Colour adjusted for readability. */
|
||||||
|
--uc-accent-adjusted: light-dark(color-mix(in oklch, AccentColor 92%, black), color-mix(in oklch, AccentColor 60%, white));
|
||||||
|
--newtab-background-color: light-dark(-moz-dialog, color-mix(in srgb, -moz-dialog 82%, black)) !important;
|
||||||
|
--newtab-background-color-secondary: light-dark(Field, color-mix(in srgb, -moz-dialog 86%, white)) !important;
|
||||||
|
--newtab-text-primary-color: -moz-dialogtext !important;
|
||||||
|
--newtab-wordmark-color: light-dark(color-mix(in srgb, -moz-dialogtext 65%, transparent), -moz-dialogtext) !important;
|
||||||
|
--newtab-primary-action-background: var(--uc-accent-adjusted) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjustments for themes. */
|
||||||
|
:root[style*="--newtab-background-color"] {
|
||||||
|
/* Make the Firefox logo workmark follow text colour. */
|
||||||
|
--newtab-wordmark-color: color-mix(in srgb, var(--newtab-text-primary-color) 60%, var(--newtab-background-color)) !important;
|
||||||
|
|
||||||
|
/* If there is no secondary background, create one from other colours. */
|
||||||
|
&:not([style*="--newtab-background-color-secondary"]) {
|
||||||
|
--newtab-background-color-secondary: color-mix(in srgb, var(--newtab-background-color) 15%, white) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark adjustments for themes. */
|
||||||
|
&[lwt-newtab-brighttext] {
|
||||||
|
/* Make the Firefox logo workmark follow text colour. */
|
||||||
|
--newtab-wordmark-color: var(--newtab-text-primary-color) !important;
|
||||||
|
|
||||||
|
/* If there is no secondary background, create one from other colours. */
|
||||||
|
&:not([style*="--newtab-background-color-secondary"]) {
|
||||||
|
--newtab-background-color-secondary: color-mix(in srgb, var(--newtab-text-primary-color) 15%, var(--newtab-background-color)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: New tab page
|
||||||
|
*/
|
||||||
|
@-moz-document url-prefix("about:newtab"),
|
||||||
|
url-prefix("about:home") {
|
||||||
|
/* Enforce system font selection. */
|
||||||
|
:where(body) {
|
||||||
|
font-family: system-ui !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide pin icons. */
|
||||||
|
.icon.icon-pin-small {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unpinned sites have lower opacity titles. */
|
||||||
|
.top-site-button .title:not(.pinned) {
|
||||||
|
opacity: 0.7 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Search bar
|
||||||
|
*/
|
||||||
|
.search-wrapper {
|
||||||
|
& .search-handoff-button {
|
||||||
|
border-radius: 99px !important;
|
||||||
|
background-position: 12px !important;
|
||||||
|
padding-inline-start: 48px !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
text-overflow: ellipsis !important;
|
||||||
|
--elevation: 4;
|
||||||
|
box-shadow:
|
||||||
|
0 0 calc((var(--elevation) * 0.225px) + 2px) rgb(0 0 0 / .11),
|
||||||
|
0 calc(var(--elevation) * 0.4px) calc((var(--elevation) * 0.9px)) rgb(0 0 0 / .13) !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
--elevation: 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .search-inner-wrapper {
|
||||||
|
min-height: 44px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.fake-focus:not(.search.disabled) .search-handoff-button {
|
||||||
|
border-color: transparent !important;
|
||||||
|
outline: 2px solid var(--newtab-primary-action-background) !important;
|
||||||
|
outline-offset: -1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search-disabled .search-handoff-button {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-handoff-button .fake-caret {
|
||||||
|
inset-inline-start: 48px !important;
|
||||||
|
top: 13px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (height > 700px) {
|
||||||
|
.fixed-search & {
|
||||||
|
padding: 15px 0 !important;
|
||||||
|
min-height: auto !important;
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fake-textbox {
|
||||||
|
overflow: hidden !important;
|
||||||
|
text-overflow: ellipsis !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outer-wrapper.only-search {
|
||||||
|
display: flex !important;
|
||||||
|
padding: 30px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sticky search bar header when scrolling. */
|
||||||
|
@media (height > 700px) {
|
||||||
|
body:not(.inline-onboarding) .fixed-search.visible-logo main {
|
||||||
|
padding-top: 246px !important;
|
||||||
|
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.hide-newtab-logo") {
|
||||||
|
padding-top: 82px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-settings {
|
||||||
|
background-image: url("../icons/settings.svg") !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Top sites tiles
|
||||||
|
*/
|
||||||
|
.top-site-outer {
|
||||||
|
& .tile {
|
||||||
|
border-radius: 12px !important;
|
||||||
|
height: 44px !important;
|
||||||
|
width: 44px !important;
|
||||||
|
box-shadow: rgb(0 0 0 / 0.1) 0px 2px 4px !important;
|
||||||
|
|
||||||
|
& .icon-wrapper {
|
||||||
|
border-radius: 4px !important;
|
||||||
|
width: 24px !important;
|
||||||
|
height: 24px !important;
|
||||||
|
|
||||||
|
&.letter-fallback::before {
|
||||||
|
font-size: 32px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .default-icon,
|
||||||
|
& .search-topsite {
|
||||||
|
background-size: 16px !important;
|
||||||
|
height: 24px !important;
|
||||||
|
width: 24px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Recent activity cards
|
||||||
|
*/
|
||||||
|
.card-outer {
|
||||||
|
--uc-border-radius: 8px;
|
||||||
|
|
||||||
|
&,
|
||||||
|
& .card,
|
||||||
|
& .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||||
|
border-radius: var(--uc-border-radius) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .card,
|
||||||
|
& .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) {
|
||||||
|
box-shadow:
|
||||||
|
rgb(0 0 0 / 0.14) 0px 1px 2px,
|
||||||
|
rgb(0 0 0 / 0.12) 0px 0px 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .card-preview-image-outer,
|
||||||
|
& .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img {
|
||||||
|
border-radius: var(--uc-border-radius) var(--uc-border-radius) 0 0 !important
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add background & adjust padding for Recent activity & Pocket section. */
|
||||||
|
.collapsible-section:not(.top-sites) {
|
||||||
|
background-color: var(--newtab-background-color) !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
padding: 10px 20px 20px !important;
|
||||||
|
|
||||||
|
& .section-list {
|
||||||
|
gap: 12px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.hide-newtab-logo") {
|
||||||
|
.logo-and-wordmark {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outer-wrapper:not(.fixed-search) .search-wrapper {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Private browsing
|
||||||
|
*/
|
||||||
|
@-moz-document url-prefix(about:privatebrowsing) {
|
||||||
|
:root {
|
||||||
|
--uc-wordmark-color: light-dark(#737373, #fff);
|
||||||
|
--uc-background-color-secondary: light-dark(#fff, #4a4a4a);
|
||||||
|
|
||||||
|
@media (-moz-bool-pref: "browser.theme.dark-private-windows") {
|
||||||
|
color-scheme: dark !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom GTK colours. */
|
||||||
|
@media (-moz-gtk-csd-available) {
|
||||||
|
:root:not([lwt-newtab]):not([style*="color"]) {
|
||||||
|
/* Colour adjusted for readability. */
|
||||||
|
--uc-accent-adjusted: light-dark(color-mix(in oklch, AccentColor 92%, black), color-mix(in oklch, AccentColor 60%, white));
|
||||||
|
--in-content-page-background: light-dark(-moz-dialog, color-mix(in srgb, -moz-dialog 82%, black)) !important;
|
||||||
|
--uc-background-color-secondary: light-dark(Field, color-mix(in srgb, -moz-dialog 86%, white)) !important;
|
||||||
|
--in-content-page-color: -moz-dialogtext !important;
|
||||||
|
--in-content-focus-outline-color: var(--uc-accent-adjusted) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Search bar
|
||||||
|
*/
|
||||||
|
.search-inner-wrapper {
|
||||||
|
height: 44px !important;
|
||||||
|
|
||||||
|
.search-handoff-button,
|
||||||
|
.search-handoff-button:active,
|
||||||
|
.search-handoff-button:enabled:hover:active {
|
||||||
|
background-color: var(--uc-background-color-secondary) !important;
|
||||||
|
border: 0 !important;
|
||||||
|
border-radius: 99px !important;
|
||||||
|
padding-inline-start: 48px !important;
|
||||||
|
--elevation: 4;
|
||||||
|
box-shadow:
|
||||||
|
0 0 calc((var(--elevation) * 0.225px) + 2px) rgb(0 0 0 / .11),
|
||||||
|
0 calc(var(--elevation) * 0.4px) calc((var(--elevation) * 0.9px)) rgb(0 0 0 / .13) !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
--elevation: 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.focused:not(.disabled) {
|
||||||
|
box-shadow: none !important;
|
||||||
|
outline: 2px solid var(--in-content-focus-outline-color) !important;
|
||||||
|
outline-offset: -1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
opacity: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .fake-textbox {
|
||||||
|
color: var(--in-content-page-color) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wordmark {
|
||||||
|
fill: var(--uc-wordmark-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Information box in private browsing. */
|
||||||
|
.info {
|
||||||
|
background-color: var(--uc-background-color-secondary) !important;
|
||||||
|
background-image: none !important;
|
||||||
|
position: relative !important;
|
||||||
|
|
||||||
|
/* Private browsing icon. */
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 32px;
|
||||||
|
top: 20px;
|
||||||
|
height: 32px;
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
background: center / contain url("../icons/account-private.svg");
|
||||||
|
border-radius: 99px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Background images
|
||||||
|
*/
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.newtab-background") {
|
||||||
|
@-moz-document url(about:newtab),
|
||||||
|
url(about:home),
|
||||||
|
url(about:privatebrowsing) {
|
||||||
|
body {
|
||||||
|
/* Specify both jpg and png file extensions, but jpg images will always
|
||||||
|
* have a higher priority. */
|
||||||
|
--bg-0: url(../background-0.jpg), url(../background-0.png);
|
||||||
|
--bg-1: url(../background-1.jpg), url(../background-1.png);
|
||||||
|
--newtab-element-hover-color: rgb(239 239 239 / .3) !important;
|
||||||
|
--newtab-element-active-color: rgb(239 239 239 / .45) !important;
|
||||||
|
--text-shadow: 0 1px 2px #000;
|
||||||
|
--icon-shadow: drop-shadow(0 0.3px 0.6px #000);
|
||||||
|
background-color: #252525 !important;
|
||||||
|
background-image: var(--bg-0) !important;
|
||||||
|
background-position: center !important;
|
||||||
|
background-size: cover !important;
|
||||||
|
background-attachment: fixed !important;
|
||||||
|
|
||||||
|
:root[lwt-newtab-brighttext] &,
|
||||||
|
:root.private & {
|
||||||
|
background-image: var(--bg-1), var(--bg-0) !important;
|
||||||
|
--newtab-element-hover-color: rgb(66 66 66 / .4) !important;
|
||||||
|
--newtab-element-active-color: rgb(66 66 66 / .55) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media not (-moz-bool-pref: "browser.theme.dark-private-windows") {
|
||||||
|
:root.private & {
|
||||||
|
background-image: var(--bg-0) !important;
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
background-image: var(--bg-1), var(--bg-0) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change text colour & add backgrounds to text over the background. */
|
||||||
|
.top-site-outer .title {
|
||||||
|
text-shadow: var(--text-shadow) !important;
|
||||||
|
color: #fff !important;
|
||||||
|
-moz-osx-font-smoothing: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wordmark,
|
||||||
|
.icon-settings,
|
||||||
|
.top-site-outer .context-menu-button {
|
||||||
|
filter: var(--icon-shadow) !important;
|
||||||
|
color: #fff !important;
|
||||||
|
fill: currentColor !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-site-outer .title .sponsored-label {
|
||||||
|
color: #eee !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add transparent sticky search header. */
|
||||||
|
@media (height > 700px) {
|
||||||
|
.fixed-search .search-wrapper {
|
||||||
|
border-bottom: 0 !important;
|
||||||
|
background: transparent linear-gradient(#0004, transparent) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/* Local overrides.
|
||||||
|
*
|
||||||
|
* userChrome.css imports this last, so anything here wins over Edge-Frfox
|
||||||
|
* without editing its files -- which keeps updating the theme a matter of
|
||||||
|
* replacing the directory rather than merging into it.
|
||||||
|
*
|
||||||
|
* Deliberately empty. The import resolving to nothing is not an error in CSS,
|
||||||
|
* but a file that exists is a seam somebody can find. */
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
/* Edge-Frfox - browser.css
|
||||||
|
* https://github.com/bmFtZQ/edge-frfox */
|
||||||
|
|
||||||
|
/* Windows has 1px missing space on top of window, but not when accent colour is
|
||||||
|
* applied to the title bar. */
|
||||||
|
@media (-moz-platform: windows) and (not (-moz-windows-accent-color-in-titlebar)) {
|
||||||
|
:root[sizemode="normal"][tabsintitlebar]:not([inFullscreen]) #navigator-toolbox {
|
||||||
|
padding-top: 1px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a shadow when the toolbars move over content, eg. in macOS hovering over
|
||||||
|
* the menu bar in fullscreen mode. */
|
||||||
|
#navigator-toolbox[style*="transform"] {
|
||||||
|
box-shadow: 0 -3px 5px 3px light-dark(rgb(0 0 0 / .3), rgb(0 0 0 / .6)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Rounded corners (Rc)
|
||||||
|
*/
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.rounded-corners") {
|
||||||
|
/* Since Firefox 120, when the bookmarks bar is set to only open on new tabs,
|
||||||
|
* the bookmarks bar overlaps the #browser element. */
|
||||||
|
|
||||||
|
/* Change the element that shifts the browser content to the correct position. */
|
||||||
|
#main-window[BookmarksToolbarOverlapsBrowser] .newTabBrowserPanel,
|
||||||
|
#main-window[BookmarksToolbarOverlapsBrowser] #sidebar-box {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-window[BookmarksToolbarOverlapsBrowser] #browser {
|
||||||
|
margin-top: var(--bookmarks-toolbar-overlapping-browser-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that the toolbars are not positioned in-front of the browser
|
||||||
|
* element. */
|
||||||
|
#main-window[BookmarksToolbarOverlapsBrowser] #navigator-toolbox:not([style*="z-index"]) {
|
||||||
|
z-index: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the browser element in-front of the toolbars when on the new tab page. */
|
||||||
|
#main-window:not([BookmarksToolbarOverlapsBrowser]) #browser {
|
||||||
|
z-index: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Rc Variables
|
||||||
|
*/
|
||||||
|
#main-window:not([chromehidden~="toolbar"]) {
|
||||||
|
--uc-tweak-rounded-corners-padding: 4px;
|
||||||
|
--uc-tweak-rounded-corners-radius: 8px;
|
||||||
|
--uc-tweak-rounded-corners-shadow:
|
||||||
|
0 -.8px 0 0 rgb(0 0 0 / 0.02),
|
||||||
|
0 0.5px 1px 1px rgb(0 0 0 / 0.06),
|
||||||
|
0 1px 1px rgb(0 0 0 / 0.1);
|
||||||
|
--browser-frame-bgcolor: var(--toolbar-bgcolor, var(--lwt-accent-color));
|
||||||
|
|
||||||
|
/* Different shadow for higher resolution displays. */
|
||||||
|
@media (resolution > 1.8dppx) {
|
||||||
|
--uc-tweak-rounded-corners-shadow:
|
||||||
|
0 0 0.5px 0.5px rgb(0 0 0 / 0.06),
|
||||||
|
0 0.5px 1.5px rgb(0 0 0 / 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.floating-tabs") {
|
||||||
|
--browser-frame-bgcolor: var(--lwt-accent-color);
|
||||||
|
|
||||||
|
&:-moz-window-inactive {
|
||||||
|
--browser-frame-bgcolor: var(--lwt-accent-color-inactive, var(--lwt-accent-color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide border below titlebar on macOS, as its titlebar already has a border. */
|
||||||
|
@media (-moz-platform: macos) {
|
||||||
|
:root[chromehidden~="toolbar"][chromehidden~="location"][chromehidden~="directories"] {
|
||||||
|
border-top: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove separator between toolbars and the browser window. */
|
||||||
|
#navigator-toolbox {
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable rounded corners in fullscreen, only if the toolbar is hidden. */
|
||||||
|
:root[inFullscreen] #navigator-toolbox[style*="margin-top"] + #browser,
|
||||||
|
:root[inDOMFullscreen] #browser {
|
||||||
|
--uc-tweak-rounded-corners-padding: 0;
|
||||||
|
--uc-tweak-rounded-corners-radius: 0;
|
||||||
|
--uc-tweak-rounded-corners-shadow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Rc Browser
|
||||||
|
*/
|
||||||
|
#appcontent .browserStack {
|
||||||
|
margin-inline: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
margin-block-end: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
border-radius: var(--uc-tweak-rounded-corners-radius) !important;
|
||||||
|
box-shadow: var(--uc-tweak-rounded-corners-shadow) !important;
|
||||||
|
background-color: var(--tabpanel-background-color) !important;
|
||||||
|
position: relative !important;
|
||||||
|
|
||||||
|
/* Use pseudo element overlay to simulate rounded corners, similar to the
|
||||||
|
* tab corners, fixes bug with backdrop-filter. */
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
/* Draw toolbar background on the negative corner space, then draw the
|
||||||
|
* same shadow from the browser window on top. */
|
||||||
|
box-shadow:
|
||||||
|
var(--uc-tweak-rounded-corners-shadow, 0 0 transparent),
|
||||||
|
0 0 0 16px var(--browser-frame-bgcolor) !important;
|
||||||
|
clip-path: inset(0);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent status panel corners and shadow from appearing outside the browser. */
|
||||||
|
#statuspanel {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Rc Sidebar
|
||||||
|
*/
|
||||||
|
#sidebar-box {
|
||||||
|
margin-inline-start: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
margin-block-end: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
border-radius: var(--uc-tweak-rounded-corners-radius) !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
box-shadow: var(--uc-tweak-rounded-corners-shadow) !important;
|
||||||
|
|
||||||
|
&[positionend] {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
margin-inline-end: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Rc Devtools
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Devtools window when docked to the left or right. */
|
||||||
|
.devtools-toolbox-side-iframe {
|
||||||
|
margin-block-end: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
border-radius: var(--uc-tweak-rounded-corners-radius) !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
box-shadow: var(--uc-tweak-rounded-corners-shadow) !important;
|
||||||
|
|
||||||
|
/* Devtools window when docked to the left. */
|
||||||
|
&:first-child {
|
||||||
|
margin-inline-start: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Devtools window when docked to the right. */
|
||||||
|
&:last-child {
|
||||||
|
margin-inline-end: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Devtools window when docked to the bottom. */
|
||||||
|
.devtools-toolbox-bottom-iframe {
|
||||||
|
margin: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
margin-block-start: 0 !important;
|
||||||
|
border-radius: var(--uc-tweak-rounded-corners-radius) !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
box-shadow: var(--uc-tweak-rounded-corners-shadow) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide devtools splitter. */
|
||||||
|
.devtools-side-splitter,
|
||||||
|
.devtools-horizontal-splitter {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive design mode. */
|
||||||
|
.browserContainer.responsive-mode {
|
||||||
|
background-color: transparent !important;
|
||||||
|
|
||||||
|
& .rdm-toolbar {
|
||||||
|
margin-inline: var(--uc-tweak-rounded-corners-padding) !important;
|
||||||
|
border-top-left-radius: var(--uc-tweak-rounded-corners-radius) !important;
|
||||||
|
border-top-right-radius: var(--uc-tweak-rounded-corners-radius) !important;
|
||||||
|
width: calc(100% - var(--uc-tweak-rounded-corners-padding) * 2) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove sidebar border when not in full screen. */
|
||||||
|
:not(:root[inFullscreen] #navigator-toolbox[style*="margin-top"]) + #browser #sidebar-splitter {
|
||||||
|
border-inline-width: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply colour to the frame around the browser window. */
|
||||||
|
#browser {
|
||||||
|
background-color: var(--browser-frame-bgcolor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change colour of page when loading */
|
||||||
|
#tabbrowser-tabpanels {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
/* Edge-Frfox - colors.css
|
||||||
|
* https://github.com/bmFtZQ/edge-frfox */
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Default colours
|
||||||
|
*/
|
||||||
|
:root:not([lwtheme]),
|
||||||
|
/* `--newtab-background-color-secondary used` to differentiate between a dark
|
||||||
|
* private window and private window with the 'Dark' theme enabled.
|
||||||
|
* May not be the most reliable method, but works for now up to FF 123. */
|
||||||
|
:root[privatebrowsingmode="temporary"]:where([style*="--lwt-accent-color: rgb(28, 27, 34)"]:not([style*="--newtab-background-color-secondary: rgb(66, 65, 77)"])) {
|
||||||
|
/* Toolbars */
|
||||||
|
--lwt-accent-color: light-dark(#cecece, #1C1C1C) !important;
|
||||||
|
--lwt-accent-color-inactive: light-dark(#e8e8e8, #2e2e2e) !important;
|
||||||
|
--lwt-text-color: light-dark(#000, #FFF) !important;
|
||||||
|
--lwt-text-color-inactive: light-dark(#3A3A3A, #CBCBCB) !important;
|
||||||
|
--tab-selected-textcolor: light-dark(#000, #fff) !important;
|
||||||
|
--tab-selected-textcolor-inactive: light-dark(#3E3E3E, #CBCBCB) !important;
|
||||||
|
--tab-selected-bgcolor: var(--toolbar-bgcolor) !important;
|
||||||
|
--tab-attention-icon-color: light-dark(#0078D4, #93d0ff) !important;
|
||||||
|
--toolbar-bgcolor: light-dark(#f7f7f7, #3B3B3B) !important;
|
||||||
|
--toolbar-non-lwt-bgcolor: var(--toolbar-bgcolor) !important;
|
||||||
|
--toolbar-color: light-dark(#000, #fff) !important;
|
||||||
|
--toolbarbutton-icon-fill: var(--toolbar-color) !important;
|
||||||
|
--toolbarbutton-icon-fill-attention: light-dark(#0078D4, #4C98D1) !important;
|
||||||
|
--toolbarseparator-color: color-mix(in srgb, currentColor 25%, transparent) !important;
|
||||||
|
--chrome-content-separator-color: light-dark(#bfbfbf, #686868) !important;
|
||||||
|
--newtab-background-color: light-dark(#f7f7f7, #252525) !important;
|
||||||
|
--tabpanel-background-color: var(--newtab-background-color, var(--toolbar-bgcolor, transparent)) !important;
|
||||||
|
/* Toolbar button overlays */
|
||||||
|
--toolbarbutton-hover-background: color-mix(in srgb, currentColor 8%, transparent) !important;
|
||||||
|
--toolbarbutton-active-background: color-mix(in srgb, currentColor 13.5%, transparent) !important;
|
||||||
|
/* Tab audio indicator overlay icon */
|
||||||
|
--tab-icon-overlay-fill: var(--toolbar-color) !important;
|
||||||
|
--tab-icon-overlay-stroke: var(--toolbar-bgcolor) !important;
|
||||||
|
/* URL bar */
|
||||||
|
--toolbar-field-background-color: light-dark(#fff, #2B2B2B) !important;
|
||||||
|
--toolbar-field-color: light-dark(#000, #fff) !important;
|
||||||
|
--toolbar-field-border-color: transparent !important;
|
||||||
|
--toolbar-field-focus-background-color: var(--toolbar-field-background-color) !important;
|
||||||
|
--toolbar-field-focus-color: var(--toolbar-field-color) !important;
|
||||||
|
--toolbar-field-focus-border-color: light-dark(#0055D780, #63ADE5) !important;
|
||||||
|
--urlbar-icon-fill-opacity: 0.58 !important;
|
||||||
|
--urlbar-box-bgcolor: light-dark(rgb(0 0 0 / .09), rgb(255 255 255 / .11)) !important;
|
||||||
|
--urlbar-box-hover-bgcolor: light-dark(rgb(0 0 0 / .09), rgb(255 255 255 / .11)) !important;
|
||||||
|
--urlbar-box-active-bgcolor: light-dark(rgb(0 0 0 / .22), rgb(255 255 255 / .28)) !important;
|
||||||
|
--urlbar-box-focus-bgcolor: var(--urlbar-box-hover-bgcolor) !important;
|
||||||
|
/* URL bar suggestions */
|
||||||
|
--link-color: light-dark(#0078D4, #75B6E8) !important;
|
||||||
|
--uc-urlbarView-accent-color: light-dark(#1A6397, #75B6E8) !important;
|
||||||
|
--urlbarView-highlight-background: light-dark(#F2F2F2, #383838) !important;
|
||||||
|
--urlbarView-highlight-color: light-dark(#000, #fff) !important;
|
||||||
|
--urlbarView-hover-background: light-dark(#e5e5e5, #444444) !important;
|
||||||
|
--urlbarView-separator-color: light-dark(#EFEFEF, #5F5F5F) !important;
|
||||||
|
/* Menus/panels */
|
||||||
|
--arrowpanel-background: light-dark(#fff, #4A4A4A) !important;
|
||||||
|
--arrowpanel-color: light-dark(#1c1c1c, #fff) !important;
|
||||||
|
--arrowpanel-border-color: light-dark(#fff, #636363) !important;
|
||||||
|
--arrowpanel-dimmed: light-dark(#565656, #565656) !important;
|
||||||
|
--arrowpanel-dimmed-further: light-dark(#707070, #707070) !important;
|
||||||
|
--panel-separator-color: light-dark(#dadada, #636363) !important;
|
||||||
|
--panel-description-color: light-dark(#000a, #fffb) !important;
|
||||||
|
--panel-disabled-color: light-dark(#9E9E9E, #B9B9B9) !important;
|
||||||
|
--panel-item-hover-bgcolor: light-dark(#eee, #646464) !important;
|
||||||
|
--panel-item-active-bgcolor: light-dark(#ddd, #747474) !important;
|
||||||
|
--panel-banner-item-update-supported-bgcolor: light-dark(#188038, #81C995) !important;
|
||||||
|
/* Primary button */
|
||||||
|
--button-primary-bgcolor: light-dark(#0078D4, #006CBE) !important;
|
||||||
|
--button-primary-color: light-dark(#fff, #fff) !important;
|
||||||
|
--button-primary-hover-bgcolor: light-dark(#006BBD, #1C7CC5) !important;
|
||||||
|
--button-primary-active-bgcolor: light-dark(#0060AA, #3289CB) !important;
|
||||||
|
/* Secondary button */
|
||||||
|
--button-bgcolor: light-dark(#EFEFEF, #5C5C5C) !important;
|
||||||
|
--button-color: light-dark(#000, #fff) !important;
|
||||||
|
--button-hover-bgcolor: light-dark(#D5D5D5, #6E6E6E) !important;
|
||||||
|
--button-active-bgcolor: light-dark(#C0C0C0, #7C7C7C) !important;
|
||||||
|
/* Text input field, e.g. bookmarks editor */
|
||||||
|
--focus-outline-color: light-dark(#0055D780, #63ADE5) !important;
|
||||||
|
--input-bgcolor: light-dark(#fff, #4A4A4A) !important;
|
||||||
|
--input-color: light-dark(#2b2b2b, #fff) !important;
|
||||||
|
--input-border-color: light-dark(#bebebe, #808080) !important;
|
||||||
|
--error-text-color: light-dark(#FF9AA2, #FF9AA2) !important;
|
||||||
|
--input-error-border-color: light-dark(#FF848A, #FF848A) !important;
|
||||||
|
/* Side bar colours. */
|
||||||
|
--sidebar-background-color: light-dark(#f7f7f7, #3b3b3b) !important;
|
||||||
|
--sidebar-text-color: light-dark(#000, #fff) !important;
|
||||||
|
--sidebar-border-color: light-dark(#bfbfbf, #686868) !important;
|
||||||
|
|
||||||
|
/* ::::: Dialog theme ::::: */
|
||||||
|
& #window-modal-dialog::backdrop {
|
||||||
|
/* Overlay when dialog is shown. */
|
||||||
|
background-color: rgb(20 20 20 / .2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[dialogroot] {
|
||||||
|
/* Dialog */
|
||||||
|
--in-content-page-background: var(--arrowpanel-background) !important;
|
||||||
|
--in-content-page-color: var(--arrowpanel-color) !important;
|
||||||
|
/* Primary button */
|
||||||
|
--in-content-primary-button-text-color: var(--button-primary-color) !important;
|
||||||
|
--in-content-primary-button-background: var(--button-primary-bgcolor) !important;
|
||||||
|
--in-content-primary-button-background-hover: var(--button-primary-hover-bgcolor) !important;
|
||||||
|
--in-content-primary-button-background-active: var(--button-primary-active-bgcolor) !important;
|
||||||
|
/* Secondary button */
|
||||||
|
--in-content-button-text-color: var(--button-color) !important;
|
||||||
|
--in-content-button-background: var(--button-bgcolor) !important;
|
||||||
|
--in-content-button-background-hover: var(--button-hover-bgcolor) !important;
|
||||||
|
--in-content-button-background-active: var(--button-active-bgcolor) !important;
|
||||||
|
/* Text input */
|
||||||
|
--in-content-box-background: var(--input-bgcolor) !important;
|
||||||
|
--in-content-box-border-color: var(--input-border-color) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that dark mode is enabled completely in private browsing mode. */
|
||||||
|
@media (-moz-bool-pref: "browser.theme.dark-private-windows") {
|
||||||
|
:root[privatebrowsingmode="temporary"],
|
||||||
|
:root[privatebrowsingmode="temporary"] #nav-bar,
|
||||||
|
:root[privatebrowsingmode="temporary"] #PersonalToolbar {
|
||||||
|
--toolbar-color-scheme: dark !important;
|
||||||
|
--tab-selected-color-scheme: dark !important;
|
||||||
|
color-scheme: dark !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply colours to the default 'Auto' theme. */
|
||||||
|
:root:not([lwtheme]) #navigator-toolbox {
|
||||||
|
background-color: var(--lwt-accent-color) !important;
|
||||||
|
color: var(--lwt-text-color) !important;
|
||||||
|
|
||||||
|
/* Inactive window background colours. */
|
||||||
|
&:-moz-window-inactive {
|
||||||
|
background-color: var(--lwt-accent-color-inactive, var(--lwt-accent-color)) !important;
|
||||||
|
color: var(--lwt-text-color-inactive, var(--lwt-text-color)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that the tab toolbar opacity is always 1, inactive window colours
|
||||||
|
* are already supplied by this theme. */
|
||||||
|
:root[tabsintitlebar] #titlebar:-moz-window-inactive {
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the titlebar buttons black/white on default themes */
|
||||||
|
:root:not([lwtheme])[tabsintitlebar] .titlebar-buttonbox {
|
||||||
|
color: var(--lwt-text-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status/link preview panel */
|
||||||
|
#statuspanel-label {
|
||||||
|
background-color: var(--toolbar-field-focus-background-color) !important;
|
||||||
|
color: var(--toolbar-field-focus-color) !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
box-shadow: 0 2px 5px #0002, 0 0 0 1px light-dark(#0001, #0002) !important;
|
||||||
|
border-radius: 0 4px 0 0 !important;
|
||||||
|
|
||||||
|
#statuspanel[mirror] & {
|
||||||
|
border-radius: 4px 0 0 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Windows
|
||||||
|
*/
|
||||||
|
@media (-moz-platform: windows) {
|
||||||
|
/* Colour the text selection background and foreground. */
|
||||||
|
::selection {
|
||||||
|
background-color: light-dark(#0078D4, #93B8E7) !important;
|
||||||
|
color: light-dark(#fff, #000) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip {
|
||||||
|
background-color: var(--arrowpanel-background) !important;
|
||||||
|
color: var(--arrowpanel-color) !important;
|
||||||
|
border-color: var(--arrowpanel-border-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use accent colour in titlebar when Windows option is enabled. */
|
||||||
|
@media (-moz-windows-accent-color-in-titlebar) and (-moz-bool-pref: "browser.theme.windows.accent-color-in-tabs.enabled") {
|
||||||
|
/* Uses :root:root to beat specificity of floating tabs adjustments. */
|
||||||
|
:root:root:not([lwtheme]) {
|
||||||
|
--lwt-accent-color: ActiveCaption !important;
|
||||||
|
--lwt-text-color: CaptionText !important;
|
||||||
|
--lwt-accent-color-inactive: InActiveCaption !important;
|
||||||
|
--lwt-text-color-inactive: InActiveCaptionText !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.titlebar-button:not(.titlebar-close):hover {
|
||||||
|
background-color: color-mix(in srgb, currentColor 11%, transparent) !important;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: color-mix(in srgb, currentColor 20%, transparent) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.titlebar-close:hover {
|
||||||
|
stroke: white !important;
|
||||||
|
background-color: #e81123 !important;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: #DC5C66 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbar[brighttext] &:active {
|
||||||
|
background-color: #971821 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Library window colour theme. */
|
||||||
|
window#places {
|
||||||
|
--organizer-color: light-dark(#000, #fff) !important;
|
||||||
|
--organizer-deemphasized-color: light-dark(#666, #bbb) !important;
|
||||||
|
--organizer-toolbar-background: light-dark(#f7f7f7, #3B3B3B) !important;
|
||||||
|
--organizer-pane-background: light-dark(#f7f7f7, #2B2B2B) !important;
|
||||||
|
--organizer-content-background: light-dark(#f7f7f7, #1C1C1C) !important;
|
||||||
|
--organizer-hover-background: light-dark(#00000025, #ffffff25) !important;
|
||||||
|
--organizer-selected-background: light-dark(#006CBE80, #006CBE80) !important;
|
||||||
|
--organizer-outline-color: light-dark(#0055D7a0, #63ADE5) !important;
|
||||||
|
--organizer-toolbar-field-background: light-dark(#fff, #2B2B2B) !important;
|
||||||
|
--organizer-toolbar-field-background-focused: light-dark(#fff, #2B2B2B) !important;
|
||||||
|
--organizer-border-color: light-dark(#bfbfbf, #686868) !important;
|
||||||
|
scrollbar-color:
|
||||||
|
light-dark(#0006, #fff6)
|
||||||
|
light-dark(#f7f7f740, #2B2B2B40) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#placesViewsBox #downloadsListBox richlistitem[selected="true"] {
|
||||||
|
background-color: light-dark(#006CBE, #006CBE) !important;
|
||||||
|
color: light-dark(#fff, #fff) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#placeContentColumns :is(treecol, treecolpicker) {
|
||||||
|
background-color: light-dark(#f7f7f7, #3B3B3B) !important;
|
||||||
|
color: light-dark(#000, #fff) !important;
|
||||||
|
border-inline-start: 1px solid light-dark(#bfbfbf, #686868) !important;
|
||||||
|
box-shadow: inset 0 -1px light-dark(#bfbfbf, #686868) !important;
|
||||||
|
appearance: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#placeContentColumns :is(treecol, treecolpicker):where(:hover) {
|
||||||
|
background-color: light-dark(#cecece, #4A4A4A) !important;
|
||||||
|
color: light-dark(#000, #fff) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent macOS vibrancy appearance, instead using a solid background. */
|
||||||
|
#sidebar-box {
|
||||||
|
appearance: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-panel:not([lwt-sidebar]) {
|
||||||
|
color: light-dark(#000, #fff) !important;
|
||||||
|
scrollbar-color: light-dark(#0006, #fff6) light-dark(#f7f7f740, #3b3b3b40) !important;
|
||||||
|
|
||||||
|
/* Sidebar search box (Windows) */
|
||||||
|
@media(-moz-platform: windows) {
|
||||||
|
& #sidebar-search-container > #search-box,
|
||||||
|
& #viewButton {
|
||||||
|
appearance: none !important;
|
||||||
|
background-color: var(--toolbar-field-background-color) !important;
|
||||||
|
color: inherit !important;
|
||||||
|
border: 1px solid var(--input-border-color) !important;
|
||||||
|
border-radius: 4px !important;
|
||||||
|
padding: 6px 8px !important;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 2px solid var(--input-border-color) !important;
|
||||||
|
outline-offset: -2px !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-document url(chrome://browser/content/syncedtabs/sidebar.xhtml) {
|
||||||
|
body {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Linux / GTK csd
|
||||||
|
*/
|
||||||
|
@media (-moz-gtk-csd-available) {
|
||||||
|
:root:not([lwtheme]),
|
||||||
|
/* `--newtab-background-color-secondary used` to differentiate between a dark
|
||||||
|
* private window and private window with the 'Dark' theme enabled.
|
||||||
|
* May not be the most reliable method, but works for now up to FF 123. */
|
||||||
|
:root[privatebrowsingmode="temporary"]:where([style*="--lwt-accent-color: rgb(28, 27, 34)"]:not([style*="--newtab-background-color-secondary: rgb(66, 65, 77)"])) {
|
||||||
|
/* Used for mixing colours differently in light/dark themes. */
|
||||||
|
--uc-tint: light-dark(black, white);
|
||||||
|
/* Colour adjusted for readability. */
|
||||||
|
--uc-accent-adjusted: light-dark(
|
||||||
|
color-mix(in oklch, AccentColor 92%, black),
|
||||||
|
color-mix(in oklch, AccentColor 60%, white)
|
||||||
|
);
|
||||||
|
/* Toolbars */
|
||||||
|
--lwt-accent-color: light-dark(color-mix(in srgb, ActiveCaption 90%, black), ActiveCaption) !important;
|
||||||
|
--lwt-accent-color-inactive: light-dark(color-mix(in srgb, InactiveCaption 94%, black), InactiveCaption) !important;
|
||||||
|
--lwt-text-color: CaptionText !important;
|
||||||
|
--lwt-text-color-inactive: color-mix(in srgb, CaptionText 65%, transparent) !important;
|
||||||
|
--tab-selected-textcolor: var(--toolbar-color) !important;
|
||||||
|
--tab-selected-textcolor-inactive: color-mix(in srgb, var(--toolbar-color) 65%, transparent) !important;
|
||||||
|
--tab-selected-bgcolor: var(--toolbar-bgcolor) !important;
|
||||||
|
--tab-attention-icon-color: var(--uc-accent-adjusted) !important;
|
||||||
|
--toolbar-bgcolor: light-dark(-moz-dialog, color-mix(in srgb, -moz-dialog 92%, white)) !important;
|
||||||
|
--toolbar-color: -moz-dialogtext !important;
|
||||||
|
--toolbarbutton-icon-fill-attention: var(--uc-accent-adjusted) !important;
|
||||||
|
--chrome-content-separator-color: color-mix(in srgb, currentColor 17%, var(--toolbar-bgcolor)) !important;
|
||||||
|
--newtab-background-color: light-dark(-moz-dialog, color-mix(in srgb, -moz-dialog 82%, black)) !important;
|
||||||
|
/* URL bar */
|
||||||
|
--toolbar-field-background-color: light-dark(Field, color-mix(in srgb, Field 96%, -moz-dialogtext)) !important;
|
||||||
|
--toolbar-field-color: FieldText !important;
|
||||||
|
--toolbar-field-focus-border-color: light-dark(color-mix(in srgb, var(--focus-outline-color) 50%, transparent), var(--focus-outline-color)) !important;
|
||||||
|
--urlbar-box-bgcolor: var(--button-bgcolor) !important;
|
||||||
|
--urlbar-box-hover-bgcolor: var(--button-hover-bgcolor) !important;
|
||||||
|
--urlbar-box-active-bgcolor: var(--button-active-bgcolor) !important;
|
||||||
|
/* URL bar suggestions. */
|
||||||
|
--link-color: var(--uc-accent-adjusted) !important;
|
||||||
|
--uc-urlbarView-accent-color: var(--uc-accent-adjusted) !important;
|
||||||
|
--urlbarView-highlight-background: var(--panel-item-hover-bgcolor) !important;
|
||||||
|
--urlbarView-highlight-color: var(--toolbar-field-color) !important;
|
||||||
|
--urlbarView-hover-background: var(--panel-item-active-bgcolor) !important;
|
||||||
|
--urlbarView-separator-color: var(--panel-separator-color) !important;
|
||||||
|
/* Menus/panels */
|
||||||
|
--arrowpanel-background: Field !important;
|
||||||
|
--arrowpanel-color: FieldText !important;
|
||||||
|
--arrowpanel-border-color: light-dark(transparent, var(--panel-separator-color)) !important;
|
||||||
|
--arrowpanel-dimmed: color-mix(in srgb, currentColor 17%, transparent) !important;
|
||||||
|
--arrowpanel-dimmed-further: color-mix(in srgb, currentColor 30%, transparent) !important;
|
||||||
|
--panel-separator-color: color-mix(in srgb, currentColor 17%, var(--arrowpanel-background)) !important;
|
||||||
|
--panel-description-color: GrayText !important;
|
||||||
|
--panel-disabled-color: GrayText !important;
|
||||||
|
--panel-item-hover-bgcolor: color-mix(in srgb, currentColor 8%, transparent) !important;
|
||||||
|
--panel-item-active-bgcolor: color-mix(in srgb, currentColor 13%, transparent) !important;
|
||||||
|
/* Primary button */
|
||||||
|
--button-primary-bgcolor: AccentColor !important;
|
||||||
|
--button-primary-color: AccentColorText !important;
|
||||||
|
--button-primary-hover-bgcolor: color-mix(in srgb, var(--uc-tint) 10%, var(--button-primary-bgcolor)) !important;
|
||||||
|
--button-primary-active-bgcolor: color-mix(in srgb, var(--uc-tint) 20%, var(--button-primary-bgcolor)) !important;
|
||||||
|
/* Secondary button */
|
||||||
|
--button-bgcolor: color-mix(in srgb, currentColor 10%, transparent) !important;
|
||||||
|
--button-color: currentColor !important;
|
||||||
|
--button-hover-bgcolor: color-mix(in srgb, currentColor 14%, transparent) !important;
|
||||||
|
--button-active-bgcolor: color-mix(in srgb, currentColor 20%, transparent) !important;
|
||||||
|
/* Text input field, e.g. bookmarks editor. */
|
||||||
|
--focus-outline-color: var(--uc-accent-adjusted) !important;
|
||||||
|
--input-bgcolor: var(--arrowpanel-background) !important;
|
||||||
|
--input-color: var(--arrowpanel-color) !important;
|
||||||
|
--input-border-color: color-mix(in srgb, currentColor 35%, var(--arrowpanel-background)) !important;
|
||||||
|
/* Sidebar */
|
||||||
|
--sidebar-background-color: var(--toolbar-bgcolor) !important;
|
||||||
|
--sidebar-text-color: var(--toolbar-color) !important;
|
||||||
|
--sidebar-border-color: var(--chrome-content-separator-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use the same sidebar splitter style as other platforms. */
|
||||||
|
.sidebar-splitter {
|
||||||
|
border: 0 solid var(--sidebar-border-color) !important;
|
||||||
|
border-inline-end-width: 1px !important;
|
||||||
|
width: 4px !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
margin-inline-start: -4px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,847 @@
|
|||||||
|
/* Edge-Frfox - popup.css */
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Variables
|
||||||
|
*/
|
||||||
|
:root {
|
||||||
|
--panel-subview-body-padding: 2px 0 !important;
|
||||||
|
--arrowpanel-border-radius: 8px !important;
|
||||||
|
--arrowpanel-menuitem-border-radius: 4px !important;
|
||||||
|
--arrowpanel-menuitem-margin: var(--uc-arrowpanel-menuitem-margin-block) var(--uc-arrowpanel-menuitem-margin-inline) !important;
|
||||||
|
--arrowpanel-menuitem-padding-block: 6px !important;
|
||||||
|
--arrowpanel-menuitem-padding-inline: 10px !important;
|
||||||
|
--uc-arrowpanel-menuicon-margin-inline: 14px;
|
||||||
|
--uc-arrowpanel-menuitem-margin-inline: 4px;
|
||||||
|
--uc-arrowpanel-menuitem-margin-block: 2px;
|
||||||
|
--panel-separator-margin-vertical: 2px !important;
|
||||||
|
--panel-separator-margin-horizontal: 0 !important;
|
||||||
|
|
||||||
|
--uc-panel-zoom-button-padding: 8px;
|
||||||
|
--uc-panel-zoom-button-inline-padding: 9px;
|
||||||
|
--uc-panel-zoom-padding-block: calc(var(--panel-separator-margin-vertical) + var(--uc-arrowpanel-menuitem-margin-block));
|
||||||
|
|
||||||
|
--uc-autocomplete-panel-menuitem-margin: 4px;
|
||||||
|
--uc-autocomplete-panel-menuicon-padding-inline: 14px;
|
||||||
|
--uc-autocomplete-panel-separator-margin-vertical: 4px;
|
||||||
|
|
||||||
|
--uc-permission-itemcontainer-padding-block: 8px;
|
||||||
|
--uc-permission-item-margin-block: 4px;
|
||||||
|
--uc-permission-item-padding-inline: 16px;
|
||||||
|
|
||||||
|
--uc-contextmenu-border-radius: 8px;
|
||||||
|
--uc-contextmenu-padding: calc(4px - var(--uc-contextmenu-menuitem-border-width)) 0;
|
||||||
|
--uc-contextmenu-menuitem-border-radius: calc(4px + var(--uc-contextmenu-menuitem-border-width));
|
||||||
|
--uc-contextmenu-menuitem-padding-block: 6px;
|
||||||
|
--uc-contextmenu-menuitem-padding-inline: 10px;
|
||||||
|
--uc-contextmenu-menuitem-border-width: 2px;
|
||||||
|
--uc-contextmenu-menuicon-margin-inline: 12px;
|
||||||
|
--uc-contextmenu-menuitem-margin-inline: calc(4px - var(--uc-contextmenu-menuitem-border-width));
|
||||||
|
--uc-contextmenu-menuitem-margin-block: 0px;
|
||||||
|
--uc-contextmenu-menuitem-margin: var(--uc-contextmenu-menuitem-margin-block) var(--uc-contextmenu-menuitem-margin-inline);
|
||||||
|
--uc-contextmenu-separator-vertical: calc(4px - var(--uc-contextmenu-menuitem-border-width));
|
||||||
|
--uc-contextmenu-separator-horizontal: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: App menu
|
||||||
|
*/
|
||||||
|
.addon-banner-item,
|
||||||
|
.panel-banner-item {
|
||||||
|
margin: 2px 4px 2px !important;
|
||||||
|
padding-inline: 4px 12px !important;
|
||||||
|
padding-block: var(--arrowpanel-menuitem-padding-block) !important;
|
||||||
|
border-radius: var(--arrowpanel-menuitem-border-radius) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-fxa-label2 label,
|
||||||
|
#PanelUI-fxa-menu-syncnow-button label {
|
||||||
|
margin-block: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-overflow-list .toolbarbutton-1:not(.toolbarbutton-combined) > .toolbarbutton-text,
|
||||||
|
.subviewbutton:not(#appMenu-zoom-controls > .subviewbutton) > .toolbarbutton-icon + .toolbarbutton-text,
|
||||||
|
#appMenu-fxa-label2 > vbox {
|
||||||
|
padding-inline-start: var(--uc-arrowpanel-menuicon-margin-inline) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* special case menuitems with no icons */
|
||||||
|
#appMenu-zoom-controls > .toolbarbutton-text,
|
||||||
|
#fxa-manage-account-button > vbox,
|
||||||
|
#PanelUI-fxa-menu-syncnow-button > hbox {
|
||||||
|
padding-inline-start: calc(16px + var(--uc-arrowpanel-menuicon-margin-inline)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subviewbutton > .toolbarbutton-icon {
|
||||||
|
width: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* firefox profile avatar in appmenu */
|
||||||
|
#appMenu-fxa-label2::before {
|
||||||
|
content: "";
|
||||||
|
display: flex;
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
background: var(--avatar-image-url) 0/16px;
|
||||||
|
scale: 1.25;
|
||||||
|
border-radius: 99px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disable proton account separator */
|
||||||
|
#appMenu-fxa-separator {
|
||||||
|
border-image: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-fxa-status2:not([fxastatus]) {
|
||||||
|
padding-block: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-fxa-status2:not([fxastatus]) > #appMenu-fxa-label2 {
|
||||||
|
margin-inline-end: calc(var(--arrowpanel-menuitem-padding-inline) * -1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zoom controls */
|
||||||
|
#appMenu-zoom-controls {
|
||||||
|
border-top: 1px solid var(--panel-separator-color) !important;
|
||||||
|
padding-inline: calc(var(--arrowpanel-menuitem-padding-inline) + var(--uc-arrowpanel-menuitem-margin-inline)) var(--uc-arrowpanel-menuitem-margin-inline) !important;
|
||||||
|
padding-block: var(--uc-panel-zoom-padding-block) !important;
|
||||||
|
margin: var(--panel-separator-margin-vertical) 0 calc(var(--panel-separator-margin-vertical) * -1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-zoom-controls > .subviewbutton {
|
||||||
|
padding: var(--uc-panel-zoom-button-padding) var(--uc-panel-zoom-button-inline-padding) !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-zoom-controls > #appMenu-zoomReset-button2 {
|
||||||
|
padding: var(--uc-panel-zoom-button-padding) calc(var(--uc-panel-zoom-button-padding) / 2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #appMenu-zoomReduce-button2, */
|
||||||
|
#appMenu-zoom-controls > #appMenu-fullscreen-button2 {
|
||||||
|
margin-left: calc((var(--panel-separator-margin-vertical) + var(--uc-arrowpanel-menuitem-margin-block)) * 2 + 1px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-zoom-controls > #appMenu-fullscreen-button2::before {
|
||||||
|
content: "";
|
||||||
|
border-inline-start: 1px solid var(--panel-separator-color);
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
height: 32px;
|
||||||
|
margin-block: calc(var(--uc-panel-zoom-button-padding) * -1);
|
||||||
|
transform: translateX(calc(var(--uc-panel-zoom-button-inline-padding) * -1 - (var(--panel-separator-margin-vertical) + var(--uc-arrowpanel-menuitem-margin-block)) - 1px));
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-zoomReset-button2 {
|
||||||
|
height: calc(16px + var(--uc-panel-zoom-button-padding) * 2) !important;
|
||||||
|
min-height: calc(16px + var(--uc-panel-zoom-button-padding) * 2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-zoomReduce-button2:not([disabled], [open], :active):is(:hover),
|
||||||
|
#appMenu-zoomEnlarge-button2:not([disabled], [open], :active):is(:hover),
|
||||||
|
#appMenu-fullscreen-button2:not([disabled], [open], :active):is(:hover),
|
||||||
|
#appMenu-zoomReset-button2:not([disabled], [open], :active):is(:hover) {
|
||||||
|
background-color: var(--panel-item-hover-bgcolor) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-zoomReduce-button2:not([disabled]):is([open], :hover:active),
|
||||||
|
#appMenu-zoomEnlarge-button2:not([disabled]):is([open], :hover:active),
|
||||||
|
#appMenu-fullscreen-button2:not([disabled]):is([open], :hover:active),
|
||||||
|
#appMenu-zoomReset-button2:not([disabled]):is([open], :hover:active) {
|
||||||
|
background-color: var(--panel-item-active-bgcolor) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-zoomReduce-button2 > .toolbarbutton-icon,
|
||||||
|
#appMenu-zoomEnlarge-button2 > .toolbarbutton-icon {
|
||||||
|
fill: currentColor !important;
|
||||||
|
stroke: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#appMenu-zoomReset-button2 > .toolbarbutton-text,
|
||||||
|
#appMenu-fullscreen-button2 > .toolbarbutton-icon {
|
||||||
|
background-color: transparent !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subviewbutton[shortcut]::after {
|
||||||
|
opacity: 0.7 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#widget-overflow-mainView .panel-subview-body {
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.PanelUI-subView > .panel-header + toolbarseparator {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.PanelUI-subView > .panel-header + toolbarseparator + .panel-subview-body {
|
||||||
|
padding-top: var(--panel-separator-margin-vertical) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#identity-popup-security-button {
|
||||||
|
margin-bottom: var(--panel-separator-margin-vertical) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permission-popup-mainView-panel-header,
|
||||||
|
#identity-popup-mainView-panel-header,
|
||||||
|
#protections-popup-mainView-panel-header,
|
||||||
|
.panel-header {
|
||||||
|
min-height: calc((var(--arrowpanel-menuitem-padding-block) + 4px) * 2 + 16px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* URL bar popup */
|
||||||
|
.panel-footer > button {
|
||||||
|
border-radius: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.identity-popup-security-connection > hbox > description {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.identity-popup-security-connection.identity-button {
|
||||||
|
margin-inline-end: calc(-1 * (var(--arrowpanel-menuitem-padding-inline) - 10px)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#identity-popup-mainView-panel-header-span,
|
||||||
|
#permission-popup-mainView-panel-header-span,
|
||||||
|
#identity-popup-mainView-panel-header label,
|
||||||
|
#permission-popup-mainView-panel-header label,
|
||||||
|
#protections-popup-mainView-panel-header-span {
|
||||||
|
margin-block: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.permission-popup-section {
|
||||||
|
padding-block: var(--uc-permission-itemcontainer-padding-block) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permission-popup-permissions-content {
|
||||||
|
padding-inline: var(--uc-permission-item-padding-inline) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.permission-popup-permission-item,
|
||||||
|
#permission-popup-storage-access-permission-list-header {
|
||||||
|
margin-block: var(--uc-permission-item-margin-block) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.permission-popup-permission-label,
|
||||||
|
.permission-popup-permission-header-label {
|
||||||
|
margin-inline-start: var(--uc-arrowpanel-menuicon-margin-inline) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editBookmarkPanel > #editBookmarkHeaderSeparator,
|
||||||
|
#editBookmarkPanel > .panel-subview-body > #editBookmarkSeparator {
|
||||||
|
margin-inline: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* subview */
|
||||||
|
.panel-header {
|
||||||
|
padding: 4px !important;
|
||||||
|
padding-top: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-header + toolbarseparator,
|
||||||
|
#identity-popup-mainView-panel-header + toolbarseparator,
|
||||||
|
#permission-popup-mainView-panel-header + toolbarseparator,
|
||||||
|
#protections-popup-mainView-panel-header-section + toolbarseparator {
|
||||||
|
margin-block-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-header > .subviewbutton-back {
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: var(--arrowpanel-menuitem-padding-block) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-subview-footer-button {
|
||||||
|
margin-bottom: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webextension-popup-browser,
|
||||||
|
.webextension-popup-stack {
|
||||||
|
margin-block-start: calc(var(--panel-separator-margin-vertical) * -.5) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Downloads
|
||||||
|
*/
|
||||||
|
.downloadTypeIcon {
|
||||||
|
height: 16px !important;
|
||||||
|
width: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.downloadButton {
|
||||||
|
min-width: calc(16px + var(--uc-toolbarbutton-inner-inline-padding) * 2) !important;
|
||||||
|
height: calc(16px + var(--toolbarbutton-inner-padding) * 2) !important;
|
||||||
|
border-radius: var(--toolbarbutton-border-radius) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.downloadProgress::-moz-progress-bar,
|
||||||
|
.downloadProgress > div {
|
||||||
|
background-color: var(--toolbarbutton-icon-fill-attention) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.downloadMainArea {
|
||||||
|
padding-block: 4px !important;
|
||||||
|
padding-inline: 12px !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#downloadsListBox > richlistitem {
|
||||||
|
padding-inline-end: 8px !important;
|
||||||
|
border-radius: var(--arrowpanel-menuitem-border-radius) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#downloadsListBox,
|
||||||
|
.downloadsPanelFooterButton {
|
||||||
|
margin: var(--arrowpanel-menuitem-margin) !important;
|
||||||
|
width: auto !important;
|
||||||
|
min-width: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#downloadsPanel-blockedSubview,
|
||||||
|
#downloadsPanel-mainView {
|
||||||
|
padding: var(--panel-separator-margin-vertical) 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#emptyDownloads {
|
||||||
|
padding: 1.5em 16px 1.7em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#downloadsHistory .button-text {
|
||||||
|
margin-block: 0 !important;
|
||||||
|
margin-inline: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.PanelUI-subView .subviewbutton-nav::after,
|
||||||
|
#PlacesToolbar menu > .menu-right,
|
||||||
|
.subviewbutton > .menu-right {
|
||||||
|
fill-opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Extensions
|
||||||
|
*/
|
||||||
|
/* #region */
|
||||||
|
|
||||||
|
.toolbaritem-combined-buttons:is(:not([cui-areatype="toolbar"]), [overflowedItem="true"]) > toolbarbutton:not(.toolbarbutton-1)[disabled] {
|
||||||
|
opacity: 1 !important;
|
||||||
|
color: var(--panel-disabled-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Removes space above extensions items. */
|
||||||
|
#unified-extensions-messages-container {
|
||||||
|
margin-block: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--uei-icon-size: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.context-menu.compact-extensions-menu") {
|
||||||
|
:root {
|
||||||
|
--uei-icon-size: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide site access permissions label. */
|
||||||
|
.unified-extensions-item-message-deck {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use smaller toolbar extension icon if available. */
|
||||||
|
toolbaritem:is([overflowedItem="true"], [cui-areatype="panel"]) > .webextension-browser-action {
|
||||||
|
list-style-image: var(--webextension-toolbar-image, var(--webextension-menupanel-image, inherit)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use smaller font-size in extensions menu on Windows. */
|
||||||
|
@media (-moz-platform: windows) {
|
||||||
|
#unified-extensions-panel .toolbarbutton-text {
|
||||||
|
font: menu !important;
|
||||||
|
font-family: inherit !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent extension labels from using >1 line, adding ellipsis if necessary. */
|
||||||
|
.unified-extensions-item-contents {
|
||||||
|
flex: 1 !important;
|
||||||
|
|
||||||
|
& > .unified-extensions-item-name,
|
||||||
|
& > .unified-extensions-item-message-deck > .unified-extensions-item-message {
|
||||||
|
max-width: calc(100% - 4px) !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
text-overflow: ellipsis !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extension item menu button. */
|
||||||
|
.unified-extensions-item-menu-button {
|
||||||
|
padding: 0 !important;
|
||||||
|
|
||||||
|
& > .toolbarbutton-icon {
|
||||||
|
border: none !important;
|
||||||
|
padding-inline: var(--arrowpanel-menuitem-padding-inline) !important;
|
||||||
|
padding-block: var(--arrowpanel-menuitem-padding-block) !important;
|
||||||
|
margin-inline-start: var(--uc-arrowpanel-menuitem-margin-inline) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add grayscale filter to extensions with no access to current site. */
|
||||||
|
.unified-extensions-list .unified-extensions-item-action-button:has(.unified-extensions-item-message[data-l10n-id="origin-controls-state-no-access"]) .unified-extensions-item-icon {
|
||||||
|
filter: grayscale(1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust spacing between the extension item's icon and label. */
|
||||||
|
.unified-extensions-item-name,
|
||||||
|
.unified-extensions-item-message {
|
||||||
|
padding-inline-start: var(--uc-arrowpanel-menuicon-margin-inline) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unified-extensions-item-icon,
|
||||||
|
.unified-extensions-item .webextension-browser-action > .toolbarbutton-badge-stack {
|
||||||
|
margin-inline-end: 0 !important;
|
||||||
|
}
|
||||||
|
/* #endregion */
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Autocomplete
|
||||||
|
*/
|
||||||
|
#PopupAutoComplete {
|
||||||
|
/* workaround for inaccessible shadow-root element
|
||||||
|
moves the shadow-root element underneath, and away from panel edges */
|
||||||
|
padding-block: 10px !important;
|
||||||
|
padding-inline: 2px !important;
|
||||||
|
|
||||||
|
& > .autocomplete-richlistbox {
|
||||||
|
background: var(--arrowpanel-background) !important;
|
||||||
|
box-shadow: 0 0 0 1px inset var(--arrowpanel-border-color) !important;
|
||||||
|
height: auto !important;
|
||||||
|
margin-block: -10px !important;
|
||||||
|
margin-inline: -2px !important;
|
||||||
|
padding: var(--uc-contextmenu-padding) !important;
|
||||||
|
border-radius: var(--uc-contextmenu-border-radius) !important;
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .autocomplete-richlistitem[originaltype="loginsFooter"] {
|
||||||
|
justify-content: start !important;
|
||||||
|
color: inherit !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
height: 28px !important;
|
||||||
|
min-height: 28px !important;
|
||||||
|
padding-inline-start: var(--uc-contextmenu-menuitem-padding-inline) !important;
|
||||||
|
position: relative !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
margin-top: calc(var(--uc-contextmenu-separator-vertical) * 2 + 1px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Separator */
|
||||||
|
& .autocomplete-richlistitem[originaltype="loginsFooter"]::before {
|
||||||
|
content: "";
|
||||||
|
width: calc(100% + var(--uc-contextmenu-menuitem-margin-inline) * 2);
|
||||||
|
border-top: 1px solid var(--panel-separator-color);
|
||||||
|
position: absolute;
|
||||||
|
top: calc((var(--uc-contextmenu-separator-vertical) + var(--uc-contextmenu-menuitem-border-width)) * -1 - 1px);
|
||||||
|
left: calc(var(--uc-contextmenu-menuitem-margin-inline) * -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .autocomplete-richlistitem:hover {
|
||||||
|
background-color: var(--panel-item-hover-bgcolor) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .autocomplete-richlistitem[selected] {
|
||||||
|
background-color: var(--panel-item-active-bgcolor) !important;
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .ac-site-icon {
|
||||||
|
fill: currentColor !important;
|
||||||
|
margin-block: auto !important;
|
||||||
|
margin-inline: 0 var(--uc-autocomplete-panel-menuicon-padding-inline) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .ac-title {
|
||||||
|
margin-inline: calc(16px + var(--uc-autocomplete-panel-menuicon-padding-inline)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .two-line-wrapper {
|
||||||
|
padding: 0 !important;
|
||||||
|
gap: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#PlacesToolbar menuitem,
|
||||||
|
#PlacesToolbar menu,
|
||||||
|
panelview .toolbarbutton-1,
|
||||||
|
.subviewbutton,
|
||||||
|
.widget-overflow-list .toolbarbutton-1 {
|
||||||
|
min-height: calc(16px + var(--uc-contextmenu-menuitem-padding-block) * 2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Search bar suggestions
|
||||||
|
*/
|
||||||
|
#PopupSearchAutoComplete {
|
||||||
|
& .searchbar-separator {
|
||||||
|
margin: 4px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search suggestions. */
|
||||||
|
& .autocomplete-richlistitem,
|
||||||
|
& .search-panel-header {
|
||||||
|
padding-block: 2px !important;
|
||||||
|
padding-inline: var(--uc-contextmenu-menuitem-padding-inline) !important;
|
||||||
|
margin: 0 var(--uc-arrowpanel-menuitem-margin-inline) !important;
|
||||||
|
border-radius: var(--arrowpanel-menuitem-border-radius) !important;
|
||||||
|
|
||||||
|
& > .ac-type-icon {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search engine selector. */
|
||||||
|
& .search-one-offs {
|
||||||
|
padding-block: 0 5px !important;
|
||||||
|
|
||||||
|
& #searchbar-one-offs-header-label {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .search-panel-one-offs-container {
|
||||||
|
margin-inline: 1px 7px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Context menu
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* disable context menu when this tweak is applied */
|
||||||
|
@media not (-moz-bool-pref: "uc.tweak.revert-context-menu") {
|
||||||
|
/* Context Menu */
|
||||||
|
menupopup:not(.PanelUI-subView),
|
||||||
|
menupopup:not(.PanelUI-subView) menuitem,
|
||||||
|
menupopup:not(.PanelUI-subView) menu,
|
||||||
|
menupopup:not(.PanelUI-subView) menuseparator,
|
||||||
|
panel:not(#PopupSearchAutoComplete) {
|
||||||
|
appearance: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menupopup:not(.PanelUI-subView),
|
||||||
|
#PopupAutoComplete,
|
||||||
|
menulist > menupopup:not(.PanelUI-subView) > menucaption {
|
||||||
|
-moz-window-shadow: none !important;
|
||||||
|
background: 0 !important;
|
||||||
|
border: 0 !important;
|
||||||
|
color: var(--arrowpanel-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-internal-box,
|
||||||
|
#PopupAutoComplete > .autocomplete-richlistbox,
|
||||||
|
.menupopup-arrowscrollbox {
|
||||||
|
background: var(--arrowpanel-background) !important;
|
||||||
|
border: 1px solid var(--arrowpanel-border-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make room for menu shadow */
|
||||||
|
menupopup:not(.PanelUI-subView) {
|
||||||
|
padding: 4px 12px 20px !important;
|
||||||
|
margin: -6px -12px -16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cut off shadow so it doesn't get in the way of the menubar items */
|
||||||
|
menubar menupopup {
|
||||||
|
padding: 1px 8px 20px !important;
|
||||||
|
margin: -1px -4px -16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menupopup {
|
||||||
|
--uc-margin: 0 !important;
|
||||||
|
--uc-outline-color: #0001;
|
||||||
|
--uc-box-shadow:
|
||||||
|
0 8px 12px #0003,
|
||||||
|
0 4px 5px #0002,
|
||||||
|
0 2px 4px #0002;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme:dark) {
|
||||||
|
menupopup {
|
||||||
|
--uc-outline-color: #0002;
|
||||||
|
--uc-box-shadow:
|
||||||
|
0 8px 12px #0003,
|
||||||
|
0 4px 5px #0003,
|
||||||
|
0 2px 4px #0002;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use default shadow for subview menupopup (eg. bookmarks) */
|
||||||
|
menupopup.PanelUI-subView {
|
||||||
|
--uc-box-shadow: 0 0 0 1px var(--panel-border-color);
|
||||||
|
--uc-margin: 1px !important;
|
||||||
|
margin-top: -5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menupopup-arrowscrollbox {
|
||||||
|
box-shadow: var(--uc-box-shadow) !important;
|
||||||
|
outline: .5px solid var(--uc-outline-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-internal-box {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-internal-box,
|
||||||
|
.menupopup-arrowscrollbox {
|
||||||
|
padding: var(--uc-contextmenu-padding) !important;
|
||||||
|
border-radius: var(--uc-contextmenu-border-radius) !important;
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menupopup menu[disabled="true"],
|
||||||
|
menupopup menuitem[disabled="true"] {
|
||||||
|
color: var(--panel-disabled-color) !important;
|
||||||
|
background: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menupopup menu:hover:not([disabled=true]),
|
||||||
|
menupopup menuitem:hover:not([disabled=true]),
|
||||||
|
menupopup menu[_moz-menuactive]:not([disabled=true]),
|
||||||
|
menupopup menuitem[_moz-menuactive]:not([disabled=true]) {
|
||||||
|
background-color: var(--panel-item-hover-bgcolor) !important;
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menupopup menuitem:hover:active:not([disabled=true]),
|
||||||
|
menupopup menu:hover:active:not([disabled=true]) {
|
||||||
|
background-color: var(--panel-item-active-bgcolor) !important;
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menupopup menuseparator,
|
||||||
|
panel menuseparator,
|
||||||
|
#PopupSearchAutoComplete .searchbar-separator {
|
||||||
|
margin: var(--uc-contextmenu-separator-vertical) 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
background: none !important;
|
||||||
|
border-top: 1px solid var(--panel-separator-color) !important;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#PlacesToolbar menupopup[placespopup="true"] menuseparator::before {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menupopup menu,
|
||||||
|
menupopup menuitem,
|
||||||
|
menupopup menucaption,
|
||||||
|
#PopupAutoComplete > richlistbox > richlistitem,
|
||||||
|
#PopupSearchAutoComplete .autocomplete-richlistitem {
|
||||||
|
padding: var(--uc-contextmenu-menuitem-padding-block) var(--uc-contextmenu-menuitem-padding-inline) !important;
|
||||||
|
margin: var(--uc-contextmenu-menuitem-margin) !important;
|
||||||
|
border-radius: var(--uc-contextmenu-menuitem-border-radius) !important;
|
||||||
|
border: var(--uc-contextmenu-menuitem-border-width) solid transparent !important;
|
||||||
|
background-clip: padding-box !important;
|
||||||
|
min-height: calc(16px + (var(--uc-contextmenu-menuitem-padding-block) + var(--uc-contextmenu-menuitem-border-width)) * 2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(:not(menubar)>menu, #ContentSelectDropdown) > menupopup > menuitem:not(.menuitem-iconic, [type="checkbox"], [type="radio"], .in-menulist, .in-menulist menuitem, .unified-nav-current),
|
||||||
|
:not(:not(menubar)>menu, #ContentSelectDropdown) > menupopup > menu:not(.menu-iconic, [type="checkbox"], [type="radio"], .in-menulist, .in-menulist menu, .unified-nav-current),
|
||||||
|
:not(:not(menubar)>menu, #ContentSelectDropdown) > menupopup > menucaption {
|
||||||
|
padding-inline-start: calc(var(--uc-contextmenu-menuitem-padding-inline) + 16px + var(--uc-contextmenu-menuicon-margin-inline)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-iconic-icon {
|
||||||
|
margin-block: 0 !important;
|
||||||
|
margin-inline-end: 0 !important;
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu > .menu-iconic-text,
|
||||||
|
menuitem > .menu-iconic-text,
|
||||||
|
/* Used for vertical context navigation tweak. */
|
||||||
|
#context-navigation > .menuitem-iconic::after {
|
||||||
|
padding-inline-start: var(--uc-contextmenu-menuicon-margin-inline) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-text,
|
||||||
|
.menu-iconic-text {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
padding-block: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-accel,
|
||||||
|
.menu-iconic-accel {
|
||||||
|
margin-inline-end: 0 !important;
|
||||||
|
padding-block: 0 !important;
|
||||||
|
opacity: 0.7 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-iconic > .menu-iconic-left,
|
||||||
|
.menuitem-iconic > .menu-iconic-left {
|
||||||
|
padding-inline-end: 0 !important;
|
||||||
|
padding-block: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menuitem:is(.menuitem-iconic:not([data-usercontextid]), [type="checkbox"], [type="radio"], [checked], [selected]) .menu-iconic-icon {
|
||||||
|
-moz-context-properties: fill !important;
|
||||||
|
fill: currentColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-right,
|
||||||
|
.menu-accel-container {
|
||||||
|
appearance: none !important;
|
||||||
|
margin-inline-end: 0 !important;
|
||||||
|
-moz-context-properties: fill;
|
||||||
|
fill: currentColor !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menupopup menuitem:is([type="checkbox"], [type="radio"]) .menu-iconic-icon,
|
||||||
|
menulist > menupopup > menuitem .menu-iconic-icon,
|
||||||
|
menu .menu-right {
|
||||||
|
height: 16px !important;
|
||||||
|
width: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menulist > menupopup > menuitem:is([checked="true"], [selected="true"])::before,
|
||||||
|
menupopup > menuitem::before,
|
||||||
|
menupopup > menu::before,
|
||||||
|
menupopup > menuitem::after {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menuitem:is([type="checkbox"], [checked="true"], [type="radio"]) > .menu-iconic-left > .menu-iconic-icon {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
menuitem[checked="true"] > .menu-iconic-left,
|
||||||
|
menu > .menu-iconic-left,
|
||||||
|
menuitem > .menu-iconic-left {
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-navigation:not([hidden]) {
|
||||||
|
padding: 0 !important;
|
||||||
|
--menuitem-min-width: calc(16px + var(--uc-contextmenu-menuitem-padding-inline) * 2) !important;
|
||||||
|
min-width: calc(4 * var(--menuitem-min-width));
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-navigation > .menuitem-iconic > .menu-iconic-left > .menu-iconic-icon {
|
||||||
|
width: 16px !important;
|
||||||
|
height: 16px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-navigation {
|
||||||
|
margin-inline: var(--uc-contextmenu-menuitem-margin-inline) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-navigation > .menuitem-iconic {
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-navigation > .menuitem-iconic {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-navigation > .menuitem-iconic {
|
||||||
|
flex-grow: 1 !important;
|
||||||
|
width: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-navigation > .menuitem-iconic[_moz-menuactive="true"] > .menu-iconic-left > .menu-iconic-icon {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-bookmarkpage[starred] .menu-iconic-icon {
|
||||||
|
fill: var(--lwt-toolbarbutton-icon-fill-attention, var(--toolbarbutton-icon-fill-attention, currentColor)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (not (-moz-bool-pref: "uc.tweak.smaller-context-menu-text")) and (-moz-platform: windows) {
|
||||||
|
.menu-text,
|
||||||
|
.menu-iconic-text,
|
||||||
|
panel .toolbarbutton-text,
|
||||||
|
#PopupSearchAutoComplete .ac-title,
|
||||||
|
/* Used for vertical context navigation tweak. */
|
||||||
|
#context-navigation > .menuitem-iconic::after {
|
||||||
|
margin-inline-start: 0 !important;
|
||||||
|
margin-block: -3px -1px !important;
|
||||||
|
padding-block: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-text,
|
||||||
|
.menu-iconic-text,
|
||||||
|
panel .toolbarbutton-text,
|
||||||
|
#appMenu-fxa-status2,
|
||||||
|
.panel-header,
|
||||||
|
#PopupSearchAutoComplete,
|
||||||
|
/* Used for vertical context navigation tweak. */
|
||||||
|
#context-navigation > .menuitem-iconic::after {
|
||||||
|
font-size: 13.6px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Dialog box
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Dialog shadow and outline adjustments. */
|
||||||
|
.dialogBox:not(.spotlightBox) {
|
||||||
|
border-radius: 8px !important;
|
||||||
|
outline: 0.5px solid var(--panel-separator-color) !important;
|
||||||
|
box-shadow:
|
||||||
|
0 20px 38px rgb(0 0 0 / 0.23),
|
||||||
|
0 5px 9px rgb(0 0 0 / 0.22) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog {
|
||||||
|
/* Dialog title. */
|
||||||
|
& #titleContainer {
|
||||||
|
/* Add larger gap between icon and title text. */
|
||||||
|
& .titleIcon {
|
||||||
|
padding-inline-end: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Match font style in Edge. */
|
||||||
|
& #titleText {
|
||||||
|
font-size: 1.18em !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust vertical alignment of title text. */
|
||||||
|
@media (-moz-platform: macOS) {
|
||||||
|
&:not([noicon]) > #titleCropper {
|
||||||
|
translate: 0 calc(-1px - max(.55 * var(--icon-size) - .6em, 0px)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input focus style. */
|
||||||
|
& input:where([type="email"], [type="tel"], [type="text"], [type="password"], [type="url"], [type="number"]):focus {
|
||||||
|
outline: 2px solid var(--in-content-box-border-color) !important;
|
||||||
|
outline-offset: -2px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FF123+ tab preview pop-up.
|
||||||
|
* CSS reference: https://searchfox.org/mozilla-central/source/browser/components/tabpreview/tabpreview.css
|
||||||
|
* Requires `browser.tabs.cardPreview.enabled` set to `true` */
|
||||||
|
.tab-preview-container {
|
||||||
|
background-color: var(--arrowpanel-background) !important;
|
||||||
|
color: var(--arrowpanel-color) !important;
|
||||||
|
border: 0.5px solid var(--panel-separator-color) !important;
|
||||||
|
border-radius: 8.5px !important;
|
||||||
|
|
||||||
|
/* Place thumbnail at the top of the tooltip. */
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column-reverse !important;
|
||||||
|
|
||||||
|
& .tab-preview-uri {
|
||||||
|
color: var(--panel-description-color) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/* Edge-Frfox - tree.css */
|
||||||
|
|
||||||
|
/* Change height of tree items and add rounded corners */
|
||||||
|
treechildren::-moz-tree-row,
|
||||||
|
treecol:not([hideheader="true"]),
|
||||||
|
.tree-columnpicker-button {
|
||||||
|
min-height: max(28px, 1.3em) !important;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the background colour on hover */
|
||||||
|
@media not (prefers-contrast) {
|
||||||
|
treechildren::-moz-tree-row(hover) {
|
||||||
|
background-color: var(--toolbarbutton-hover-background) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the background colour when pressed */
|
||||||
|
treechildren::-moz-tree-row(selected) {
|
||||||
|
background-color: var(--toolbarbutton-active-background) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the background colour when focused */
|
||||||
|
treechildren::-moz-tree-row(selected, focus) {
|
||||||
|
background-color: var(--button-primary-bgcolor) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-row(current, focus) {
|
||||||
|
outline: var(--default-focusring);
|
||||||
|
outline-color: var(--button-primary-bgcolor) !important;
|
||||||
|
outline-offset: calc(-1 * var(--default-focusring-width));
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(selected),
|
||||||
|
treechildren::-moz-tree-twisty(selected),
|
||||||
|
treechildren::-moz-tree-cell-text(selected) {
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-image(selected, focus),
|
||||||
|
treechildren::-moz-tree-twisty(selected, focus),
|
||||||
|
treechildren::-moz-tree-cell-text(selected, focus) {
|
||||||
|
color: var(--button-primary-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spacing between icon and label */
|
||||||
|
treechildren::-moz-tree-image {
|
||||||
|
margin-inline-end: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Separator appearance */
|
||||||
|
treechildren::-moz-tree-separator {
|
||||||
|
border-top: 1px solid var(--toolbarseparator-color) !important;
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the colour of the drop feedback elements */
|
||||||
|
treechildren::-moz-tree-cell-text(primary, dropOn) {
|
||||||
|
background-color: var(--button-primary-bgcolor) !important;
|
||||||
|
color: var(--button-primary-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-drop-feedback {
|
||||||
|
background-color: var(--toolbarbutton-icon-fill-attention) !important;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the appearance for the expandable items */
|
||||||
|
treechildren::-moz-tree-twisty {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
padding-inline: 4px !important;
|
||||||
|
width: 16px !important;
|
||||||
|
list-style-image: url("../icons/arrow-filled-right.svg") !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren:-moz-locale-dir(rtl)::-moz-tree-twisty(closed) {
|
||||||
|
list-style-image: url("../icons/arrow-filled-left.svg") !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
treechildren::-moz-tree-twisty(open) {
|
||||||
|
list-style-image: url("../icons/arrow-filled-down.svg") !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the identation of child items */
|
||||||
|
treechildren::-moz-tree-indentation {
|
||||||
|
width: 16px !important;
|
||||||
|
}
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
/* Edge-Frfox - tweaks.css */
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Disable drag space
|
||||||
|
*/
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.disable-drag-space") {
|
||||||
|
/* disable drag space above tabs */
|
||||||
|
:root {
|
||||||
|
--uc-tab-top-margin: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Force tab colour
|
||||||
|
*/
|
||||||
|
/* force tabs to toolbar bg (useful for proton themes) (might experience some
|
||||||
|
bugs with certain themes eg. dark text on dark background.) */
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.force-tab-colour") {
|
||||||
|
:root[lwtheme] {
|
||||||
|
--tab-selected-bgcolor: var(--toolbar-bgcolor) !important;
|
||||||
|
--tab-selected-textcolor: var(--toolbar-color) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Remove tab separators
|
||||||
|
*/
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.remove-tab-separators") {
|
||||||
|
.tabbrowser-tab .tab-stack {
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: initial !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Floating tabs
|
||||||
|
*/
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.floating-tabs") {
|
||||||
|
:root:not([lwtheme]),
|
||||||
|
/* `--newtab-background-color-secondary used` to differentiate between a dark
|
||||||
|
* private window and private window with the 'Dark' theme enabled.
|
||||||
|
* May not be the most reliable method, but works for now up to FF 123. */
|
||||||
|
:root[privatebrowsingmode="temporary"]:where([style*="--lwt-accent-color: rgb(28, 27, 34)"]:not([style*="--newtab-background-color-secondary: rgb(66, 65, 77)"])) {
|
||||||
|
--lwt-accent-color: light-dark(#f3f3f3, #202020) !important;
|
||||||
|
--lwt-accent-color-inactive: unset !important;
|
||||||
|
--toolbar-bgcolor: light-dark(#fff, #3F3F3F) !important;
|
||||||
|
--lwt-tab-text: light-dark(#262626, #fff) !important;
|
||||||
|
--chrome-content-separator-color: light-dark(#bfbfbf, #535353) !important;
|
||||||
|
--lwt-tab-line-color: light-dark(transparent, rgb(255 255 255 / 0.06)) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Uses :root body to avoid affecting other variables by changing
|
||||||
|
* --toolbar-color. */
|
||||||
|
:root body {
|
||||||
|
/* Use tabbar colours for better readability when using custom themes. */
|
||||||
|
--toolbar-color: var(--lwt-text-color) !important;
|
||||||
|
--toolbarbutton-icon-fill: var(--lwt-text-color) !important;
|
||||||
|
|
||||||
|
&:-moz-window-inactive {
|
||||||
|
--toolbar-color: var(--lwt-text-color-inactive, var(--lwt-text-color)) !important;
|
||||||
|
--toolbarbutton-icon-fill: var(--lwt-text-color-inactive, var(--lwt-text-color)) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (-moz-gtk-csd-available) {
|
||||||
|
:root:not([lwtheme]) {
|
||||||
|
--toolbar-bgcolor: color-mix(in srgb, -moz-dialog 80%, #fff) !important;
|
||||||
|
--toolbar-field-background-color: Field !important;
|
||||||
|
--lwt-tab-text: -moz-dialogtext !important;
|
||||||
|
--lwt-tab-line-color: rgb(255 255 255 / 0.06) !important;
|
||||||
|
--lwt-accent-color: var(--toolbox-non-lwt-bgcolor) !important;
|
||||||
|
|
||||||
|
&:-moz-window-inactive {
|
||||||
|
--lwt-accent-color: var(--toolbox-non-lwt-bgcolor-inactive) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shadow for navbar and tabs */
|
||||||
|
:root,
|
||||||
|
:root .tabbrowser-tab {
|
||||||
|
--uc-titlebar-shadow: none;
|
||||||
|
--uc-tab-shadow-outline: rgb(0 0 0 / .11);
|
||||||
|
--uc-tab-shadow: 0 2.5px 3px 1px rgb(0 0 0 / .08);
|
||||||
|
|
||||||
|
& [brighttext],
|
||||||
|
& [brighttext] .tabbrowser-tab {
|
||||||
|
--uc-titlebar-shadow: none;
|
||||||
|
--uc-tab-shadow-outline: transparent;
|
||||||
|
--uc-tab-shadow: 0 2px 3px rgb(0 0 0 / .12);
|
||||||
|
}
|
||||||
|
|
||||||
|
& #TabsToolbar {
|
||||||
|
--tab-border-radius: 8px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove toolbar bg */
|
||||||
|
#nav-bar,
|
||||||
|
#PersonalToolbar {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* invert bottom corner radius for tabs */
|
||||||
|
.tab-background {
|
||||||
|
border-radius: var(--tab-border-radius) !important;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-background[selected] {
|
||||||
|
border: 1px solid var(--lwt-tab-line-color, var(--lwt-tabs-border-color, transparent)) !important;
|
||||||
|
outline: 1px solid var(--uc-tab-shadow-outline) !important;
|
||||||
|
|
||||||
|
/* Fractional scaling adjustments (150%, 175%, etc.) */
|
||||||
|
@media (1dppx < resolution < 2dppx) {
|
||||||
|
outline-width: 1.5px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust spacing of area above tabs */
|
||||||
|
@media not (-moz-platform: macos) {
|
||||||
|
:root[sizemode="maximized"] {
|
||||||
|
--uc-tab-top-margin: 4px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:root:is([inFullscreen], :not([tabsintitlebar])) {
|
||||||
|
--uc-tab-top-margin: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.disable-drag-space") {
|
||||||
|
:root {
|
||||||
|
--uc-tab-top-margin: 4px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IMPORTANT: Adds padding and removes margin on top of tabs to allow user to
|
||||||
|
* select it from the top edge of the window */
|
||||||
|
#tabbrowser-tabs {
|
||||||
|
margin-top: calc(var(--uc-tab-top-margin) - 4px) !important;
|
||||||
|
|
||||||
|
& .tabbrowser-tab,
|
||||||
|
& #tabs-newtab-button {
|
||||||
|
padding-top: 4px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#scrollbutton-up:not(.menupopup-scrollbutton),
|
||||||
|
#scrollbutton-down:not(.menupopup-scrollbutton) {
|
||||||
|
&,
|
||||||
|
& ~ spacer {
|
||||||
|
margin-top: 4px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move tab shadow behind urlbar */
|
||||||
|
.tabbrowser-tab[visuallyselected="true"],
|
||||||
|
#nav-bar {
|
||||||
|
z-index: 2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tab shadow adjustments */
|
||||||
|
.tabbrowser-tab {
|
||||||
|
overflow-clip-margin: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabbrowser-arrowscrollbox > *,
|
||||||
|
#scrollbutton-up:not(.menupopup-scrollbutton),
|
||||||
|
#scrollbutton-up:not(.menupopup-scrollbutton) ~ spacer,
|
||||||
|
#scrollbutton-down:not(.menupopup-scrollbutton) {
|
||||||
|
margin-bottom: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabbrowser-arrowscrollbox {
|
||||||
|
margin-bottom: -8px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Vertical context nav
|
||||||
|
*/
|
||||||
|
@media (not (-moz-platform: macos)) and (not (-moz-bool-pref: "uc.tweak.revert-context-menu")) {
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.vertical-context-navigation") {
|
||||||
|
#context-navigation {
|
||||||
|
/* Stack menu items vertically. */
|
||||||
|
flex-direction: column !important;
|
||||||
|
|
||||||
|
/* Align the image and label to the left edge. */
|
||||||
|
& > .menuitem-iconic {
|
||||||
|
justify-content: start !important;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
/* Get the menuitem label from the aria-label attribute. */
|
||||||
|
content: attr(aria-label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Hide access key
|
||||||
|
*/
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.context-menu.hide-access-key") {
|
||||||
|
:where(menuitem, menu) > :is(.menu-text, .menu-iconic-text)[value]:not([value=""]) {
|
||||||
|
&::before {
|
||||||
|
/* The default value is -moz-label-content, which takes the data from the
|
||||||
|
* value attribute and highlights the character found in the accesskey
|
||||||
|
* attribute. This skips that and uses the value attribute directly. */
|
||||||
|
content: attr(value) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Show tab close button
|
||||||
|
*/
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.show-tab-close-button-on-hover") {
|
||||||
|
#tabbrowser-tabs[closebuttons="activetab"] .tabbrowser-tab:not([pinned], [selected]):hover .tab-close-button {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Hide forward button
|
||||||
|
*/
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.hide-forward-button") {
|
||||||
|
:root:not([customizing]) #forward-button[disabled] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
MARK: Hide Firefox account
|
||||||
|
*/
|
||||||
|
@media (-moz-bool-pref: "uc.tweak.context-menu.hide-firefox-account") {
|
||||||
|
#appMenu-fxa-status2,
|
||||||
|
#appMenu-fxa-separator {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M8 0a2.5 2.5 0 0 0-2.396 3.213l-2.24-.847a1.746 1.746 0 0 0-1.245 3.26L5 6.736v2.398l-1.643 4.524a1.747 1.747 0 0 0 3.284 1.194L8 11.145l1.365 3.702a1.745 1.745 0 0 0 3.278-1.2L11 9.124V6.73l2.867-1.087a1.752 1.752 0 1 0-1.244-3.278l-2.227.843A2.5 2.5 0 0 0 8 0zm0 1a1.5 1.5 0 1 1 0 2.999 1.5 1.5 0 0 1 0-3zM2.729 3.252a.74.74 0 0 1 .28.05l4.104 1.551c.571.216 1.201.216 1.772 0l4.094-1.552a.754.754 0 1 1 .535 1.41l-3.192 1.208a.498.498 0 0 0-.322.467V9.21c0 .058.01.117.03.171l1.673 4.608a.745.745 0 0 1-1.4.511l-1.37-3.719c-.319-.867-1.547-.866-1.865.002L5.703 14.51a.747.747 0 1 1-1.404-.511l1.67-4.606A.497.497 0 0 0 6 9.222v-2.83a.5.5 0 0 0-.32-.467L2.479 4.693a.745.745 0 0 1 .25-1.44z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 834 B |
@@ -0,0 +1,13 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="a" x1="4.22" x2="11.78" y1="7.979" y2="7.979" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#b2b2b2" offset="0"/>
|
||||||
|
<stop stop-color="#b2b2b2" stop-opacity="0" offset="1"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<path fill="#303030" d="M0 0h16v16H0z"/>
|
||||||
|
<g fill="url(#a)">
|
||||||
|
<circle cx="8" cy="5.767" r="2.433"/>
|
||||||
|
<path d="M5.244 8.867c-.613 0-1.024.46-1.024 1.107 0 1.949 1.996 2.651 3.78 2.651 1.784 0 3.78-.702 3.78-2.651 0-.648-.41-1.107-1.023-1.107z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 584 B |
@@ -0,0 +1,7 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill="#fafafa" d="M0 0h16v16H0z"/>
|
||||||
|
<g fill="#8f8f8f">
|
||||||
|
<circle cx="8" cy="5.767" r="2.433"/>
|
||||||
|
<path d="M5.244 8.867c-.613 0-1.024.46-1.024 1.107 0 1.949 1.996 2.651 3.78 2.651 1.784 0 3.78-.702 3.78-2.651 0-.648-.41-1.107-1.023-1.107z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 332 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h4.35a5.769 5.769 0 0 1-1.076-1H4.001a1 1 0 0 1-1-1h3.605a5.376 5.376 0 0 1-.406-1H3V2a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v4.199a5.2 5.2 0 0 1 1 .398V2a2 2 0 0 0-2-2H4zm1 2a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H5zm0 1h6v1H5V3z"/>
|
||||||
|
<path d="M16 11.5a4.5 4.5 0 1 1-9 0 4.5 4.5 0 0 1 9 0zm-4-2a.5.5 0 0 0-1 0V11H9.5a.5.5 0 0 0 0 1H11v1.5a.5.5 0 0 0 1 0V12h1.5a.5.5 0 0 0 0-1H12z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 571 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M8 11.5a.547.547 0 0 1-.389-.162L2.146 5.854a.5.5 0 1 1 .707-.705L8 10.313l5.146-5.164a.5.5 0 1 1 .71.705l-5.466 5.484A.55.55 0 0 1 8 11.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 281 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path transform="rotate(90)" transform-origin="center" d="M6.479 2.729 11.1 7.35a.92.92 0 0 1 0 1.3l-4.621 4.621a.72.72 0 0 1-1.229-.509V3.237a.72.72 0 0 1 1.229-.508z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 300 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path transform="rotate(180)" transform-origin="center" d="M6.479 2.729 11.1 7.35a.92.92 0 0 1 0 1.3l-4.621 4.621a.72.72 0 0 1-1.229-.509V3.237a.72.72 0 0 1 1.229-.508z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 301 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M6.479 2.729 11.1 7.35a.92.92 0 0 1 0 1.3l-4.621 4.621a.72.72 0 0 1-1.229-.509V3.237a.72.72 0 0 1 1.229-.508z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 251 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path transform="scale(-1 1) translate(-16 0)" d="M5.5 2a.5.5 0 0 0-.354.853L10.313 8l-5.167 5.146a.5.5 0 0 0 .707.71l5.484-5.468a.548.548 0 0 0 0-.777L5.853 2.143A.496.496 0 0 0 5.5 2z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 318 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M5.5 2a.5.5 0 0 0-.354.853L10.313 8l-5.167 5.146a.5.5 0 0 0 .707.71l5.484-5.468a.548.548 0 0 0 0-.777L5.853 2.143A.496.496 0 0 0 5.5 2z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 277 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M8 4.5a.547.547 0 0 0-.389.162l-5.465 5.484a.5.5 0 1 0 .707.705L8 5.687l5.146 5.164a.5.5 0 1 0 .71-.705L8.388 4.662A.55.55 0 0 0 8 4.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 277 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M14.13 7c-.478 0-.957.18-1.322.547l-4.828 4.83a2.2 2.2 0 0 0-.578 1.02l-.375 1.498a.889.889 0 0 0 1.078 1.078l1.498-.375a2.2 2.2 0 0 0 1.02-.578l4.828-4.828A1.872 1.872 0 0 0 14.13 7zm-.002 1.002c.427.002.671.224.8.537.13.314.116.643-.187.947l-4.826 4.826a1.204 1.204 0 0 1-.556.315l-1.316.332.33-1.32H8.37c.053-.21.163-.403.316-.557l4.828-4.83a.85.85 0 0 1 .614-.25zm-6.266 7 .002.002H7.86z"/>
|
||||||
|
<path d="M12.94.182c-.08.004-.162.02-.242.045l-7 2.188a.998.998 0 0 0-.701.953V11.5a2.5 2.5 0 1 0 1 2V6.368l7-2.188v2.055c.32-.137.66-.213 1-.229V1.18c0-.59-.5-1.032-1.057-.998zm.057.998v1.953l-7 2.188V3.368l7-2.188zM3.497 12a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 801 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<defs><clipPath id="a"><path d="M2.1 0 16 13.9V0zM0 .7V16h15.3z"/></clipPath></defs>
|
||||||
|
<path clip-path="url(#a)" d="M12.94.182c-.08.004-.162.017-.242.043l-7 2.188a1 1 0 0 0-.701.955V11.5a2.5 2.5 0 1 0 1 2V6.368l7-2.188V9.5a2.5 2.5 0 1 0 1 2V1.18c0-.59-.5-1.032-1.057-.998zm.057.998v1.953l-7 2.188V3.368l7-2.188zm-1.5 8.82a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm-8 2a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3z"/>
|
||||||
|
<path d="M.5 0a.5.5 0 0 0-.354.146.5.5 0 0 0 0 .707l15 15a.5.5 0 0 0 .707 0 .5.5 0 0 0 0-.707l-15-15A.5.5 0 0 0 .499 0z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 658 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M12.94.182c-.08.004-.162.017-.242.043l-7 2.188a1 1 0 0 0-.701.955V11.5a2.5 2.5 0 1 0 1 2V6.368l7-2.188V9.5a2.5 2.5 0 1 0 1 2V1.18c0-.59-.5-1.032-1.057-.998zm.057.998v1.953l-7 2.188V3.368l7-2.188zm-1.5 8.82a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm-8 2a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 426 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M7.527.5a.5.5 0 0 0-.361.127L.322 6.764a.998.998 0 0 0 0 1.473l6.844 6.137a.5.5 0 0 0 .707-.04.5.5 0 0 0-.04-.706L1.558 8h13.44a.5.5 0 0 0 0-1H1.557l6.277-5.627a.5.5 0 0 0 .039-.707A.5.5 0 0 0 7.527.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 343 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M8.002.3a.99.99 0 0 0-.898.557L5.174 4.77l-4.316.627a1 1 0 0 0-.555 1.705l3.123 3.045-.736 4.3A1 1 0 0 0 4.14 15.5l3.862-2.029 3.859 2.03a1 1 0 0 0 1.45-1.056l-.736-4.299 3.123-3.045a1 1 0 0 0-.554-1.705l-4.316-.627L8.898.857A.987.987 0 0 0 8 .301zm0 1 1.93 3.91c.146.296.426.5.752.548l4.318.629-3.125 3.043c-.236.23-.343.562-.287.886l.738 4.3-3.86-2.03a1.002 1.002 0 0 0-.932 0l-3.86 2.03.737-4.3a1.003 1.003 0 0 0-.287-.886L1.003 6.387l4.316-.63a.998.998 0 0 0 .752-.546z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 615 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="context-fill" stroke-opacity="context-fill-opacity" stroke-linecap="round" stroke-width="1.001">
|
||||||
|
<path d="m8 12.95-4.09 2.151a.501.501 0 0 1-.727-.528l.731-4.266a.561.562 0 0 0-.161-.498L.655 6.79a.501.501 0 0 1 .278-.855l4.28-.623a.561.562 0 0 0 .423-.307L7.55 1.123a.501.501 0 0 1 .9 0l2.031 4.115a.475.475 0 0 0 .426.264H15.5"/>
|
||||||
|
<path d="M15.5 8.5h-5M10.5 11.5h5"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 463 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M8.002.3a.99.99 0 0 0-.898.557L5.174 4.77l-4.316.627a1 1 0 0 0-.555 1.705l3.123 3.045-.736 4.3A1 1 0 0 0 4.14 15.5l3.862-2.029 3.859 2.03a1 1 0 0 0 1.45-1.056l-.736-4.299 3.123-3.045a1 1 0 0 0-.554-1.705l-4.316-.627L8.898.857A.987.987 0 0 0 8 .301z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 390 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<defs><clipPath id="a"><path d="M2.1 0 16 13.9V0zM0 .7V16h15.3z"/></clipPath></defs>
|
||||||
|
<path clip-path="url(#a)" d="M6.119 0a1.5 1.5 0 0 0-1.34.826L4.189 2H2.5A2.5 2.5 0 0 0 0 4.5v8A2.5 2.5 0 0 0 2.5 15h11a2.5 2.5 0 0 0 2.5-2.5v-8A2.5 2.5 0 0 0 13.5 2h-1.689L11.225.83A1.501 1.501 0 0 0 9.883 0H6.12zm0 1h3.764a.5.5 0 0 1 .447.277l.725 1.445c.085.17.256.278.445.278h2A1.5 1.5 0 0 1 15 4.5v8a1.5 1.5 0 0 1-1.5 1.5h-11A1.5 1.5 0 0 1 1 12.5v-8A1.5 1.5 0 0 1 2.5 3h1.998a.5.5 0 0 0 .447-.276l.727-1.449A.5.5 0 0 1 6.12 1zm1.877 3a4 4 0 1 0 0 8 4 4 0 0 0 0-8zm0 1a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/>
|
||||||
|
<path d="M.5 0a.5.5 0 0 0-.354.146.5.5 0 0 0 0 .707l15 15a.5.5 0 0 0 .707 0 .5.5 0 0 0 0-.707l-15-15A.5.5 0 0 0 .499 0z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 845 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M6.119 0a1.5 1.5 0 0 0-1.34.826L4.189 2H2.5A2.5 2.5 0 0 0 0 4.5v8A2.5 2.5 0 0 0 2.5 15h11a2.5 2.5 0 0 0 2.5-2.5v-8A2.5 2.5 0 0 0 13.5 2h-1.689L11.225.83A1.501 1.501 0 0 0 9.883 0H6.12zm0 1h3.764a.5.5 0 0 1 .447.277l.725 1.445c.085.17.256.278.445.278h2A1.5 1.5 0 0 1 15 4.5v8a1.5 1.5 0 0 1-1.5 1.5h-11A1.5 1.5 0 0 1 1 12.5v-8A1.5 1.5 0 0 1 2.5 3h1.998a.5.5 0 0 0 .447-.276l.727-1.449A.5.5 0 0 1 6.12 1zm1.877 3a4 4 0 1 0 0 8 4 4 0 0 0 0-8zm0 1a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 613 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<defs><clipPath id="a"><path d="M2.1 0 16 13.9V0zM0 .7V16h15.3z"/></clipPath></defs>
|
||||||
|
<path clip-path="url(#a)" d="M4 1a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3V4a3 3 0 0 0-3-3H4zm0 1h8a2 2 0 0 1 2 2v8c0 .373-.102.72-.28 1.02L9.05 8.432a1.5 1.5 0 0 0-2.101 0l-4.67 4.588a1.988 1.988 0 0 1-.28-1.02V4a2 2 0 0 1 2-2zm6.5 2a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zm0 1a.5.5 0 1 1 0 1 .5.5 0 0 1 0-1zM8 9.002c.127 0 .252.047.35.143l4.662 4.582A1.99 1.99 0 0 1 12 14H4c-.37 0-.715-.099-1.012-.273L7.65 9.145A.496.496 0 0 1 8 9.002z"/>
|
||||||
|
<path d="M.5 0a.5.5 0 0 0-.354.146.5.5 0 0 0 0 .707l15 15a.5.5 0 0 0 .707 0 .5.5 0 0 0 0-.707l-15-15A.5.5 0 0 0 .499 0z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 786 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M4 1a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3V4a3 3 0 0 0-3-3H4zm0 1h8a2 2 0 0 1 2 2v8c0 .373-.102.72-.28 1.02L9.05 8.432a1.5 1.5 0 0 0-2.101 0l-4.67 4.588a1.988 1.988 0 0 1-.28-1.02V4a2 2 0 0 1 2-2zm6.5 2a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zm0 1a.5.5 0 1 1 0 1 .5.5 0 0 1 0-1zM8 9.002c.127 0 .252.047.35.143l4.662 4.582A1.99 1.99 0 0 1 12 14H4c-.37 0-.715-.099-1.012-.273L7.65 9.145A.496.496 0 0 1 8 9.002z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 554 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M14.5 2a.5.5 0 0 0-.379.174l-9.129 10.57-4.12-4.578a.5.5 0 0 0-.706-.037.5.5 0 0 0-.037.705l4.5 5a.5.5 0 0 0 .75-.008l9.5-11a.5.5 0 0 0-.053-.705A.5.5 0 0 0 14.5 2z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 306 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M2.5 2a.5.5 0 0 0-.353.146.5.5 0 0 0 0 .708L7.293 8l-5.146 5.145a.5.5 0 0 0 0 .707.5.5 0 0 0 .707 0l5.5-5.5a.5.5 0 0 0 0-.707l-5.5-5.5A.5.5 0 0 0 2.5 2z"/>
|
||||||
|
<path d="M8.146 2.146a.5.5 0 0 0 0 .707l5.146 5.146-5.146 5.146a.5.5 0 0 0 0 .707.5.5 0 0 0 .707 0l5.5-5.5a.5.5 0 0 0 0-.707l-5.5-5.5a.5.5 0 0 0-.707 0z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 452 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="9" height="9" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M1 .412a.588.588 0 0 0-.416.172.588.588 0 0 0 0 .832L3.668 4.5.584 7.584a.588.588 0 0 0 0 .832.588.588 0 0 0 .832 0L4.5 5.332l3.084 3.084a.588.588 0 0 0 .832 0 .588.588 0 0 0 0-.832L5.332 4.5l3.084-3.084a.588.588 0 0 0 0-.832.588.588 0 0 0-.832 0L4.5 3.668 1.416.584A.588.588 0 0 0 1 .412z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 429 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M2.5 2a.5.5 0 0 0-.353.146.5.5 0 0 0 0 .708L7.293 8l-5.146 5.145a.5.5 0 0 0 0 .707.5.5 0 0 0 .707 0L8 8.706l5.146 5.146a.5.5 0 0 0 .706 0 .5.5 0 0 0 0-.707L8.708 8l5.146-5.146a.5.5 0 0 0 0-.707.5.5 0 0 0-.707 0L8 7.292 2.854 2.146A.5.5 0 0 0 2.5 2z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 390 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M2 0C.901 0 0 .901 0 2v1.5a.5.5 0 0 0 .5.5.5.5 0 0 0 .5-.5V2c0-.558.442-1 1-1h1.5A.5.5 0 0 0 4 .5a.5.5 0 0 0-.5-.5H2zm10.5 0a.5.5 0 0 0-.5.5.5.5 0 0 0 .5.5H14c.558 0 1 .442 1 1v1.5a.5.5 0 0 0 .5.5.5.5 0 0 0 .5-.5V2c0-1.099-.901-2-2-2h-1.5zm-8 2A2.508 2.508 0 0 0 2 4.5v7C2 12.875 3.125 14 4.5 14h7c1.375 0 2.5-1.125 2.5-2.5v-7C14 3.125 12.875 2 11.5 2h-7zm0 1H7v1.5C7 5.323 7.677 6 8.5 6H13v5.5c0 .834-.666 1.5-1.5 1.5h-7c-.834 0-1.5-.666-1.5-1.5v-7C3 3.666 3.666 3 4.5 3zM8 3h3.5c.834 0 1.5.666 1.5 1.5V5H8.5a.493.493 0 0 1-.5-.5V3zM.5 12a.5.5 0 0 0-.5.5V14c0 1.099.901 2 2 2h1.5a.5.5 0 0 0 .5-.5.5.5 0 0 0-.5-.5H2c-.558 0-1-.442-1-1v-1.5a.5.5 0 0 0-.5-.5zm15 0a.5.5 0 0 0-.5.5V14c0 .558-.442 1-1 1h-1.5a.5.5 0 0 0-.5.5.5.5 0 0 0 .5.5H14c1.099 0 2-.901 2-2v-1.5a.5.5 0 0 0-.5-.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 922 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M3.5 0a.5.5 0 0 0-.5.5v8.504a2 2 0 0 0 2 2h1.004v2.998a2 2 0 1 0 4 0v-2.998H11a2 2 0 0 0 2-2V.5a.5.5 0 0 0-.5-.5h-9zM4 1h4v1.5a.5.5 0 1 0 1 0V1h1v2.502a.5.5 0 0 0 1 0V1h1v6.004H4V1zm0 7.004h8v1a1 1 0 0 1-1 1H9.504a.5.5 0 0 0-.5.5v3.498a1 1 0 1 1-2 0v-3.498a.5.5 0 0 0-.5-.5H5a1 1 0 0 1-1-1v-1z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 435 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<defs><clipPath id="a"><path d="M2.1 0 16 13.9V0zM0 .7V16h15.3z"/></clipPath></defs>
|
||||||
|
<path clip-path="url(#a)" d="M8 0C4.692 0 2 2.692 2 6v3.4l-.928 2.229c-.265.636.225 1.371.914 1.371H5.5c0 1.375 1.125 2.5 2.5 2.5s2.5-1.125 2.5-2.5h3.514c.69 0 1.18-.735.914-1.371L14.001 9.4V6c0-3.308-2.692-6-6-6zm0 1c2.767 0 5 2.233 5 5v3.5a.5.5 0 0 0 .04.191l.96 2.31H2l.96-2.31A.5.5 0 0 0 3 9.5V6c0-2.767 2.233-5 5-5zM6.5 13h3c0 .834-.666 1.5-1.5 1.5s-1.5-.666-1.5-1.5z" style="-inkscape-stroke:none;color:#000;stroke-linecap:round;stroke-linejoin:round"/>
|
||||||
|
<path d="M.5 0a.5.5 0 0 0-.354.146.5.5 0 0 0 0 .707l15 15a.5.5 0 0 0 .707 0 .5.5 0 0 0 0-.707l-15-15A.5.5 0 0 0 .499 0z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 801 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M8 0C4.692 0 2 2.692 2 6v3.4l-.928 2.229c-.265.636.225 1.371.914 1.371H5.5c0 1.375 1.125 2.5 2.5 2.5s2.5-1.125 2.5-2.5h3.514c.69 0 1.18-.735.914-1.371L14.001 9.4V6c0-3.308-2.692-6-6-6zm0 1c2.767 0 5 2.233 5 5v3.5a.5.5 0 0 0 .04.191l.96 2.31H2l.96-2.31A.5.5 0 0 0 3 9.5V6c0-2.767 2.233-5 5-5zM6.5 13h3c0 .834-.666 1.5-1.5 1.5s-1.5-.666-1.5-1.5z" style="-inkscape-stroke:none;color:#000;stroke-linecap:round;stroke-linejoin:round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 569 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M11.5 0a4.5 4.5 0 0 0-4.418 5.36L.656 12.016a2.358 2.358 0 0 0 3.375 3.294l6.365-6.447a4.5 4.5 0 0 0 5.207-6.215.503.503 0 0 0-.81-.149L12.5 4.793 11.207 3.5 13.5 1.207A.5.5 0 0 0 13.353.4 4.49 4.49 0 0 0 11.499 0zm0 1c.247 0 .487.026.719.074l-2.072 2.072a.5.5 0 0 0 0 .707l2 2a.5.5 0 0 0 .707 0l2.072-2.072a3.5 3.5 0 0 1-4.52 4.045.502.502 0 0 0-.514.123L3.32 14.61a1.358 1.358 0 0 1-1.943-1.896L7.99 5.859a.498.498 0 0 0 .123-.473A3.5 3.5 0 0 1 11.5.999z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 598 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M8 0a.5.5 0 0 0-.5.5v10.79L3.854 7.644a.5.5 0 1 0-.707.707l4.5 4.5a.5.5 0 0 0 .707 0l4.5-4.5a.5.5 0 0 0-.707-.707L8.501 11.29V.5a.5.5 0 0 0-.5-.5z"/>
|
||||||
|
<path d="M1.5 12a.5.5 0 0 0-.5.5v1C1 14.875 2.125 16 3.5 16h9c1.375 0 2.5-1.125 2.5-2.5v-1a.5.5 0 0 0-1 0v1c0 .834-.666 1.5-1.5 1.5h-9c-.834 0-1.5-.666-1.5-1.5v-1a.5.5 0 0 0-.5-.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 474 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M5.5 0A2.5 2.5 0 0 0 3 2.5v8A2.5 2.5 0 0 0 5.5 13h8a2.5 2.5 0 0 0 2.5-2.5v-8A2.5 2.5 0 0 0 13.5 0h-8zm0 1H7v1.5A1.5 1.5 0 0 0 8.5 4H15v6.5a1.5 1.5 0 0 1-1.5 1.5h-8A1.5 1.5 0 0 1 4 10.5v-8A1.5 1.5 0 0 1 5.5 1zM8 1h5.5A1.5 1.5 0 0 1 15 2.5V3H8.5a.5.5 0 0 1-.5-.5V1zM2 3.05A2.5 2.5 0 0 0 0 5.5V12a4 4 0 0 0 4 4h6.5a2.5 2.5 0 0 0 2.45-2h-1.036a1.5 1.5 0 0 1-1.414 1H4a3 3 0 0 1-3-3V5.5a1.5 1.5 0 0 1 1-1.414V3.05z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 551 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M11.72 6.586c-.799.537-1.787 1.167-3.303 1.422a.5.5 0 0 0-.418.492v2.564c0 2.288 1.648 4.08 3.822 4.902a.5.5 0 0 0 .356 0c2.174-.822 3.822-2.614 3.822-4.902V8.5a.5.5 0 0 0-.419-.492c-1.514-.255-2.503-.885-3.302-1.422a.5.5 0 0 0-.56 0zm.28.992c.716.47 1.69.982 3 1.281v2.205c0 1.741-1.23 3.108-3 3.848-1.77-.74-3-2.107-3-3.848V8.86a9.083 9.083 0 0 0 3-1.28z"/>
|
||||||
|
<path d="M6 0C4.901 0 4 .901 4 2v10c0 1.099.901 2 2 2h1.836a5.373 5.373 0 0 1-.488-1H6c-.558 0-1-.442-1-1V2c0-.558.442-1 1-1h6c.558 0 1 .442 1 1v3.865c.203.139.748.48 1 .592V2c0-1.1-.902-2-2-2H6z"/>
|
||||||
|
<path d="M3 2.271C2.404 2.619 2 3.265 2 4v8.5C2 14.427 3.573 16 5.5 16h4.252a7.236 7.236 0 0 1-1.154-1H5.5A2.492 2.492 0 0 1 3 12.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 837 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M6 0a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H6zm0 1h6a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM3 2.268C2.402 2.614 2 3.26 2 4v8.5A3.5 3.5 0 0 0 5.5 16H10c.74 0 1.387-.402 1.732-1H5.5A2.5 2.5 0 0 1 3 12.5V2.27z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 397 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M3.508 0a.5.5 0 0 0-.428.771L7.404 7.43 5.48 10.39a3 3 0 1 0 .78.636L8 8.347l1.74 2.68a3 3 0 1 0 .78-.636L3.92.23a.503.503 0 0 0-.412-.228zm8.984 0a.503.503 0 0 0-.412.229L8.596 5.594l.598.918L12.92.772A.5.5 0 0 0 12.493 0zM4 11a2 2 0 1 1 0 4 2 2 0 0 1 0-4zm8 0a2 2 0 1 1 0 4 2 2 0 0 1 0-4z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 432 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M8 .5A2.5 2.5 0 0 0 5.5 3H1a.5.5 0 0 0-.5.5l.008.09A.5.5 0 0 0 1 4h.553L2.85 14.229A2 2 0 0 0 4.836 16h6.328a2 2 0 0 0 1.986-1.771L14.445 4H15a.5.5 0 0 0 0-1h-4.5A2.5 2.5 0 0 0 8 .5zm0 1A1.5 1.5 0 0 1 9.5 3h-3A1.5 1.5 0 0 1 8 1.5zM2.56 4h10.877l-1.28 10.116a.998.998 0 0 1-.993.884H4.836a.998.998 0 0 1-.992-.884zM6.5 6.5c-.276 0-.5.196-.5.438v5.124l.008.078c.042.204.247.36.492.36.276 0 .5-.196.5-.438V6.938l-.008-.079C6.95 6.655 6.745 6.5 6.5 6.5zm3 0c-.276 0-.5.196-.5.438v5.124l.008.078c.042.204.247.36.492.36.276 0 .5-.196.5-.438V6.938l-.008-.079C9.95 6.655 9.745 6.5 9.5 6.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 723 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M6.5 0a1.5 1.5 0 0 0-1.414 1H3.5A1.5 1.5 0 0 0 2 2.5v12A1.5 1.5 0 0 0 3.5 16h3a.5.5 0 0 0 0-1h-3a.5.5 0 0 1-.5-.5v-12a.5.5 0 0 1 .5-.5h1.586A1.5 1.5 0 0 0 6.5 3h3a1.5 1.5 0 0 0 1.414-1H12.5a.5.5 0 0 1 .5.5v1a.5.5 0 0 0 1 0v-1A1.5 1.5 0 0 0 12.5 1h-1.586A1.5 1.5 0 0 0 9.5 0h-3zm0 1h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1 0-1zm3 4A1.5 1.5 0 0 0 8 6.5v8A1.5 1.5 0 0 0 9.5 16h5a1.5 1.5 0 0 0 1.5-1.5v-8A1.5 1.5 0 0 0 14.5 5h-5zm0 1h5a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-.5.5h-5a.5.5 0 0 1-.5-.5v-8a.5.5 0 0 1 .5-.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 639 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path transform="scale(-1 1) translate(-16 0)" d="M1.5 0a.5.5 0 0 0-.5.5v4.9a.6.6 0 0 0 .6.6h4.9a.5.5 0 0 0 0-1H2.906L6.38 1.98a4 4 0 1 1 5.248 6.04l-8.172 7.103a.5.5 0 1 0 .656.754l8.172-7.104a5.001 5.001 0 0 0-6.56-7.547L2 4.464V.5a.5.5 0 0 0-.5-.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 384 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M6 0a2 2 0 0 0-2 2v.5a.5.5 0 0 0 1 0V2a1 1 0 0 1 1-1h.5a.5.5 0 0 0 0-1H6zm2.5 0a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zm5 0a.5.5 0 0 0 0 1h.5a1 1 0 0 1 1 1v.5a.5.5 0 0 0 1 0V2a2 2 0 0 0-2-2h-.5zM2 4a2 2 0 0 0-2 2v6.5A3.5 3.5 0 0 0 3.5 16H10a2 2 0 0 0 2-2v-1h-1v1a1 1 0 0 1-1 1H3.5A2.5 2.5 0 0 1 1 12.5V6a1 1 0 0 1 1-1h1V4H2zm2.5 0a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 1 0v-3a.5.5 0 0 0-.5-.5zm11 0a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 1 0v-3a.5.5 0 0 0-.5-.5zm-11 5a.5.5 0 0 0-.5.5v.5a2 2 0 0 0 2 2h.5a.5.5 0 0 0 0-1H6a1 1 0 0 1-1-1v-.5a.5.5 0 0 0-.5-.5zm11 0a.5.5 0 0 0-.5.5v.5a1 1 0 0 1-1 1h-.5a.5.5 0 0 0 0 1h.5a2 2 0 0 0 2-2v-.5a.5.5 0 0 0-.5-.5zm-7 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 813 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M1.5 0a.5.5 0 0 0-.5.5v4.9a.6.6 0 0 0 .6.6h4.9a.5.5 0 0 0 0-1H2.906L6.38 1.98a4 4 0 1 1 5.248 6.04l-8.172 7.103a.5.5 0 1 0 .656.754l8.172-7.104a5.001 5.001 0 0 0-6.56-7.547L2 4.464V.5a.5.5 0 0 0-.5-.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 343 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M11.25.815a2.783 2.783 0 0 1 4.066 3.796l-.13.14-9.606 9.605a2 2 0 0 1-.723.463l-.165.053-4.055 1.106a.5.5 0 0 1-.63-.535l.016-.08L1.13 11.31a2 2 0 0 1 .398-.76l.117-.128zm-.86 2.275-8.04 8.038a1 1 0 0 0-.215.321l-.042.123-.876 3.211 3.212-.876a1 1 0 0 0 .238-.1l.108-.071.098-.086 8.038-8.04zm4.089-1.568a1.784 1.784 0 0 0-2.402-.11l-.12.11-.86.86 2.52 2.522.861-.86a1.784 1.784 0 0 0 .11-2.402z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 538 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<defs><clipPath id="a"><path d="M2.1 0 16 13.9V0zM0 .7V16h15.3z"/></clipPath></defs>
|
||||||
|
<path clip-path="url(#a)" d="m8.25 0-.154.006a2.249 2.249 0 0 0-2.074 1.939L6.014 2H3.502l-.145.006A1.5 1.5 0 0 0 2.002 3.5v2.264l-.058.006A2.25 2.25 0 0 0 0 8.001l.006.155a2.249 2.249 0 0 0 1.939 2.074l.056.005v2.266l.006.145A1.5 1.5 0 0 0 3.502 14h2.014l.006.055a2.25 2.25 0 0 0 2.23 1.943l.154-.006a2.25 2.25 0 0 0 2.074-1.94L9.986 14h2.516a1.5 1.5 0 0 0 1.5-1.5L14 9.247l-1.75.002-.123-.006A1.246 1.246 0 0 1 11 8l.006-.123A1.246 1.246 0 0 1 12.25 6.75L14 6.747l.002-3.246-.008-.144a1.499 1.499 0 0 0-1.492-1.355h-2.018l-.004-.057A2.252 2.252 0 0 0 8.25 0zm0 1c.69 0 1.25.56 1.25 1.25V3l3.002.002.09.008a.5.5 0 0 1 .41.492v2.246l-.752.002a2.25 2.25 0 0 0-2.242 2.066L10 7.98c0 1.194.903 2.167 2.066 2.262l.164.008.772-.002v2.254a.5.5 0 0 1-.5.5L9 13l.002.752a1.25 1.25 0 0 1-2.5-.002L6.5 13l-2.998.002a.5.5 0 0 1-.5-.5L3 9.25l-.752.002a1.249 1.249 0 1 1 .002-2.5L3 6.75l.002-3.248a.5.5 0 0 1 .5-.5L7 3v-.75C7 1.56 7.56 1 8.25 1z"/>
|
||||||
|
<path d="M.5 0a.5.5 0 0 0-.354.146.5.5 0 0 0 0 .707l15 15a.5.5 0 0 0 .707 0 .5.5 0 0 0 0-.707l-15-15A.5.5 0 0 0 .499 0z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="m8.25 0-.154.006a2.249 2.249 0 0 0-2.074 1.939L6.014 2H3.502l-.145.006a1.5 1.5 0 0 0-1.355 1.494v2.264l-.058.006A2.25 2.25 0 0 0 0 8.001l.006.155a2.249 2.249 0 0 0 1.939 2.074l.056.005v2.266l.006.145A1.5 1.5 0 0 0 3.502 14h2.014l.006.055a2.25 2.25 0 0 0 2.23 1.943l.154-.006a2.25 2.25 0 0 0 2.074-1.94l.006-.052h2.516a1.5 1.5 0 0 0 1.5-1.5L14 9.247l-1.75.002-.123-.006A1.246 1.246 0 0 1 11 8l.006-.123A1.246 1.246 0 0 1 12.25 6.75L14 6.747l.002-3.246-.008-.144a1.499 1.499 0 0 0-1.492-1.355h-2.018l-.004-.057A2.252 2.252 0 0 0 8.25 0zm0 1c.69 0 1.25.56 1.25 1.25V3l3.002.002.09.008a.5.5 0 0 1 .41.492v2.246l-.752.002a2.25 2.25 0 0 0-2.242 2.066L10 7.98c0 1.194.903 2.167 2.066 2.262l.164.008.772-.002v2.254a.5.5 0 0 1-.5.5L9 13l.002.752a1.25 1.25 0 0 1-2.5-.002L6.5 13l-2.998.002a.5.5 0 0 1-.5-.5L3 9.25l-.752.002a1.249 1.249 0 1 1 .002-2.5L3 6.75l.002-3.248a.5.5 0 0 1 .5-.5L7 3v-.75C7 1.56 7.56 1 8.25 1z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="context-fill" fill-opacity="context-fill-opacity">
|
||||||
|
<path d="M5.5 7a.5.5 0 0 0-.5.5.5.5 0 0 0 .5.5h5a.5.5 0 0 0 .5-.5.5.5 0 0 0-.5-.5zM4 2c-.736 0-1.381.404-1.729 1h11.46c-.347-.596-.993-1-1.729-1zM3 4c-1.099 0-2 .9-2 2v7c0 1.099.9 2 2 2h10c1.099 0 2-.9 2-2V6c0-1.099-.9-2-2-2zm0 1h10c.563 0 1 .437 1 1v7c0 .563-.437 1-1 1H3c-.563 0-1-.437-1-1V6c0-.563.437-1 1-1z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 444 B |