Initial commit: NexusOS project + desktop theme baseline
Captures the known-good state after theme consolidation and consistency reconciliation: - NexusOS GTK/xfwm4/icon theme assets (assets/themes, management/Mint-Y-Nexus) - Tightened right-click menus, visible separators, no menu icons - assets/themes/install-theme.sh: idempotent restore of all wiring (symlinks, xfconf xsettings+xfwm4, GTK 3/4 settings.ini) - .gitignore excludes venv/ollama/models/runtime/db Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@@ -0,0 +1,24 @@
|
||||
# Theme Asset Credits
|
||||
|
||||
The NexusOS theme is assembled from original work plus assets adapted from the following upstream projects. All upstream sources are GPL-3.0 (or compatible), so the NexusOS theme inherits GPL-3.0.
|
||||
|
||||
## Sources
|
||||
|
||||
### WhiteSur GTK Theme — `gtk-2.0/`, `xfwm4/`
|
||||
- **Project**: https://github.com/vinceliuice/WhiteSur-gtk-theme
|
||||
- **Author**: Vince Liu (vinceliuice)
|
||||
- **License**: GPL-3.0
|
||||
- **Variant used as base**: `WhiteSur-Dark-purple`
|
||||
- **What we use**: The entire `gtk-2.0/` and `xfwm4/` directories are cloned verbatim from WhiteSur-Dark-purple. We rely on these for macOS-style window controls (stoplight buttons) and the GTK2 application skin.
|
||||
|
||||
### Mint-Y Icon Theme — `NexusOS-icons/` (folder geometry reference)
|
||||
- **Project**: https://github.com/linuxmint/mint-y-icons
|
||||
- **Author**: Linux Mint team
|
||||
- **License**: GPL-3.0
|
||||
- **What we use**: Visual reference only for the folder shape language (flat folder with tab + lip). No PNGs are copied from Mint-Y; our folder set is regenerated from scratch via `NexusOS-icons-src/build.py` against a master SVG we authored.
|
||||
|
||||
## NexusOS-original content
|
||||
- `gtk-3.0/*.css` — original work
|
||||
- `NexusOS-icons-src/*` and the rendered output in `NexusOS-icons/places/` — original work
|
||||
- The `n-small.png` badge composited into `folder-nexus-core` is the NexusOS logo at `nexus-core/assets/n-small.png`
|
||||
- `index.theme` files in each theme directory — original work
|
||||
@@ -0,0 +1,23 @@
|
||||
NexusOS theme assets — attribution and license
|
||||
================================================
|
||||
|
||||
The NexusOS GTK2 and xfwm4 themes are derived from Mint-Y-Dark-Aqua,
|
||||
part of the mint-themes package shipped by Linux Mint.
|
||||
|
||||
Upstream:
|
||||
https://github.com/linuxmint/mint-themes
|
||||
Copyright (c) 2017-2024 Linux Mint <root@linuxmint.com>
|
||||
Licensed under the GNU General Public License v3.0 or later.
|
||||
|
||||
Derivative work in this directory:
|
||||
- NexusOS/gtk-2.0/ (PNGs recolored from Mint-Y-Dark-Aqua/gtk-2.0/)
|
||||
- NexusOS/xfwm4/ (PNGs recolored from Mint-Y-Dark-Aqua/xfwm4/)
|
||||
- NexusOS-gtk2-src/ (build script that performs the recolor)
|
||||
- NexusOS-xfwm4-src/ (build script that performs the recolor)
|
||||
|
||||
As a derivative of GPLv3 material, these files are likewise distributed
|
||||
under the terms of the GNU General Public License version 3 or later. See
|
||||
https://www.gnu.org/licenses/gpl-3.0.html for the full license text.
|
||||
|
||||
The NexusOS GTK3 theme (NexusOS/gtk-3.0/) and the NexusOS icon set
|
||||
(NexusOS-icons*/) are original works and not derived from Mint-Y.
|
||||
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build NexusOS GTK2 theme from Mint-Y-Dark-Aqua base.
|
||||
|
||||
- Copies .rc files + assets/ from /usr/share/themes/Mint-Y-Dark-Aqua/gtk-2.0/
|
||||
- Recolors PNGs containing the Aqua accent (#1f9ede) to NexusOS green (#8cc63f)
|
||||
- Rewrites the gtk-color-scheme block in gtkrc to NexusOS palette
|
||||
- Replaces remaining aqua hex literals in .rc files
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import colorsys
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
THEMES_ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(THEMES_ROOT))
|
||||
import _palette as P # noqa: E402
|
||||
|
||||
from PIL import Image # noqa: E402
|
||||
|
||||
SRC = Path("/usr/share/themes/Mint-Y-Dark-Aqua/gtk-2.0")
|
||||
OUT = THEMES_ROOT / "NexusOS" / "gtk-2.0"
|
||||
|
||||
AQUA_RGB = (0x1F, 0x9E, 0xDE)
|
||||
AQUA_HSV = colorsys.rgb_to_hsv(*(c / 255 for c in AQUA_RGB))
|
||||
GREEN_HSV = P.hex_to_hsv(P.BRAND_GREEN)
|
||||
|
||||
HUE_TOLERANCE = 30 / 360
|
||||
SAT_FLOOR = 0.18
|
||||
|
||||
S_SCALE = GREEN_HSV[1] / AQUA_HSV[1]
|
||||
V_SCALE = GREEN_HSV[2] / AQUA_HSV[2]
|
||||
|
||||
|
||||
def hue_distance(a: float, b: float) -> float:
|
||||
d = abs(a - b)
|
||||
return min(d, 1 - d)
|
||||
|
||||
|
||||
def recolor_pixel(r: int, g: int, b: int, a: int) -> tuple[int, int, int, int]:
|
||||
if a < 8:
|
||||
return (r, g, b, a)
|
||||
h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255)
|
||||
if s < SAT_FLOOR or hue_distance(h, AQUA_HSV[0]) > HUE_TOLERANCE:
|
||||
return (r, g, b, a)
|
||||
new_s = min(1.0, s * S_SCALE)
|
||||
new_v = min(1.0, v * V_SCALE)
|
||||
nr, ng, nb = colorsys.hsv_to_rgb(GREEN_HSV[0], new_s, new_v)
|
||||
return (round(nr * 255), round(ng * 255), round(nb * 255), a)
|
||||
|
||||
|
||||
def recolor_png(path: Path) -> int:
|
||||
"""Recolor aqua pixels in-place. Returns count of pixels changed."""
|
||||
im = Image.open(path).convert("RGBA")
|
||||
px = im.load()
|
||||
w, h = im.size
|
||||
changed = 0
|
||||
for y in range(h):
|
||||
for x in range(w):
|
||||
r, g, b, a = px[x, y]
|
||||
new = recolor_pixel(r, g, b, a)
|
||||
if new != (r, g, b, a):
|
||||
px[x, y] = new
|
||||
changed += 1
|
||||
if changed:
|
||||
im.save(path, optimize=True)
|
||||
return changed
|
||||
|
||||
|
||||
# ── gtkrc color-scheme block ──────────────────────────────────────────
|
||||
NEW_COLOR_SCHEME = (
|
||||
f"base_color:#{P.BASE_BG}\\n"
|
||||
f"fg_color:#{P.TEXT_PRIMARY}\\n"
|
||||
f"tooltip_fg_color:#{P.TEXT_PRIMARY}\\n"
|
||||
f"selected_bg_color:#{P.BRAND_PURPLE_DARK}\\n"
|
||||
f"selected_fg_color:#{P.TEXT_ON_SELECTION}\\n"
|
||||
f"text_color:#{P.TEXT_PRIMARY}\\n"
|
||||
f"bg_color:#{P.SURFACE_BG}\\n"
|
||||
f"insensitive_bg_color:#{P.SURFACE_BG}\\n"
|
||||
f"insensitive_fg_color:#{P.TEXT_DISABLED}\\n"
|
||||
f"notebook_bg:#{P.BASE_BG}\\n"
|
||||
f"dark_sidebar_bg:#{P.SURFACE_BG_ALT}\\n"
|
||||
f"tooltip_bg_color:#{P.OVERLAY_BG}\\n"
|
||||
f"link_color:#{P.BRAND_GREEN_LIGHT}\\n"
|
||||
f"menu_bg:#{P.SURFACE_BG}\\n"
|
||||
f"menu_separator_color:#{P.BORDER}"
|
||||
)
|
||||
|
||||
|
||||
def patch_gtkrc(path: Path) -> None:
|
||||
text = path.read_text()
|
||||
out_lines = []
|
||||
for line in text.splitlines():
|
||||
if line.startswith("gtk-color-scheme"):
|
||||
out_lines.append(f'gtk-color-scheme = "{NEW_COLOR_SCHEME}"')
|
||||
else:
|
||||
out_lines.append(line)
|
||||
path.write_text("\n".join(out_lines) + "\n")
|
||||
|
||||
|
||||
# ── Remaining hex literals in .rc files ───────────────────────────────
|
||||
# Captured from Mint-Y-Dark-Aqua; map source hex → NexusOS replacement.
|
||||
RC_HEX_REPLACEMENTS = {
|
||||
# accent / focus / selection
|
||||
"#1f9ede": f"#{P.BRAND_GREEN}",
|
||||
"#1F9EDE": f"#{P.BRAND_GREEN}",
|
||||
"#5294E2": f"#{P.BRAND_GREEN_LIGHT}", # link_color fallback if quoted literal
|
||||
"#5294e2": f"#{P.BRAND_GREEN_LIGHT}",
|
||||
# Mint-Y greys we want to nudge onto our surface family
|
||||
"#2b2b2b": f"#{P.SURFACE_BG_ALT}",
|
||||
"#383838": f"#{P.SURFACE_BG}",
|
||||
"#404040": f"#{P.BASE_BG}",
|
||||
"#3e3e3e": f"#{P.SURFACE_BG}",
|
||||
"#dadada": f"#{P.TEXT_PRIMARY}",
|
||||
"#DADADA": f"#{P.TEXT_PRIMARY}",
|
||||
"#d3d3d3": f"#{P.TEXT_PRIMARY}",
|
||||
"#D3D3D3": f"#{P.TEXT_PRIMARY}",
|
||||
}
|
||||
|
||||
|
||||
def patch_rc(path: Path) -> int:
|
||||
text = path.read_text()
|
||||
count = 0
|
||||
for src, dst in RC_HEX_REPLACEMENTS.items():
|
||||
n = text.count(src)
|
||||
if n:
|
||||
text = text.replace(src, dst)
|
||||
count += n
|
||||
path.write_text(text)
|
||||
return count
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if OUT.exists():
|
||||
shutil.rmtree(OUT)
|
||||
shutil.copytree(SRC, OUT)
|
||||
print(f"Copied {SRC} → {OUT}")
|
||||
|
||||
# Recolor PNGs
|
||||
recolored = 0
|
||||
for png in sorted((OUT / "assets").glob("*.png")):
|
||||
changed = recolor_png(png)
|
||||
if changed:
|
||||
recolored += 1
|
||||
print(f" recolored {png.name}: {changed}px")
|
||||
print(f"Recolored {recolored} PNGs")
|
||||
|
||||
# Patch rc files
|
||||
patched_total = 0
|
||||
for rc in sorted(OUT.glob("*.rc")):
|
||||
n = patch_rc(rc)
|
||||
if n:
|
||||
print(f" patched {rc.name}: {n} replacements")
|
||||
patched_total += n
|
||||
gtkrc = OUT / "gtkrc"
|
||||
patch_rc(gtkrc)
|
||||
patch_gtkrc(gtkrc)
|
||||
print(f"Rewrote gtkrc color scheme; total .rc hex replacements: {patched_total}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 882 B |
|
After Width: | Height: | Size: 955 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 921 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,254 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
NexusOS folder icon builder.
|
||||
|
||||
Emits one SVG per variant into places/, then rasterizes to
|
||||
~/.icons/NexusOS/<size>/places/<name>.png at 16/22/24/32/48/64/128.
|
||||
|
||||
Run: python3 build.py # builds SVGs + renders all PNGs
|
||||
python3 build.py --svg-only # just rewrite SVGs
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import base64
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
PLACES = ROOT / "places"
|
||||
ICONS_OUT = Path.home() / ".icons" / "NexusOS"
|
||||
SIZES = [16, 22, 24, 32, 48, 64, 128]
|
||||
|
||||
# N logo source. Inkscape's headless renderer doesn't follow external href
|
||||
# references, so we inline it as a base64 data URI.
|
||||
LOGO_PATH = Path.home() / "nexus-core" / "assets" / "n-small.png"
|
||||
LOGO_DATA_URI = (
|
||||
"data:image/png;base64,"
|
||||
+ base64.b64encode(LOGO_PATH.read_bytes()).decode("ascii")
|
||||
)
|
||||
|
||||
# ── master folder geometry ────────────────────────────────────────────
|
||||
# viewBox 0 0 128 128. Badge area: roughly (32,52)-(96,108).
|
||||
MASTER = """\
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
"""
|
||||
|
||||
# Open-folder geometry used by folder-open and folder-drag-accept.
|
||||
# The front face is angled forward, exposing the back as a triangle on top.
|
||||
OPEN_MASTER = """\
|
||||
<!-- Folder back, same as closed -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face, tilted forward — wider at bottom, narrower at top -->
|
||||
<path d="M 22 44 L 106 44 L 118 110 Q 118 114 114 114
|
||||
L 14 114 Q 10 114 10 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on tilted front face -->
|
||||
<path d="M 22 44 L 106 44 L 106.5 46 L 21.5 46 Z" fill="#88008f"/>
|
||||
"""
|
||||
|
||||
# ── badge fragments ───────────────────────────────────────────────────
|
||||
# All badges drawn in white (#f2f2f2) and centered around (64, 78).
|
||||
# Keep glyphs in roughly a 40-50px box for legibility at 22-32 sizes.
|
||||
|
||||
BADGES = {
|
||||
"folder": "", # the base, no badge
|
||||
|
||||
"folder-documents": """\
|
||||
<!-- Document with folded corner -->
|
||||
<path d="M 48 58 L 72 58 L 80 66 L 80 98 L 48 98 Z"
|
||||
fill="#f2f2f2"/>
|
||||
<path d="M 72 58 L 72 66 L 80 66 Z" fill="#cccccc"/>
|
||||
<rect x="52" y="72" width="24" height="2" fill="#5e0066"/>
|
||||
<rect x="52" y="78" width="24" height="2" fill="#5e0066"/>
|
||||
<rect x="52" y="84" width="20" height="2" fill="#5e0066"/>
|
||||
<rect x="52" y="90" width="24" height="2" fill="#5e0066"/>
|
||||
""",
|
||||
|
||||
"folder-download": """\
|
||||
<!-- Down arrow over a tray -->
|
||||
<rect x="60" y="56" width="8" height="22" fill="#f2f2f2"/>
|
||||
<path d="M 50 76 L 78 76 L 64 92 Z" fill="#f2f2f2"/>
|
||||
<rect x="48" y="96" width="32" height="4" rx="1" fill="#f2f2f2"/>
|
||||
""",
|
||||
|
||||
"folder-music": """\
|
||||
<!-- Eighth note -->
|
||||
<rect x="68" y="58" width="4" height="32" fill="#f2f2f2"/>
|
||||
<path d="M 68 58 L 84 62 L 84 70 L 72 66 Z" fill="#f2f2f2"/>
|
||||
<ellipse cx="62" cy="92" rx="9" ry="6" fill="#f2f2f2"/>
|
||||
""",
|
||||
|
||||
"folder-pictures": """\
|
||||
<!-- Landscape: sun + mountains in a frame -->
|
||||
<rect x="44" y="58" width="40" height="40" rx="2" fill="#f2f2f2"/>
|
||||
<circle cx="74" cy="68" r="4" fill="#8cc63f"/>
|
||||
<path d="M 46 96 L 60 78 L 70 88 L 78 80 L 82 96 Z" fill="#5e0066"/>
|
||||
""",
|
||||
|
||||
"folder-videos": """\
|
||||
<!-- Filmstrip with play triangle -->
|
||||
<rect x="44" y="60" width="40" height="36" rx="2" fill="#f2f2f2"/>
|
||||
<rect x="44" y="60" width="40" height="4" fill="#5e0066"/>
|
||||
<rect x="44" y="92" width="40" height="4" fill="#5e0066"/>
|
||||
<rect x="46" y="60" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="56" y="60" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="66" y="60" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="76" y="60" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="46" y="92" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="56" y="92" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="66" y="92" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="76" y="92" width="4" height="4" fill="#f2f2f2"/>
|
||||
<path d="M 58 70 L 74 78 L 58 86 Z" fill="#8cc63f"/>
|
||||
""",
|
||||
|
||||
"folder-templates": """\
|
||||
<!-- Pencil over a page -->
|
||||
<path d="M 50 60 L 70 60 L 78 68 L 78 96 L 50 96 Z" fill="#f2f2f2"/>
|
||||
<path d="M 70 60 L 70 68 L 78 68 Z" fill="#cccccc"/>
|
||||
<!-- Pencil at 45deg -->
|
||||
<path d="M 60 88 L 80 68 L 84 72 L 64 92 Z" fill="#8cc63f"/>
|
||||
<path d="M 60 88 L 64 92 L 58 94 Z" fill="#5e0066"/>
|
||||
""",
|
||||
|
||||
"folder-publicshare": """\
|
||||
<!-- Three small people silhouettes -->
|
||||
<circle cx="52" cy="68" r="6" fill="#f2f2f2"/>
|
||||
<path d="M 42 92 Q 42 78 52 78 Q 62 78 62 92 Z" fill="#f2f2f2"/>
|
||||
<circle cx="76" cy="68" r="6" fill="#f2f2f2"/>
|
||||
<path d="M 66 92 Q 66 78 76 78 Q 86 78 86 92 Z" fill="#f2f2f2"/>
|
||||
<circle cx="64" cy="60" r="5" fill="#f2f2f2"/>
|
||||
<path d="M 56 76 Q 56 66 64 66 Q 72 66 72 76 Z" fill="#f2f2f2"/>
|
||||
""",
|
||||
|
||||
"folder-home": """\
|
||||
<!-- House silhouette -->
|
||||
<path d="M 64 56 L 88 76 L 84 76 L 84 96 L 70 96 L 70 84
|
||||
L 58 84 L 58 96 L 44 96 L 44 76 L 40 76 Z"
|
||||
fill="#f2f2f2"/>
|
||||
""",
|
||||
|
||||
"folder-recent": """\
|
||||
<!-- Clock face -->
|
||||
<circle cx="64" cy="80" r="20" fill="#f2f2f2"/>
|
||||
<circle cx="64" cy="80" r="20" fill="none" stroke="#5e0066" stroke-width="2"/>
|
||||
<rect x="63" y="66" width="2" height="16" fill="#5e0066"/>
|
||||
<rect x="63" y="79" width="14" height="2" fill="#5e0066"/>
|
||||
""",
|
||||
|
||||
"folder-remote": """\
|
||||
<!-- Globe / network -->
|
||||
<circle cx="64" cy="80" r="20" fill="#f2f2f2"/>
|
||||
<ellipse cx="64" cy="80" rx="20" ry="8" fill="none" stroke="#5e0066" stroke-width="1.5"/>
|
||||
<ellipse cx="64" cy="80" rx="8" ry="20" fill="none" stroke="#5e0066" stroke-width="1.5"/>
|
||||
<line x1="44" y1="80" x2="84" y2="80" stroke="#5e0066" stroke-width="1.5"/>
|
||||
<line x1="64" y1="60" x2="64" y2="100" stroke="#5e0066" stroke-width="1.5"/>
|
||||
""",
|
||||
|
||||
"folder-saved-search": """\
|
||||
<!-- Magnifying glass -->
|
||||
<circle cx="58" cy="74" r="12" fill="none" stroke="#f2f2f2" stroke-width="4"/>
|
||||
<line x1="68" y1="84" x2="82" y2="98" stroke="#f2f2f2" stroke-width="5" stroke-linecap="round"/>
|
||||
""",
|
||||
|
||||
"folder-drag-accept": "USE_OPEN_MASTER", # uses OPEN_MASTER, no extra badge
|
||||
"folder-open": "USE_OPEN_MASTER",
|
||||
|
||||
"folder-nexus-core": f"""\
|
||||
<!-- N logo (base64 of assets/n-small.png), centered on front face. -->
|
||||
<!-- Source is 598x341 (aspect 1.754:1). -->
|
||||
<image xlink:href="{LOGO_DATA_URI}" x="28" y="58" width="72" height="41"
|
||||
preserveAspectRatio="xMidYMid meet"/>
|
||||
""",
|
||||
}
|
||||
|
||||
|
||||
def svg_for(name: str, badge: str) -> str:
|
||||
if badge == "USE_OPEN_MASTER":
|
||||
body = OPEN_MASTER
|
||||
extra = ""
|
||||
else:
|
||||
body = MASTER
|
||||
extra = badge
|
||||
return f"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
{body}{extra}</svg>
|
||||
"""
|
||||
|
||||
|
||||
def write_svgs() -> list[str]:
|
||||
PLACES.mkdir(parents=True, exist_ok=True)
|
||||
written = []
|
||||
for name, badge in BADGES.items():
|
||||
path = PLACES / f"{name}.svg"
|
||||
path.write_text(svg_for(name, badge))
|
||||
written.append(name)
|
||||
return written
|
||||
|
||||
|
||||
def render_pngs(names: list[str]) -> None:
|
||||
for name in names:
|
||||
svg = PLACES / f"{name}.svg"
|
||||
for size in SIZES:
|
||||
out_dir = ICONS_OUT / f"{size}x{size}" / "places"
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
out = out_dir / f"{name}.png"
|
||||
subprocess.run(
|
||||
[
|
||||
"inkscape",
|
||||
str(svg),
|
||||
"--export-type=png",
|
||||
f"--export-filename={out}",
|
||||
f"--export-width={size}",
|
||||
f"--export-height={size}",
|
||||
],
|
||||
check=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
print(f" rendered {name} @ {size}")
|
||||
|
||||
|
||||
def backup_existing_nexus_core() -> None:
|
||||
"""Move the existing chunky 3D folder-nexus-core PNGs aside before overwriting."""
|
||||
backup = ROOT / "_backup" / "folder-nexus-core-original"
|
||||
backup.mkdir(parents=True, exist_ok=True)
|
||||
for size in SIZES:
|
||||
src = ICONS_OUT / f"{size}x{size}" / "places" / "folder-nexus-core.png"
|
||||
if src.exists():
|
||||
shutil.copy2(src, backup / f"{size}.png")
|
||||
print(f" backed up original folder-nexus-core to {backup}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
svg_only = "--svg-only" in sys.argv
|
||||
names = write_svgs()
|
||||
print(f"Wrote {len(names)} SVGs into {PLACES}")
|
||||
if svg_only:
|
||||
return
|
||||
backup_existing_nexus_core()
|
||||
render_pngs(names)
|
||||
# Refresh the GTK icon cache so file managers pick up the new icons.
|
||||
subprocess.run(
|
||||
["gtk-update-icon-cache", "-f", str(ICONS_OUT)],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
print(f"\nDone. Set theme to NexusOS in your DE to see the icons.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,270 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
NexusOS folder icon generator.
|
||||
|
||||
Composes each variant SVG from a shared master + a per-variant badge fragment,
|
||||
then rasterizes each to PNG at 16/22/24/32/48/64/128 and drops the result into
|
||||
~/.icons/NexusOS/<size>/places/<name>.png.
|
||||
|
||||
Run from this directory:
|
||||
python3 build_icons.py [--svg-only] [--no-cache-update]
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from textwrap import dedent
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parent
|
||||
PLACES_DIR = ROOT / "places"
|
||||
LOGO_SRC = ROOT.parent.parent / "assets" / "n-small.png"
|
||||
ICONS_OUT = pathlib.Path.home() / ".icons" / "NexusOS"
|
||||
SIZES = (16, 22, 24, 32, 48, 64, 128)
|
||||
|
||||
# ── colors (mirror gtk-3.0/colors.css) ───────────────────────────────────────
|
||||
BODY = "#5e0066" # brand_purple_dark — folder body
|
||||
HIGHLIGHT = "#88008f" # brand_purple — top-of-face highlight stripe
|
||||
TAB = "#8cc63f" # brand_green — folder tab
|
||||
TAB_BRIGHT = "#b8e373" # brand_green_light — drag-accept tab
|
||||
LIP = "#f2f2f2" # text_primary — inner lip stripe & badge fill
|
||||
|
||||
# Embedded logo (base64) populated at runtime
|
||||
_LOGO_B64: str | None = None
|
||||
|
||||
|
||||
def logo_data_uri() -> str:
|
||||
global _LOGO_B64
|
||||
if _LOGO_B64 is None:
|
||||
_LOGO_B64 = base64.b64encode(LOGO_SRC.read_bytes()).decode("ascii")
|
||||
return f"data:image/png;base64,{_LOGO_B64}"
|
||||
|
||||
|
||||
def folder_svg(badge: str, *, tab_color: str = TAB) -> str:
|
||||
"""Build a full variant SVG by injecting `badge` into the master template."""
|
||||
return dedent(f"""\
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30 L 110 30
|
||||
Q 114 30 114 34 L 114 110 Q 114 114 110 114 L 18 114
|
||||
Q 14 114 14 110 Z" fill="{tab_color}"/>
|
||||
<rect x="14" y="36" width="100" height="3" fill="{LIP}"/>
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114 L 18 114
|
||||
Q 14 114 14 110 Z" fill="{BODY}"/>
|
||||
<rect x="14" y="39" width="100" height="2" fill="{HIGHLIGHT}"/>
|
||||
<g id="badge">{badge}</g>
|
||||
</svg>
|
||||
""")
|
||||
|
||||
|
||||
# ── badge fragments (centered on front face ~x=64, y=78) ─────────────────────
|
||||
# Each is a simple white-on-purple glyph kept readable at 16-22px.
|
||||
|
||||
BADGES: dict[str, str] = {
|
||||
# Base folder — no badge
|
||||
"folder": "",
|
||||
|
||||
# Folder-open: lighter tab + slight perspective on front (simple variant)
|
||||
"folder-open": (
|
||||
f'<path d="M 14 41 L 22 39 L 106 39 L 114 41 L 114 110 '
|
||||
f'Q 114 114 110 114 L 18 114 Q 14 114 14 110 Z" '
|
||||
f'fill="{HIGHLIGHT}" opacity="0.55"/>'
|
||||
),
|
||||
|
||||
# Documents — page with folded corner
|
||||
"folder-documents": (
|
||||
f'<path d="M 50 58 L 70 58 L 80 68 L 80 100 L 50 100 Z" fill="{LIP}"/>'
|
||||
f'<path d="M 70 58 L 70 68 L 80 68" fill="none" '
|
||||
f'stroke="{BODY}" stroke-width="2" stroke-linejoin="miter"/>'
|
||||
),
|
||||
|
||||
# Download — down arrow
|
||||
"folder-download": (
|
||||
f'<path d="M 60 58 L 68 58 L 68 80 L 78 80 L 64 98 L 50 80 L 60 80 Z" '
|
||||
f'fill="{LIP}"/>'
|
||||
),
|
||||
|
||||
# Drag-accept — uses bright green tab, plus white plus glyph
|
||||
"folder-drag-accept": (
|
||||
f'<path d="M 60 64 L 68 64 L 68 76 L 80 76 L 80 84 L 68 84 L 68 96 '
|
||||
f'L 60 96 L 60 84 L 48 84 L 48 76 L 60 76 Z" fill="{LIP}"/>'
|
||||
),
|
||||
|
||||
# Home — house
|
||||
"folder-home": (
|
||||
f'<path d="M 64 56 L 84 74 L 80 74 L 80 100 L 70 100 L 70 86 L 58 86 '
|
||||
f'L 58 100 L 48 100 L 48 74 L 44 74 Z" fill="{LIP}"/>'
|
||||
),
|
||||
|
||||
# Music — eighth note
|
||||
"folder-music": (
|
||||
f'<rect x="70" y="56" width="4" height="32" fill="{LIP}"/>'
|
||||
f'<path d="M 70 56 L 70 64 Q 78 60 82 64 L 82 56 Z" fill="{LIP}"/>'
|
||||
f'<ellipse cx="64" cy="90" rx="8" ry="6" fill="{LIP}"/>'
|
||||
),
|
||||
|
||||
# Pictures — sun over mountains
|
||||
"folder-pictures": (
|
||||
f'<rect x="44" y="60" width="40" height="40" rx="3" fill="{LIP}"/>'
|
||||
f'<circle cx="74" cy="70" r="3" fill="{BODY}"/>'
|
||||
f'<path d="M 44 100 L 56 82 L 66 92 L 74 84 L 84 100 Z" fill="{BODY}"/>'
|
||||
),
|
||||
|
||||
# Publicshare — two people
|
||||
"folder-publicshare": (
|
||||
f'<circle cx="56" cy="66" r="6" fill="{LIP}"/>'
|
||||
f'<circle cx="72" cy="66" r="6" fill="{LIP}"/>'
|
||||
f'<path d="M 46 100 L 46 88 Q 46 78 56 78 L 62 78 Q 64 78 64 80 '
|
||||
f'Q 64 78 66 78 L 72 78 Q 82 78 82 88 L 82 100 Z" fill="{LIP}"/>'
|
||||
),
|
||||
|
||||
# Recent — clock face
|
||||
"folder-recent": (
|
||||
f'<circle cx="64" cy="80" r="14" fill="{LIP}"/>'
|
||||
f'<path d="M 64 70 L 64 80 L 71 84" fill="none" stroke="{BODY}" '
|
||||
f'stroke-width="2.5" stroke-linecap="round"/>'
|
||||
),
|
||||
|
||||
# Remote — globe (circle + ellipse + meridian)
|
||||
"folder-remote": (
|
||||
f'<circle cx="64" cy="80" r="14" fill="{LIP}"/>'
|
||||
f'<ellipse cx="64" cy="80" rx="14" ry="6" fill="none" '
|
||||
f'stroke="{BODY}" stroke-width="2"/>'
|
||||
f'<line x1="64" y1="66" x2="64" y2="94" stroke="{BODY}" stroke-width="2"/>'
|
||||
),
|
||||
|
||||
# Saved search — magnifying glass
|
||||
"folder-saved-search": (
|
||||
f'<circle cx="60" cy="76" r="10" fill="none" stroke="{LIP}" stroke-width="4"/>'
|
||||
f'<line x1="67" y1="83" x2="78" y2="94" stroke="{LIP}" stroke-width="5" '
|
||||
f'stroke-linecap="round"/>'
|
||||
),
|
||||
|
||||
# Templates — page with horizontal lines
|
||||
"folder-templates": (
|
||||
f'<rect x="48" y="58" width="32" height="42" rx="2" fill="{LIP}"/>'
|
||||
f'<rect x="53" y="64" width="22" height="2" fill="{BODY}"/>'
|
||||
f'<rect x="53" y="70" width="22" height="2" fill="{BODY}"/>'
|
||||
f'<rect x="53" y="76" width="18" height="2" fill="{BODY}"/>'
|
||||
f'<rect x="53" y="82" width="20" height="2" fill="{BODY}"/>'
|
||||
f'<rect x="53" y="88" width="14" height="2" fill="{BODY}"/>'
|
||||
),
|
||||
|
||||
# Videos — play triangle
|
||||
"folder-videos": (
|
||||
f'<path d="M 54 62 L 54 98 L 82 80 Z" fill="{LIP}"/>'
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def nexus_core_svg() -> str:
|
||||
"""folder-nexus-core embeds the bicolor N logo via base64 data URI."""
|
||||
return dedent(f"""\
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="128" height="128" viewBox="0 0 128 128">
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30 L 110 30
|
||||
Q 114 30 114 34 L 114 110 Q 114 114 110 114 L 18 114
|
||||
Q 14 114 14 110 Z" fill="{TAB}"/>
|
||||
<rect x="14" y="36" width="100" height="3" fill="{LIP}"/>
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114 L 18 114
|
||||
Q 14 114 14 110 Z" fill="{BODY}"/>
|
||||
<rect x="14" y="39" width="100" height="2" fill="{HIGHLIGHT}"/>
|
||||
<image xlink:href="{logo_data_uri()}" x="32" y="58" width="64" height="37"
|
||||
preserveAspectRatio="xMidYMid meet"/>
|
||||
</svg>
|
||||
""")
|
||||
|
||||
|
||||
def write_variants() -> list[tuple[str, pathlib.Path]]:
|
||||
PLACES_DIR.mkdir(parents=True, exist_ok=True)
|
||||
written: list[tuple[str, pathlib.Path]] = []
|
||||
|
||||
for name, badge in BADGES.items():
|
||||
tab = TAB_BRIGHT if name == "folder-drag-accept" else TAB
|
||||
path = PLACES_DIR / f"{name}.svg"
|
||||
path.write_text(folder_svg(badge, tab_color=tab))
|
||||
written.append((name, path))
|
||||
|
||||
nx_path = PLACES_DIR / "folder-nexus-core.svg"
|
||||
nx_path.write_text(nexus_core_svg())
|
||||
written.append(("folder-nexus-core", nx_path))
|
||||
|
||||
return written
|
||||
|
||||
|
||||
def render_one(svg_path: pathlib.Path, name: str) -> None:
|
||||
for size in SIZES:
|
||||
out_dir = ICONS_OUT / f"{size}x{size}" / "places"
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
out_png = out_dir / f"{name}.png"
|
||||
subprocess.run(
|
||||
[
|
||||
"inkscape",
|
||||
str(svg_path),
|
||||
"--export-type=png",
|
||||
f"--export-filename={out_png}",
|
||||
f"--export-width={size}",
|
||||
f"--export-height={size}",
|
||||
],
|
||||
check=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
print(f" {name} → {size}x{size}")
|
||||
|
||||
|
||||
def backup_existing() -> None:
|
||||
backup = ROOT / "_backup" / "folder-nexus-core-pre-rebuild"
|
||||
if backup.exists():
|
||||
return
|
||||
backup.mkdir(parents=True, exist_ok=True)
|
||||
for size in SIZES:
|
||||
src = ICONS_OUT / f"{size}x{size}" / "places" / "folder-nexus-core.png"
|
||||
if src.exists():
|
||||
shutil.copy2(src, backup / f"{size}-folder-nexus-core.png")
|
||||
print(f"Backed up existing folder-nexus-core PNGs → {backup}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--svg-only", action="store_true",
|
||||
help="only write SVG sources, skip rasterization")
|
||||
parser.add_argument("--no-cache-update", action="store_true",
|
||||
help="skip gtk-update-icon-cache at the end")
|
||||
args = parser.parse_args()
|
||||
|
||||
if not LOGO_SRC.exists():
|
||||
print(f"ERROR: logo source missing at {LOGO_SRC}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print("Writing variant SVGs…")
|
||||
variants = write_variants()
|
||||
print(f" {len(variants)} SVGs written to {PLACES_DIR}")
|
||||
|
||||
if args.svg_only:
|
||||
return 0
|
||||
|
||||
backup_existing()
|
||||
|
||||
print("Rendering PNGs…")
|
||||
for name, svg_path in variants:
|
||||
render_one(svg_path, name)
|
||||
|
||||
if not args.no_cache_update:
|
||||
print("Refreshing icon cache…")
|
||||
subprocess.run(
|
||||
["gtk-update-icon-cache", "-f", "-t", str(ICONS_OUT)],
|
||||
check=False,
|
||||
)
|
||||
|
||||
print(f"\nDone. Rendered {len(variants)} variants × {len(SIZES)} sizes "
|
||||
f"= {len(variants) * len(SIZES)} PNGs.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Document with folded corner -->
|
||||
<path d="M 48 58 L 72 58 L 80 66 L 80 98 L 48 98 Z"
|
||||
fill="#f2f2f2"/>
|
||||
<path d="M 72 58 L 72 66 L 80 66 Z" fill="#cccccc"/>
|
||||
<rect x="52" y="72" width="24" height="2" fill="#5e0066"/>
|
||||
<rect x="52" y="78" width="24" height="2" fill="#5e0066"/>
|
||||
<rect x="52" y="84" width="20" height="2" fill="#5e0066"/>
|
||||
<rect x="52" y="90" width="24" height="2" fill="#5e0066"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Down arrow over a tray -->
|
||||
<rect x="60" y="56" width="8" height="22" fill="#f2f2f2"/>
|
||||
<path d="M 50 76 L 78 76 L 64 92 Z" fill="#f2f2f2"/>
|
||||
<rect x="48" y="96" width="32" height="4" rx="1" fill="#f2f2f2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 994 B |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Folder back, same as closed -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face, tilted forward — wider at bottom, narrower at top -->
|
||||
<path d="M 22 44 L 106 44 L 118 110 Q 118 114 114 114
|
||||
L 14 114 Q 10 114 10 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on tilted front face -->
|
||||
<path d="M 22 44 L 106 44 L 106.5 46 L 21.5 46 Z" fill="#88008f"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 802 B |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- House silhouette -->
|
||||
<path d="M 64 56 L 88 76 L 84 76 L 84 96 L 70 96 L 70 84
|
||||
L 58 84 L 58 96 L 44 96 L 44 76 L 40 76 Z"
|
||||
fill="#f2f2f2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 942 B |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Eighth note -->
|
||||
<rect x="68" y="58" width="4" height="32" fill="#f2f2f2"/>
|
||||
<path d="M 68 58 L 84 62 L 84 70 L 72 66 Z" fill="#f2f2f2"/>
|
||||
<ellipse cx="62" cy="92" rx="9" ry="6" fill="#f2f2f2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 981 B |
|
After Width: | Height: | Size: 247 KiB |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Folder back, same as closed -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face, tilted forward — wider at bottom, narrower at top -->
|
||||
<path d="M 22 44 L 106 44 L 118 110 Q 118 114 114 114
|
||||
L 14 114 Q 10 114 10 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on tilted front face -->
|
||||
<path d="M 22 44 L 106 44 L 106.5 46 L 21.5 46 Z" fill="#88008f"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 802 B |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Landscape: sun + mountains in a frame -->
|
||||
<rect x="44" y="58" width="40" height="40" rx="2" fill="#f2f2f2"/>
|
||||
<circle cx="74" cy="68" r="4" fill="#8cc63f"/>
|
||||
<path d="M 46 96 L 60 78 L 70 88 L 78 80 L 82 96 Z" fill="#5e0066"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1014 B |
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Three small people silhouettes -->
|
||||
<circle cx="52" cy="68" r="6" fill="#f2f2f2"/>
|
||||
<path d="M 42 92 Q 42 78 52 78 Q 62 78 62 92 Z" fill="#f2f2f2"/>
|
||||
<circle cx="76" cy="68" r="6" fill="#f2f2f2"/>
|
||||
<path d="M 66 92 Q 66 78 76 78 Q 86 78 86 92 Z" fill="#f2f2f2"/>
|
||||
<circle cx="64" cy="60" r="5" fill="#f2f2f2"/>
|
||||
<path d="M 56 76 Q 56 66 64 66 Q 72 66 72 76 Z" fill="#f2f2f2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Clock face -->
|
||||
<circle cx="64" cy="80" r="20" fill="#f2f2f2"/>
|
||||
<circle cx="64" cy="80" r="20" fill="none" stroke="#5e0066" stroke-width="2"/>
|
||||
<rect x="63" y="66" width="2" height="16" fill="#5e0066"/>
|
||||
<rect x="63" y="79" width="14" height="2" fill="#5e0066"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Globe / network -->
|
||||
<circle cx="64" cy="80" r="20" fill="#f2f2f2"/>
|
||||
<ellipse cx="64" cy="80" rx="20" ry="8" fill="none" stroke="#5e0066" stroke-width="1.5"/>
|
||||
<ellipse cx="64" cy="80" rx="8" ry="20" fill="none" stroke="#5e0066" stroke-width="1.5"/>
|
||||
<line x1="44" y1="80" x2="84" y2="80" stroke="#5e0066" stroke-width="1.5"/>
|
||||
<line x1="64" y1="60" x2="64" y2="100" stroke="#5e0066" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Magnifying glass -->
|
||||
<circle cx="58" cy="74" r="12" fill="none" stroke="#f2f2f2" stroke-width="4"/>
|
||||
<line x1="68" y1="84" x2="82" y2="98" stroke="#f2f2f2" stroke-width="5" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 984 B |
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Pencil over a page -->
|
||||
<path d="M 50 60 L 70 60 L 78 68 L 78 96 L 50 96 Z" fill="#f2f2f2"/>
|
||||
<path d="M 70 60 L 70 68 L 78 68 Z" fill="#cccccc"/>
|
||||
<!-- Pencil at 45deg -->
|
||||
<path d="M 60 88 L 80 68 L 84 72 L 64 92 Z" fill="#8cc63f"/>
|
||||
<path d="M 60 88 L 64 92 L 58 94 Z" fill="#5e0066"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
<!-- Filmstrip with play triangle -->
|
||||
<rect x="44" y="60" width="40" height="36" rx="2" fill="#f2f2f2"/>
|
||||
<rect x="44" y="60" width="40" height="4" fill="#5e0066"/>
|
||||
<rect x="44" y="92" width="40" height="4" fill="#5e0066"/>
|
||||
<rect x="46" y="60" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="56" y="60" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="66" y="60" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="76" y="60" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="46" y="92" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="56" y="92" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="66" y="92" width="4" height="4" fill="#f2f2f2"/>
|
||||
<rect x="76" y="92" width="4" height="4" fill="#f2f2f2"/>
|
||||
<path d="M 58 70 L 74 78 L 58 86 Z" fill="#8cc63f"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128" viewBox="0 0 128 128">
|
||||
<!-- Back of folder: tab + body silhouette in green -->
|
||||
<path d="M 14 24 Q 14 20 18 20 L 50 20 Q 53 20 55 22 L 62 30
|
||||
L 110 30 Q 114 30 114 34 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#8cc63f"/>
|
||||
<!-- White inner lip stripe -->
|
||||
<rect x="14" y="36" width="100" height="3" fill="#f2f2f2"/>
|
||||
<!-- Front face: deep purple body -->
|
||||
<path d="M 14 39 L 114 39 L 114 110 Q 114 114 110 114
|
||||
L 18 114 Q 14 114 14 110 Z" fill="#5e0066"/>
|
||||
<!-- Top-edge highlight on the front face -->
|
||||
<rect x="14" y="39" width="100" height="2" fill="#88008f"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 776 B |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 1012 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 882 B |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 407 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 417 B |
|
After Width: | Height: | Size: 438 B |
|
After Width: | Height: | Size: 413 B |
|
After Width: | Height: | Size: 464 B |
|
After Width: | Height: | Size: 417 B |
|
After Width: | Height: | Size: 455 B |
|
After Width: | Height: | Size: 452 B |
|
After Width: | Height: | Size: 461 B |
|
After Width: | Height: | Size: 456 B |
|
After Width: | Height: | Size: 440 B |
|
After Width: | Height: | Size: 428 B |
|
After Width: | Height: | Size: 436 B |
|
After Width: | Height: | Size: 324 B |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 407 B |
|
After Width: | Height: | Size: 466 B |
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 526 B |
|
After Width: | Height: | Size: 432 B |
|
After Width: | Height: | Size: 578 B |
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 519 B |
|
After Width: | Height: | Size: 542 B |
|
After Width: | Height: | Size: 554 B |
|
After Width: | Height: | Size: 527 B |
|
After Width: | Height: | Size: 456 B |
|
After Width: | Height: | Size: 509 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 486 B |
|
After Width: | Height: | Size: 481 B |
|
After Width: | Height: | Size: 513 B |
|
After Width: | Height: | Size: 528 B |
|
After Width: | Height: | Size: 501 B |