Compare commits
43 commits
4f5cbbb3c2
...
d91dc1d5e2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d91dc1d5e2 | ||
|
|
13bd7e1522 | ||
|
|
da3e655ffd | ||
|
|
a2a7eb6cd7 | ||
|
|
a031911156 | ||
|
|
1da89ad9a6 | ||
|
|
a30cdd0538 | ||
|
|
79050a43b3 | ||
|
|
510bc28e4a | ||
|
|
213d1d3039 | ||
|
|
fa4c4db944 | ||
|
|
4f07615b13 | ||
|
|
a308aa1987 | ||
|
|
2703cac433 | ||
|
|
f0c4ffbc00 | ||
|
|
fa250dda5f | ||
|
|
23823a9b59 | ||
|
|
64dbb318b0 | ||
|
|
9385499c4b | ||
|
|
7e90058e7a | ||
|
|
ec61bbe5d5 | ||
|
|
d1bba69bcf | ||
|
|
5e94d75a3e | ||
|
|
6ada11778a | ||
|
|
c828a6af47 | ||
|
|
581a853b6f | ||
|
|
f9b7a9739f | ||
|
|
7662f00723 | ||
|
|
4fb5461321 | ||
|
|
04cae9d50b | ||
|
|
fb9d583c71 | ||
|
|
25543cb7ba | ||
|
|
e259d9b63c | ||
|
|
17da0c0234 | ||
|
|
2379562aec | ||
|
|
376dc56e52 | ||
|
|
28eed3e03d | ||
|
|
7d1446302d | ||
|
|
7f54531db5 | ||
|
|
c6ed6b5074 | ||
|
|
85e5b16938 | ||
|
|
45f45dc4b9 | ||
|
|
d1a46defd5 |
68
.gitea/workflows/build.yml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
name: Build & Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: docker
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install pnpm
|
||||
run: npm install -g pnpm@10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set version from tag
|
||||
run: |
|
||||
VERSION="${{ github.ref_name }}"
|
||||
VERSION="${VERSION#v}"
|
||||
node -e "const fs=require('fs'),p=JSON.parse(fs.readFileSync('package.json')); p.version='$VERSION'; fs.writeFileSync('package.json', JSON.stringify(p, null, 2)+'\n')"
|
||||
|
||||
- name: Install Linux build deps
|
||||
run: |
|
||||
for i in 1 2 3; do
|
||||
apt-get update && apt-get install -y --fix-missing python3 make g++ libgtk-3-dev libnss3-dev libxss1 libasound2-dev libgbm-dev dpkg fakeroot zip && break
|
||||
echo "apt attempt $i failed, retrying in 10s..."
|
||||
sleep 10
|
||||
done
|
||||
|
||||
- name: Build Linux (deb + zip)
|
||||
run: pnpm make
|
||||
env:
|
||||
PLATFORM: linux
|
||||
|
||||
- name: Build Windows (zip)
|
||||
run: pnpm make --platform win32 --arch x64
|
||||
env:
|
||||
PLATFORM: win32
|
||||
|
||||
- name: Create release and upload artifacts
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
TAG="${{ github.ref_name }}"
|
||||
API="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
||||
|
||||
RELEASE_ID=$(curl -sf -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"$API/releases" \
|
||||
-d "{\"tag_name\":\"$TAG\",\"name\":\"Sanctum $TAG\"}" \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
||||
|
||||
find out/make -name "*.deb" -o -name "*.zip" | while read file; do
|
||||
curl -sf -X POST \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
"$API/releases/$RELEASE_ID/assets?name=$(basename "$file")" \
|
||||
--data-binary @"$file"
|
||||
done
|
||||
97
README.md
|
|
@ -1,84 +1,59 @@
|
|||
<div align="center">
|
||||
<h1>
|
||||
Stoat for Desktop
|
||||
|
||||
[](https://github.com/stoatchat/for-desktop/stargazers)
|
||||
[](https://github.com/stoatchat/for-desktop/network/members)
|
||||
[](https://github.com/stoatchat/for-desktop/pulls)
|
||||
[](https://github.com/stoatchat/for-desktop/issues)
|
||||
[](https://github.com/stoatchat/for-desktop/graphs/contributors)
|
||||
[](https://github.com/stoatchat/for-desktop/blob/main/LICENSE)
|
||||
</h1>
|
||||
Application for Windows, macOS, and Linux.
|
||||
<img src="assets/desktop/icon.png" width="120" alt="Sanctum" />
|
||||
|
||||
# Sanctum
|
||||
|
||||
**The desktop client for [mithraic.space](https://mithraic.space)**
|
||||
Private. Self-hosted. No tracking, no telemetry, no nonsense.
|
||||
Windows & Linux.
|
||||
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
## Installation
|
||||
---
|
||||
|
||||
<a href="https://repology.org/project/stoat-desktop/versions">
|
||||
<img src="https://repology.org/badge/vertical-allrepos/stoat-desktop.svg" alt="Packaging status" align="right">
|
||||
</a>
|
||||
## What is Sanctum?
|
||||
|
||||
- All downloads and instructions for Stoat can be found on our [Website](https://stoat.chat/download).
|
||||
Sanctum is the official desktop client for **mithraic.space** — a private, self-hosted chat community. It's hardwired to connect exclusively to mithraic.space and ships with custom branding and a fully self-contained auto-update pipeline hosted on a private Forgejo instance.
|
||||
|
||||
## Development Guide
|
||||
Built on top of [Stoat for Desktop](https://github.com/stoatchat/for-desktop), which is itself built on the open-source [Revolt](https://revolt.chat) platform.
|
||||
|
||||
_Contribution guidelines for Desktop app TBA!_
|
||||
No reliance on external services. Everything stays in-house.
|
||||
|
||||
<!-- Before contributing, make yourself familiar with [our contribution guidelines](https://developers.revolt.chat/contrib.html), the [code style guidelines](./GUIDELINES.md), and the [technical documentation for this project](https://revoltchat.github.io/frontend/). -->
|
||||
---
|
||||
|
||||
Before getting started, you'll want to install:
|
||||
## Installing
|
||||
|
||||
- Git
|
||||
- Node.js
|
||||
- pnpm (run `corepack enable`)
|
||||
Grab the latest build from the [Releases page](https://git.mithraic.cloud/ad3laid3/sanctum/releases).
|
||||
|
||||
Then proceed to setup:
|
||||
### Linux
|
||||
|
||||
```bash
|
||||
# clone the repository
|
||||
git clone --recursive https://github.com/stoatchat/for-desktop stoat-for-desktop
|
||||
cd stoat-for-desktop
|
||||
mkdir -p ~/.local/share/sanctum
|
||||
unzip Sanctum-linux-x64-*.zip -d /tmp/sanctum-extract
|
||||
cp -rT /tmp/sanctum-extract/Sanctum-linux-x64 ~/.local/share/sanctum/
|
||||
|
||||
# install all packages
|
||||
pnpm i --frozen-lockfile
|
||||
|
||||
# start the application
|
||||
pnpm start
|
||||
# ... or build the bundle
|
||||
pnpm package
|
||||
# ... or build all distributables
|
||||
pnpm make
|
||||
cat > ~/.local/share/applications/sanctum.desktop << EOF
|
||||
[Desktop Entry]
|
||||
Name=Sanctum
|
||||
Exec=$HOME/.local/share/sanctum/sanctum
|
||||
Icon=$HOME/.local/share/sanctum/resources/assets/desktop/icon.png
|
||||
Type=Application
|
||||
Categories=Network;InstantMessaging;
|
||||
StartupWMClass=sanctum
|
||||
EOF
|
||||
```
|
||||
|
||||
Various useful commands for development testing:
|
||||
Search for **Sanctum** in your app launcher and you're in.
|
||||
|
||||
```bash
|
||||
# connect to the development server
|
||||
pnpm start -- --force-server http://localhost:5173
|
||||
### Windows
|
||||
|
||||
# test the flatpak (after `make`)
|
||||
pnpm install:flatpak
|
||||
pnpm run:flatpak
|
||||
# ... also connect to dev server like so:
|
||||
pnpm run:flatpak --force-server http://localhost:5173
|
||||
Extract the zip, run `sanctum.exe`.
|
||||
|
||||
# Nix-specific instructions for testing
|
||||
pnpm package
|
||||
pnpm run:nix
|
||||
# ... as before:
|
||||
pnpm run:nix --force-server=http://localhost:5173
|
||||
# a better solution would be telling
|
||||
# Electron Forge where system Electron is
|
||||
```
|
||||
---
|
||||
|
||||
### Pulling in Stoat's assets
|
||||
## Auto-updates
|
||||
|
||||
If you want to pull in Stoat brand assets after pulling, run the following:
|
||||
Sanctum checks for updates on every launch. When a new version is available, you'll get a desktop notification — it downloads and installs in the background. Click the notification to restart into the new version.
|
||||
|
||||
```bash
|
||||
# update the assets
|
||||
git -c submodule."assets".update=checkout submodule update --init assets
|
||||
```
|
||||
|
||||
Currently, this is required to build, any forks are expected to provide their own assets.
|
||||
You can also trigger a manual check anytime from the tray icon → **Check for Updates**.
|
||||
|
|
|
|||
1
assets
|
|
@ -1 +0,0 @@
|
|||
Subproject commit bd432f2298901a8566a092636eef0c35a3a80fbc
|
||||
1
assets/README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Assets intended for direct use in applications.
|
||||
7
assets/badges/amog.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<svg width="292" height="412" viewBox="0 0 292 412" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M123.504 267.035L128.535 258.859L138.241 252.156L154.5 249.777L183.052 252.156L197.725 256.518L203.277 269.604V287.788L197.725 312.316L188.604 316.718L165.604 319.571L154.5 333.698V350.899L169.966 356.451L197.725 361.606L217.156 364.382L243.726 356.451L269.409 342.968L273.812 319.571L276.243 287.788V249.777L273.812 197.227L269.409 151.317L264.378 118.614L258.718 97.2312L246.769 76.4775L234.191 56.9815L212.179 47.548L185.765 43.7746H161.238L137.969 47.548L123.504 56.9815L111.555 84.0243L97.7191 126.79L86.3988 180.246L71.9341 262.003L63.1295 290.304H57.4694L38.6023 287.788H26.0243L15.9619 295.335L10.3017 307.284L15.9619 316.718L31.0555 328.667L57.4694 333.698L105.895 328.667L128.535 312.316V299.109L123.504 280.242V267.035Z" fill="#BD0F11" stroke="black" stroke-width="10" stroke-linejoin="round"/>
|
||||
<rect x="143.273" y="91.2935" width="76.4135" height="25.6717" fill="#9DC7D7"/>
|
||||
<path d="M138.788 96.1069L145.638 109.56L154.76 115.762L166.846 118.169L180.083 120.174H191.335C194.544 119.372 199.78 119.171 202.767 118.169C205.754 117.166 208.048 116.43 209.987 115.762H214.6L218.01 111.951L222.622 104.53" stroke="#4E626B" stroke-width="10" stroke-linejoin="round"/>
|
||||
<path d="M148.155 123.275L135.465 111.775V99.4813L140.224 91.1536L148.155 86.7914H160.845H175.518H189.794H202.087L212.398 91.1536L221.518 99.4813L223.898 108.999L217.949 118.119L208.035 123.275L186.225 127.24H165.604L148.155 123.275Z" stroke="black" stroke-width="10" stroke-linejoin="round"/>
|
||||
<path d="M176.895 99.9176L174.287 98.1125V96.9092L176.895 95.7058H181.708H186.923H191.536L196.75 96.9092L200.36 98.1125L204.572 99.9176L202.767 101.121H196.75H191.536H186.12L181.708 99.9176H176.895Z" fill="white" stroke="white" stroke-width="4" stroke-linejoin="bevel"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
3018
assets/badges/amorbus.svg
Normal file
|
After Width: | Height: | Size: 258 KiB |
245
assets/badges/battlepass.svg
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1000 1000" style="enable-background:new 0 0 1000 1000;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#FFEB84;}
|
||||
.st2{fill:#FFFD80;}
|
||||
.st3{fill:#FFFFC0;}
|
||||
.st4{fill:#FFFFE8;}
|
||||
.st5{fill:#E1AF21;}
|
||||
.st6{fill:#FFDA51;}
|
||||
.st7{fill:#FFFBC0;}
|
||||
.st8{fill:#FFE27B;}
|
||||
.st9{fill:#DEB142;}
|
||||
.st10{fill:url(#SVGID_1_);}
|
||||
.st11{fill:#FDDB4A;}
|
||||
.st12{fill:#FFED89;}
|
||||
.st13{fill:#AB6D10;}
|
||||
.st14{fill:#ECBF39;}
|
||||
.st15{fill:#FFDA63;}
|
||||
.st16{fill:#D6A442;}
|
||||
.st17{fill:#C28631;}
|
||||
.st18{fill:#652C07;}
|
||||
.st19{fill:#C67726;}
|
||||
.st20{fill:#875117;}
|
||||
.st21{fill:#E0A053;}
|
||||
.st22{fill:#D68931;}
|
||||
.st23{fill:#945108;}
|
||||
.st24{fill:#C1823C;}
|
||||
.st25{fill:#FFC571;}
|
||||
.st26{fill:#DA9D52;}
|
||||
.st27{fill:#FCB54F;}
|
||||
.st28{fill:#BA6D1C;}
|
||||
.st29{fill:#ECCE82;}
|
||||
.st30{fill:#E9AF5C;}
|
||||
.st31{fill:#FFE173;}
|
||||
.st32{fill:#FFFFC8;}
|
||||
.st33{fill:#CE8229;}
|
||||
.st34{fill:url(#SVGID_00000170236236534105620470000017283433196162258594_);}
|
||||
.st35{fill:url(#SVGID_00000154411126143589039630000017497239855776706224_);}
|
||||
.st36{fill:#532308;}
|
||||
.st37{fill:#683218;}
|
||||
.st38{fill:#844929;}
|
||||
.st39{fill:#582309;}
|
||||
.st40{fill:#7A4021;}
|
||||
.st41{fill:#783F21;}
|
||||
.st42{fill:#5A250A;}
|
||||
.st43{fill:#3C0F07;}
|
||||
.st44{fill:#4F1E06;}
|
||||
.st45{fill:#210308;}
|
||||
.st46{fill:url(#SVGID_00000146478660205493002300000009688568192017483139_);}
|
||||
.st47{fill:url(#SVGID_00000010288141256007762670000007620850369090276751_);}
|
||||
.st48{fill:#944918;}
|
||||
.st49{fill:#773810;}
|
||||
.st50{fill:#AD6121;}
|
||||
.st51{fill:url(#SVGID_00000034800115922175574390000013293002930374637188_);}
|
||||
.st52{fill:#FFFFD9;}
|
||||
.st53{fill:#8C4918;}
|
||||
.st54{fill:#5C2D0E;}
|
||||
.st55{fill:#EFDC84;}
|
||||
.st56{fill:#FFF7DB;}
|
||||
</style>
|
||||
<g id="Layer_2">
|
||||
<g>
|
||||
<polygon class="st0" points="500,74 324,250 135,193 270,670 340,705 500,746 "/>
|
||||
<path class="st1" d="M324,250l-82.5,97.5c22.9-3.8,110.1-21,174.5-100.5c48.6-60,58.5-123.7,61.1-150.1C426,148,375,199,324,250z"
|
||||
/>
|
||||
<polygon class="st2" points="283.7,237.9 241.5,347.5 324,250 "/>
|
||||
<polygon class="st3" points="185.3,208.2 241.5,347.5 283.7,237.9 "/>
|
||||
<polygon class="st4" points="135,193 241.5,347.5 185.3,208.2 "/>
|
||||
<path class="st5" d="M244.2,579c4.5,4.7,28,32,28.8,33c7.9,10.9,33.7,40.9,74.5,68.5C406,720,458.6,734.7,456,734
|
||||
c-38.6-9.9-77.4-19.1-116-29l-70-35L244.2,579z"/>
|
||||
<polygon class="st6" points="241.5,347.5 283.7,626.3 310.5,588.5 "/>
|
||||
<polygon class="st7" points="500,705.1 283.7,626.3 310.5,588.5 500,646.8 "/>
|
||||
<path class="st8" d="M500,746c-31-6.5-75-19.3-122.5-46.5c-42.3-24.2-73.1-51.7-93.8-73.2c72.1,26.3,144.2,52.6,216.3,78.8V746z"
|
||||
/>
|
||||
<polygon class="st9" points="135,193 241.5,347.5 283.7,626.3 244.2,579 "/>
|
||||
</g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="393.5" y1="180.5" x2="806.5" y2="593.5">
|
||||
<stop offset="0" style="stop-color:#FDDB4A"/>
|
||||
<stop offset="1" style="stop-color:#C28631"/>
|
||||
</linearGradient>
|
||||
<polygon class="st10" points="500,74 676,250 865,193 730,670 660,705 500,746 "/>
|
||||
<polygon class="st11" points="716.3,237.9 758.5,347.5 676,250 "/>
|
||||
<polygon class="st12" points="814.7,208.2 758.5,347.5 716.3,237.9 "/>
|
||||
<polygon class="st4" points="865,193 758.5,347.5 814.7,208.2 "/>
|
||||
<path class="st13" d="M755.8,579c-4.5,4.7-28,32-28.8,33c-7.9,10.9-33.7,40.9-74.5,68.5C594,720,541.4,734.7,544,734
|
||||
c38.6-9.9,77.4-19.1,116-29l70-35L755.8,579z"/>
|
||||
<polygon class="st14" points="758.5,347.5 716.3,626.3 689.5,588.5 "/>
|
||||
<polygon class="st15" points="500,705.1 716.3,626.3 689.5,588.5 500,646.8 "/>
|
||||
<path class="st16" d="M500,746c31-6.5,75-19.3,122.5-46.5c42.3-24.2,73.1-51.7,93.8-73.2c-72.1,26.3-144.2,52.6-216.3,78.8V746z"/>
|
||||
<polygon class="st17" points="865,193 758.5,347.5 716.3,626.3 755.8,579 "/>
|
||||
<g>
|
||||
<path class="st18" d="M372,741l24.9,61.1l30.4,10.9l38.2-37.6c-18-5.9-36.5-12.3-55.5-19.5C396.9,751.1,384.3,746.1,372,741z"/>
|
||||
<polygon class="st19" points="408.5,831.5 396.9,802.1 427.3,813.1 "/>
|
||||
<path class="st20" d="M305.9,753.3L372,741l24.9,61.1c-14.1-5.3-30-12.1-46.9-21.1C332.9,771.8,318.2,762.3,305.9,753.3z"/>
|
||||
<path class="st21" d="M256.7,753.4l49.1-0.2c12.9,9.1,28,18.6,45.1,27.7c16.3,8.7,31.8,15.6,45.9,21.1c3.9,9.8,7.7,19.6,11.6,29.4
|
||||
C387,825.8,361,817,333,803C300.9,787,275.5,769,256.7,753.4z"/>
|
||||
<path class="st22" d="M227.6,727.1l19.8-22.9L277,731c-8,0-16.9-0.2-26-1C242.7,729.3,234.9,728.3,227.6,727.1z"/>
|
||||
<path class="st23" d="M341.5,724.2c-11.1,1.9-22.9,3.5-35.5,4.8c-10.1,1-19.8,1.6-29,2c-9.9-8.9-19.8-17.8-29.6-26.7l28.6-33
|
||||
L341.5,724.2z"/>
|
||||
<polygon class="st24" points="209,658 247.4,704.3 276,671.2 "/>
|
||||
<path class="st25" d="M162.8,643.1c7.5,2.7,15.2,5.3,23.2,7.9c7.8,2.5,15.5,4.8,23,7c12.8,15.4,25.6,30.8,38.4,46.3l-19.8,22.9
|
||||
C215.8,715.9,202.8,702,190,685C178.8,670.2,169.9,655.9,162.8,643.1z"/>
|
||||
<path class="st26" d="M162.1,546.4c1.8,7.3,3.7,14.8,5.9,22.6c2.2,7.7,4.5,15.1,6.8,22.2c10.9-6.5,22.2-12.6,33.2-19.2
|
||||
L162.1,546.4z"/>
|
||||
<path class="st27" d="M145.3,609.6l29.5-18.5l17.6,39c-7.6-2.1-16.2-5-25.4-9.1C158.7,617.3,151.5,613.4,145.3,609.6z"/>
|
||||
<path class="st28" d="M174.8,591.2L208,572c5.1,10.8,10.7,21.9,18,34c8.5,14.1,17.2,26.5,25.5,37.1c-19.7-4.3-39.4-8.7-59.1-13
|
||||
L174.8,591.2z"/>
|
||||
<path class="st28" d="M223,608"/>
|
||||
<path class="st29" d="M111.9,508c6.2,5.6,12.9,11.3,20.1,17c10.4,8.2,20.5,15.3,30.1,21.4c4.3,14.9,8.5,29.8,12.8,44.7l-29.5,18.5
|
||||
c-6.9-13.2-14.1-29.1-20.3-47.6C118.3,542,114.3,523.6,111.9,508z"/>
|
||||
<polygon class="st30" points="159,430 178.5,452.5 156.5,456.2 "/>
|
||||
<path class="st31" d="M106.3,469l50.2-12.8l0.6,57.1c-7.9-5.4-16.3-11.8-25-19.3C122,485.4,113.5,476.9,106.3,469z"/>
|
||||
<path class="st32" d="M108.5,357.5L159,430l-2.5,26.2L106.3,469c-1.7-16.9-2.7-36-2.3-57C104.5,391.9,106.2,373.7,108.5,357.5z"/>
|
||||
<path class="st33" d="M156.5,456.2l22-3.7c0.5,13,1.9,28.4,5.5,45.5c3.3,15.6,7.5,29.2,11.9,40.6c-12.9-8.4-25.9-16.9-38.8-25.3
|
||||
c-0.6-9.6-1-19.7-1-30.3C155.9,473.7,156.1,464.8,156.5,456.2z"/>
|
||||
<path class="st25" d="M184,647"/>
|
||||
|
||||
<linearGradient id="SVGID_00000181052587624855630620000008982042343058031036_" gradientUnits="userSpaceOnUse" x1="37.5" y1="635" x2="437.5" y2="635">
|
||||
<stop offset="0" style="stop-color:#844215"/>
|
||||
<stop offset="1" style="stop-color:#D38047"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000181052587624855630620000008982042343058031036_);" d="M108.5,357.5
|
||||
C104.2,385.9,82,550.1,195,691c76.7,95.6,174.6,129.4,213.5,140.5c9.7,27,19.3,54,29,81C400.4,906.1,246.9,875.2,137,733
|
||||
C48,617.8,38.8,495.9,37.5,452.5C61.2,420.8,84.8,389.2,108.5,357.5z"/>
|
||||
|
||||
<linearGradient id="SVGID_00000124853241788307491970000002479847885029808270_" gradientUnits="userSpaceOnUse" x1="90" y1="683.9865" x2="418.2433" y2="683.9865">
|
||||
<stop offset="4.792333e-09" style="stop-color:#904C1D"/>
|
||||
<stop offset="1" style="stop-color:#7D3810"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000124853241788307491970000002479847885029808270_);" d="M408.5,831.5
|
||||
C373.5,822,287.9,793.9,214,713c-72.9-79.8-95.5-169.3-102-205c-8,19.7-14,42.3-22,62c15.8,39.8,51.8,115.1,128,183
|
||||
c77.8,69.3,158.7,96.2,200.2,107C415,850.5,411.7,841,408.5,831.5z"/>
|
||||
<path class="st36" d="M106.3,469l5.6,39.1c-5.9,14.1-11.6,29.4-16.9,46c-8.3,25.8-15,53.1-19,75c-3-7.4-6.1-15-9-23
|
||||
c-2.9-7.9-5.6-16.5-8-24c5.3-18.4,13.1-38.6,22-60C89.1,502.3,97.8,484.6,106.3,469z"/>
|
||||
<path class="st37" d="M145.3,609.6l17.4,33.5c-0.4,17.9-0.1,37.2,1.2,57.9c1.6,24.7,4.5,51.5,8,72c-6.1-5.9-12.5-12.5-19-20
|
||||
c-6-6.9-11.3-13.6-16-20c-0.8-16.8,0-36.3,1-56C139.2,652.3,141.9,629.7,145.3,609.6z"/>
|
||||
<path class="st38" d="M227.1,726.5l29.6,27c4.5,15.1,10.2,31.4,17.3,48.6c10.7,25.8,23.6,50.1,35,69c-7.6-3.5-15.7-7.5-24-12
|
||||
c-7.9-4.3-15.2-8.7-22-13c-6.6-17.1-13-36.4-19-56C237.1,767.7,231.6,746.5,227.1,726.5z"/>
|
||||
<path class="st39" d="M227.1,726.5c1.7,8.2,3.6,16.7,5.9,25.5c1.6,6.2,3.3,12.2,5.1,17.9c10.9,7.9,21.7,15.9,32.6,23.8l-13.9-40.8
|
||||
L227.1,726.5z"/>
|
||||
<path class="st39" d="M163.7,696l-24.8-33.5c0.5-7.5,1.2-15.4,2.1-23.5c1.2-10.3,2.7-20.1,4.3-29.4c5.8,11.2,11.6,22.3,17.4,33.5
|
||||
L163.7,696z"/>
|
||||
<path class="st40" d="M195.9,538.6c-12-6.9-25.1-15.2-38.8-25.3c-2.3-1.7-4.7-3.5-7-5.3c-17.4-13.4-31.9-26.8-43.7-39
|
||||
c-0.5,5.5-0.6,12.8,0.7,21c1.1,7.2,3,13.3,4.9,18c16.7,15.7,31.8,26.6,43.1,34c2.4,1.5,4.7,3,7.1,4.4
|
||||
c16.6,10.1,31.6,17.2,44.9,22.6C203.1,558.8,199.8,548.8,195.9,538.6z"/>
|
||||
<path class="st41" d="M251.5,643.1c-13.6-1.5-29.4-4.3-46.5-9.1c-24.2-6.9-44.2-15.9-59.7-24.4c1.2,4.5,3,9.7,5.7,15.4
|
||||
c3.7,7.7,8.1,13.8,11.8,18.1c4.7,2.1,11.7,5,20.2,7.9c12.6,4.3,22.5,6.4,30,8c25.7,5.4,49.6,9.8,63,12.2
|
||||
C267.8,661.9,259.7,652.5,251.5,643.1z"/>
|
||||
<path class="st42" d="M227.6,727.1c17,2.2,37,3.6,59.4,2.9c20.5-0.7,38.8-2.9,54.5-5.8c9.8,5.9,19.7,11.8,29.5,17.8
|
||||
c-12.7,4.3-29.9,6.3-47,9c-26.2,4.2-49.2,4-67.3,2.4c-4.6-2.7-10.1-6.4-15.7-11.4C235.2,736.8,230.8,731.5,227.6,727.1z"/>
|
||||
<polygon class="st43" points="192.4,630.1 209,658 276,671.2 251.5,643.1 "/>
|
||||
<polyline class="st44" points="208,572 162.1,546.4 157,513.3 195.9,538.6 208,572 "/>
|
||||
<path class="st45" d="M277,731l28.9,22.3c10.8-1.1,22.4-2.6,34.6-4.8c10.8-1.9,22-5.1,31.5-7.5c-9.8-5.9-20.7-10.8-30.5-16.8
|
||||
c-9.8,1.6-20.1,3.1-31,4.3C298.7,729.8,287.7,730.5,277,731z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st18" d="M627,741l-24.9,61.1l-30.4,10.9l-38.2-37.6c18-5.9,36.5-12.3,55.5-19.5C602.1,751.1,614.7,746.1,627,741z"/>
|
||||
<polygon class="st19" points="590.5,831.5 602.1,802.1 571.7,813.1 "/>
|
||||
<path class="st20" d="M693.1,753.3L627,741l-24.9,61.1c14.1-5.3,30-12.1,46.9-21.1C666.1,771.8,680.8,762.3,693.1,753.3z"/>
|
||||
<path class="st21" d="M742.3,753.4l-49.1-0.2c-12.9,9.1-28,18.6-45.1,27.7c-16.3,8.7-31.8,15.6-45.9,21.1
|
||||
c-3.9,9.8-7.7,19.6-11.6,29.4C612,825.8,638,817,666,803C698.1,787,723.5,769,742.3,753.4z"/>
|
||||
<path class="st22" d="M771.4,727.1l-19.8-22.9L722,731c8,0,16.9-0.2,26-1C756.3,729.3,764.1,728.3,771.4,727.1z"/>
|
||||
<path class="st23" d="M657.5,724.2c11.1,1.9,22.9,3.5,35.5,4.8c10.1,1,19.8,1.6,29,2c9.9-8.9,19.8-17.8,29.6-26.7l-28.6-33
|
||||
L657.5,724.2z"/>
|
||||
<polygon class="st24" points="790,658 751.6,704.3 723,671.2 "/>
|
||||
<path class="st25" d="M836.2,643.1c-7.5,2.7-15.2,5.3-23.2,7.9c-7.8,2.5-15.5,4.8-23,7c-12.8,15.4-25.6,30.8-38.4,46.3l19.8,22.9
|
||||
c11.7-11.2,24.7-25.2,37.6-42.1C820.2,670.2,829.1,655.9,836.2,643.1z"/>
|
||||
<path class="st26" d="M836.9,546.4c-1.8,7.3-3.7,14.8-5.9,22.6c-2.2,7.7-4.5,15.1-6.8,22.2c-10.9-6.5-22.2-12.6-33.2-19.2
|
||||
L836.9,546.4z"/>
|
||||
<path class="st27" d="M853.7,609.6l-29.5-18.5l-17.6,39c7.6-2.1,16.2-5,25.4-9.1C840.3,617.3,847.5,613.4,853.7,609.6z"/>
|
||||
<path class="st28" d="M824.2,591.2L791,572c-5.1,10.8-10.7,21.9-18,34c-8.5,14.1-17.2,26.5-25.5,37.1c19.7-4.3,39.4-8.7,59.1-13
|
||||
L824.2,591.2z"/>
|
||||
<path class="st28" d="M776,608"/>
|
||||
<path class="st29" d="M887.1,508c-6.2,5.6-12.9,11.3-20.1,17c-10.4,8.2-20.5,15.3-30.1,21.4c-4.3,14.9-8.5,29.8-12.8,44.7
|
||||
l29.5,18.5c6.9-13.2,14.1-29.1,20.3-47.6C880.7,542,884.7,523.6,887.1,508z"/>
|
||||
<polygon class="st30" points="840,430 820.5,452.5 842.5,456.2 "/>
|
||||
<path class="st31" d="M892.7,469l-50.2-12.8l-0.6,57.1c7.9-5.4,16.3-11.8,25-19.3C877,485.4,885.5,476.9,892.7,469z"/>
|
||||
<path class="st32" d="M890.5,357.5L840,430l2.5,26.2l50.2,12.8c1.7-16.9,2.7-36,2.3-57C894.5,391.9,892.8,373.7,890.5,357.5z"/>
|
||||
<path class="st33" d="M842.5,456.2l-22-3.7c-0.5,13-1.9,28.4-5.5,45.5c-3.3,15.6-7.5,29.2-11.9,40.6c12.9-8.4,25.9-16.9,38.8-25.3
|
||||
c0.6-9.6,1-19.7,1-30.3C843.1,473.7,842.9,464.8,842.5,456.2z"/>
|
||||
<path class="st25" d="M815,647"/>
|
||||
|
||||
<linearGradient id="SVGID_00000109747415768703344880000013296253376583759777_" gradientUnits="userSpaceOnUse" x1="267.5" y1="635" x2="667.5" y2="635" gradientTransform="matrix(-1 0 0 1 1229 0)">
|
||||
<stop offset="0" style="stop-color:#844215"/>
|
||||
<stop offset="1" style="stop-color:#D38047"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000109747415768703344880000013296253376583759777_);" d="M890.5,357.5
|
||||
C894.8,385.9,917,550.1,804,691c-76.7,95.6-174.6,129.4-213.5,140.5c-9.7,27-19.3,54-29,81c37.1-6.4,190.6-37.3,300.5-179.5
|
||||
c89-115.2,98.2-237.1,99.5-280.5C937.8,420.8,914.2,389.2,890.5,357.5z"/>
|
||||
|
||||
<linearGradient id="SVGID_00000017506882430593231550000015389667641078630316_" gradientUnits="userSpaceOnUse" x1="320" y1="683.9865" x2="648.2432" y2="683.9865" gradientTransform="matrix(-1 0 0 1 1229 0)">
|
||||
<stop offset="4.792333e-09" style="stop-color:#904C1D"/>
|
||||
<stop offset="1" style="stop-color:#7D3810"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000017506882430593231550000015389667641078630316_);" d="M590.5,831.5
|
||||
c35-9.5,120.6-37.6,194.5-118.5c72.9-79.8,95.5-169.3,102-205c8,19.7,14,42.3,22,62c-15.8,39.8-51.8,115.1-128,183
|
||||
c-77.8,69.3-158.7,96.2-200.2,107C584,850.5,587.3,841,590.5,831.5z"/>
|
||||
<path class="st36" d="M892.7,469l-5.6,39.1c5.9,14.1,11.6,29.4,16.9,46c8.3,25.8,15,53.1,19,75c3-7.4,6.1-15,9-23
|
||||
c2.9-7.9,5.6-16.5,8-24c-5.3-18.4-13.1-38.6-22-60C909.9,502.3,901.2,484.6,892.7,469z"/>
|
||||
<path class="st37" d="M853.7,609.6l-17.4,33.5c0.4,17.9,0.1,37.2-1.2,57.9c-1.6,24.7-4.5,51.5-8,72c6.1-5.9,12.5-12.5,19-20
|
||||
c6-6.9,11.3-13.6,16-20c0.8-16.8,0-36.3-1-56C859.8,652.3,857.1,629.7,853.7,609.6z"/>
|
||||
<path class="st38" d="M771.9,726.5l-29.6,27c-4.5,15.1-10.2,31.4-17.3,48.6c-10.7,25.8-23.6,50.1-35,69c7.6-3.5,15.7-7.5,24-12
|
||||
c7.9-4.3,15.2-8.7,22-13c6.6-17.1,13-36.4,19-56C761.9,767.7,767.4,746.5,771.9,726.5z"/>
|
||||
<path class="st39" d="M771.9,726.5c-1.7,8.2-3.6,16.7-5.9,25.5c-1.6,6.2-3.3,12.2-5.1,17.9c-10.9,7.9-21.7,15.9-32.6,23.8
|
||||
l13.9-40.8L771.9,726.5z"/>
|
||||
<path class="st39" d="M835.3,696l24.8-33.5c-0.5-7.5-1.2-15.4-2.1-23.5c-1.2-10.3-2.7-20.1-4.3-29.4
|
||||
c-5.8,11.2-11.6,22.3-17.4,33.5L835.3,696z"/>
|
||||
<path class="st40" d="M803.1,538.6c12-6.9,25.1-15.2,38.8-25.3c2.3-1.7,4.7-3.5,7-5.3c17.4-13.4,31.9-26.8,43.7-39
|
||||
c0.5,5.5,0.6,12.8-0.7,21c-1.1,7.2-3,13.3-4.9,18c-16.7,15.7-31.8,26.6-43.1,34c-2.4,1.5-4.7,3-7.1,4.4
|
||||
c-16.6,10.1-31.6,17.2-44.9,22.6C795.9,558.8,799.2,548.8,803.1,538.6z"/>
|
||||
<path class="st41" d="M747.5,643.1c13.6-1.5,29.4-4.3,46.5-9.1c24.2-6.9,44.2-15.9,59.7-24.4c-1.2,4.5-3,9.7-5.7,15.4
|
||||
c-3.7,7.7-8.1,13.8-11.8,18.1c-4.7,2.1-11.7,5-20.2,7.9c-12.6,4.3-22.5,6.4-30,8c-25.7,5.4-49.6,9.8-63,12.2
|
||||
C731.2,661.9,739.3,652.5,747.5,643.1z"/>
|
||||
<path class="st42" d="M771.4,727.1c-17,2.2-37,3.6-59.4,2.9c-20.5-0.7-38.8-2.9-54.5-5.8c-9.8,5.9-19.7,11.8-29.5,17.8
|
||||
c12.7,4.3,29.9,6.3,47,9c26.2,4.2,49.2,4,67.3,2.4c4.6-2.7,10.1-6.4,15.7-11.4C763.8,736.8,768.2,731.5,771.4,727.1z"/>
|
||||
<polygon class="st43" points="806.6,630.1 790,658 723,671.2 747.5,643.1 "/>
|
||||
<polyline class="st44" points="791,572 836.9,546.4 842,513.3 803.1,538.6 791,572 "/>
|
||||
<path class="st45" d="M722,731l-28.9,22.3c-10.8-1.1-22.4-2.6-34.6-4.8c-10.8-1.9-22-5.1-31.5-7.5c9.8-5.9,20.7-10.8,30.5-16.8
|
||||
c9.8,1.6,20.1,3.1,31,4.3C700.3,729.8,711.3,730.5,722,731z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Layer_3">
|
||||
<polygon class="st48" points="241.5,347.5 500,229 500,646 310.5,588.5 "/>
|
||||
<polygon class="st49" points="758,347.5 499.5,229 499.5,646 689,588.5 "/>
|
||||
<path class="st50" d="M499.5,260L737,367.5c-7.6,25.8-17,56.8-28,92c-17.4,55.5-22.8,70.1-37,86c-4,4.5-16.7,18-61,39
|
||||
c-25.8,12.2-63.2,27.4-111.5,38.5C499.5,502,499.5,381,499.5,260z"/>
|
||||
|
||||
<linearGradient id="SVGID_00000014612060945716269740000004954183021845470646_" gradientUnits="userSpaceOnUse" x1="381.25" y1="623" x2="381.25" y2="283.2944">
|
||||
<stop offset="9.244864e-02" style="stop-color:#C67121"/>
|
||||
<stop offset="1" style="stop-color:#FFCE48"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000014612060945716269740000004954183021845470646_);" d="M500,260L262.5,367.5
|
||||
c7.6,25.8,17,56.8,28,92c17.4,55.5,22.8,70.1,37,86c4,4.5,16.7,18,61,39c25.8,12.2,63.2,27.4,111.5,38.5C500,502,500,381,500,260z"
|
||||
/>
|
||||
<polygon class="st52" points="301.5,388.5 341.5,523.5 500,523.5 500,320 421.5,427.5 "/>
|
||||
<polygon class="st53" points="341.5,523.5 500,579 500,523.5 "/>
|
||||
<polygon class="st54" points="658,523.5 499.5,579 499.5,523.5 "/>
|
||||
<polygon class="st0" points="301.5,388.5 426.5,462.5 500,320 421.5,427.5 "/>
|
||||
<polygon class="st55" points="698,388.5 658,523.5 499.5,523.5 499.5,320 578,427.5 "/>
|
||||
<polygon class="st56" points="698,388.5 573,462.5 499.5,320 578,427.5 "/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
40
assets/badges/developer.svg
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="343"
|
||||
height="343"
|
||||
viewBox="0 0 343 343"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="developer.svg"
|
||||
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.5451895"
|
||||
inkscape:cx="171.30355"
|
||||
inkscape:cy="171.5"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2089"
|
||||
inkscape:window-x="1680"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
d="M 305.64988,87.191016 247.50845,145.3188 194.6717,92.467053 252.79949,34.340626 C 217.61455,19.871627 175.68861,26.897158 147.12599,55.489784 118.56337,84.052402 111.52229,125.99334 125.99184,161.17828 l -93.806513,93.79014 c -5.84347,5.84347 -5.84347,15.29069 0,21.13416 l 31.7176,31.7176 c 5.84347,5.84347 15.290685,5.84347 21.134154,0 l 93.790139,-93.80651 c 35.18495,14.46818 77.12589,7.42846 105.68851,-21.13416 28.56262,-28.57762 35.58869,-70.51856 21.13415,-105.688494 z"
|
||||
fill="#99aab5"
|
||||
id="path4"
|
||||
style="stroke-width:1.36402" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
4
assets/badges/early_adopter.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="343" height="343" viewBox="0 0 343 343" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M252.571 30L333.429 171.5L252.571 313H90.8571L10 171.5L90.8571 30H252.571Z" fill="#509AF0"/>
|
||||
<path d="M164.486 82.3018C182.31 82.3018 196.421 86.5928 206.818 95.1748C217.298 103.757 222.538 115.722 222.538 131.071C222.538 139.323 220.475 146.791 216.349 153.475C212.223 160.159 206.406 165.523 198.896 169.566C209.046 173.032 216.803 178.561 222.167 186.153C227.613 193.744 230.336 202.945 230.336 213.755C230.336 230.672 225.427 243.875 215.607 253.365C205.787 262.772 192.295 267.476 175.131 267.476C162.093 267.476 150.499 264.34 140.349 258.068V313H104.577V137.012C104.577 126.697 107.176 117.373 112.375 109.038C117.573 100.621 124.794 94.0608 134.036 89.3572C143.278 84.6536 153.428 82.3018 164.486 82.3018ZM186.766 133.794C186.766 127.027 184.703 121.581 180.577 117.455C176.534 113.329 171.17 111.266 164.486 111.266C157.472 111.266 151.695 113.618 147.157 118.322C142.618 122.943 140.349 129.338 140.349 137.507V231.456C147.115 236.242 156.028 238.635 167.085 238.635C175.502 238.635 182.186 236.283 187.137 231.58C192.089 226.793 194.564 220.687 194.564 213.26C194.564 204.348 192.295 197.416 187.756 192.465C183.3 187.432 176.699 184.915 167.952 184.915H155.945V158.797H165.6C179.711 158.302 186.766 149.968 186.766 133.794Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
41
assets/badges/founder.svg
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="343"
|
||||
height="343"
|
||||
viewBox="0 0 343 343"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="founder.svg"
|
||||
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.5451895"
|
||||
inkscape:cx="171.30355"
|
||||
inkscape:cy="171.5"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2089"
|
||||
inkscape:window-x="1680"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
d="m 233.20363,120.30495 c 0,23.32978 -12.69345,37.33415 -39.78401,37.33415 h -44.853 V 83.816247 h 44.86112 c 27.08244,0 39.77589,14.422841 39.77589,36.488703 z M 32.781712,23.579841 76.206371,83.95858 V 321.35524 H 148.57475 V 208.96003 h 17.35345 l 61.7961,112.41959 h 81.68066 L 240.84435,203.44414 c 19.14242,-4.66948 36.11939,-15.75136 48.12217,-31.41064 12.00278,-15.65927 18.31226,-34.95744 17.88296,-54.70047 0,-51.756865 -36.39295,-93.753189 -109.18833,-93.753189 H 76.206371 Z"
|
||||
fill="#efab44"
|
||||
stroke="#efab44"
|
||||
stroke-width="0.97733"
|
||||
id="path2" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
154
assets/badges/moderation.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
38
assets/badges/paw.svg
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<metadata>
|
||||
<rdf:RDF xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:dc = "http://purl.org/dc/elements/1.1/"
|
||||
>
|
||||
|
||||
<rdf:Description rdf:about="">
|
||||
<dc:title>Mutant Standard emoji 2020.04</dc:title>
|
||||
</rdf:Description>
|
||||
|
||||
<cc:work rdf:about="">
|
||||
<cc:license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/"/>
|
||||
<cc:attributionName>Dzuk</cc:attributionName>
|
||||
<cc:attributionURL>http://mutant.tech/</cc:attributionURL>
|
||||
</cc:work>
|
||||
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
|
||||
<rect id="v--paw-" serif:id="v [paw]" x="0" y="0" width="32" height="32" style="fill:none;"/>
|
||||
<clipPath id="_clip1">
|
||||
<rect x="0" y="0" width="32" height="32"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#_clip1)">
|
||||
<g id="Layer10">
|
||||
<path d="M19.25,3.52c0.755,-2.176 3.064,-3.455 5.341,-2.886c2.41,0.603 3.877,3.048 3.275,5.457l-1.866,7.463l0,1.77c0.832,0.315 1.575,0.85 2.142,1.563c0.948,1.193 1.301,2.753 0.959,4.237c-0.116,0.502 -0.238,1.032 -0.363,1.574c-1.257,5.445 -6.105,9.302 -11.693,9.302l-0.045,-0.018l0,0.014c0,0 -0.412,0 -1.035,0c-5.571,0 -10.426,-3.79 -11.778,-9.194c-0.609,-2.431 -1.178,-4.706 -1.178,-4.706c-0.603,-2.409 0.864,-4.855 3.273,-5.457c0.165,-0.042 0.331,-0.073 0.495,-0.096c0.188,-1.832 1.498,-3.436 3.387,-3.909c0.358,-0.089 0.718,-0.133 1.072,-0.135l-0.602,-2.408c-0.602,-2.409 0.865,-4.854 3.275,-5.457c2.277,-0.569 4.586,0.71 5.341,2.886Z"/>
|
||||
</g>
|
||||
<g id="Layer9">
|
||||
<path d="M7,15c2.268,-2.268 2.496,-1.997 5,-4c0.736,-0.589 1.057,-2 2,-2c0.943,0 1.333,1.333 2,2l8,4l0,9l-8,-2l-9,0l0,-1.606c-0.517,-0.015 -1.015,-0.156 -1.455,-0.402l-0.558,-2.229l2.013,-2.763Z" style="fill:#5E3583;"/>
|
||||
<path d="M24.229,17c0.914,0 1.778,0.417 2.348,1.132c0.569,0.716 0.781,1.652 0.575,2.543c-0.116,0.502 -0.238,1.032 -0.363,1.574c-1.047,4.537 -5.088,7.751 -9.744,7.751l-0.045,0c0.001,-0.001 0.001,-0.003 0.002,-0.004l-0.002,0l-1.035,0c-4.653,0 -8.709,-3.166 -9.838,-7.679l-0.582,-2.325c0.681,0.381 1.503,0.511 2.316,0.308c0.01,-0.002 0.021,-0.005 0.031,-0.008c0.933,-0.233 1.709,-0.877 2.111,-1.75c0.138,-0.299 0.226,-0.614 0.266,-0.933c0.694,0.426 1.549,0.577 2.385,0.368c0.001,0 0.002,-0.001 0.002,-0.001c0.201,-0.05 0.393,-0.119 0.574,-0.205c-0.02,0.019 0.978,0.078 0.909,-0.655c0.538,-0.562 0.861,-1.321 0.861,-2.141c0,-0.161 0,-0.313 0,-0.447c0,-0.405 -0.068,-0.807 -0.2,-1.19l-1.059,-3.064l-1.166,-4.668c-0.335,-1.338 0.48,-2.697 1.819,-3.031c1.338,-0.335 2.697,0.48 3.031,1.819l1.825,7.298l1.825,-7.298c0.088,-0.344 0.243,-0.666 0.463,-0.944c0.2,-0.252 0.448,-0.465 0.728,-0.624c0.271,-0.154 0.57,-0.257 0.879,-0.301c0.277,-0.04 0.561,-0.032 0.836,0.022c0.269,0.052 0.529,0.149 0.766,0.286c0.22,0.126 0.42,0.286 0.591,0.473c0.347,0.377 0.574,0.86 0.641,1.369c0.041,0.312 0.02,0.627 -0.054,0.931l-1.925,7.702l0,1.692l-8,0l0,1.663l-1,1.337c0,3.314 3.686,6 7,6l1,-1l0,-2l-1,0c-2.209,0 -4,-1.791 -4,-4l6.229,0Zm-19.242,0.763l-0.038,-0.152c-0.335,-1.339 0.48,-2.697 1.818,-3.032c0.521,-0.131 1.045,-0.087 1.511,0.094l0.786,1.573c0.295,0.589 0.306,1.28 0.031,1.878c-0.275,0.598 -0.807,1.039 -1.446,1.198c-0.01,0.003 -0.02,0.005 -0.031,0.008c-1.119,0.28 -2.262,-0.365 -2.6,-1.468l-0.031,-0.099Zm3.816,-4.275c-0.26,-1.299 0.546,-2.589 1.846,-2.913c0.876,-0.219 1.761,0.054 2.361,0.645l0.845,2.444c0.096,0.278 0.145,0.57 0.145,0.864c0,0.134 0,0.286 0,0.447c0,0.961 -0.654,1.798 -1.586,2.031c-0.001,0 -0.002,0.001 -0.003,0.001c-0.96,0.24 -1.958,-0.219 -2.401,-1.105l-1.207,-2.414Z" style="fill:#C596FD;"/>
|
||||
<path d="M23,23l0,1.158c0,0.923 -0.426,1.796 -1.154,2.364c-0.728,0.569 -1.677,0.77 -2.574,0.546c-0.917,-0.229 -1.782,-0.445 -2.294,-0.574c-0.318,-0.079 -0.643,-0.119 -0.97,-0.119l-0.016,0c-0.327,0 -0.652,0.04 -0.97,0.119c-0.512,0.129 -1.377,0.345 -2.294,0.574c-0.897,0.224 -1.846,0.023 -2.574,-0.546c-0.728,-0.568 -1.154,-1.441 -1.154,-2.364c0,-0.172 0,-0.34 0,-0.501c0,-1.061 0.421,-2.078 1.172,-2.829c0.819,-0.819 1.951,-1.951 3,-3c0.019,-0.019 0.038,-0.038 0.058,-0.057c0.345,-0.163 0.652,-0.386 0.909,-0.655c0.569,-0.299 1.207,-0.459 1.861,-0.459l0,0.343c0,3.314 2.686,6 6,6l1,0Z" style="fill:#8149BC;"/>
|
||||
<path d="M23.704,4.041c1.047,0.261 1.589,1.707 1.21,3.226c-0.378,1.52 -1.536,2.542 -2.583,2.281c-1.047,-0.261 -1.589,-1.707 -1.21,-3.227c0.379,-1.519 1.536,-2.541 2.583,-2.28Zm-8.943,0.001c-1.047,0.261 -1.596,1.677 -1.227,3.16c0.37,1.483 1.52,2.475 2.567,2.214c1.047,-0.261 1.597,-1.677 1.227,-3.16c-0.37,-1.483 -1.52,-2.475 -2.567,-2.214Z" style="fill:#8149BC;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
20
assets/badges/raccoon.svg
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-miterlimit:3;">
|
||||
<metadata>
|
||||
<rdf:RDF xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:dc = "http://purl.org/dc/elements/1.1/"
|
||||
>
|
||||
|
||||
<rdf:Description rdf:about="">
|
||||
<dc:title>Mutant Standard emoji 2020.04</dc:title>
|
||||
</rdf:Description>
|
||||
|
||||
<cc:work rdf:about="">
|
||||
<cc:license rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/"/>
|
||||
<cc:attributionName>Dzuk</cc:attributionName>
|
||||
<cc:attributionURL>http://mutant.tech/</cc:attributionURL>
|
||||
</cc:work>
|
||||
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<rect id="raccoon" x="0" y="0" width="32" height="32" style="fill:none;"/><clipPath id="_clip1"><rect x="0" y="0" width="32" height="32"/></clipPath><g clip-path="url(#_clip1)"><g id="outline"><path d="M21.369,8.952c0.087,-0.295 0.247,-0.568 0.471,-0.792c0.001,-0.001 0.001,-0.001 0.002,-0.002c0.105,-0.105 0.226,-0.192 0.358,-0.258c0.792,-0.396 3.729,-1.865 5.094,-2.547c0.187,-0.094 0.404,-0.109 0.603,-0.043c0.198,0.066 0.362,0.209 0.456,0.396c0,0 0,0 0,0.001c0.407,0.814 0.407,1.772 0,2.586c-0.575,1.151 -1.401,2.803 -1.906,3.813c-0.009,0.017 -0.018,0.034 -0.027,0.051c0.715,0.946 1.222,2.054 1.462,3.255c0.536,2.68 1.118,5.588 1.118,5.588l-2,0l0,2l-2,-1c0,0 -3.283,2.189 -4.992,3.328c-0.657,0.438 -1.429,0.672 -2.219,0.672c-1.042,0 -2.536,0 -3.578,0c-0.79,0 -1.562,-0.234 -2.219,-0.672c-1.709,-1.139 -4.992,-3.328 -4.992,-3.328l-2,1l0,-2l-2,0l1.118,-5.588c0.24,-1.201 0.747,-2.309 1.462,-3.255c-0.009,-0.017 -0.018,-0.034 -0.027,-0.051c-0.505,-1.01 -1.331,-2.662 -1.906,-3.813c-0.407,-0.814 -0.407,-1.772 0,-2.586c0,-0.001 0,-0.001 0,-0.001c0.094,-0.187 0.258,-0.33 0.456,-0.396c0.199,-0.066 0.416,-0.051 0.603,0.043c1.365,0.682 4.302,2.151 5.094,2.547c0.132,0.066 0.253,0.153 0.358,0.258c0.001,0.001 0.001,0.001 0.002,0.002c0.224,0.224 0.384,0.497 0.471,0.792l1.268,-0.461c2.649,-0.963 5.553,-0.963 8.202,0l1.268,0.461Z" style="fill:none;stroke:#000;stroke-width:4px;"/></g><g id="emoji"><g><path d="M3.993,16.036l0.125,-0.624c0.548,-2.74 2.485,-4.995 5.11,-5.95c0.877,-0.318 1.799,-0.654 2.671,-0.971c2.649,-0.963 5.553,-0.963 8.202,0c0.872,0.317 1.794,0.653 2.671,0.971c2.625,0.955 4.562,3.21 5.11,5.95l0.125,0.624c-2.191,-1.95 -5.028,-3.036 -7.978,-3.036c-0.009,0 -0.019,0 -0.029,0c-1.657,0 -3,1.343 -3,3c0,1.105 0.895,2 2,2c0,0 0,0 0,0l1,1l-4,4l-4,-4l1,-1l0,0c1.105,0 2,-0.895 2,-2c0,-1.657 -1.343,-3 -3,-3c-0.01,0 -0.02,0 -0.029,0c-2.95,0 -5.787,1.086 -7.978,3.036Z" style="fill:#878787;"/><path d="M19.333,19.667c0.01,0.004 3.479,0.333 3.479,0.333c0,0 -0.353,2.537 0,3.459l-2.804,1.869c-0.657,0.438 -1.429,0.672 -2.219,0.672c-1.042,0 -2.536,0 -3.578,0c-0.79,0 -1.562,-0.234 -2.219,-0.672l-2.804,-1.869c0.342,-0.893 0,-3.097 0,-3.097c0,0 3.469,-0.691 3.479,-0.695l3.333,3.333l3.333,-3.333Zm-1.319,-1.927c-0.606,-0.343 -1.014,-0.994 -1.014,-1.74c0,-1.657 1.343,-3 3,-3c0.01,0 0.02,0 0.029,0c2.95,0 5.787,1.086 7.978,3.036l0.993,4.964l-1.667,0c0,0 -9.328,-3.346 -9.319,-3.26Zm-13.347,3.26l-1.667,0l0.993,-4.964c2.191,-1.95 5.028,-3.036 7.978,-3.036c0.009,0 0.019,0 0.029,0c1.657,0 3,1.343 3,3c0,0.746 -0.408,1.397 -1.014,1.74c0.009,-0.086 -9.319,3.26 -9.319,3.26Z" style="fill:#e1e1e1;"/><path d="M4.667,21l1.626,-2.927c1.054,-1.897 3.053,-3.073 5.222,-3.073c0.003,0 0.006,0 0.009,0c1.367,0 2.476,1.109 2.476,2.476c0,0.001 0,0.002 0,0.002c0,0.933 -0.527,1.785 -1.361,2.202c-0.015,0.008 -0.03,0.016 -0.046,0.023c-1.567,0.784 -2.781,2.126 -3.405,3.756l-2.188,-1.459l-2,1l0,-2l-0.333,0Zm18.145,2.459c-0.624,-1.63 -1.838,-2.972 -3.405,-3.756c-0.016,-0.007 -0.031,-0.015 -0.046,-0.023c-0.834,-0.417 -1.361,-1.269 -1.361,-2.202c0,0 0,-0.001 0,-0.002c0,-1.367 1.109,-2.476 2.476,-2.476c0.003,0 0.006,0 0.009,0c2.169,0 4.168,1.176 5.222,3.073l1.626,2.927l-0.333,0l0,2l-2,-1l-2.188,1.459Z" style="fill:#484848;"/><g><circle cx="11.5" cy="17.5" r="1.5"/><circle cx="20.5" cy="17.5" r="1.5"/><path d="M15.236,21c-0.155,0 -0.308,0.036 -0.447,0.106c-0.047,0.023 -0.1,0.049 -0.158,0.078c-0.901,0.451 -1.266,1.546 -0.815,2.447c0,0.001 0,0.001 0,0.001c0.113,0.226 0.343,0.368 0.595,0.368c0.768,0 2.41,0 3.178,0c0.252,0 0.482,-0.142 0.595,-0.368c0,0 0,0 0,-0.001c0.451,-0.901 0.086,-1.996 -0.815,-2.447c-0.058,-0.029 -0.111,-0.055 -0.158,-0.078c-0.139,-0.07 -0.292,-0.106 -0.447,-0.106c-0.385,0 -1.143,0 -1.528,0Z"/></g></g><path d="M6.894,12.553c-0.494,0.247 -1.094,0.047 -1.341,-0.447c-0.505,-1.01 -1.331,-2.662 -1.906,-3.813c-0.407,-0.814 -0.407,-1.772 0,-2.586c0,-0.001 0,-0.001 0,-0.001c0.094,-0.187 0.258,-0.33 0.456,-0.396c0.199,-0.066 0.416,-0.051 0.603,0.043c1.365,0.682 4.302,2.151 5.094,2.547c0.132,0.066 0.253,0.153 0.358,0.258c0.001,0.001 0.001,0.001 0.002,0.002c0.426,0.426 0.621,1.031 0.525,1.627c-0.097,0.595 -0.474,1.107 -1.013,1.377c-0.973,0.486 -2.044,1.022 -2.778,1.389Zm18.212,0c0.494,0.247 1.094,0.047 1.341,-0.447c0.505,-1.01 1.331,-2.662 1.906,-3.813c0.407,-0.814 0.407,-1.772 0,-2.586c0,-0.001 0,-0.001 0,-0.001c-0.094,-0.187 -0.258,-0.33 -0.456,-0.396c-0.199,-0.066 -0.416,-0.051 -0.603,0.043c-1.365,0.682 -4.302,2.151 -5.094,2.547c-0.132,0.066 -0.253,0.153 -0.358,0.258c-0.001,0.001 -0.001,0.001 -0.002,0.002c-0.426,0.426 -0.621,1.031 -0.525,1.627c0.097,0.595 0.474,1.107 1.013,1.377c0.973,0.486 2.044,1.022 2.778,1.389Z" style="fill:#484848;"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
41
assets/badges/revolt_r.svg
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="343"
|
||||
height="343"
|
||||
viewBox="0 0 343 343"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="founder.svg"
|
||||
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.5451895"
|
||||
inkscape:cx="171.30355"
|
||||
inkscape:cy="171.5"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2089"
|
||||
inkscape:window-x="1680"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<path
|
||||
d="m 233.20363,120.30495 c 0,23.32978 -12.69345,37.33415 -39.78401,37.33415 h -44.853 V 83.816247 h 44.86112 c 27.08244,0 39.77589,14.422841 39.77589,36.488703 z M 32.781712,23.579841 76.206371,83.95858 V 321.35524 H 148.57475 V 208.96003 h 17.35345 l 61.7961,112.41959 h 81.68066 L 240.84435,203.44414 c 19.14242,-4.66948 36.11939,-15.75136 48.12217,-31.41064 12.00278,-15.65927 18.31226,-34.95744 17.88296,-54.70047 0,-51.756865 -36.39295,-93.753189 -109.18833,-93.753189 H 76.206371 Z"
|
||||
fill="#efab44"
|
||||
stroke="#efab44"
|
||||
stroke-width="0.97733"
|
||||
id="path2" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
153
assets/badges/supporter.svg
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 32 32"
|
||||
version="1.1"
|
||||
xml:space="preserve"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"
|
||||
id="svg46"
|
||||
sodipodi:docname="supporter.svg"
|
||||
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><defs
|
||||
id="defs50" /><sodipodi:namedview
|
||||
id="namedview48"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="27.28125"
|
||||
inkscape:cx="15.981672"
|
||||
inkscape:cy="16"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="2089"
|
||||
inkscape:window-x="1680"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg46" />
|
||||
<metadata
|
||||
id="metadata2">
|
||||
<rdf:RDF>
|
||||
|
||||
<rdf:Description
|
||||
rdf:about="">
|
||||
<dc:title>Mutant Standard emoji 2020.04</dc:title>
|
||||
</rdf:Description>
|
||||
|
||||
<cc:work
|
||||
rdf:about="">
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" />
|
||||
<cc:attributionName>Dzuk</cc:attributionName>
|
||||
<cc:attributionURL>http://mutant.tech/</cc:attributionURL>
|
||||
</cc:work>
|
||||
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
|
||||
<rect
|
||||
id="green_money"
|
||||
x="0"
|
||||
y="0"
|
||||
width="32"
|
||||
height="32"
|
||||
style="fill:none;" />
|
||||
|
||||
<g
|
||||
id="Layer2">
|
||||
<path
|
||||
d="M29,21l-26,0l-1,1l0,3l28,0l0,-3l-1,-1Z"
|
||||
style="fill:#60ae33;"
|
||||
id="path8" />
|
||||
<rect
|
||||
x="2"
|
||||
y="7"
|
||||
width="28"
|
||||
height="15"
|
||||
style="fill:#80c95b;"
|
||||
id="rect10" />
|
||||
<g
|
||||
id="g24">
|
||||
<path
|
||||
d="M8.5,9.5c0,-0.828 -0.672,-1.5 -1.5,-1.5l-2.5,0c-0.398,0 -0.779,0.158 -1.061,0.439c-0.281,0.282 -0.439,0.663 -0.439,1.061c0,0.828 0.672,1.5 1.5,1.5l2.5,0c0.828,0 1.5,-0.672 1.5,-1.5l0,0Z"
|
||||
style="fill:#5da436;"
|
||||
id="path12" />
|
||||
<path
|
||||
d="M8.5,19.5c0,-0.828 -0.672,-1.5 -1.5,-1.5l-2.5,0c-0.398,0 -0.779,0.158 -1.061,0.439c-0.281,0.282 -0.439,0.663 -0.439,1.061c0,0.828 0.672,1.5 1.5,1.5l2.5,0c0.828,0 1.5,-0.672 1.5,-1.5l0,0Z"
|
||||
style="fill:#5da436;"
|
||||
id="path14" />
|
||||
<path
|
||||
d="M29,9.5c0,-0.828 -0.672,-1.5 -1.5,-1.5l-2.5,0c-0.398,0 -0.779,0.158 -1.061,0.439c-0.281,0.282 -0.439,0.663 -0.439,1.061c0,0.828 0.672,1.5 1.5,1.5l2.5,0c0.828,0 1.5,-0.672 1.5,-1.5l0,0Z"
|
||||
style="fill:#5da436;"
|
||||
id="path16" />
|
||||
<path
|
||||
d="M29,19.5c0,-0.828 -0.672,-1.5 -1.5,-1.5l-2.5,0c-0.398,0 -0.779,0.158 -1.061,0.439c-0.281,0.282 -0.439,0.663 -0.439,1.061c0,0.828 0.672,1.5 1.5,1.5l2.5,0c0.828,0 1.5,-0.672 1.5,-1.5l0,0Z"
|
||||
style="fill:#5da436;"
|
||||
id="path18" />
|
||||
<path
|
||||
d="M21,14c0,-0.552 -0.448,-1 -1,-1c-0.552,0 -1,0.448 -1,1c0,0.322 0,0.678 0,1c0,0.552 0.448,1 1,1c0.552,0 1,-0.448 1,-1c0,-0.322 0,-0.678 0,-1Z"
|
||||
style="fill:#5da436;"
|
||||
id="path20" />
|
||||
<path
|
||||
d="M24,14c0,-0.552 -0.448,-1 -1,-1c-0.552,0 -1,0.448 -1,1c0,0.322 0,0.678 0,1c0,0.552 0.448,1 1,1c0.552,0 1,-0.448 1,-1c0,-0.322 0,-0.678 0,-1Z"
|
||||
style="fill:#5da436;"
|
||||
id="path22" />
|
||||
</g>
|
||||
<rect
|
||||
x="8"
|
||||
y="11"
|
||||
width="8"
|
||||
height="7"
|
||||
style="fill:none;"
|
||||
id="rect26" />
|
||||
<clipPath
|
||||
id="_clip1">
|
||||
<rect
|
||||
x="8"
|
||||
y="11"
|
||||
width="8"
|
||||
height="7"
|
||||
id="rect28" />
|
||||
</clipPath>
|
||||
<g
|
||||
clip-path="url(#_clip1)"
|
||||
id="g37">
|
||||
<path
|
||||
d="M16,14l-8,0l0,-1l8,0l0,1Z"
|
||||
style="fill:#fff;"
|
||||
id="path31" />
|
||||
<path
|
||||
d="M16,16l-8,0l0,-1l8,0l0,1Z"
|
||||
style="fill:#fff;"
|
||||
id="path33" />
|
||||
<path
|
||||
d="M15,10.335l0,7.665l-1,0l0,-4.5l-1.771,4.25l-0.458,0l-1.771,-4.25l0,4.5l-1,0l0,-7.665l0.706,-0.141l2.294,5.506l2.294,-5.506l0.706,0.141Z"
|
||||
style="fill:#fff;"
|
||||
id="path35" />
|
||||
</g>
|
||||
<path
|
||||
d="M27,20l-22,0l0,-11l22,0l0,11Zm-21,-10l0,9l20,0l0,-9l-20,0Z"
|
||||
style="fill:#5da436;"
|
||||
id="path39" />
|
||||
<path
|
||||
d="M20,22l-1,-1l-6,0l-1,1l0,3l8,0l0,-3Z"
|
||||
style="fill:#ccc;"
|
||||
id="path41" />
|
||||
<rect
|
||||
x="12"
|
||||
y="7"
|
||||
width="8"
|
||||
height="15"
|
||||
style="fill:#eee;"
|
||||
id="rect43" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
15
assets/badges/translator.svg
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<svg width="343" height="343" viewBox="0 0 343 343" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<rect x="141.421" y="31" width="200" height="200" transform="rotate(45 141.421 31)" fill="#01BE6E"/>
|
||||
<path d="M137.926 182.464C128.751 173.507 120.668 165.642 116.08 147.51H148.194V133.965H116.298V116.051H102.535V134.184H70.4214V147.728H103.191C103.191 147.728 102.972 150.35 102.535 152.316C97.9475 170.23 92.486 181.59 70.4214 192.731L75.0091 206.276C95.9814 195.134 106.904 181.153 111.711 165.642C116.298 177.439 124.163 187.051 133.12 195.79L137.926 182.464Z" fill="white"/>
|
||||
<path d="M180.307 138.551H161.956L129.842 228.775H143.605L152.781 201.686H189.482L198.658 228.775H212.421L180.307 138.551ZM157.368 188.142L171.132 152.095L184.895 188.36L157.368 188.142Z" fill="white"/>
|
||||
<path d="M305.473 170.182L208.174 267.48C206.834 268.82 205.148 269.773 203.306 270.234L148.421 281.018L159.206 226.123C159.666 224.291 160.619 222.605 161.959 221.265L259.258 123.967L274.421 108.803L320.421 103.921V155.233L305.473 170.182Z" fill="#99AAB5"/>
|
||||
<path d="M208.174 267.478L305.473 170.18L259.258 123.965L161.959 221.263C160.619 222.603 159.666 224.289 159.206 226.121L148.421 281.016L203.306 270.232C205.148 269.771 206.834 268.818 208.174 267.478ZM336.883 138.769C345.06 130.592 345.06 117.337 336.883 109.16L320.278 92.5542C312.1 84.3771 298.845 84.3771 290.668 92.5542L274.063 109.16L320.278 155.375L336.883 138.769Z" fill="#EA596E"/>
|
||||
<path d="M305.473 170.182L208.174 267.48C206.834 268.82 205.148 269.773 203.306 270.234L148.421 281.018L159.206 226.123C159.666 224.291 160.619 222.605 161.959 221.265L259.258 123.967L305.473 170.182Z" fill="#FFCC4D"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="343" height="343" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
1
assets/badges/verified.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1813.46 1814.1"><path d="M921.08.24H999.8L1006,2.16c6.23,1.17,13.75-1.26,19.44.48a5.52,5.52,0,0,0,2.16,3.12c3.16,1.43,7.67.35,11.52,1.44,2.09.59,3.31,2.7,5,3.36l7,1c2.8.67,4.61,2.41,6.72,3.36l7.2,1.2c12.55,5,24.78,11.55,37.2,16.8,1.89.8,3,3.13,4.56,3.84l4.08.24,3.84,4.08L1120,43.2c2.74,1.66,5,4.77,7.68,6.24l5,1.68c8.83,6.07,16.73,13.82,25,20.4,8.67,6.93,17.76,14.41,24.72,23l5.76,6,.24,7.68,2.64-2.64,1.2-1,7.68,7.44,48,49.2c5.63,5.63,9.25,12.8,19,14.4h41.28c10.65,0,23.19.31,32.64-1.2l35.52.24c9.24-1.38,25.9-2,35-.24l12,2.88,16.32.48,8.64,3.6,11.28.24,5.76,3.6,11,.48,3.6,3.12c7.54,3.39,18,3.14,22.32,9.6a54.24,54.24,0,0,1,8.4.24l1.68,6.24v-.48l.72-2.16,6.72,1,1.68,3.12,6.24.72,1,2.88,7,1.44a6.7,6.7,0,0,0,1.44,3.84,11.63,11.63,0,0,1,5.28.72c1.6,3.8,3.39,2.21,7,4.08,2.53,1.33,6.21,6.69,8.64,7.92l3.6.48,2.64,3.12c3,2.27,5.63,4.58,8.64,6.72v16.56l9.36-9.84,4.08,4.08c4.5,2.2,8.94,8.09,12.24,11.76,5.58,6.21,12.5,11.46,17.76,18l9.6,13.44c8.15,10.51,16.51,21.35,23.52,33.12l1.92,5.76c3.68,5.82,7.9,12.21,10.8,19l1.44,5.28,3.12,3.6.72,5,3.36,5.28c2.6,6.5,3.2,11.73,5.52,18.48l2.88,5.52,1,8.16,3.12,8.64,1.2,10.8c.76,2.59,2.3,5,2.88,8.16l.48,11.76,3.36,23.52v32.16c0,13.43,1.62,29.68-.48,42.24v30c-1.15,7.43-1.24,28.83.48,35.28,1.51,5.68,20.48,21.44,25.44,26.4L1786,699.12c11.59,14.43,24.59,28.4,34.56,44.4,15.84,25.41,27.31,54.64,37.2,85.92l1,9.6,3.84,10.32.48,13.2,3.36,15.36.24,21.12-.24,38.88-3.12,14.16-1.2,14.64c-10.22,47.84-30.48,87.55-54.72,121.44-5.68,7.94-11.74,15.07-17.76,22.56l-10.56,10.8-7.2,7.92-7.68,4.56-16.8,17c-2.39,2.39-6.08,4.6-8.16,7.2l-3.84,6.72-20.88,20.88-18,17.76c-3.08,2.3-5.81,4.45-7.44,8.16-1.8,4.09-1.2,11.21-1.2,17l-.24,26.16.24,49.2,3.12,6.72-.24,41.28c-7.07,5.4-1.08,14.6-2.88,25.2a265.49,265.49,0,0,1-7.44,32.88l-2.16,11c-8,20.27-14.89,40.47-24.72,58.8-12.75,23.77-30.76,43.38-47,63.6-8.91,11.07-21.32,20.11-32.64,28.8-33.16,25.46-71.21,45.91-118.08,57.84l-9.36,1-11,3.12c-11.56,2.36-24.16,1.72-35.52,3.6l-135.84.48c-8,2-17.66,15-23.28,20.64l-53.28,54c-33.3,35.63-74.19,65.09-124.56,83.52l-6.24,1.2c-6,2.07-13.87,5.06-20.16,7l-8.64,1.2-10.32,3.36-15.84,1-6.72,2.16c-8.44,1.87-30.53,2.58-40.32,1l-22.32.24c-5.44-.89-10.21-1.79-14.64-2.88-5.62-1.38-12.46-.12-17.52-1.44-43.65-11.4-82-25.84-114.24-48.48-13.42-9.43-24.89-20.61-37.44-30.72l-65.52-66-12.48-12.48c-3.32-4.12-8.24-10.48-13.44-12.48-7.2-2.77-28.85-1-38.64-1H514.28l-12.48-2.16c-1.4-.21-2.79,1.05-3.12,1l-6.72-1.92-7.92-.24-10.32-3.12-10.8-1.2c-32.62-8.51-66.3-22-91.44-38.4-9.39-6.13-18.22-13.61-27.12-20.16-11-8.11-23.15-17.25-31.68-27.84-17.47-21.68-34.42-40.92-47.76-67.2-3-5.82-6.17-12-9.36-18.24l-3.12-4.56-.24-4.32-3.36-5.52c-1.75-4.37-3.31-8.5-4.56-12.48-4.71-15-8.92-31.62-12.24-47.76-1.1-5.35-2.41-13-1.2-19.44.4-2.13,2-6.72.72-9.36l-3.12-2.88v-6.24c-1.3-8-1.64-20.48,0-28.32l.48-75.84c0-10.11,1.78-24.72-1.44-32.4-1.44-3.43-5.18-5.9-7.68-8.4L202,1183.68l-51.6-50.88c-6.65-5.35-12.9-12.75-18.24-19.44-7.9-9.9-17-19-24.48-29.52C84.53,1051.17,67.63,1011.91,56.84,967l-.72-13.68-2.88-11.52v-25.2c0-19.55-.36-39.72,2.4-55.68l.72-13c17.69-69.5,44.37-116.85,87.84-160.32L204,628.8l17.76-17.52,5.52-5.76c2.58-6.63,1.2-29,1.2-38.88,0-11.42-2.88-25.12-1-37l.24-29.76-.24-37.68,2.88-18.48.72-14.4,3.6-11.52.72-9.12c12.23-40.89,27.69-76.22,49.44-107.28,6.68-9.54,15.3-18.34,22.56-27.36a165.5,165.5,0,0,1,24-24c2.84-2.3,5.31-7,8.88-8.4l2.64.24,2.64-3.12,12-10.32,2.88.24,9.36-8.4,2.64.24,5.28-4.8c1.43-.62,3.22-.2,4.32-.72l2.16-3.6c5.28,0,4.6-1.83,7.2-3.6,4.19-2.85,5.28.63,7.92-5,5.87-.59,7.08-.23,9.6-4.32,2.73.07,6.45.2,8.4-.72l1.44-3.84h7.68l3.12-3.36,8.4-.48,4.08-3.84,12-.72,4.8-4.08h13.44l5-3.6H494.6l15.6-3.36,36.24-.24,71.52,1c9,0,31.14,2.41,37.92-.24,5-2,8.44-7,12-10.56l21.6-22.08,33.12-33.6c9.59-12,23-24.51,35-34.08L769.4,63.36c7.37-5.24,14.67-9.63,22.08-14.88,1.83-1.3,3.78-2.46,5.76-3.84l2.64-3.12h3.84L807.8,37h3.6l5.52-4.56h3.6l4.32-3.6,4.32-.48,4.32-4.08,5-.24,4.56-4.32,6.72-.24,4.32-3.36,7.68-1.44L864.44,12,875,10.8l3.12-3.6L889.64,7l3.6-4.08c4.54-2.38,15,1.13,20.64-.24A58.28,58.28,0,0,0,921.08.24Z" transform="translate(-53.22 -0.24)" style="fill:#fff;fill-rule:evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
BIN
assets/desktop/badges/-1.ico
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
assets/desktop/badges/1.ico
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
assets/desktop/badges/10.ico
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
assets/desktop/badges/2.ico
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
assets/desktop/badges/3.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
assets/desktop/badges/4.ico
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
assets/desktop/badges/5.ico
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
assets/desktop/badges/6.ico
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
assets/desktop/badges/7.ico
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
assets/desktop/badges/8.ico
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
assets/desktop/badges/9.ico
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
assets/desktop/badges/badges.penpot
Normal file
BIN
assets/desktop/hicolor/128x128.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/desktop/hicolor/16x16.png
Normal file
|
After Width: | Height: | Size: 729 B |
BIN
assets/desktop/hicolor/256x256.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
assets/desktop/hicolor/32x32.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/desktop/hicolor/512x512.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/desktop/hicolor/64x64.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/desktop/icon.ico
Normal file
|
After Width: | Height: | Size: 361 KiB |
BIN
assets/desktop/icon.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
12
assets/desktop/icon.svg
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 307 307" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-3137.299793,-1719.592766)">
|
||||
<g transform="matrix(0.902657,0,0,0.902657,2863.823104,1374.738098)">
|
||||
<path d="M356.97,675.638C323.753,644.676 302.968,600.546 302.968,551.6C302.968,458.019 378.944,382.044 472.524,382.044C566.105,382.044 642.08,458.019 642.08,551.6C642.08,629.48 589.46,695.166 517.864,715.015C501.974,691.667 487.572,670.399 498.34,635.393C485.202,642.099 476.944,655.288 474.445,669.626C469.556,661.943 464.129,654.533 457.841,647.931C441.837,631.125 420.016,619.373 409.919,597.549C405.306,587.241 402.145,572.504 405.799,561.838C408.436,582.54 418.507,601.587 436.545,612.617C450.296,621.023 465.703,622.408 481.126,625.661C497.203,629.048 522.738,636.688 538.403,633.928C551.425,631.638 578.749,617.255 578.02,601.656C577.765,596.289 571.213,587.245 568.79,582.066C565.566,575.171 567.48,573.682 567.848,566.765C568.885,547.188 563.715,537.516 554.206,521.395C542.674,501.84 530.016,490.024 508.095,482.087C488.062,474.831 457.231,478.938 456.996,479.271C461.046,483.711 464.773,488.906 465.295,495.055C457.084,487.46 449.14,479.387 439.945,472.948C419.607,458.71 406.868,460.052 398.782,484.817C394.568,497.72 391.382,515.255 395.288,528.453C397.657,536.447 402.575,542.952 408.175,548.951C397.217,547.458 390.574,537.94 388.158,527.623C360.997,586.373 354.951,614.782 356.97,675.638ZM553.254,508.59C555.938,471.688 555.624,447.806 521.4,481.304C534.318,487.312 545.181,496.897 553.254,508.59ZM486.399,552.769C503.076,550.51 505.109,576.334 489.02,577.418C472.931,578.502 471.118,554.84 486.399,552.769ZM559.47,568.921C555.834,562.599 554.722,560.76 552.607,556.182C551.168,553.064 550.439,549.366 555.655,549.256C565.117,549.055 568.395,564.041 561.026,569.27C560.844,569.397 560.628,569.465 560.407,569.465C560.02,569.465 559.662,569.257 559.47,568.921ZM430.213,501.5C431.753,505.171 434.926,507.616 437.667,510.309C431.445,512.197 425.166,510.394 419.704,507.264C420.028,513.033 424.299,518.121 427.498,522.174C422.225,523.384 417.564,521.577 413.944,517.769C413.891,523.13 415.717,527.806 418.347,532.34C408.062,537.456 403.622,526.696 403.097,518.275C402.522,509.02 406.267,485.669 412.907,478.941C420.336,471.412 431.875,480.182 438.166,485.238C443.719,489.698 449.061,495.087 454.092,500.111C447.487,504.476 437.648,504.294 430.213,501.5ZM558.455,619.379L558.452,619.376C554.235,619.505 550.344,617.264 547.164,614.697C545.37,613.176 542.74,611.209 542.372,608.931C541.643,604.396 545.254,601.153 547.406,599.808C549.251,598.658 551.495,598.017 553.613,597.527C558.442,596.411 563.455,595.377 568.319,596.323C569.774,596.606 571.22,597.077 572.417,597.951C573.614,598.821 574.544,600.138 574.705,601.612C574.824,602.705 574.525,603.796 574.164,604.833C573.322,607.217 572.16,609.476 570.71,611.548C569.274,613.613 567.556,615.508 565.485,616.934C563.414,618.361 560.969,619.304 558.455,619.379Z" style="fill:rgb(39,32,56);"/>
|
||||
</g>
|
||||
<g transform="matrix(0.283653,0,0,0.283653,3185.723372,1793.419676)">
|
||||
<path d="M1.131,674.022C-5.294,480.363 13.948,389.958 100.38,203C108.07,235.83 129.21,266.12 164.08,270.87C146.26,251.78 130.61,231.08 123.07,205.64C110.64,163.64 120.78,107.84 134.19,66.78C159.92,-12.03 200.46,-16.3 265.18,29.01C294.44,49.5 319.72,75.19 345.85,99.36C344.19,79.79 332.33,63.26 319.44,49.13C320.19,48.07 418.3,35 482.05,58.09C551.81,83.35 592.09,120.95 628.79,183.18C659.05,234.48 675.5,265.26 672.2,327.56C671.03,349.57 664.94,354.31 675.2,376.25C682.91,392.73 703.76,421.51 704.57,438.59C706.89,488.23 619.94,534 578.5,541.29C528.65,550.07 447.39,525.76 396.23,514.98C347.15,504.63 298.12,500.22 254.36,473.47C196.96,438.37 164.91,377.76 156.52,311.88C144.89,345.82 154.95,392.72 169.63,425.52C201.76,494.97 271.2,532.37 322.13,585.85C342.14,606.86 359.41,630.44 374.97,654.89C382.92,609.26 409.2,567.29 451.01,545.95C416.741,657.349 462.573,725.027 513.139,799.329C467.207,812.064 418.82,818.869 368.857,818.869C226.818,818.869 97.524,763.871 1.131,674.022ZM625.76,142.43C600.07,105.22 565.5,74.72 524.39,55.6C633.3,-51 634.3,25 625.76,142.43ZM413.01,283.02C364.38,289.61 370.15,364.91 421.35,361.46C472.55,358.01 466.08,275.83 413.01,283.02ZM234.21,119.87C257.87,128.76 289.18,129.34 310.2,115.45C294.19,99.46 277.19,82.31 259.52,68.12C239.5,52.03 202.78,24.12 179.14,48.08C158.01,69.49 146.09,143.8 147.92,173.25C149.59,200.05 163.72,234.29 196.45,218.01C188.08,203.58 182.27,188.7 182.44,171.64C193.96,183.76 208.79,189.51 225.57,185.66C215.39,172.76 201.8,156.57 200.77,138.21C218.15,148.17 238.13,153.91 257.93,147.9C249.21,139.33 239.11,131.55 234.21,119.87ZM642.31,494.99C650.31,494.75 658.09,491.75 664.68,487.21C671.27,482.67 676.74,476.64 681.31,470.07C685.923,463.476 689.62,456.287 692.3,448.7C693.45,445.4 694.4,441.93 694.02,438.45C693.51,433.76 690.55,429.57 686.74,426.8C682.93,424.02 678.33,422.52 673.7,421.62C658.22,418.61 642.27,421.9 626.9,425.45C620.16,427.01 613.02,429.05 607.15,432.71C600.3,436.99 588.81,447.31 591.13,461.74C592.3,468.99 600.67,475.25 606.38,480.09C616.5,488.26 628.88,495.39 642.3,494.98L642.31,494.99ZM645.54,334.42C646.149,335.489 647.289,336.152 648.52,336.152C649.225,336.152 649.913,335.935 650.49,335.53C673.94,318.89 663.51,271.2 633.4,271.84C616.8,272.19 619.12,283.96 623.7,293.88C630.43,308.45 633.97,314.3 645.54,334.42Z" style="fill:white;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
BIN
assets/desktop/icon@2x.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
assets/desktop/icon@3x.png
Normal file
|
After Width: | Height: | Size: 220 KiB |
BIN
assets/desktop/iconTemplate.png
Normal file
|
After Width: | Height: | Size: 480 B |
BIN
assets/web/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
assets/web/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
assets/web/icon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/web/masking-512x512.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
14
assets/web/monochrome.svg
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 307 307" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-757,-1483)">
|
||||
<g transform="matrix(1.432974,0,0,1.80298,-288.929017,-864.20063)">
|
||||
<g transform="matrix(0.629919,0,0,0.500647,539.407527,1110.972982)">
|
||||
<path d="M356.969,675.637C323.753,644.675 302.968,600.546 302.968,551.6C302.968,458.019 378.944,382.044 472.524,382.044C566.105,382.044 642.08,458.019 642.08,551.6C642.08,629.48 589.46,695.166 517.864,715.015C501.974,691.667 487.572,670.399 498.34,635.393C485.202,642.099 476.944,655.288 474.445,669.626C469.556,661.943 464.129,654.533 457.841,647.931C441.837,631.125 420.016,619.373 409.919,597.549C405.306,587.241 402.145,572.504 405.799,561.838C408.436,582.54 418.507,601.587 436.545,612.617C450.296,621.023 465.703,622.408 481.126,625.661C497.203,629.048 522.738,636.688 538.403,633.928C551.425,631.638 578.749,617.255 578.02,601.656C577.765,596.289 571.213,587.245 568.79,582.066C565.566,575.171 567.48,573.682 567.848,566.765C568.885,547.188 563.715,537.516 554.206,521.395C542.674,501.84 530.016,490.024 508.095,482.087C488.062,474.831 457.231,478.938 456.996,479.271C461.046,483.711 464.773,488.906 465.295,495.055C457.084,487.46 449.14,479.387 439.945,472.948C419.607,458.71 406.868,460.052 398.782,484.817C394.568,497.72 391.382,515.255 395.288,528.453C397.657,536.447 402.575,542.952 408.175,548.951C397.217,547.458 390.574,537.94 388.158,527.623C360.997,586.373 354.95,614.781 356.969,675.637ZM558.455,619.379L558.452,619.376C554.235,619.505 550.344,617.264 547.164,614.697C545.37,613.176 542.74,611.209 542.372,608.931C541.643,604.396 545.254,601.153 547.406,599.808C549.251,598.658 551.495,598.017 553.613,597.527C558.442,596.411 563.455,595.377 568.319,596.323C569.774,596.606 571.22,597.077 572.417,597.951C573.614,598.821 574.544,600.138 574.705,601.612C574.824,602.705 574.525,603.796 574.164,604.833C573.322,607.217 572.16,609.476 570.71,611.548C569.274,613.613 567.556,615.508 565.485,616.934C563.414,618.361 560.969,619.304 558.455,619.379ZM486.399,552.769C503.076,550.51 505.109,576.334 489.02,577.418C472.931,578.502 471.118,554.84 486.399,552.769ZM430.213,501.5C431.753,505.171 434.926,507.616 437.667,510.309C431.445,512.197 425.166,510.394 419.704,507.264C420.028,513.033 424.299,518.121 427.498,522.174C422.225,523.384 417.564,521.577 413.944,517.769C413.891,523.13 415.717,527.806 418.347,532.34C408.062,537.456 403.622,526.696 403.097,518.275C402.522,509.02 406.267,485.669 412.907,478.941C420.336,471.412 431.875,480.182 438.166,485.238C443.719,489.698 449.061,495.087 454.092,500.111C447.487,504.476 437.648,504.294 430.213,501.5ZM559.47,568.921C555.834,562.599 554.722,560.76 552.607,556.182C551.168,553.064 550.439,549.366 555.655,549.256C565.117,549.055 568.395,564.041 561.026,569.27C560.844,569.397 560.628,569.465 560.407,569.465C560.02,569.465 559.662,569.257 559.47,568.921ZM553.254,508.59C555.938,471.688 555.624,447.806 521.4,481.304C534.318,487.312 545.181,496.897 553.254,508.59Z"/>
|
||||
</g>
|
||||
<g transform="matrix(1.730725,0,0,1.375547,-3179.052619,-90.872445)">
|
||||
<circle cx="2320.479" cy="1074.483" r="61.711" style="fill:white;fill-opacity:0;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
29
assets/web/wordmark.svg
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 1076 307" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-757,-1483)">
|
||||
<g transform="matrix(1.432974,0,0,1.80298,-288.929017,-864.20063)">
|
||||
<g>
|
||||
<g transform="matrix(0.629919,0,0,0.500647,539.407527,1110.972982)">
|
||||
<path d="M356.969,675.637C323.753,644.675 302.968,600.546 302.968,551.6C302.968,458.019 378.944,382.044 472.524,382.044C566.105,382.044 642.08,458.019 642.08,551.6C642.08,629.48 589.46,695.166 517.864,715.015C501.974,691.667 487.572,670.399 498.34,635.393C485.202,642.099 476.944,655.288 474.445,669.626C469.556,661.943 464.129,654.533 457.841,647.931C441.837,631.125 420.016,619.373 409.919,597.549C405.306,587.241 402.145,572.504 405.799,561.838C408.436,582.54 418.507,601.587 436.545,612.617C450.296,621.023 465.703,622.408 481.126,625.661C497.203,629.048 522.738,636.688 538.403,633.928C551.425,631.638 578.749,617.255 578.02,601.656C577.765,596.289 571.213,587.245 568.79,582.066C565.566,575.171 567.48,573.682 567.848,566.765C568.885,547.188 563.715,537.516 554.206,521.395C542.674,501.84 530.016,490.024 508.095,482.087C488.062,474.831 457.231,478.938 456.996,479.271C461.046,483.711 464.773,488.906 465.295,495.055C457.084,487.46 449.14,479.387 439.945,472.948C419.607,458.71 406.868,460.052 398.782,484.817C394.568,497.72 391.382,515.255 395.288,528.453C397.657,536.447 402.575,542.952 408.175,548.951C397.217,547.458 390.574,537.94 388.158,527.623C360.997,586.373 354.95,614.781 356.969,675.637ZM558.455,619.379L558.452,619.376C554.235,619.505 550.344,617.264 547.164,614.697C545.37,613.176 542.74,611.209 542.372,608.931C541.643,604.396 545.254,601.153 547.406,599.808C549.251,598.658 551.495,598.017 553.613,597.527C558.442,596.411 563.455,595.377 568.319,596.323C569.774,596.606 571.22,597.077 572.417,597.951C573.614,598.821 574.544,600.138 574.705,601.612C574.824,602.705 574.525,603.796 574.164,604.833C573.322,607.217 572.16,609.476 570.71,611.548C569.274,613.613 567.556,615.508 565.485,616.934C563.414,618.361 560.969,619.304 558.455,619.379ZM486.399,552.769C503.076,550.51 505.109,576.334 489.02,577.418C472.931,578.502 471.118,554.84 486.399,552.769ZM430.213,501.5C431.753,505.171 434.926,507.616 437.667,510.309C431.445,512.197 425.166,510.394 419.704,507.264C420.028,513.033 424.299,518.121 427.498,522.174C422.225,523.384 417.564,521.577 413.944,517.769C413.891,523.13 415.717,527.806 418.347,532.34C408.062,537.456 403.622,526.696 403.097,518.275C402.522,509.02 406.267,485.669 412.907,478.941C420.336,471.412 431.875,480.182 438.166,485.238C443.719,489.698 449.061,495.087 454.092,500.111C447.487,504.476 437.648,504.294 430.213,501.5ZM559.47,568.921C555.834,562.599 554.722,560.76 552.607,556.182C551.168,553.064 550.439,549.366 555.655,549.256C565.117,549.055 568.395,564.041 561.026,569.27C560.844,569.397 560.628,569.465 560.407,569.465C560.02,569.465 559.662,569.257 559.47,568.921ZM553.254,508.59C555.938,471.688 555.624,447.806 521.4,481.304C534.318,487.312 545.181,496.897 553.254,508.59Z"/>
|
||||
</g>
|
||||
<g transform="matrix(1.730725,0,0,1.375547,-3179.052619,-90.872445)">
|
||||
<circle cx="2320.479" cy="1074.483" r="61.711" style="fill:white;fill-opacity:0;"/>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="matrix(4.075683,0,0,3.239275,-459.164053,-1247.728679)">
|
||||
<path d="M371.565,830.572C369.399,830.572 367.307,830.355 365.29,829.922C363.274,829.488 361.399,828.838 359.665,827.972C357.932,827.105 356.432,826.005 355.165,824.672L360.765,817.422C361.699,818.555 362.799,819.505 364.065,820.272C365.332,821.038 366.657,821.613 368.04,821.997C369.424,822.38 370.765,822.572 372.065,822.572C372.832,822.572 373.499,822.505 374.065,822.372C374.632,822.238 375.065,822.03 375.365,821.747C375.665,821.463 375.815,821.088 375.815,820.622C375.815,820.055 375.615,819.572 375.215,819.172C374.815,818.772 374.165,818.413 373.265,818.097C372.365,817.78 371.165,817.488 369.665,817.222L366.315,816.572C364.882,816.305 363.532,815.93 362.265,815.447C360.999,814.963 359.874,814.33 358.89,813.547C357.907,812.763 357.14,811.805 356.59,810.672C356.04,809.538 355.765,808.172 355.765,806.572C355.765,804.305 356.357,802.397 357.54,800.847C358.724,799.297 360.324,798.13 362.34,797.347C364.357,796.563 366.599,796.172 369.065,796.172C372.332,796.172 375.24,796.688 377.79,797.722C380.34,798.755 382.449,800.105 384.115,801.772L378.565,808.922C377.232,807.522 375.59,806.38 373.64,805.497C371.69,804.613 369.815,804.172 368.015,804.172C367.449,804.172 366.932,804.238 366.465,804.372C365.999,804.505 365.64,804.705 365.39,804.972C365.14,805.238 365.015,805.572 365.015,805.972C365.015,806.905 365.482,807.588 366.415,808.022C367.349,808.455 368.632,808.855 370.265,809.222L374.215,810.122C376.049,810.522 377.64,811.022 378.99,811.622C380.34,812.222 381.465,812.938 382.365,813.772C383.265,814.605 383.94,815.563 384.39,816.647C384.84,817.73 385.065,818.972 385.065,820.372C385.065,822.638 384.474,824.53 383.29,826.047C382.107,827.563 380.499,828.697 378.465,829.447C376.432,830.197 374.132,830.572 371.565,830.572Z"/>
|
||||
<path d="M405.109,827.587C404.564,828.157 403.683,828.785 402.465,829.472C401.165,830.205 399.515,830.572 397.515,830.572C395.382,830.572 393.674,830.197 392.39,829.447C391.107,828.697 390.182,827.688 389.615,826.422C389.049,825.155 388.765,823.722 388.765,822.122L388.765,812.172L385.265,812.172L385.265,805.372L388.765,805.372L388.765,802.572L397.765,798.572L397.765,805.372L403.765,805.372L403.765,812.172L397.765,812.172L397.765,820.822C397.765,821.455 397.924,821.938 398.24,822.272C398.557,822.605 398.999,822.772 399.565,822.772C400.132,822.772 400.707,822.588 401.29,822.222C401.777,821.916 402.199,821.518 402.558,821.026C402.745,822.809 403.242,824.449 404.049,825.947C404.363,826.531 404.717,827.078 405.109,827.587Z"/>
|
||||
<g transform="matrix(1,0,0,1,-0.799373,0)">
|
||||
<path d="M418.265,830.572C415.632,830.572 413.357,830.013 411.44,828.897C409.524,827.78 408.04,826.247 406.99,824.297C405.94,822.347 405.415,820.155 405.415,817.722C405.415,815.255 405.94,813.055 406.99,811.122C408.04,809.188 409.524,807.663 411.44,806.547C413.357,805.43 415.632,804.872 418.265,804.872C421.032,804.872 423.407,805.43 425.39,806.547C427.374,807.663 428.89,809.188 429.94,811.122C430.99,813.055 431.515,815.255 431.515,817.722C431.515,820.155 430.99,822.347 429.94,824.297C428.89,826.247 427.374,827.78 425.39,828.897C423.407,830.013 421.032,830.572 418.265,830.572ZM418.465,823.372C419.232,823.372 419.907,823.197 420.49,822.847C421.074,822.497 421.532,821.913 421.865,821.097C422.199,820.28 422.365,819.155 422.365,817.722C422.365,816.288 422.199,815.163 421.865,814.347C421.532,813.53 421.074,812.947 420.49,812.597C419.907,812.247 419.232,812.072 418.465,812.072C417.699,812.072 417.024,812.247 416.44,812.597C415.857,812.947 415.399,813.53 415.065,814.347C414.732,815.163 414.565,816.288 414.565,817.722C414.565,819.155 414.732,820.28 415.065,821.097C415.399,821.913 415.857,822.497 416.44,822.847C417.024,823.197 417.699,823.372 418.465,823.372Z"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-1.50815,-0.391222)">
|
||||
<path d="M447.689,814.448C447.609,814.034 447.501,813.692 447.365,813.422C447.032,812.755 446.149,812.422 444.715,812.422C443.282,812.422 441.832,812.772 440.365,813.472C438.899,814.172 437.649,815.105 436.615,816.272L432.615,809.672C433.649,808.738 434.815,807.913 436.115,807.197C437.415,806.48 438.832,805.913 440.365,805.497C441.899,805.08 443.515,804.872 445.215,804.872C448.382,804.872 450.882,805.655 452.715,807.222C454.549,808.788 455.465,811.155 455.465,814.322L455.465,821.772C455.465,822.305 455.557,822.68 455.74,822.897C455.924,823.113 456.232,823.222 456.665,823.222L458.115,823.222L458.115,830.072L453.015,830.072C452.082,830.072 451.19,829.922 450.34,829.622C449.49,829.322 448.799,828.83 448.265,828.147C447.958,827.752 447.739,827.277 447.608,826.722C447.259,827.232 446.831,827.72 446.354,828.167C444.654,829.764 442.17,830.587 439.743,830.622C437.949,830.648 436.429,830.138 435.183,829.172C433.938,828.205 433.315,826.605 433.315,824.372C433.315,822.372 433.924,820.763 435.14,819.547C436.357,818.33 438.332,817.305 441.065,816.472L447.689,814.448ZM447.465,821.468L447.465,819.936L443.415,821.372C442.582,821.672 442.024,821.955 441.74,822.222C441.457,822.488 441.315,822.788 441.315,823.122C441.315,823.522 441.475,823.83 441.794,824.047C442.114,824.263 442.592,824.372 443.231,824.372C443.97,824.372 444.608,824.297 445.146,824.147C445.684,823.997 446.129,823.772 446.482,823.472C446.835,823.172 447.095,822.788 447.263,822.322C447.356,822.063 447.424,821.778 447.465,821.468Z"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-2.465302,0)">
|
||||
<path d="M461.865,812.172L458.365,812.172L458.365,805.372L461.865,805.372L461.865,802.572L470.865,798.572L470.865,805.372L476.865,805.372L476.865,812.172L470.865,812.172L470.865,820.822C470.865,821.455 471.024,821.938 471.34,822.272C471.657,822.605 472.099,822.772 472.665,822.772C473.232,822.772 473.807,822.588 474.39,822.222C474.974,821.855 475.465,821.355 475.865,820.722L478.315,827.472C477.782,828.072 476.865,828.738 475.565,829.472C474.265,830.205 472.615,830.572 470.615,830.572C468.482,830.572 466.774,830.197 465.49,829.447C464.207,828.697 463.282,827.688 462.715,826.422C462.149,825.155 461.865,823.722 461.865,822.122L461.865,812.172Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.7 KiB |
386
docs/superpowers/plans/2026-04-22-sanctum-web-layout-redesign.md
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
# sanctum-web Layout Redesign Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Fork stoatchat/for-web into sanctum-web, fix the root layout so the message area fills the screen properly, and deploy it to mithraic.space/app via Forgejo CI.
|
||||
|
||||
**Architecture:** The root layout lives in two files — `Interface.tsx` (the grid shell) and `Sidebar.tsx` (server list + channel list). Both use Panda CSS (`styled-system/jsx`). We replace the loose flex layout with an explicit CSS Grid, add `min-width: 0` guards on grid children, and wire up a Forgejo Actions pipeline that builds and rsyncs to the VPS on every push to main.
|
||||
|
||||
**Tech Stack:** Solid.js, Vite, TypeScript, Panda CSS (`styled-system/jsx`), pnpm monorepo, Forgejo Actions, rsync
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
| Action | Path | Purpose |
|
||||
|---|---|---|
|
||||
| Clone | `git.mithraic.cloud/ad3laid3/sanctum-web` | The fork (already created) |
|
||||
| Modify | `packages/client/src/Interface.tsx` | Root grid shell — Layout + Content styled components |
|
||||
| Modify | `packages/client/src/interface/Sidebar.tsx` | Server list + channel list sizing |
|
||||
| Create | `.forgejo/workflows/deploy.yml` | CI: build + rsync to VPS on push to main |
|
||||
| Create | `packages/client/.env` | API URLs pointing at mithraic.space services |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Clone the fork and add upstream remote
|
||||
|
||||
**Files:**
|
||||
- Working directory: wherever you keep projects locally
|
||||
|
||||
- [ ] **Step 1: Clone the fork**
|
||||
|
||||
```bash
|
||||
git clone https://git.mithraic.cloud/ad3laid3/sanctum-web
|
||||
cd sanctum-web
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add the upstream so you can pull fixes from stoatchat later**
|
||||
|
||||
```bash
|
||||
git remote add upstream https://github.com/stoatchat/for-web
|
||||
git fetch upstream
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Install dependencies**
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Confirm dev server starts**
|
||||
|
||||
```bash
|
||||
cd packages/client
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Expected: Vite dev server starts, browser opens the app (will show login screen since no backend is configured yet — that's fine).
|
||||
|
||||
- [ ] **Step 5: Commit the baseline (upstream content as-is)**
|
||||
|
||||
```bash
|
||||
cd ../..
|
||||
git add .
|
||||
git commit -m "chore: initial fork from stoatchat/for-web"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Configure environment for mithraic.space
|
||||
|
||||
**Files:**
|
||||
- Create: `packages/client/.env`
|
||||
|
||||
- [ ] **Step 1: Create the env file**
|
||||
|
||||
```bash
|
||||
cat > packages/client/.env << 'EOF'
|
||||
VITE_API_URL=https://mithraic.space/api
|
||||
VITE_WS_URL=wss://mithraic.space/ws
|
||||
VITE_MEDIA_URL=https://mithraic.space/media
|
||||
VITE_PROXY_URL=https://mithraic.space/proxy
|
||||
EOF
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Confirm build succeeds with these env vars**
|
||||
|
||||
```bash
|
||||
cd packages/client
|
||||
pnpm build
|
||||
```
|
||||
|
||||
Expected: `dist/` folder is created with no errors.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
cd ../..
|
||||
git add packages/client/.env
|
||||
git commit -m "chore: configure env for mithraic.space"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Fix the root layout in Interface.tsx
|
||||
|
||||
**Files:**
|
||||
- Modify: `packages/client/src/Interface.tsx`
|
||||
|
||||
The current `Layout` uses `display: flex` with no explicit column widths, and `Content` uses `width: 100%` which doesn't fill remaining space properly in a flex context. The fix: switch Layout to CSS Grid with `auto 1fr` columns, and replace `width: 100%` on Content with `minWidth: 0` so it respects the grid.
|
||||
|
||||
- [ ] **Step 1: Open `packages/client/src/Interface.tsx` and find the two styled components at the bottom of the file**
|
||||
|
||||
They look like this:
|
||||
```typescript
|
||||
const Layout = styled("div", {
|
||||
base: {
|
||||
display: "flex",
|
||||
height: "100%",
|
||||
minWidth: 0,
|
||||
},
|
||||
// ...
|
||||
});
|
||||
|
||||
const Content = styled("div", {
|
||||
base: {
|
||||
background: "var(--md-sys-color-surface-container-low)",
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
minWidth: 0,
|
||||
},
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Replace `Layout` base styles — switch from flex to grid**
|
||||
|
||||
Change the `Layout` styled component's `base` to:
|
||||
```typescript
|
||||
const Layout = styled("div", {
|
||||
base: {
|
||||
display: "grid",
|
||||
gridTemplateColumns: "auto 1fr",
|
||||
height: "100%",
|
||||
overflow: "hidden",
|
||||
},
|
||||
variants: {
|
||||
disconnected: {
|
||||
true: {
|
||||
color: "var(--md-sys-color-on-primary-container)",
|
||||
background: "var(--md-sys-color-primary-container)",
|
||||
},
|
||||
false: {
|
||||
color: "var(--md-sys-color-outline)",
|
||||
background: "var(--md-sys-color-surface-container-high)",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Replace `Content` base styles — remove width:100%, add minWidth:0**
|
||||
|
||||
```typescript
|
||||
const Content = styled("div", {
|
||||
base: {
|
||||
background: "var(--md-sys-color-surface-container-low)",
|
||||
display: "flex",
|
||||
minWidth: 0,
|
||||
overflow: "hidden",
|
||||
},
|
||||
variants: {
|
||||
sidebar: {
|
||||
false: {
|
||||
borderTopLeftRadius: "var(--borderRadius-lg)",
|
||||
borderBottomLeftRadius: "var(--borderRadius-lg)",
|
||||
overflow: "hidden",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Start the dev server and verify the message area now fills the screen**
|
||||
|
||||
```bash
|
||||
cd packages/client && pnpm dev
|
||||
```
|
||||
|
||||
Expected: The message area takes up the majority of the window. Sidebar stays on the left without overflowing.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
cd ../..
|
||||
git add packages/client/src/Interface.tsx
|
||||
git commit -m "fix: switch root layout to CSS Grid, message area fills remaining space"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Fix Sidebar panel widths
|
||||
|
||||
**Files:**
|
||||
- Modify: `packages/client/src/interface/Sidebar.tsx`
|
||||
|
||||
The Sidebar wraps both the server icon list and the channel list in a single `display: flex` div. We need to give each child an explicit width so they never squeeze or overflow.
|
||||
|
||||
- [ ] **Step 1: Open `packages/client/src/interface/Sidebar.tsx` and find the root return statement**
|
||||
|
||||
It looks like:
|
||||
```typescript
|
||||
return (
|
||||
<div style={{ display: "flex", "flex-shrink": 0 }}>
|
||||
<ServerList ... />
|
||||
<Show when={...}>
|
||||
<Switch fallback={<Home />}>
|
||||
<Match when={params.server}><Server /></Match>
|
||||
</Switch>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Wrap ServerList in a fixed-width container (65px) and the channel sidebar in a 240px container**
|
||||
|
||||
```typescript
|
||||
return (
|
||||
<div style={{ display: "flex", height: "100%", "flex-shrink": 0 }}>
|
||||
<div style={{ width: "65px", "flex-shrink": 0, overflow: "hidden" }}>
|
||||
<ServerList
|
||||
orderedServers={state.ordering.orderedServers(client())}
|
||||
setServerOrder={state.ordering.setServerOrder}
|
||||
unreadConversations={state.ordering
|
||||
.orderedConversations(client())
|
||||
.filter((channel) => channel.unread)}
|
||||
user={user()!}
|
||||
selectedServer={() => params.server}
|
||||
onCreateOrJoinServer={() =>
|
||||
openModal({ type: "create_or_join_server", client: client() })
|
||||
}
|
||||
menuGenerator={props.menuGenerator}
|
||||
/>
|
||||
</div>
|
||||
<Show
|
||||
when={
|
||||
state.layout.getSectionState(LAYOUT_SECTIONS.PRIMARY_SIDEBAR, true) &&
|
||||
!location.pathname.startsWith("/discover")
|
||||
}
|
||||
>
|
||||
<div style={{ width: "240px", "flex-shrink": 0, overflow: "hidden" }}>
|
||||
<Switch fallback={<Home />}>
|
||||
<Match when={params.server}>
|
||||
<Server />
|
||||
</Match>
|
||||
</Switch>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Check in dev server — server icon column should be narrow (65px), channel list should be 240px, message area fills the rest**
|
||||
|
||||
Expected: Three visually distinct columns. The message area is clearly the widest.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add packages/client/src/interface/Sidebar.tsx
|
||||
git commit -m "fix: explicit 65px server list and 240px channel sidebar widths"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: Set up Forgejo CI — build and deploy
|
||||
|
||||
**Files:**
|
||||
- Create: `.forgejo/workflows/deploy.yml`
|
||||
|
||||
This workflow runs on every push to `main`, builds the client, and rsyncs the output to the VPS directory that Caddy serves at `mithraic.space/app`.
|
||||
|
||||
- [ ] **Step 1: Add an SSH deploy key to Forgejo**
|
||||
|
||||
On the VPS, generate a deploy key (if one doesn't exist):
|
||||
```bash
|
||||
ssh-keygen -t ed25519 -C "sanctum-web-deploy" -f ~/.ssh/sanctum_web_deploy -N ""
|
||||
cat ~/.ssh/sanctum_web_deploy.pub >> ~/.ssh/authorized_keys
|
||||
cat ~/.ssh/sanctum_web_deploy # copy this — it's the private key for the secret
|
||||
```
|
||||
|
||||
In Forgejo → `sanctum-web` repo → Settings → Secrets, add:
|
||||
- `DEPLOY_KEY` = the private key content from above
|
||||
- `DEPLOY_HOST` = your VPS IP or hostname
|
||||
- `DEPLOY_USER` = the SSH user on the VPS (e.g. `root` or `deploy`)
|
||||
- `DEPLOY_PATH` = the path Caddy serves for mithraic.space/app (e.g. `/var/www/sanctum-web`)
|
||||
|
||||
- [ ] **Step 2: Create the workflow file**
|
||||
|
||||
```bash
|
||||
mkdir -p .forgejo/workflows
|
||||
```
|
||||
|
||||
Create `.forgejo/workflows/deploy.yml`:
|
||||
```yaml
|
||||
name: Build & Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: docker
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install pnpm
|
||||
run: npm install -g pnpm@10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter client build
|
||||
|
||||
- name: Deploy to VPS
|
||||
env:
|
||||
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
||||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
||||
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "$DEPLOY_KEY" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts
|
||||
rsync -avz --delete \
|
||||
-e "ssh -i ~/.ssh/deploy_key" \
|
||||
packages/client/dist/ \
|
||||
"$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/"
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Commit and push — watch the Actions tab on Forgejo**
|
||||
|
||||
```bash
|
||||
git add .forgejo/workflows/deploy.yml
|
||||
git commit -m "ci: build and deploy to VPS on push to main"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
Expected: Forgejo Actions picks up the workflow, builds successfully, and rsyncs `dist/` to the VPS. Visit `mithraic.space/app` — the new layout should be live.
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Verify the live deployment
|
||||
|
||||
- [ ] **Step 1: Open `mithraic.space/app` in a browser**
|
||||
|
||||
Check:
|
||||
- Server icon column is narrow on the left
|
||||
- Channel list is a fixed-width column next to it
|
||||
- Message area fills the remaining screen width
|
||||
- No horizontal overflow or clipped panels
|
||||
|
||||
- [ ] **Step 2: Open Sanctum desktop app**
|
||||
|
||||
Since it loads `mithraic.space/app`, it should automatically show the new layout. Verify the same proportions hold in the desktop window.
|
||||
|
||||
- [ ] **Step 3: Test on a narrow browser window (900px wide)**
|
||||
|
||||
Expected: The layout still shows the message area without horizontal scrollbar. If the member list appears (in a text channel), it can collapse or overlap at this width — that's acceptable for v1.
|
||||
|
||||
- [ ] **Step 4: Tag the first release**
|
||||
|
||||
```bash
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
```
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
# sanctum-web Layout Redesign
|
||||
|
||||
**Date:** 2026-04-22
|
||||
**Repo:** git.mithraic.cloud/ad3laid3/sanctum-web
|
||||
**Base:** stoatchat/for-web (Solid.js + Vite + TypeScript)
|
||||
|
||||
---
|
||||
|
||||
## Goal
|
||||
|
||||
Fork the Stoat web frontend and fix its layout proportions so the app feels native on desktop and works properly as a PWA. The message area should dominate the screen. Nothing in the API, auth, or business logic layer is changed.
|
||||
|
||||
---
|
||||
|
||||
## Layout
|
||||
|
||||
The root shell is rebuilt as a four-column CSS Grid:
|
||||
|
||||
```
|
||||
[server icons 65px] [channels 240px] [messages 1fr] [members 240px]
|
||||
```
|
||||
|
||||
| Panel | Width | Behaviour |
|
||||
|---|---|---|
|
||||
| Server icon sidebar | 65px fixed | Icon-only, scrollable, always visible |
|
||||
| Channel list | 240px default | User-resizable, collapsible |
|
||||
| Message area | fills remaining space (1fr) | Message list + pinned input at bottom |
|
||||
| Member list | 240px | Collapsible, hidden by default on narrow viewports |
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
**Changed:**
|
||||
- Root layout shell component — CSS replaced with proper grid
|
||||
- Global CSS spacing/sizing tokens that cause proportion issues
|
||||
|
||||
**Not changed:**
|
||||
- API client
|
||||
- WebSocket layer
|
||||
- Auth flow
|
||||
- Message rendering components
|
||||
- Channel/server/member components
|
||||
- Any business logic
|
||||
|
||||
---
|
||||
|
||||
## Build & Deployment
|
||||
|
||||
- Repo: `git.mithraic.cloud/ad3laid3/sanctum-web`
|
||||
- CI: Forgejo Actions — `pnpm build` on push to `main`, rsync `dist/` to VPS
|
||||
- Serves at: `mithraic.space/app` (replaces current for-web output, no Caddy changes)
|
||||
- Sanctum desktop app picks up the new frontend automatically on next launch
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Tauri desktop wrapper (separate project, builds on this frontend)
|
||||
- Feature additions beyond layout fixes
|
||||
- Mobile/responsive breakpoints beyond basic collapse behaviour
|
||||
- Rebranding (keep existing Stoat/Revolt dark aesthetic)
|
||||
104
forge.config.ts
|
|
@ -6,55 +6,64 @@ import { MakerSquirrel } from "@electron-forge/maker-squirrel";
|
|||
import { MakerZIP } from "@electron-forge/maker-zip";
|
||||
import { FusesPlugin } from "@electron-forge/plugin-fuses";
|
||||
import { VitePlugin } from "@electron-forge/plugin-vite";
|
||||
import { PublisherGithub } from "@electron-forge/publisher-github";
|
||||
import type { ForgeConfig } from "@electron-forge/shared-types";
|
||||
import { FuseV1Options, FuseVersion } from "@electron/fuses";
|
||||
|
||||
// import { globSync } from "node:fs";
|
||||
|
||||
const STRINGS = {
|
||||
author: "Revolt Platforms LTD",
|
||||
name: "Stoat",
|
||||
execName: "stoat-desktop",
|
||||
description: "Open source user-first chat platform.",
|
||||
author: "MiTHRAL",
|
||||
name: "Sanctum",
|
||||
execName: "sanctum",
|
||||
description: "Private self-hosted chat for mithraic.space.",
|
||||
};
|
||||
|
||||
const ASSET_DIR = "assets/desktop";
|
||||
|
||||
/**
|
||||
* Build targets for the desktop app
|
||||
*/
|
||||
// PLATFORM env var controls which makers are active:
|
||||
// unset → local dev (all makers)
|
||||
// linux → CI Linux build (deb + zip)
|
||||
// win32 → CI Windows build (zip only, no Wine needed)
|
||||
const CI_PLATFORM = process.env.PLATFORM;
|
||||
|
||||
const makers: ForgeConfig["makers"] = [
|
||||
new MakerSquirrel({
|
||||
name: STRINGS.name,
|
||||
authors: STRINGS.author,
|
||||
// todo: hoist this
|
||||
iconUrl: `https://stoat.chat/app/assets/icon-DUSNE-Pb.ico`,
|
||||
// todo: loadingGif
|
||||
setupIcon: `${ASSET_DIR}/icon.ico`,
|
||||
description: STRINGS.description,
|
||||
exe: `${STRINGS.execName}.exe`,
|
||||
setupExe: `${STRINGS.execName}-setup.exe`,
|
||||
copyright: "Copyright (C) 2025 Revolt Platforms LTD",
|
||||
}),
|
||||
new MakerZIP({}),
|
||||
];
|
||||
|
||||
// skip these makers in CI/CD
|
||||
if (!process.env.PLATFORM) {
|
||||
if (CI_PLATFORM === "linux") {
|
||||
makers.push(
|
||||
// must be manually built (freezes CI process)
|
||||
// not much use in being published anyhow
|
||||
new MakerDeb({
|
||||
options: {
|
||||
productName: STRINGS.name,
|
||||
productDescription: STRINGS.description,
|
||||
categories: ["Network"],
|
||||
icon: `${ASSET_DIR}/icon.png`,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (!CI_PLATFORM) {
|
||||
// local dev: include everything
|
||||
makers.push(
|
||||
new MakerSquirrel({
|
||||
name: STRINGS.name,
|
||||
authors: STRINGS.author,
|
||||
iconUrl: `https://mithraic.space/app/assets/icon-DUSNE-Pb.ico`,
|
||||
setupIcon: `${ASSET_DIR}/icon.ico`,
|
||||
description: STRINGS.description,
|
||||
exe: `${STRINGS.execName}.exe`,
|
||||
setupExe: `${STRINGS.execName}-setup.exe`,
|
||||
copyright: `Copyright (C) 2025 ${STRINGS.author}`,
|
||||
}),
|
||||
new MakerAppX({
|
||||
certPass: "",
|
||||
packageExecutable: `app\\${STRINGS.execName}.exe`,
|
||||
publisher: "CN=B040CC7E-0016-4AF5-957F-F8977A6CFA3B",
|
||||
}),
|
||||
// flatpak publishing should occur through flathub repos.
|
||||
// this is just for testing purposes
|
||||
new MakerFlatpak({
|
||||
options: {
|
||||
id: "chat.stoat.stoat-desktop",
|
||||
id: "cloud.mithraic.sanctum",
|
||||
description: STRINGS.description,
|
||||
productName: STRINGS.name,
|
||||
productDescription: STRINGS.description,
|
||||
|
|
@ -69,7 +78,6 @@ if (!process.env.PLATFORM) {
|
|||
} as unknown,
|
||||
categories: ["Network"],
|
||||
modules: [
|
||||
// use the latest zypak -- Electron sandboxing for Flatpak
|
||||
{
|
||||
name: "zypak",
|
||||
sources: [
|
||||
|
|
@ -82,8 +90,6 @@ if (!process.env.PLATFORM) {
|
|||
},
|
||||
],
|
||||
finishArgs: [
|
||||
// default arguments found by running
|
||||
// DEBUG=electron-installer-flatpak* pnpm make
|
||||
"--socket=fallback-x11",
|
||||
"--share=ipc",
|
||||
"--device=dri",
|
||||
|
|
@ -92,32 +98,11 @@ if (!process.env.PLATFORM) {
|
|||
"--env=TMPDIR=/var/tmp",
|
||||
"--share=network",
|
||||
"--talk-name=org.freedesktop.Notifications",
|
||||
// add Unity talk name for badges
|
||||
"--talk-name=com.canonical.Unity",
|
||||
],
|
||||
// files: [
|
||||
// // is this necessary?
|
||||
// // https://stackoverflow.com/q/79745700
|
||||
// ...[16, 32, 64, 128, 256, 512].map(
|
||||
// (size) =>
|
||||
// [
|
||||
// `assets/desktop/hicolor/${size}x${size}.png`,
|
||||
// `/app/share/icons/hicolor/${size}x${size}/apps/chat.stoat.stoat-desktop.png`,
|
||||
// ] as [string, string],
|
||||
// ),
|
||||
// [
|
||||
// `assets/desktop/icon.svg`,
|
||||
// `/app/share/icons/hicolor/scalable/apps/chat.stoat.stoat-desktop.svg`,
|
||||
// ] as [string, string],
|
||||
// ],
|
||||
files: [],
|
||||
} as MakerFlatpakOptionsConfig,
|
||||
/* as Omit<
|
||||
MakerFlatpakOptionsConfig,
|
||||
"files"
|
||||
> */
|
||||
}),
|
||||
// testing purposes
|
||||
new MakerDeb({
|
||||
options: {
|
||||
productName: STRINGS.name,
|
||||
|
|
@ -135,20 +120,13 @@ const config: ForgeConfig = {
|
|||
name: STRINGS.name,
|
||||
executableName: STRINGS.execName,
|
||||
icon: `${ASSET_DIR}/icon`,
|
||||
// extraResource: [
|
||||
// // include all the asset files
|
||||
// ...globSync(ASSET_DIR + "/**/*"),
|
||||
// ],
|
||||
},
|
||||
rebuildConfig: {},
|
||||
makers,
|
||||
plugins: [
|
||||
new VitePlugin({
|
||||
// `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.
|
||||
// If you are familiar with Vite configuration, it will look really familiar.
|
||||
build: [
|
||||
{
|
||||
// `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`.
|
||||
entry: "src/main.ts",
|
||||
config: "vite.main.config.ts",
|
||||
target: "main",
|
||||
|
|
@ -161,8 +139,6 @@ const config: ForgeConfig = {
|
|||
],
|
||||
renderer: [],
|
||||
}),
|
||||
// Fuses are used to enable/disable various Electron functionality
|
||||
// at package time, before code signing the application
|
||||
new FusesPlugin({
|
||||
version: FuseVersion.V1,
|
||||
[FuseV1Options.RunAsNode]: false,
|
||||
|
|
@ -173,14 +149,6 @@ const config: ForgeConfig = {
|
|||
[FuseV1Options.OnlyLoadAppFromAsar]: true,
|
||||
}),
|
||||
],
|
||||
publishers: [
|
||||
new PublisherGithub({
|
||||
repository: {
|
||||
owner: "stoatchat",
|
||||
name: "for-desktop",
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"name": "stoat-desktop",
|
||||
"productName": "stoat-desktop",
|
||||
"name": "sanctum",
|
||||
"productName": "sanctum",
|
||||
"version": "1.3.0",
|
||||
"main": ".vite/build/main.js",
|
||||
"repository": "stoatchat/desktop",
|
||||
"repository": "https://git.mithraic.cloud/ad3laid3/sanctum",
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
|
|
@ -52,7 +52,6 @@
|
|||
"discord-rpc": "^4.0.1",
|
||||
"electron-squirrel-startup": "^1.0.1",
|
||||
"electron-store": "^10.1.0",
|
||||
"update-electron-app": "^3.1.1",
|
||||
"utf-8-validate": "^6.0.5"
|
||||
},
|
||||
"packageManager": "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34"
|
||||
|
|
|
|||
29
pnpm-lock.yaml
generated
|
|
@ -29,9 +29,6 @@ importers:
|
|||
electron-store:
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0
|
||||
update-electron-app:
|
||||
specifier: ^3.1.1
|
||||
version: 3.1.1
|
||||
utf-8-validate:
|
||||
specifier: ^6.0.5
|
||||
version: 6.0.5
|
||||
|
|
@ -907,6 +904,7 @@ packages:
|
|||
'@xmldom/xmldom@0.8.11':
|
||||
resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
deprecated: this version has critical issues, please update to the latest version
|
||||
|
||||
abbrev@1.1.1:
|
||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
||||
|
|
@ -1702,9 +1700,6 @@ packages:
|
|||
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
github-url-to-object@4.0.6:
|
||||
resolution: {integrity: sha512-NaqbYHMUAlPcmWFdrAB7bcxrNIiiJWJe8s/2+iOc9vlcHlwHqSGrPk+Yi3nu6ebTwgsZEa7igz+NH2vEq3gYwQ==}
|
||||
|
||||
glob-parent@5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
engines: {node: '>= 6'}
|
||||
|
|
@ -1715,12 +1710,12 @@ packages:
|
|||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
glob@8.1.0:
|
||||
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
|
||||
engines: {node: '>=12'}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
global-agent@3.0.0:
|
||||
resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==}
|
||||
|
|
@ -1992,9 +1987,6 @@ packages:
|
|||
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
is-url@1.2.4:
|
||||
resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
|
||||
|
||||
is-weakmap@2.0.2:
|
||||
resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -2876,6 +2868,7 @@ packages:
|
|||
tar@6.2.1:
|
||||
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
|
||||
engines: {node: '>=10'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
temp@0.9.4:
|
||||
resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==}
|
||||
|
|
@ -3006,9 +2999,6 @@ packages:
|
|||
resolution: {integrity: sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
update-electron-app@3.1.1:
|
||||
resolution: {integrity: sha512-7duRr6sYn014tifhKgT/5i8N+6xLzmJVJ8hVtNrHXlIDNP6QbRe6VxZ1hSi2UH5oJPzhor/PH7yKU9em5xjRzQ==}
|
||||
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
|
|
@ -5289,10 +5279,6 @@ snapshots:
|
|||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
github-url-to-object@4.0.6:
|
||||
dependencies:
|
||||
is-url: 1.2.4
|
||||
|
||||
glob-parent@5.1.2:
|
||||
dependencies:
|
||||
is-glob: 4.0.3
|
||||
|
|
@ -5600,8 +5586,6 @@ snapshots:
|
|||
|
||||
is-unicode-supported@0.1.0: {}
|
||||
|
||||
is-url@1.2.4: {}
|
||||
|
||||
is-weakmap@2.0.2: {}
|
||||
|
||||
is-weakref@1.1.1:
|
||||
|
|
@ -6654,11 +6638,6 @@ snapshots:
|
|||
|
||||
untildify@3.0.3: {}
|
||||
|
||||
update-electron-app@3.1.1:
|
||||
dependencies:
|
||||
github-url-to-object: 4.0.6
|
||||
ms: 2.1.3
|
||||
|
||||
uri-js@4.4.1:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
|
|
|||
27
src/main.ts
|
|
@ -1,14 +1,19 @@
|
|||
import { IUpdateInfo, updateElectronApp } from "update-electron-app";
|
||||
|
||||
import { BrowserWindow, Notification, app, shell } from "electron";
|
||||
import { BrowserWindow, app, shell } from "electron";
|
||||
import started from "electron-squirrel-startup";
|
||||
|
||||
import { autoLaunch } from "./native/autoLaunch";
|
||||
import { config } from "./native/config";
|
||||
import { initDiscordRpc } from "./native/discordRpc";
|
||||
import { initTray } from "./native/tray";
|
||||
import { checkForUpdates } from "./native/updater";
|
||||
import { BUILD_URL, createMainWindow, mainWindow } from "./native/window";
|
||||
|
||||
// Linux GPU sandbox causes fatal crash on some AMD/CachyOS setups
|
||||
if (process.platform === "linux") {
|
||||
app.commandLine.appendSwitch("disable-gpu-sandbox");
|
||||
app.commandLine.appendSwitch("disable-software-rasterizer");
|
||||
}
|
||||
|
||||
// Squirrel-specific logic
|
||||
// create/remove shortcuts on Windows when installing / uninstalling
|
||||
// we just need to close out of the app immediately
|
||||
|
|
@ -24,20 +29,7 @@ if (!config.hardwareAcceleration) {
|
|||
// ensure only one copy of the application can run
|
||||
const acquiredLock = app.requestSingleInstanceLock();
|
||||
|
||||
const onNotifyUser = (_info: IUpdateInfo) => {
|
||||
const notification = new Notification({
|
||||
title: "Update Available",
|
||||
body: "Restart the app to install the update.",
|
||||
silent: true,
|
||||
});
|
||||
|
||||
notification.show();
|
||||
};
|
||||
|
||||
if (acquiredLock) {
|
||||
// start auto update logic
|
||||
updateElectronApp({ onNotifyUser });
|
||||
|
||||
// create and configure the app when electron is ready
|
||||
app.on("ready", () => {
|
||||
// create window and application contexts
|
||||
|
|
@ -53,10 +45,11 @@ if (acquiredLock) {
|
|||
|
||||
initTray();
|
||||
initDiscordRpc();
|
||||
checkForUpdates();
|
||||
|
||||
// Windows specific fix for notifications
|
||||
if (process.platform === "win32") {
|
||||
app.setAppUserModelId("chat.stoat.notifications");
|
||||
app.setAppUserModelId("cloud.mithraic.sanctum");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { ipcMain } from "electron";
|
|||
import { mainWindow } from "./window";
|
||||
|
||||
export const autoLaunch = new AutoLaunch({
|
||||
name: "Stoat",
|
||||
name: "Sanctum",
|
||||
});
|
||||
|
||||
ipcMain.handle("getAutostart", async () => {
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ export async function setBadgeCount(count: number) {
|
|||
signature: "sa{sv}",
|
||||
body: [
|
||||
process.env.container === "1"
|
||||
? "application://chat.stoat.stoat-desktop.desktop" // flatpak handling
|
||||
: "application://stoat-desktop.desktop",
|
||||
? "application://cloud.mithraic.sanctum.desktop" // flatpak handling
|
||||
: "application://sanctum.desktop",
|
||||
[
|
||||
["count", ["x", Math.min(count, 0)]],
|
||||
["count-visible", ["b", count !== 0]],
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ export async function initDiscordRpc() {
|
|||
|
||||
rpc.on("ready", () =>
|
||||
rpc.setActivity({
|
||||
state: "stoat.chat",
|
||||
state: "mithraic.space",
|
||||
details: "Chatting with others",
|
||||
largeImageKey: "qr",
|
||||
largeImageText: "Join Stoat!",
|
||||
largeImageText: "Join Sanctum!",
|
||||
buttons: [
|
||||
{
|
||||
label: "Join Stoat",
|
||||
url: "https://stoat.chat/",
|
||||
label: "Join Sanctum",
|
||||
url: "https://mithraic.space/",
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
|
|
|||
65
src/native/themes.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import { app, shell } from "electron";
|
||||
import { mkdirSync, readdirSync, readFileSync, existsSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
const themesDir = join(app.getPath("userData"), "themes");
|
||||
|
||||
let activeFile: string | null = null;
|
||||
let cssKey: string | null = null;
|
||||
|
||||
export function getThemesDir() {
|
||||
return themesDir;
|
||||
}
|
||||
|
||||
export function getThemeFiles(): string[] {
|
||||
try {
|
||||
mkdirSync(themesDir, { recursive: true });
|
||||
return readdirSync(themesDir).filter(f => f.endsWith(".css")).sort();
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function getActiveTheme(): string | null {
|
||||
return activeFile;
|
||||
}
|
||||
|
||||
// Call at the start of did-finish-load — old page context is gone, key is stale
|
||||
export function invalidateCssKey() {
|
||||
cssKey = null;
|
||||
}
|
||||
|
||||
export async function applyTheme(wc: Electron.WebContents, file: string | null) {
|
||||
if (cssKey) {
|
||||
try { await wc.removeInsertedCSS(cssKey); } catch {}
|
||||
cssKey = null;
|
||||
}
|
||||
activeFile = file;
|
||||
if (!file) return;
|
||||
try {
|
||||
const css = readFileSync(join(themesDir, file), "utf-8");
|
||||
cssKey = await wc.insertCSS(css);
|
||||
} catch (err) {
|
||||
console.error("[themes] failed to load", file, err);
|
||||
}
|
||||
}
|
||||
|
||||
export async function cycleTheme(wc: Electron.WebContents): Promise<string | null> {
|
||||
const files = getThemeFiles();
|
||||
if (files.length === 0) return null;
|
||||
const idx = activeFile ? files.indexOf(activeFile) : -1;
|
||||
const next = files[(idx + 1) % files.length];
|
||||
await applyTheme(wc, next);
|
||||
return next;
|
||||
}
|
||||
|
||||
export async function reloadTheme(wc: Electron.WebContents) {
|
||||
const file = activeFile;
|
||||
if (!file) return;
|
||||
await applyTheme(wc, file);
|
||||
}
|
||||
|
||||
export function openThemesFolder() {
|
||||
mkdirSync(themesDir, { recursive: true });
|
||||
shell.openPath(themesDir);
|
||||
}
|
||||
|
|
@ -5,9 +5,13 @@ import macOsTrayIconAsset from "../../assets/desktop/iconTemplate.png?asset";
|
|||
import { version } from "../../package.json";
|
||||
|
||||
import { mainWindow, quitApp } from "./window";
|
||||
import { checkForUpdates } from "./updater";
|
||||
import { getThemeFiles, getActiveTheme, applyTheme, cycleTheme, reloadTheme, openThemesFolder } from "./themes";
|
||||
|
||||
// internal tray state
|
||||
let tray: Tray = null;
|
||||
// Keep strong reference to prevent garbage collection on Linux
|
||||
let trayIcon: Electron.NativeImage;
|
||||
|
||||
// Create and resize tray icon for macOS
|
||||
function createTrayIcon() {
|
||||
|
|
@ -15,17 +19,18 @@ function createTrayIcon() {
|
|||
const image = nativeImage.createFromDataURL(macOsTrayIconAsset);
|
||||
const resized = image.resize({ width: 20, height: 20 });
|
||||
resized.setTemplateImage(true);
|
||||
return resized;
|
||||
trayIcon = resized;
|
||||
} else {
|
||||
return nativeImage.createFromDataURL(trayIconAsset);
|
||||
trayIcon = nativeImage.createFromDataURL(trayIconAsset);
|
||||
}
|
||||
return trayIcon;
|
||||
}
|
||||
|
||||
export function initTray() {
|
||||
const trayIcon = createTrayIcon();
|
||||
tray = new Tray(trayIcon);
|
||||
updateTrayMenu();
|
||||
tray.setToolTip("Stoat for Desktop");
|
||||
tray.setToolTip(`Sanctum ${version}`);
|
||||
tray.setImage(trayIcon);
|
||||
tray.on("click", () => {
|
||||
if (mainWindow.isVisible()) {
|
||||
|
|
@ -38,9 +43,10 @@ export function initTray() {
|
|||
}
|
||||
|
||||
export function updateTrayMenu() {
|
||||
if (!tray) return;
|
||||
tray.setContextMenu(
|
||||
Menu.buildFromTemplate([
|
||||
{ label: "Stoat for Desktop", type: "normal", enabled: false },
|
||||
{ label: "Sanctum", type: "normal", enabled: false },
|
||||
{
|
||||
label: "Version",
|
||||
type: "submenu",
|
||||
|
|
@ -52,6 +58,45 @@ export function updateTrayMenu() {
|
|||
},
|
||||
]),
|
||||
},
|
||||
{
|
||||
label: "Check for Updates",
|
||||
type: "normal",
|
||||
click: () => checkForUpdates(),
|
||||
},
|
||||
{
|
||||
label: "Themes",
|
||||
type: "submenu",
|
||||
submenu: Menu.buildFromTemplate([
|
||||
{
|
||||
label: "None",
|
||||
type: "radio",
|
||||
checked: getActiveTheme() === null,
|
||||
click: () => { applyTheme(mainWindow.webContents, null); updateTrayMenu(); },
|
||||
},
|
||||
...getThemeFiles().map(file => ({
|
||||
label: file.replace(/\.css$/i, ""),
|
||||
type: "radio" as const,
|
||||
checked: getActiveTheme() === file,
|
||||
click: () => { applyTheme(mainWindow.webContents, file); updateTrayMenu(); },
|
||||
})),
|
||||
{ type: "separator" as const },
|
||||
{
|
||||
label: "Cycle Theme",
|
||||
type: "normal" as const,
|
||||
click: () => { cycleTheme(mainWindow.webContents).then(() => updateTrayMenu()); },
|
||||
},
|
||||
{
|
||||
label: "Reload Theme",
|
||||
type: "normal" as const,
|
||||
click: () => reloadTheme(mainWindow.webContents),
|
||||
},
|
||||
{
|
||||
label: "Open Themes Folder",
|
||||
type: "normal" as const,
|
||||
click: () => openThemesFolder(),
|
||||
},
|
||||
]),
|
||||
},
|
||||
{ type: "separator" },
|
||||
{
|
||||
label: mainWindow.isVisible() ? "Hide App" : "Show App",
|
||||
|
|
|
|||
83
src/native/update-window.ts
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import { BrowserWindow, app, ipcMain } from "electron";
|
||||
|
||||
let win: BrowserWindow | null = null;
|
||||
|
||||
const HTML = `<!DOCTYPE html><html><head><meta charset="utf-8"><style>
|
||||
*{margin:0;padding:0;box-sizing:border-box}
|
||||
body{font-family:system-ui,sans-serif;background:#1e1e2e;color:#cdd6f4;
|
||||
display:flex;flex-direction:column;align-items:center;justify-content:center;
|
||||
height:100vh;padding:28px 32px;gap:14px;user-select:none;-webkit-app-region:drag}
|
||||
h2{font-size:15px;font-weight:600;letter-spacing:.3px}
|
||||
#status{font-size:13px;color:#a6adc8}
|
||||
.track{width:100%;height:6px;background:#313244;border-radius:3px}
|
||||
#bar{height:6px;background:#89b4fa;border-radius:3px;width:0%;transition:width .4s ease}
|
||||
#btn{display:none;margin-top:6px;padding:9px 24px;background:#89b4fa;color:#1e1e2e;
|
||||
border:none;border-radius:6px;font-size:13px;font-weight:700;cursor:pointer;
|
||||
-webkit-app-region:no-drag}
|
||||
#btn:hover{background:#b4befe}
|
||||
</style></head><body>
|
||||
<h2 id="title">Updating Sanctum</h2>
|
||||
<div id="status">Downloading…</div>
|
||||
<div class="track"><div id="bar"></div></div>
|
||||
<button id="btn">Restart Now</button>
|
||||
<script>
|
||||
const {ipcRenderer}=require('electron');
|
||||
ipcRenderer.on('upd-progress',(_,p)=>{
|
||||
document.getElementById('bar').style.width=p+'%';
|
||||
document.getElementById('status').textContent=p<100?'Downloading… '+p+'%':'Installing…';
|
||||
});
|
||||
ipcRenderer.on('upd-ready',(_,v)=>{
|
||||
document.getElementById('title').textContent='Sanctum '+v+' installed';
|
||||
document.getElementById('bar').style.width='100%';
|
||||
var s=document.getElementById('status');
|
||||
var n=2;
|
||||
s.textContent='Restarting in '+n+'…';
|
||||
var t=setInterval(function(){
|
||||
n--;
|
||||
if(n<=0){clearInterval(t);s.textContent='Restarting…';}
|
||||
else s.textContent='Restarting in '+n+'…';
|
||||
},1000);
|
||||
});
|
||||
ipcRenderer.on('upd-error',(_,msg)=>{
|
||||
document.getElementById('title').textContent='Update Failed';
|
||||
document.getElementById('status').textContent=msg;
|
||||
document.getElementById('bar').style.background='#f38ba8';
|
||||
});
|
||||
</script></body></html>`;
|
||||
|
||||
export function showUpdateWindow() {
|
||||
if (win) { win.focus(); return; }
|
||||
win = new BrowserWindow({
|
||||
width: 400,
|
||||
height: 180,
|
||||
resizable: false,
|
||||
minimizable: false,
|
||||
maximizable: false,
|
||||
fullscreenable: false,
|
||||
title: "Sanctum Update",
|
||||
frame: false,
|
||||
alwaysOnTop: true,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
},
|
||||
});
|
||||
win.loadURL("data:text/html;charset=utf-8," + encodeURIComponent(HTML));
|
||||
win.on("closed", () => { win = null; });
|
||||
}
|
||||
|
||||
export function setUpdateProgress(percent: number) {
|
||||
win?.webContents.send("upd-progress", Math.round(percent));
|
||||
}
|
||||
|
||||
export function setUpdateReady(version: string, relaunch: boolean) {
|
||||
win?.webContents.send("upd-ready", version);
|
||||
setTimeout(() => {
|
||||
if (relaunch) app.relaunch();
|
||||
app.exit(0);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
export function setUpdateError(msg: string) {
|
||||
win?.webContents.send("upd-error", msg);
|
||||
}
|
||||
154
src/native/updater.ts
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import { Notification, app, ipcMain } from "electron";
|
||||
import { exec, spawn } from "child_process";
|
||||
import { createWriteStream, mkdirSync, writeFileSync } from "fs";
|
||||
import { dirname, join } from "path";
|
||||
import { tmpdir } from "os";
|
||||
|
||||
import { showUpdateWindow, setUpdateProgress, setUpdateReady, setUpdateError } from "./update-window";
|
||||
|
||||
ipcMain.handle("checkForUpdates", () => checkForUpdates());
|
||||
|
||||
const RELEASES_URL =
|
||||
"https://git.mithraic.cloud/api/v1/repos/ad3laid3/sanctum/releases/latest";
|
||||
|
||||
interface Asset {
|
||||
name: string;
|
||||
browser_download_url: string;
|
||||
}
|
||||
|
||||
interface Release {
|
||||
tag_name: string;
|
||||
html_url: string;
|
||||
assets: Asset[];
|
||||
}
|
||||
|
||||
export async function checkForUpdates() {
|
||||
try {
|
||||
console.log("[updater] checking:", RELEASES_URL);
|
||||
|
||||
const res = await fetch(RELEASES_URL);
|
||||
if (!res.ok) {
|
||||
console.error("[updater] releases API returned", res.status, res.statusText);
|
||||
notify("Update Check Failed", `API returned ${res.status}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const release = (await res.json()) as Release;
|
||||
const latest = release.tag_name.replace(/^v/, "");
|
||||
const current = app.getVersion();
|
||||
|
||||
console.log(`[updater] current=${current} latest=${latest}`);
|
||||
|
||||
if (!isNewer(latest, current)) {
|
||||
notify("Already Up to Date", `You're on Sanctum ${current}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const asset = findAsset(release.assets);
|
||||
if (!asset) {
|
||||
const names = release.assets.map(a => a.name).join(", ");
|
||||
console.error("[updater] no matching asset for platform:", process.platform, names);
|
||||
notify("Update Failed", `No ${process.platform} asset found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[updater] update available: ${current} → ${latest}, downloading ${asset.name}`);
|
||||
showUpdateWindow();
|
||||
await downloadAndInstall(asset.browser_download_url, latest);
|
||||
} catch (err) {
|
||||
console.error("[updater] update check failed:", err);
|
||||
setUpdateError(String(err));
|
||||
}
|
||||
}
|
||||
|
||||
function findAsset(assets: Asset[]): Asset | undefined {
|
||||
if (process.platform === "linux")
|
||||
return assets.find((a) => a.name.includes("linux") && a.name.endsWith(".zip"));
|
||||
if (process.platform === "win32")
|
||||
return assets.find((a) => a.name.includes("win32") && a.name.endsWith(".zip"));
|
||||
}
|
||||
|
||||
async function downloadAndInstall(url: string, version: string) {
|
||||
const tmpDir = join(tmpdir(), `sanctum-update-${version}`);
|
||||
mkdirSync(tmpDir, { recursive: true });
|
||||
const zipPath = join(tmpDir, "update.zip");
|
||||
const extractDir = join(tmpDir, "extracted");
|
||||
const installDir = dirname(process.execPath);
|
||||
|
||||
console.log(`[updater] downloading from ${url}`);
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`Download failed: ${res.status}`);
|
||||
|
||||
const total = Number(res.headers.get("content-length")) || 0;
|
||||
let downloaded = 0;
|
||||
const writer = createWriteStream(zipPath);
|
||||
const reader = res.body.getReader();
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
writer.write(value);
|
||||
downloaded += value.length;
|
||||
if (total > 0) setUpdateProgress(Math.round((downloaded / total) * 90));
|
||||
}
|
||||
await new Promise<void>(resolve => writer.end(resolve));
|
||||
|
||||
setUpdateProgress(95);
|
||||
console.log(`[updater] download complete, extracting to ${installDir}`);
|
||||
|
||||
if (process.platform === "win32") {
|
||||
// Extract zip while the app is still running (no locked files yet)
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const cmd = `powershell -Command "Expand-Archive -Force -Path '${zipPath}' -DestinationPath '${extractDir}'"`;
|
||||
exec(cmd, (err, _stdout, stderr) => {
|
||||
if (err) { console.error("[updater] extract failed:", stderr); reject(err); }
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// Write a batch script that runs after we exit: waits, copies, relaunches
|
||||
const batchPath = join(tmpDir, "apply-update.bat");
|
||||
const bat = [
|
||||
"@echo off",
|
||||
"timeout /t 3 /nobreak >nul",
|
||||
`for /d %%D in ("${extractDir}\\*") do set SUB=%%D`,
|
||||
`xcopy /E /Y /I "%SUB%\\*" "${installDir}\\"`,
|
||||
`start "" "${join(installDir, "sanctum.exe")}"`,
|
||||
`del "%~f0"`,
|
||||
].join("\r\n");
|
||||
writeFileSync(batchPath, bat);
|
||||
|
||||
// Spawn batch truly detached so it outlives this process
|
||||
const child = spawn("cmd.exe", ["/C", batchPath], {
|
||||
detached: true,
|
||||
stdio: "ignore",
|
||||
windowsHide: false,
|
||||
});
|
||||
child.unref();
|
||||
setUpdateReady(version, false); // batch script handles relaunch
|
||||
} else {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const cmd = `unzip -o "${zipPath}" -d "${extractDir}" && SUBDIR=$(ls "${extractDir}" | head -1) && rm -f "${installDir}/sanctum" && cp -rT "${extractDir}/$SUBDIR" "${installDir}"`;
|
||||
exec(cmd, { shell: "/bin/bash" }, (err, _stdout, stderr) => {
|
||||
if (err) { console.error("[updater] extract failed:", stderr); reject(err); }
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
setUpdateReady(version, true);
|
||||
}
|
||||
}
|
||||
|
||||
function notify(title: string, body: string) {
|
||||
const n = new Notification({ title, body, silent: true });
|
||||
n.show();
|
||||
return n;
|
||||
}
|
||||
|
||||
function isNewer(latest: string, current: string): boolean {
|
||||
const parse = (v: string) => v.split(".").map(p => Number(p) || 0);
|
||||
const [lA, lB, lC] = parse(latest);
|
||||
const [cA, cB, cC] = parse(current);
|
||||
if (lA !== cA) return lA > cA;
|
||||
if (lB !== cB) return lB > cB;
|
||||
return lC > cC;
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import windowIconAsset from "../../assets/desktop/icon.png?asset";
|
|||
|
||||
import { config } from "./config";
|
||||
import { updateTrayMenu } from "./tray";
|
||||
import { invalidateCssKey, applyTheme, getActiveTheme } from "./themes";
|
||||
|
||||
// global reference to main window
|
||||
export let mainWindow: BrowserWindow;
|
||||
|
|
@ -21,7 +22,7 @@ export let mainWindow: BrowserWindow;
|
|||
export const BUILD_URL = new URL(
|
||||
app.commandLine.hasSwitch("force-server")
|
||||
? app.commandLine.getSwitchValue("force-server")
|
||||
: /*MAIN_WINDOW_VITE_DEV_SERVER_URL ??*/ "https://stoat.chat/app",
|
||||
: /*MAIN_WINDOW_VITE_DEV_SERVER_URL ??*/ "https://mithraic.space/app",
|
||||
);
|
||||
|
||||
// internal window state
|
||||
|
|
@ -138,11 +139,20 @@ export function createMainWindow() {
|
|||
) {
|
||||
event.preventDefault();
|
||||
mainWindow.webContents.reload();
|
||||
} else if (input.key === "F12") {
|
||||
mainWindow.webContents.toggleDevTools();
|
||||
}
|
||||
});
|
||||
|
||||
ensureThemesFolder();
|
||||
|
||||
// send the config
|
||||
mainWindow.webContents.on("did-finish-load", () => config.sync());
|
||||
mainWindow.webContents.on("did-finish-load", () => {
|
||||
config.sync();
|
||||
injectBranding(mainWindow.webContents);
|
||||
invalidateCssKey();
|
||||
applyTheme(mainWindow.webContents, getActiveTheme());
|
||||
});
|
||||
|
||||
// configure spellchecker context menu
|
||||
mainWindow.webContents.on("context-menu", (_, params) => {
|
||||
|
|
@ -200,6 +210,53 @@ export function createMainWindow() {
|
|||
// setInterval(() => setBadgeCount((++i % 30) + 1), 1000);
|
||||
}
|
||||
|
||||
function injectBranding(wc: Electron.WebContents) {
|
||||
wc.insertCSS(`
|
||||
[class*="wordmark"], [class*="Wordmark"], [data-app-name] { display: none !important; }
|
||||
`);
|
||||
wc.executeJavaScript(`
|
||||
(function() {
|
||||
const BRAND_RE = /\\b(Revolt|Stoat)\\b/g;
|
||||
const SKIP_TAGS = new Set(['SCRIPT','STYLE','TEXTAREA','INPUT','CODE','PRE']);
|
||||
|
||||
function patchText(root) {
|
||||
var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
||||
var node;
|
||||
while ((node = walker.nextNode())) {
|
||||
if (SKIP_TAGS.has(node.parentElement && node.parentElement.tagName)) continue;
|
||||
if (BRAND_RE.test(node.nodeValue)) {
|
||||
node.nodeValue = node.nodeValue.replace(BRAND_RE, 'Sanctum');
|
||||
}
|
||||
BRAND_RE.lastIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function patchTitle() {
|
||||
if (BRAND_RE.test(document.title)) {
|
||||
document.title = document.title.replace(BRAND_RE, 'Sanctum');
|
||||
}
|
||||
BRAND_RE.lastIndex = 0;
|
||||
}
|
||||
|
||||
patchText(document.documentElement);
|
||||
patchTitle();
|
||||
|
||||
new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(m) {
|
||||
m.addedNodes.forEach(function(n) {
|
||||
if (n.nodeType === 1) patchText(n);
|
||||
else if (n.nodeType === 3 && !SKIP_TAGS.has(n.parentElement && n.parentElement.tagName)) {
|
||||
if (BRAND_RE.test(n.nodeValue)) n.nodeValue = n.nodeValue.replace(BRAND_RE, 'Sanctum');
|
||||
BRAND_RE.lastIndex = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
patchTitle();
|
||||
}).observe(document.documentElement, { childList: true, subtree: true });
|
||||
})();
|
||||
`, true).catch(function() {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Quit the entire app
|
||||
*/
|
||||
|
|
|
|||