Compare commits
3 Commits
feat/zone-
...
e2532a8136
| Author | SHA1 | Date | |
|---|---|---|---|
| e2532a8136 | |||
|
|
27f9c6b7b6 | ||
|
|
98f4f82db2 |
117
.github/workflows/pr-iphone-deploy.yml
vendored
117
.github/workflows/pr-iphone-deploy.yml
vendored
@@ -8,12 +8,11 @@ on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
types: [opened, synchronize, reopened]
|
||||
# Only run the iOS build+deploy when the PR actually touches the Swift app
|
||||
# or this workflow itself. Docs-only / backend-only / admin-web-only PRs
|
||||
# skip the runner entirely (no point rebuilding an unchanged .app).
|
||||
paths:
|
||||
- 'tabatago-swift/**'
|
||||
- '.github/workflows/pr-iphone-deploy.yml'
|
||||
# NOTE: no trigger-level `paths:` here — Gitea Actions does not reliably
|
||||
# honor `on.pull_request.paths:` filters (the workflow silently fails to
|
||||
# trigger even when changed files match). Path gating is done at the job
|
||||
# level via dorny/paths-filter@v3 in the `changes` job below (same pattern
|
||||
# as ci.yml). Docs/backend-only PRs then skip the macOS runner.
|
||||
|
||||
# Every mutation (comments, merge) goes through the Gitea API with PR_API_TOKEN,
|
||||
# never the runner's native GITHUB_TOKEN — so a `permissions:` block would be
|
||||
@@ -26,8 +25,29 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
|
||||
# ── Path filter — determines whether the macOS build+deploy is worth running ──
|
||||
# Gitea Actions does not honor trigger-level `on.pull_request.paths:`, so we
|
||||
# gate at the job level with dorny/paths-filter (same pattern as ci.yml).
|
||||
changes:
|
||||
name: Detect Changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
ios: ${{ steps.filter.outputs.ios }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
ios:
|
||||
- 'tabatago-swift/**'
|
||||
- '.github/workflows/pr-iphone-deploy.yml'
|
||||
|
||||
build-deploy:
|
||||
name: Build & Deploy to iPhone (devicectl)
|
||||
needs: changes
|
||||
if: needs.changes.outputs.ios == 'true'
|
||||
runs-on: macos
|
||||
timeout-minutes: 30
|
||||
|
||||
@@ -172,15 +192,25 @@ jobs:
|
||||
run: |
|
||||
PR="${{ github.event.pull_request.number }}"
|
||||
REPO="${{ github.repository }}"
|
||||
# The HTML comment is invisible in Gitea's rendered markdown but is
|
||||
# present in the raw body — wait-approval uses it as a sentinel to
|
||||
# skip THIS bot comment when scanning for LGTM/KO (otherwise the
|
||||
# instruction text "Reply LGTM pour merger" would self-trigger a
|
||||
# merge ~30s after deploy). DO NOT remove or reword without also
|
||||
# updating the scanner in the wait-approval job.
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token ${GT_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"body\":\"## 📱 Prêt à tester !\\n\\nL'app est déployée sur l'iPhone (devicectl).\\n\\n- Teste les changements\\n- Reply **LGTM** pour merger\\n- Reply **KO** pour bloquer\"}" \
|
||||
-d "{\"body\":\"## 📱 Prêt à tester !\\n\\nL'app est déployée sur l'iPhone (devicectl).\\n\\n<!-- tabatago:ready-to-test -->\\n\\n- Teste les changements\\n- Reply **LGTM** pour merger\\n- Reply **KO** pour bloquer\"}" \
|
||||
"${GITEA_URL}/api/v1/repos/${REPO}/issues/${PR}/comments"
|
||||
|
||||
wait-approval:
|
||||
name: Wait for LGTM comment
|
||||
needs: build-deploy
|
||||
# Only run when build-deploy actually deployed. Without this, a skipped
|
||||
# build-deploy (filtered out by `changes`) would still launch this job and
|
||||
# the merge poll would run against a PR that was never deployed to device.
|
||||
if: needs.build-deploy.result == 'success'
|
||||
runs-on: macos
|
||||
timeout-minutes: 120
|
||||
|
||||
@@ -202,6 +232,19 @@ jobs:
|
||||
# Re-fetch ALL comments each cycle (not since_id) so we also catch
|
||||
# edits — e.g. a reviewer changing "KO" → "LGTM". Negligible cost for
|
||||
# PRs with <50 comments.
|
||||
#
|
||||
# Parsing is done with python3 (preinstalled on the macOS runner and
|
||||
# already used by scripts/ci-status.py) rather than grep over raw JSON:
|
||||
# - the bot's "Ready to test" comment body literally contains the
|
||||
# words LGTM/KO as instructions to the reviewer, so any naive
|
||||
# body grep would self-match and auto-merge ~30s after deploy.
|
||||
# We skip it via the <!-- tabatago:ready-to-test --> sentinel
|
||||
# embedded by the build-deploy job;
|
||||
# - json.loads avoids false matches when the literal "body" key or
|
||||
# trigger words appear inside another string field.
|
||||
# KO is checked BEFORE LGTM so a PR with both signals blocks (matches
|
||||
# the existing "KO blocks" intent — a reviewer who flip-flops shouldn't
|
||||
# merge just because an older LGTM is still in the history).
|
||||
|
||||
while [ $TRIES -lt $MAX ]; do
|
||||
sleep 30
|
||||
@@ -210,23 +253,51 @@ jobs:
|
||||
COMMENTS=$(curl -s -H "Authorization: token ${GT_TOKEN}" \
|
||||
"${API}/issues/${PR}/comments?limit=50&page=1")
|
||||
|
||||
# Match LGTM/KO anywhere in the body (with a word boundary so "KOM"
|
||||
# or "LGTMX" don't trigger). Case-insensitive.
|
||||
if echo "$COMMENTS" | grep -qiE '"body":[[:space:]]*"[^"]*\bLGTM\b'; then
|
||||
echo "✅ LGTM reçu ! Squash-merge..."
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token ${GT_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"Do\":\"squash\"}" \
|
||||
"${API}/pulls/${PR}/merge"
|
||||
echo "✅ Mergée (squash)."
|
||||
exit 0
|
||||
fi
|
||||
DECISION=$(python3 - "$COMMENTS" <<'PY'
|
||||
import json, re, sys
|
||||
MARKER = "<!-- tabatago:ready-to-test -->"
|
||||
try:
|
||||
comments = json.loads(sys.argv[1] or "[]")
|
||||
except Exception:
|
||||
comments = []
|
||||
lgtm = re.compile(r"\bLGTM\b", re.IGNORECASE)
|
||||
ko = re.compile(r"\bKO\b", re.IGNORECASE)
|
||||
hit_lgtm = hit_ko = False
|
||||
for c in comments:
|
||||
body = c.get("body") or ""
|
||||
if MARKER in body:
|
||||
# Skip the bot's own "Ready to test" comment — its body mentions
|
||||
# LGTM/KO as instructions and would otherwise self-trigger.
|
||||
continue
|
||||
if ko.search(body):
|
||||
hit_ko = True
|
||||
if lgtm.search(body):
|
||||
hit_lgtm = True
|
||||
if hit_ko:
|
||||
print("KO")
|
||||
elif hit_lgtm:
|
||||
print("LGTM")
|
||||
else:
|
||||
print("PENDING")
|
||||
PY
|
||||
)
|
||||
|
||||
if echo "$COMMENTS" | grep -qiE '"body":[[:space:]]*"[^"]*\bKO\b'; then
|
||||
echo "❌ KO reçu. Bloquée."
|
||||
exit 1
|
||||
fi
|
||||
case "$DECISION" in
|
||||
LGTM)
|
||||
echo "✅ LGTM reçu ! Squash-merge..."
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token ${GT_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"Do\":\"squash\"}" \
|
||||
"${API}/pulls/${PR}/merge"
|
||||
echo "✅ Mergée (squash)."
|
||||
exit 0
|
||||
;;
|
||||
KO)
|
||||
echo "❌ KO reçu. Bloquée."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ $((TRIES % 4)) -eq 0 ]; then
|
||||
echo " ⏳ ... (${TRIES}/240, $(date +%H:%M))"
|
||||
|
||||
@@ -167,7 +167,7 @@ Complications : `TabataGoComplication`.
|
||||
6. **xcodegen generate** → `xcodebuild -resolvePackageDependencies` → **build** (`-scheme TabataGo`, Debug, auto-provisioning, team `2MJF39L8VY`). Le scheme build les 4 targets : `TabataGo` (app iOS), `TabataGoWidget` (widget iOS, vrai target — ne pas confondre avec `TabataGoWatchWidget` qui est watchOS), `TabataGoWatch` (app watchOS), `TabataGoWatchWidget` (complication watchOS).
|
||||
7. **Deploy iPhone** UDID `00008120-000925CE3672201E` : `xcrun devicectl device install app` uniquement. `devicectl` gère nativement la découverte WiFi (réseau) et filaire (USB-C/Thunderbolt) — pas de fallback `ios-deploy`.
|
||||
8. **Post comment** "Prêt à tester" sur la PR.
|
||||
9. **Job `wait-approval`** : poll (30s, max 240 = 2h). **Re-fetche TOUS les comments** chaque cycle (pas `since_id`) pour attraper aussi les edits (un reviewer passant de "KO" à "LGTM"). Match LGTM/KO n'importe où dans le body (regex `\bLGTM\b` / `\bKO\b`, case-insensitive) — "Tested, LGTM!" compte ; "KOM" ne compte pas. `LGTM` → **squash-merge** (`{"Do":"squash"}`). `KO` → blocage. Timeout → fail.
|
||||
9. **Job `wait-approval`** : poll (30s, max 240 = 2h). **Re-fetche TOUS les comments** chaque cycle (pas `since_id`) pour attraper aussi les edits (un reviewer passant de "KO" à "LGTM"). Le parsing se fait en **python3** (`json.loads` + regex, pas de `grep` sur JSON brut). **Le commentaire bot "Prêt à tester" porte un marker sentinel `<!-- tabatago:ready-to-test -->`** et est **ignoré** par le scanner — sinon son propre body (qui mentionne LGTM/KO comme instructions au reviewer) déclencherait un auto-merge ~30s après le deploy (bug historique). KO est checké **avant** LGTM (un PR avec les deux signaux bloque). Match LGTM/KO n'importe où dans le body (regex `\bLGTM\b` / `\bKO\b`, case-insensitive) — "Tested, LGTM!" compte ; "KOM" ne compte pas. `LGTM` → **squash-merge** (`{"Do":"squash"}`). `KO` → blocage. Timeout → fail.
|
||||
|
||||
### Secrets
|
||||
|
||||
@@ -187,6 +187,7 @@ Complications : `TabataGoComplication`.
|
||||
- `-skipPackagePluginValidation -allowProvisioningUpdates`.
|
||||
- **Concurrency** : le bloc `concurrency:` est volontaire — ne pas le retirer, sinon les pushes successifs empilent des pipelines et tentent des double-merges.
|
||||
- **LGTM/KO regex** : matche n'importe où dans le body avec `\b...\b` (word boundary). Ne pas revenir à un `grep '"body": *"LGTM"'` ancré — il raterait "Tested, LGTM!".
|
||||
- **Self-match sentinel** : le commentaire bot "Prêt à tester" contient littéralement `Reply **LGTM** pour merger` et `Reply **KO**` — sans précaution, le scanner matche son **propre** commentaire et auto-merge ~30s après le deploy. Le body porte donc un marker `<!-- tabatago:ready-to-test -->` que `wait-approval` ignore. **Tout commentaire bot posté par ce workflow doit porter ce marker** ; ne pas le retirer ni poster d'autre commentaire contenant LGTM/KO sans marker.
|
||||
- **Squash-merge** (`{"Do":"squash"}`) — pas merge commit ni rebase. Garde l'historique `main` linéaire.
|
||||
- **Comment edits** : `wait-approval` re-fetche tous les comments chaque cycle (pas `since_id`) pour attraper les edits.
|
||||
|
||||
@@ -249,6 +250,8 @@ Node.js (`server.js`, `package.json`, `Dockerfile`). Télécharge l'audio de pla
|
||||
| Compter sur un bloc `permissions:` natif Gitea Actions | Tout passe par l'API Gitea avec `PR_API_TOKEN` ; le bloc natif serait no-op |
|
||||
| Retirer le bloc `concurrency:` | Permet double-merge et pipelines empilés |
|
||||
| Ancre le grep LGTM au début du body (`'"body": *"LGTM"'`) | Regex `\bLGTM\b` n'importe où dans le body (attrape "Tested, LGTM!") |
|
||||
| Poster un commentaire bot dont le body contient "LGTM"/"KO" sans le marker `<!-- tabatago:ready-to-test -->` | Le scanner bot-scan ignore les comments portant le marker — tout commentaire bot du workflow doit l'inclure (sinon auto-merge en ~30s) |
|
||||
| Scanner les comments en `grep` sur le JSON brut | `python3` + `json.loads` (gère unicode/quotes, pas de false match sur la clé `"body"`) |
|
||||
| `{"Do":"merge"}` (merge commit) | `{"Do":"squash"}` pour un `main` linéaire |
|
||||
| Supprimer le scheme explicite dans `project.yml` | xcodegen 2.45.4 n'en crée pas — scheme doit lister `TabataGo`/`TabataGoWidget`/`TabataGoWatch`/`TabataGoWatchWidget` |
|
||||
| Compter sur `admin-web/` pour la app iOS | Dashboard admin séparé, communique via Supabase uniquement |
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "full.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 495 1461" width="495" height="1461">
|
||||
<defs>
|
||||
<linearGradient id="g1" x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(178.668,1429.023,-572.914,71.631,128.681,37.656)">
|
||||
<stop offset="0" stop-color="#ff6b35"/>
|
||||
<stop offset=".275" stop-color="#cc5dd1"/>
|
||||
<stop offset=".345" stop-color="#a657cd"/>
|
||||
<stop offset=".503" stop-color="#8050c9"/>
|
||||
<stop offset=".627" stop-color="#a657cd"/>
|
||||
<stop offset=".714" stop-color="#cc5dd1"/>
|
||||
<stop offset="1" stop-color="#ff6b35"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<style>
|
||||
.s0 { fill: url(#g1) }
|
||||
</style>
|
||||
<g id="Layer 1">
|
||||
<path class="s0" d="m149.03 544.34c3.59-7.27-0.19-15.12 7.36-21.63 3.92-2.3 11.09-2.83 15.4-3.51 44.94-7.04 91.17-3.55 136.49-3.53 10.92 0 23.53-3.85 34.44-2.73 0.29 6.52 0.21 8.62-0.55 15.1l1.98 0.54c-0.19 10.19 0.74 18.24 1.72 28.16 4.72 29.55 15.11 54.57 22.13 83.56 3.69 15.25 0.25 49.47 3.91 59.74 17.91 50.16 30.14 101.44 29.47 155.05-0.24 21.26-3.62 42.37-10.03 62.65-9.96 31.18-22.38 45.91-19.61 79.68 1.43 16.48 5.24 32.66 11.29 48.06 10.62 27.24 29.51 58.1 28.02 88.22-2.55 51.69-18.34 101.56-27.01 152.81-7.33 43.37-5.74 87.73 34.56 114.99 12.04 8.15 23.8 17.44 37.37 23.36 8.86 3.65 20.16 1.23 25.52 11.62 0.12 6.51-11.3 10.06-16.94 10.17-38.13 0.75-78.38 0.62-116.36-0.07-12.03-0.22-18.15-14.26-14.45-22.95 1.69-10.01 10.18-25.03 10.62-33 3.01-53.65 1.91-113.08-15.15-164.51-7.62-22.97-22.39-39.17-24.76-64.01-4.36-37.82 3.93-74.64 9.04-111.51-6.48-12.98-11.74-23.79-15.37-38-7.22-29.23-5.52-56.92-11.65-86.72-6.19-30.1-16.42-56.79-24.98-85.83-5.37-18.22-13.09-56.73-13.41-75.86l-2.13-2.45c-1.42 20.22-5.31 51.68-11.23 70.93-12.01 39.43-30.84 84.8-32.77 126.47-1.84 39.64-5.04 56.11-22.62 92.02 6.01 35.03 14.58 75.52 9.45 111.04-3.29 22.78-16.2 41.16-24.26 62.2-13.16 34.38-16.78 77.17-17.34 113.84-0.26 16.75-1.22 35.85 1.36 52.32 2.12 13.5 16.56 34.31 9.9 47.51-1.3 2.58-3.47 5.5-6.34 6.37-4.53 1.38-9.47 2.1-14.19 2.41-13.51 0.87-114.42 1.81-120.26-2.21-2.57-1.78-4.91-4.83-4.78-8.1 0.02-0.62 0.21-1.22 0.37-1.81 1.47-5.48 8.4-6.26 13.02-7.07 20.23-3.54 38.54-18.08 54.46-30.54 19.62-15.36 29.84-38.78 32.02-63.37 1.68-18.86-1.76-38.54-5.08-57.1-7.72-43.25-21.12-86.38-24.7-130.18-3.43-42.06 14.35-65.14 28.23-101.9 5.69-15.1 8.98-31.36 10.51-47.4 2.79-29.35-11.78-53.53-20.03-80.63-7.1-23.21-10.35-47.43-9.61-71.69 1.34-36.47 7.09-72.63 17.12-107.71 2.92-10.46 11.61-31.56 12.54-40.67 1.88-20.29-1.06-47.02 5.37-66.41 10.1-30.44 18.11-53.31 21.94-85.72zm79.43-519.52c22.38-4.99 46.23-3.52 63.26 13.9 20.08 17.43 23.2 41.99 19.84 66.29-1.05 7.63-0.85 8.56 5.85 10.63 1.3 1.4 2.95 3.1 2.22 5.42-4.18 13.37-8.51 31.09-17.55 41.8-2.27 2.69-6.69 1.3-8.05 7.08-11.41 48.56 19.04 64.83 58.08 78.29 36.4 9.7 71.89 11.72 93.52 48.05 11.63 19.54 14.83 50.36 9.42 72.21-1.55 8.52 9.91 89.43 1.67 130.98 4.95 8.12 9.09 14.57 12.9 23.34 18.89 34.96 15.91 75.2 8.06 112.62q-0.06 0.19-0.11 0.37l-0.91-2.59c-6.63 0.91-14.16 2.49-20.65 2.63-10.14 0.21-17.09-1.62-27.3-0.03l2.99 0.78c-2.06 0.51-4.5 1.19-6.56 1.53-7.52-11.89-17.63-36.39-21.52-49.49-5.19-17.46-4.07-44.93-0.68-62.88l1.28-10.65c-11.34-26.61-19.11-47.16-26.23-74.9-3.69 10.15-9.9 27.91-15.38 36.64-11.81 23.58-16.14 26.38-18.51 52.09l-2.19-0.67c0.76-6.48 0.66-8.78 0.37-15.3-10.91-1.12-22.08 2.71-33 2.71-45.32-0.02-91.55-3.51-136.49 3.53-4.31 0.68-11.48 1.21-15.4 3.51-7.55 6.51-3.77 14.36-7.36 21.63 0.14-13.93 0.79-28.35-4.64-41.58-2.19-5.36-6.52-11.7-8.41-16.89l-0.56-1.6c-6.86-11-14.64-31.32-19.55-43.55-3.95 21.45-16.92 53.79-25.63 73.85 2.28 17.84 7.52 61.35-0.73 77.33-2.29 9.23-11.96 30.2-16.64 39.3-0.36-0.98-1.15-2.68-1.18-3.6q0.43-0.51 0.85-1.02c-2.02-1.71-14.63-1.9-17.03-2.37-12.22-2.39-23.74 2.59-35.49-2.76 0.62-0.47 1.28-0.77 1.42-1.51l-0.19-0.2c-0.69-0.17-3.92 0.69-4.59 0.81l0.01-0.02c-0.48-3.07-1.08-3.66-2.91-5.91-1.65-3.12-2.87-22.76-3-26.85q-0.11-0.37-0.21-0.73c-1.78-31.25 10.69-61.99 26.32-86.97-3.25-20.68-4.17-36.75-3.67-57.55 1.23-16.98 11.03-63.02 9.34-65.62-6.42-9.85-6.43-35.25-4.59-46.11 0.18-9.32 3.97-22.85 8.31-31.07 31.5-59.72 109.32-33.15 147.52-82.33 11.03-14.2 9.09-34.13 6.05-50.94-13.96-3.76-16.46-20.24-21.19-31.43-2.11-8.16-8.45-18.14 3.1-21.54 1.9-0.56-0.89-26.55-0.64-30.57 0.52-8.64 2.73-17.08 6.51-24.86 8.45-17.15 22.07-27.28 39.85-33.23zm-213.96 588.23c1.83 2.25 3.56 3.43 4.04 6.5l-0.15 0.37c0.67-0.12 3.42-0.65 4.11-0.48l0.78 0.28c-0.14 0.74-0.64 1.26-1.26 1.73 11.75 5.35 23.86-1.69 35.49 2.76 2.43 0.93 11.87-0.55 18.16 3.27 0.58 0.35-1.16 1.99-1.07 2.25-10.21 21.3-28.3 54.35-20.7 77.65 1.92 5.9 9.04 18.82 10.42 23.47 4.35 14.58 21.56 61.89 20.91 74.23-2.68 3.12-1.08 2.16-4.82 3.24-11.96-3.71-16.34-30.99-25.42-36.29l-2.27 0.3c-3.56 5.93 1.59 32.99 4.03 40.14 9.22 7.46 24.44 10.78 26.67 20.94-3.82 12.96-39.66-3.08-44.06-10.36-7.77-13.39-16.13-28.79-21.59-43.23-2.98-7.89-1.06-24.82 0.46-33.55 6.82-39.15 5.42-69.96 0.59-109.18-1.25-6.86-3.84-17.11-4.32-24.04zm410.44 25.02c2.06-0.34 3.75-0.95 5.81-1.46l-2.41-1c10.21-1.59 18.92 0.05 29.06-0.16 6.49-0.14 14.59-3.22 21.22-4.13l-1.07 5.11c-2.79 19.29-4.66 36.49-4.32 56.19 0.44 26.21 8.13 54.31 7.54 80.08-0.23 10.16-20.08 49.4-28.96 55.68-5.53 3.92-45.28 21.83-33.91-1.79 1.3-2.67 17.29-9.46 22-12.64 4.1-8.86 7.54-30.98 4.79-40.46l-1.47-1.07c-9.59 4.12-14.95 32.94-26.61 36.34-16.08-7.05 29.95-99.54 28.23-116.21-2.14-20.7-11.35-36.01-19.9-54.48z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.3 KiB |
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "lower.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 495 1461" width="495" height="1461">
|
||||
<defs>
|
||||
<linearGradient id="g1" x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(118.66,949.065,-461.315,57.678,134.904,524.495)">
|
||||
<stop offset="0" stop-color="#262bdf"/>
|
||||
<stop offset="1" stop-color="#ff004a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="g2" x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(115.853,-95.706,134.182,162.429,-1.643,770.379)">
|
||||
<stop offset="0" stop-color="#010319"/>
|
||||
<stop offset="1" stop-color="#432640"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="g3" x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(67.601,0,0,205.585,413.199,632.988)">
|
||||
<stop offset="0" stop-color="#432640"/>
|
||||
<stop offset=".618" stop-color="#221320"/>
|
||||
<stop offset="1" stop-color="#000000"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<style>
|
||||
.s0 { fill: url(#g1) }
|
||||
.s1 { fill: #432640 }
|
||||
.s2 { fill: #420a44 }
|
||||
.s3 { fill: url(#g2) }
|
||||
.s4 { fill: url(#g3) }
|
||||
</style>
|
||||
<g id="Layer 1">
|
||||
<path class="s0" d="m151.03 544.34c3.59-7.27-0.19-15.12 7.36-21.63 3.92-2.3 11.09-2.83 15.4-3.51 44.94-7.04 91.17-3.55 136.49-3.53 10.92 0 23.53-3.85 34.44-2.73 0.29 6.52 0.21 8.62-0.55 15.1l1.98 0.54c-0.19 10.19 0.74 18.24 1.72 28.16 4.72 29.55 15.11 54.57 22.13 83.56 3.69 15.25 0.25 49.47 3.91 59.74 17.91 50.16 30.14 101.44 29.47 155.05-0.24 21.26-3.62 42.37-10.03 62.65-9.96 31.18-22.38 45.91-19.61 79.68 1.43 16.48 5.24 32.66 11.29 48.06 10.62 27.24 29.51 58.1 28.02 88.22-2.55 51.69-18.34 101.56-27.01 152.81-7.33 43.37-5.74 87.73 34.56 114.99 12.04 8.15 23.8 17.44 37.37 23.36 8.86 3.65 20.16 1.23 25.52 11.62 0.12 6.51-11.3 10.06-16.94 10.17-38.13 0.75-78.38 0.62-116.36-0.07-12.03-0.22-18.15-14.26-14.45-22.95 1.69-10.01 10.18-25.03 10.62-33 3.01-53.65 1.91-113.08-15.15-164.51-7.62-22.97-22.39-39.17-24.76-64.01-4.36-37.82 3.93-74.64 9.04-111.51-6.48-12.98-11.74-23.79-15.37-38-7.22-29.23-5.52-56.92-11.65-86.72-6.19-30.1-16.42-56.79-24.98-85.83-5.37-18.22-13.09-56.73-13.41-75.86l-2.13-2.45c-1.42 20.22-5.31 51.68-11.23 70.93-12.01 39.43-30.84 84.8-32.77 126.47-1.84 39.64-5.04 56.11-22.62 92.02 6.01 35.03 14.58 75.52 9.45 111.04-3.29 22.78-16.2 41.16-24.26 62.2-13.16 34.38-16.78 77.17-17.34 113.84-0.26 16.75-1.22 35.85 1.36 52.32 2.12 13.5 16.56 34.31 9.9 47.51-1.3 2.58-3.47 5.5-6.34 6.37-4.53 1.38-9.47 2.1-14.19 2.41-13.51 0.87-114.42 1.81-120.26-2.21-2.57-1.78-4.91-4.83-4.78-8.1 0.02-0.62 0.21-1.22 0.37-1.81 1.47-5.48 8.4-6.26 13.02-7.07 20.23-3.54 38.54-18.08 54.46-30.54 19.62-15.36 29.84-38.78 32.02-63.37 1.68-18.86-1.76-38.54-5.08-57.1-7.72-43.25-21.12-86.38-24.7-130.18-3.43-42.06 14.35-65.14 28.23-101.9 5.69-15.1 8.98-31.36 10.51-47.4 2.79-29.35-11.78-53.53-20.03-80.63-7.1-23.21-10.35-47.43-9.61-71.69 1.34-36.47 7.09-72.63 17.12-107.71 2.92-10.46 11.61-31.56 12.54-40.67 1.88-20.29-1.06-47.02 5.37-66.41 10.1-30.44 18.11-53.31 21.94-85.72z"/>
|
||||
<path class="s1" d="m228.46 24.82c22.38-4.99 46.23-3.52 63.26 13.9 20.08 17.43 23.2 41.99 19.84 66.29-1.05 7.63-0.85 8.56 5.85 10.63 1.3 1.4 2.95 3.1 2.22 5.42-4.18 13.37-8.51 31.09-17.55 41.8-2.27 2.69-6.69 1.3-8.05 7.08-11.41 48.56 19.04 64.83 58.08 78.29 36.4 9.7 71.89 11.72 93.52 48.05 11.63 19.54 14.83 50.36 9.42 72.21-1.55 8.52 9.91 89.43 1.67 130.98 4.95 8.12 9.09 14.57 12.9 23.34 18.89 34.96 15.91 75.2 8.06 112.62q-0.06 0.19-0.11 0.37l-0.91-2.59c-6.63 0.91-14.16 2.49-20.65 2.63-10.14 0.21-17.09-1.62-27.3-0.03l2.99 0.78c-2.06 0.51-4.5 1.19-6.56 1.53-7.52-11.89-17.63-36.39-21.52-49.49-5.19-17.46-4.07-44.93-0.68-62.88l1.28-10.65c-11.34-26.61-19.11-47.16-26.23-74.9-3.69 10.15-9.9 27.91-15.38 36.64-11.81 23.58-15.09 26.03-17.46 51.74l-1.98-0.54c0.76-6.48 0.84-8.58 0.55-15.1-10.91-1.12-23.52 2.73-34.44 2.73-45.32-0.02-91.55-3.51-136.49 3.53-4.31 0.68-11.48 1.21-15.4 3.51-7.55 6.51-2.89 15.84-6.48 23.11 0.14-13.93-0.09-29.83-5.52-43.06-2.19-5.36-6.52-11.7-8.41-16.89l-0.56-1.6c-6.86-11-14.64-31.32-19.55-43.55-3.95 21.45-16.92 53.79-25.63 73.85 2.28 17.84 7.52 61.35-0.73 77.33-2.29 9.23-11.96 30.2-16.64 39.3-0.36-0.98-1.15-2.68-1.18-3.6q0.43-0.51 0.85-1.02c-2.02-1.71-14.63-1.9-17.03-2.37-12.22-2.39-23.74 2.59-35.49-2.76 0.62-0.47 1.28-0.77 1.42-1.51l-0.19-0.2c-0.69-0.17-3.92 0.69-4.59 0.81l0.01-0.02c-0.48-3.07-1.08-3.66-2.91-5.91-1.65-3.12-2.87-22.76-3-26.85q-0.11-0.37-0.21-0.73c-1.78-31.25 10.69-61.99 26.32-86.97-3.25-20.68-4.17-36.75-3.67-57.55 1.23-16.98 11.03-63.02 9.34-65.62-6.42-9.85-6.43-35.25-4.59-46.11 0.18-9.32 3.97-22.85 8.31-31.07 31.5-59.72 109.32-33.15 147.52-82.33 11.03-14.2 9.09-34.13 6.05-50.94-13.96-3.76-16.46-20.24-21.19-31.43-2.11-8.16-8.45-18.14 3.1-21.54 1.9-0.56-0.89-26.55-0.64-30.57 0.52-8.64 2.73-17.08 6.51-24.86 8.45-17.15 22.07-27.28 39.85-33.23z"/>
|
||||
<path class="s2" d="m137.49 486.15l0.83 0.4c3.58 3.86 4.57 6.2 7.04 10.78 2.53 1.37 29.78-6.88 35.79-7.66 31.97-4.15 57.07-8.91 89.05-5.22 14.5 1.66 73.6-6.97 83.4 4.36 3.86-2.96 2.27-7.93 6.54-10.82l1.66 0.39c-11.83 23.62-11.9 26.19-15.71 50.68l-3.13-1.07c0.76-6.49 0.74-6.53 0.45-13.06-10.93-1.13-22.64 2.8-33.58 2.8-45.39-0.02-91.69-3.51-136.7 3.54-4.31 0.68-14.32-0.91-15.42 3.51-3.59 14.44-3.36 14.33-6.95 21.62 0.14-13.96 0.37-28.35-5.06-41.6-2.2-5.37-5.47-11.9-7.36-17.1zm-125.64 103.79c-0.05-0.1 4.68 12.22 3.52 10.71 0.38 0 7.47-4.2 11.74-1.94 0.09 0.04 7.38 0.95 7.68 1.41 9.61-0.67 19.35-1.03 28.95 0.48 5 0.8 12.28-1.42 16.12 1.4 2.04 1.69 3.07-2.07 4.4 1.27l0.47 0.38c-0.52 0.44 2.95-9.32 5.93-12.26-2.3 9.24-12.2 32.91-16.89 42.03-0.36-0.98-0.86-2.66-0.89-3.58q0.43-0.51 0.85-1.02c-2.02-1.71-14.65-1.9-17.06-2.37-12.24-2.4-23.77 2.59-35.54-2.77 0.62-0.47 1.28-0.77 1.42-1.51l-0.19-0.2c-0.69-0.17-3.93 0.69-4.6 0.81l0.01-0.02c-0.48-3.07-1.08-3.66-2.91-5.92-1.64-3.12-2.88-22.79-3.01-26.9z"/>
|
||||
<path class="s1" d="m52.76 380.21c1.37 2.56 1.35 8.38 1.48 11.3l-1.27 1.58c-4.76 5.75 0.61 8.2-4.45 13.72-0.83 0.9-0.88 2.54-0.98 3.59-1.84 2.76-0.81 6.37-1.73 8.77-1.8 4.72 1.73 8.02-0.56 11.78-2.34 3.4 1.25 7.72-0.94 10.32q-0.94 0.84-1.89 1.67-0.19 0.17-0.38 0.33c-0.53-17.02 1.6-48.35 10.72-63.06z"/>
|
||||
<path class="s1" d="m146.83 300c0.83-3.28 2.54-4.24 7.14-4.06 4.96 0.2 3.67-1.38 6.81-1.97 0.4 4.07 5.05 0.81 7.46 2.52 0.78-0.54-11.99 4.75-12.8 5.04-6.77 2.38-12.92 3.93-19.38 7.33-5.8 2.87-2.93 1.63-5.27-0.28-1.44 0.13-1.59 4.98-3.34 3.63-0.26-0.2-2.01-2.29-2.37-2.65 3.82-15.23-2.85 11.41 0 2.23-1.07 3.47-13.54 10.35-17.46 12.26-2.93-2.2 3.96-3.51 4.37-5.03-0.22-0.65-0.83-0.83-0.67-1.57 1.13-1.24 2.95-0.34 3.64-1.95 0.3-0.71-0.28-1.34 0.35-2.22 1.65-0.74 1.43 0.22 3.59-1.15 5.05-4.04 4.65-6.42 9.73-9.97 1.09-0.75 8.74-0.94 8.79-0.92 0.13 0.53 0 1.21 0.24 1.66 2.96 1.13 1.02-5.73 4.18-4.37 0.47 1.14-0.53 2.33-0.17 3.44 3.23-1.43 1.84-1.39 5.16-1.97z"/>
|
||||
<path class="s3" d="m14.38 614.82c1.83 2.25 3.81 2.64 4.29 5.71l-0.01 0.02c0.67-0.12 3.9-0.98 4.59-0.81l0.19 0.2c-0.14 0.74-0.8 1.04-1.42 1.51 11.75 5.35 23.27 0.37 35.49 2.76 2.4 0.47 15.01 0.66 17.03 2.37q-0.42 0.51-0.85 1.02c0.03 0.92 0.82 2.62 1.18 3.6-10.21 21.3-28.57 52.88-20.97 76.18 1.92 5.9 9.04 18.82 10.42 23.47 4.35 14.58 21.56 61.89 20.91 74.23-2.68 3.12-1.08 2.16-4.82 3.24-11.96-3.71-16.34-30.99-25.42-36.29l-2.27 0.3c-3.56 5.93 1.59 32.99 4.03 40.14 9.22 7.46 24.44 10.78 26.67 20.94-3.82 12.96-39.66-3.08-44.06-10.36-7.77-13.39-16.13-28.79-21.59-43.23-2.98-7.89-1.06-24.82 0.46-33.55 6.82-39.15 5.42-69.96 0.59-109.18-1.25-6.86-3.96-15.34-4.44-22.27z"/>
|
||||
<path class="s4" d="m425 638.26c0.01-0.17-0.43-0.84-0.56-1.11l-0.61-1.1c10.8-2.24 22.84-0.22 32.98-0.43 6.49-0.14 12.95-1.72 19.58-2.63l1.42 1.71c-2.79 19.29-4.92 38.22-4.58 57.92 0.44 26.21 8.13 54.31 7.54 80.08-0.23 10.16-20.08 49.4-28.96 55.68-5.53 3.92-45.28 21.83-33.91-1.79 1.3-2.67 17.29-9.46 22-12.64 4.1-8.86 7.54-30.98 4.79-40.46l-1.47-1.07c-9.59 4.12-14.95 32.94-26.61 36.34-16.08-7.05 29.95-99.54 28.23-116.21-2.14-20.7-11.29-35.82-19.84-54.29z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 7.7 KiB |
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "upper.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 495 1461" width="495" height="1461">
|
||||
<defs>
|
||||
<linearGradient id="g1" x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(79.084,632.495,-470.376,58.814,180.959,30.752)">
|
||||
<stop offset="0" stop-color="#ff0031"/>
|
||||
<stop offset="1" stop-color="#ff9f0a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="g2" x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(115.853,-95.706,133.729,161.88,-1.421,770.649)">
|
||||
<stop offset="0" stop-color="#190a01"/>
|
||||
<stop offset="1" stop-color="#442a27"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="g3" x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(135.335,-111.799,103.573,125.376,377.747,785.651)">
|
||||
<stop offset="0" stop-color="#442a27"/>
|
||||
<stop offset="1" stop-color="#190a01"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<style>
|
||||
.s0 { fill: #442a27 }
|
||||
.s1 { fill: url(#g1) }
|
||||
.s2 { fill: #b27866 }
|
||||
.s3 { fill: #fe0128 }
|
||||
.s4 { fill: #ff9f0a }
|
||||
.s5 { fill: url(#g2) }
|
||||
.s6 { fill: url(#g3) }
|
||||
</style>
|
||||
<g id="Layer 1">
|
||||
<path class="s0" d="m149.03 544.34c3.59-7.27-0.19-15.12 7.36-21.63 3.92-2.3 11.09-2.83 15.4-3.51 44.94-7.04 91.17-3.55 136.49-3.53 10.92 0 23.53-3.85 34.44-2.73 0.29 6.52 0.21 8.62-0.55 15.1l1.98 0.54c-0.19 10.19 0.74 18.24 1.72 28.16 4.72 29.55 15.11 54.57 22.13 83.56 3.69 15.25 0.25 49.47 3.91 59.74 17.91 50.16 30.14 101.44 29.47 155.05-0.24 21.26-3.62 42.37-10.03 62.65-9.96 31.18-22.38 45.91-19.61 79.68q0.54 6.17 1.52 12.29 0.98 6.12 2.39 12.15 1.42 6.03 3.27 11.94 1.84 5.91 4.11 11.68c10.62 27.24 29.51 58.1 28.02 88.22-2.55 51.69-18.34 101.56-27.01 152.81-7.33 43.37-5.74 87.73 34.56 114.99 12.04 8.15 23.8 17.44 37.37 23.36 8.86 3.65 20.16 1.23 25.52 11.62 0.12 6.51-11.3 10.06-16.94 10.17-38.13 0.75-78.38 0.62-116.36-0.07-12.03-0.22-18.15-14.26-14.45-22.95 1.69-10.01 10.18-25.03 10.62-33 3.01-53.65 1.91-113.08-15.15-164.51-7.62-22.97-22.39-39.17-24.76-64.01-4.36-37.82 3.93-74.64 9.04-111.51-6.48-12.98-11.74-23.79-15.37-38-7.22-29.23-5.52-56.92-11.65-86.72-6.19-30.1-16.42-56.79-24.98-85.83-5.37-18.22-13.09-56.73-13.41-75.86l-2.13-2.45c-1.42 20.22-5.31 51.68-11.23 70.93-12.01 39.43-30.84 84.8-32.77 126.47-1.84 39.64-5.04 56.11-22.62 92.02 6.01 35.03 14.58 75.52 9.45 111.04-3.29 22.78-16.2 41.16-24.26 62.2-13.16 34.38-16.78 77.17-17.34 113.84-0.26 16.75-1.22 35.85 1.36 52.32 2.12 13.5 16.56 34.31 9.9 47.51-1.3 2.58-3.47 5.5-6.34 6.37-4.53 1.38-9.47 2.1-14.19 2.41-13.51 0.87-114.42 1.81-120.26-2.21-2.57-1.78-4.91-4.83-4.78-8.1 0.02-0.62 0.21-1.22 0.37-1.81 1.47-5.48 8.4-6.26 13.02-7.07 20.23-3.54 38.54-18.08 54.46-30.54 19.62-15.36 29.84-38.78 32.02-63.37 1.68-18.86-1.76-38.54-5.08-57.1-7.72-43.25-21.12-86.38-24.7-130.18-3.43-42.06 14.35-65.14 28.23-101.9 5.69-15.1 8.98-31.36 10.51-47.4 2.79-29.35-11.78-53.53-20.03-80.63q-2.66-8.69-4.6-17.57-1.94-8.87-3.14-17.88-1.21-9.01-1.68-18.08-0.47-9.08-0.19-18.16c1.34-36.47 7.09-72.63 17.12-107.71 2.92-10.46 11.61-31.56 12.54-40.67 1.88-20.29-1.06-47.02 5.37-66.41 10.1-30.44 18.11-53.31 21.94-85.72z"/>
|
||||
<path class="s1" d="m229.46 24.82c22.38-4.99 46.23-3.52 63.26 13.9 20.08 17.43 23.2 41.99 19.84 66.29-1.05 7.63-0.85 8.56 5.85 10.63 1.3 1.4 2.95 3.1 2.22 5.42-4.18 13.37-8.51 31.09-17.55 41.8-2.27 2.69-6.69 1.3-8.05 7.08-11.41 48.56 19.04 64.83 58.08 78.29 36.4 9.7 71.89 11.72 93.52 48.05 11.63 19.54 14.83 50.36 9.42 72.21-1.55 8.52 9.91 89.43 1.67 130.98 4.95 8.12 9.09 14.57 12.9 23.34 18.89 34.96 15.91 75.2 8.06 112.62q-0.06 0.19-0.11 0.37l-0.91-2.59c-6.63 0.91-14.16 2.49-20.65 2.63-10.14 0.21-17.09-1.62-27.3-0.03l2.99 0.78c-2.06 0.51-4.5 1.19-6.56 1.53-7.52-11.89-17.63-36.39-21.52-49.49-5.19-17.46-4.07-44.93-0.68-62.88l1.28-10.65c-11.34-26.61-19.11-47.16-26.23-74.9-3.69 10.15-9.9 27.91-15.38 36.64-11.81 23.58-17.01 26.91-19.38 52.62l-1.99-1.31c0.76-6.48 0.72-8.7 0.43-15.22-10.91-1.12-21.47 2.74-32.39 2.74-45.32-0.02-91.55-3.51-136.49 3.53-4.31 0.68-11.48 1.21-15.4 3.51-7.55 6.51-5.57 14.61-9.16 21.88 0.14-13.93 2.59-28.6-2.84-41.83-2.19-5.36-6.52-11.7-8.41-16.89l-0.56-1.6c-6.86-11-14.64-31.32-19.55-43.55-3.95 21.45-16.92 53.79-25.63 73.85 2.28 17.84 7.52 61.35-0.73 77.33-2.29 9.23-11.96 30.2-16.64 39.3-0.36-0.98-1.15-2.68-1.18-3.6q0.43-0.51 0.85-1.02c-2.02-1.71-14.63-1.9-17.03-2.37-12.22-2.39-23.74 2.59-35.49-2.76 0.62-0.47 1.28-0.77 1.42-1.51l-0.19-0.2c-0.69-0.17-3.92 0.69-4.59 0.81l0.01-0.02c-0.48-3.07-1.08-3.66-2.91-5.91-1.65-3.12-2.87-22.76-3-26.85q-0.11-0.37-0.21-0.73c-1.78-31.25 10.69-61.99 26.32-86.97-3.25-20.68-4.17-36.75-3.67-57.55 1.23-16.98 11.03-63.02 9.34-65.62-6.42-9.85-6.43-35.25-4.59-46.11 0.18-9.32 3.97-22.85 8.31-31.07 31.5-59.72 109.32-33.15 147.52-82.33 11.03-14.2 9.09-34.13 6.05-50.94-13.96-3.76-16.46-20.24-21.19-31.43-2.11-8.16-8.45-18.14 3.1-21.54 1.9-0.56-0.89-26.55-0.64-30.57 0.52-8.64 2.73-17.08 6.51-24.86 8.45-17.15 22.07-27.28 39.85-33.23z"/>
|
||||
<path class="s2" d="m137.42 484.27l1.61 0.27c3.58 3.85 4.56 6.19 7.03 10.76 2.53 1.37 29.73-6.87 35.73-7.65 31.93-4.14 56.99-8.89 88.92-5.21 14.47 1.66 74.45-6.2 84.24 5.11 3.85-2.95 2.1-8.27 6.37-11.16l2.29 0.45c-11.81 23.58-16.74 26.67-19.11 52.38l-2.66-1.06c0.76-6.48 1.14-8.44 0.85-14.96-10.91-1.12-21.49 2.47-32.41 2.47-45.32-0.02-91.55-3.51-136.49 3.53-4.31 0.68-11.48 1.21-15.4 3.51-7.55 6.51-5.64 15-9.23 22.27 0.14-13.93 2.66-28.99-2.76-42.22-2.2-5.36-6.53-11.7-8.42-16.89zm-124.66 103.49c-0.05-0.1 4.67 12.2 3.51 10.69 0.38 0 7.46-4.19 11.72-1.93 0.09 0.04 7.37 0.94 7.67 1.4 9.6-0.67 19.32-1.03 28.91 0.48 4.99 0.8 12.26-1.42 16.09 1.4 2.04 1.69 3.07-2.07 4.39 1.27l0.47 0.38c-0.52 0.44 3.02-6.61 5.99-9.55-2.29 9.23-11.96 30.2-16.64 39.3-0.36-0.98-1.15-2.68-1.18-3.6q0.43-0.51 0.85-1.02c-2.02-1.71-14.63-1.9-17.03-2.37-12.22-2.39-23.74 2.59-35.49-2.76 0.62-0.47 1.28-0.77 1.42-1.51l-0.19-0.2c-0.69-0.17-3.92 0.69-4.59 0.81l0.01-0.02c-0.48-3.07-1.08-3.66-2.91-5.91-1.64-3.12-2.87-22.76-3-26.86z"/>
|
||||
<path class="s3" d="m229.46 24.82c22.38-4.99 46.23-3.52 63.26 13.9-2.94 1.76-2.44 1.37-5.52-0.39-1.43-0.82-3.91-3.96-5-4.09-1.5 1.08-0.84 2.69-3.47 2.7-1.6 0.16-4.72-1.05-6 0.5-2.05 2.55-4.53 0.56-7.19 2.17-3.3 1.99 1.76 2.77 1.25 4.74-0.29 0.31-9.15 1.4-10.69 4.55-2.58 5.28-14.9-3.85-2.01-6 3.28-0.54 4.16-1.21 2.39-4.21-1.21 0.13-5.75 0.69-6.93 1.04-2.64 0.78-13.46 2.1-15.32 0.13-5.43-5.79-7.22-9.32 2.21-9.37l-0.02-0.19c-2.05-2.36-2.01 1.66-6.96-5.48z"/>
|
||||
<path class="s4" d="m52.76 380.21c1.37 2.56 1.35 8.38 1.48 11.3l-1.27 1.58c-4.76 5.75 0.61 8.2-4.45 13.72-0.83 0.9-0.88 2.54-0.98 3.59-1.84 2.76-0.81 6.37-1.73 8.77-1.8 4.72 1.73 8.02-0.56 11.78-2.34 3.4 1.25 7.72-0.94 10.32q-0.94 0.84-1.89 1.67-0.19 0.17-0.38 0.33c-0.53-17.02 1.6-48.35 10.72-63.06z"/>
|
||||
<path class="s4" d="m146.83 300c0.83-3.28 2.54-4.24 7.14-4.06 4.96 0.2 3.67-1.38 6.81-1.97 0.4 4.07 5.05 0.81 7.46 2.52 0.78-0.54-11.99 4.75-12.8 5.04-6.77 2.38-12.92 3.93-19.38 7.33-5.8 2.87-2.93 1.63-5.27-0.28-1.44 0.13-1.59 4.98-3.34 3.63-0.26-0.2-2.01-2.29-2.37-2.65 3.82-15.23-2.85 11.41 0 2.23-1.07 3.47-13.54 10.35-17.46 12.26-2.93-2.2 3.96-3.51 4.37-5.03-0.22-0.65-0.83-0.83-0.67-1.57 1.13-1.24 2.95-0.34 3.64-1.95 0.3-0.71-0.28-1.34 0.35-2.22 1.65-0.74 1.43 0.22 3.59-1.15 5.05-4.04 4.65-6.42 9.73-9.97 1.09-0.75 8.74-0.94 8.79-0.92 0.13 0.53 0 1.21 0.24 1.66 2.96 1.13 1.02-5.73 4.18-4.37 0.47 1.14-0.53 2.33-0.17 3.44 3.23-1.43 1.84-1.39 5.16-1.97z"/>
|
||||
<path class="s5" d="m15.76 614.62c1.83 2.25 2.43 2.84 2.91 5.91l-0.01 0.02c0.67-0.12 3.9-0.98 4.59-0.81l0.19 0.2c-0.14 0.74-0.8 1.04-1.42 1.51 11.75 5.35 23.27 0.37 35.49 2.76 2.4 0.47 15.01 0.66 17.03 2.37q-0.42 0.51-0.85 1.02c0.03 0.92 0.82 2.62 1.18 3.6-10.21 21.3-28.57 52.88-20.97 76.18 1.92 5.9 9.04 18.82 10.42 23.47 4.35 14.58 21.56 61.89 20.91 74.23-2.68 3.12-1.08 2.16-4.82 3.24-11.96-3.71-16.34-30.99-25.42-36.29l-2.27 0.3c-3.56 5.93 1.59 32.99 4.03 40.14 9.22 7.46 24.44 10.78 26.67 20.94-3.82 12.96-39.66-3.08-44.06-10.36-7.77-13.39-16.13-28.79-21.59-43.23-2.98-7.89-1.06-24.82 0.46-33.55 6.82-39.15 5.42-69.96 0.59-109.18-1.25-6.86-2.58-15.54-3.06-22.47z"/>
|
||||
<path class="s6" d="m426.14 638.12c-0.82-1.16-1.29-1.71-0.49-1.65l4.06-0.66c10.21-1.59 17.16 0.24 27.3 0.03 6.49-0.14 15.56-2.18 22.19-3.09l-0.56 3.13c-2.79 19.29-5.75 37.04-5.41 56.74 0.44 26.21 8.13 54.31 7.54 80.08-0.23 10.16-20.08 49.4-28.96 55.68-5.53 3.92-45.28 21.83-33.91-1.79 1.3-2.67 17.29-9.46 22-12.64 4.1-8.86 7.54-30.98 4.79-40.46l-1.47-1.07c-9.59 4.12-14.95 32.94-26.61 36.34-16.08-7.05 29.95-99.54 28.23-116.21-2.14-20.7-10.15-35.96-18.7-54.43z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 8.3 KiB |
@@ -1,35 +1,131 @@
|
||||
import SwiftUI
|
||||
|
||||
/// Body-zone highlight icon backed by vector SVG assets in `Assets.xcassets`.
|
||||
///
|
||||
/// Each zone renders its own artwork:
|
||||
/// - `upper-body` → `ZoneIconUpper`
|
||||
/// - `lower-body` → `ZoneIconLower`
|
||||
/// - `full-body` → `ZoneIconFull`
|
||||
///
|
||||
/// The SVGs ship with their own baked-in colors, so the icon is **not**
|
||||
/// tinted by `Theme.zoneGradient` — it shows the artwork as authored.
|
||||
/// To make icons auto-recolor per zone instead, switch the imagesets to
|
||||
/// single-color SVGs and set `"template-rendering-intent": "template"`
|
||||
/// in each `Contents.json`, then apply `.foregroundStyle(...)` here.
|
||||
///
|
||||
/// Drawn on a 56×80 frame with `scaledToFit()` so the SVG keeps its
|
||||
/// native aspect ratio inside the card.
|
||||
struct BodySilhouetteShape: Shape {
|
||||
func path(in rect: CGRect) -> Path {
|
||||
let w = rect.width
|
||||
let h = rect.height
|
||||
let mx = w * 0.5
|
||||
var p = Path()
|
||||
|
||||
let headCY = h * 0.09
|
||||
let headR = w * 0.12
|
||||
p.addEllipse(in: CGRect(
|
||||
x: mx - headR, y: headCY - headR,
|
||||
width: headR * 2, height: headR * 2
|
||||
))
|
||||
|
||||
let neckW = w * 0.06
|
||||
let neckTop = headCY + headR
|
||||
let shoulderY = h * 0.20
|
||||
p.addRect(CGRect(
|
||||
x: mx - neckW, y: neckTop,
|
||||
width: neckW * 2, height: shoulderY - neckTop
|
||||
))
|
||||
|
||||
let shoulderHW = w * 0.42
|
||||
let armOuterBotY = h * 0.44
|
||||
let armInnerBotY = h * 0.44
|
||||
let armOuterX = w * 0.06
|
||||
let armInnerX = w * 0.12
|
||||
|
||||
p.move(to: CGPoint(x: mx - neckW, y: shoulderY))
|
||||
p.addLine(to: CGPoint(x: mx - shoulderHW, y: shoulderY))
|
||||
p.addLine(to: CGPoint(x: mx - armOuterX, y: armOuterBotY))
|
||||
p.addLine(to: CGPoint(x: mx - armInnerX, y: armInnerBotY))
|
||||
p.closeSubpath()
|
||||
|
||||
p.move(to: CGPoint(x: mx + neckW, y: shoulderY))
|
||||
p.addLine(to: CGPoint(x: mx + shoulderHW, y: shoulderY))
|
||||
p.addLine(to: CGPoint(x: mx + armOuterX, y: armOuterBotY))
|
||||
p.addLine(to: CGPoint(x: mx + armInnerX, y: armInnerBotY))
|
||||
p.closeSubpath()
|
||||
|
||||
let torsoHW = w * 0.18
|
||||
let waistY = h * 0.46
|
||||
let waistHW = w * 0.15
|
||||
p.move(to: CGPoint(x: mx - torsoHW, y: shoulderY))
|
||||
p.addLine(to: CGPoint(x: mx + torsoHW, y: shoulderY))
|
||||
p.addLine(to: CGPoint(x: mx + waistHW, y: waistY))
|
||||
p.addLine(to: CGPoint(x: mx - waistHW, y: waistY))
|
||||
p.closeSubpath()
|
||||
|
||||
let hipHW = w * 0.22
|
||||
let hipY = h * 0.52
|
||||
p.move(to: CGPoint(x: mx - waistHW, y: waistY))
|
||||
p.addLine(to: CGPoint(x: mx + waistHW, y: waistY))
|
||||
p.addLine(to: CGPoint(x: mx + hipHW, y: hipY))
|
||||
p.addLine(to: CGPoint(x: mx - hipHW, y: hipY))
|
||||
p.closeSubpath()
|
||||
|
||||
let gap = w * 0.02
|
||||
let legBotY = h * 0.92
|
||||
let footH = h * 0.05
|
||||
let footExtra = w * 0.04
|
||||
|
||||
p.move(to: CGPoint(x: mx - hipHW, y: hipY))
|
||||
p.addLine(to: CGPoint(x: mx - gap, y: hipY))
|
||||
p.addLine(to: CGPoint(x: mx - gap, y: legBotY))
|
||||
p.addLine(to: CGPoint(x: mx - hipHW - footExtra, y: legBotY + footH))
|
||||
p.addLine(to: CGPoint(x: mx - hipHW, y: legBotY))
|
||||
p.closeSubpath()
|
||||
|
||||
p.move(to: CGPoint(x: mx + gap, y: hipY))
|
||||
p.addLine(to: CGPoint(x: mx + hipHW, y: hipY))
|
||||
p.addLine(to: CGPoint(x: mx + hipHW, y: legBotY))
|
||||
p.addLine(to: CGPoint(x: mx + hipHW + footExtra, y: legBotY + footH))
|
||||
p.addLine(to: CGPoint(x: mx + gap, y: legBotY))
|
||||
p.closeSubpath()
|
||||
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
struct ZoneHighlightIcon: View {
|
||||
let zone: String
|
||||
|
||||
private var waistFraction: CGFloat { 0.50 }
|
||||
|
||||
var body: some View {
|
||||
Image(decorative: imageName, bundle: .main)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 56, height: 80)
|
||||
let shape = BodySilhouetteShape()
|
||||
ZStack {
|
||||
shape
|
||||
.fill(.white.opacity(0.12))
|
||||
|
||||
shape
|
||||
.fill(zoneGradient)
|
||||
.mask(zoneMask)
|
||||
}
|
||||
.frame(width: 56, height: 80)
|
||||
}
|
||||
|
||||
private var imageName: String {
|
||||
switch zone.lowercased() {
|
||||
case "upper-body", "upper": return "ZoneIconUpper"
|
||||
case "lower-body", "lower": return "ZoneIconLower"
|
||||
default: return "ZoneIconFull"
|
||||
private var zoneGradient: LinearGradient {
|
||||
switch zone {
|
||||
case "upper-body":
|
||||
LinearGradient(colors: [.orange, .red.opacity(0.8)], startPoint: .top, endPoint: .bottom)
|
||||
case "lower-body":
|
||||
LinearGradient(colors: [.blue, .purple.opacity(0.8)], startPoint: .top, endPoint: .bottom)
|
||||
case "full-body":
|
||||
LinearGradient(colors: [Theme.brand, .purple], startPoint: .top, endPoint: .bottom)
|
||||
default:
|
||||
LinearGradient(colors: [.gray, .secondary], startPoint: .top, endPoint: .bottom)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var zoneMask: some View {
|
||||
switch zone {
|
||||
case "upper-body":
|
||||
Rectangle()
|
||||
.frame(height: 80 * waistFraction)
|
||||
.frame(maxHeight: .infinity, alignment: .top)
|
||||
case "lower-body":
|
||||
Rectangle()
|
||||
.frame(height: 80 * waistFraction)
|
||||
.frame(maxHeight: .infinity, alignment: .bottom)
|
||||
case "full-body":
|
||||
Rectangle()
|
||||
default:
|
||||
Rectangle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user