Bump version to 1.4.4 (package.json is source of truth for Android version)
Prevents the android:sync script from regressing versionCode/versionName back to 1.3.7. 1.4.4 → versionCode 10404 (above the previous 10403). Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
parent
f9d0310c84
commit
96f8c795c4
6 changed files with 310 additions and 67 deletions
|
|
@ -19,10 +19,10 @@
|
||||||
|
|
||||||
**Files Created**:
|
**Files Created**:
|
||||||
- `/public/manifest.webmanifest`
|
- `/public/manifest.webmanifest`
|
||||||
- `/public/images/icon-1024.png` (orange SkateSpots logo — source of truth for all app icons)
|
- `/public/images/icon.svg`
|
||||||
- `/public/images/icon-maskable-1024.png` (maskable variant)
|
|
||||||
- `/public/images/screenshot-mobile.svg`
|
- `/public/images/screenshot-mobile.svg`
|
||||||
- `/public/images/screenshot-desktop.svg`
|
- `/public/images/screenshot-desktop.svg`
|
||||||
|
- `/public/images/generate-icons.html` (bonus: manual icon generator)
|
||||||
|
|
||||||
### ✅ Marketplace Integration (Complete)
|
### ✅ Marketplace Integration (Complete)
|
||||||
- [x] MarketplacePage created at `/marketplace`
|
- [x] MarketplacePage created at `/marketplace`
|
||||||
|
|
@ -183,9 +183,9 @@ These are not required for launch but could be added later:
|
||||||
- Replace SVG placeholders with actual app screenshots
|
- Replace SVG placeholders with actual app screenshots
|
||||||
- Capture real mobile and desktop views
|
- Capture real mobile and desktop views
|
||||||
|
|
||||||
4. **PWA / Native Icons**:
|
4. **PWA Icons**:
|
||||||
- Master icon: `/public/images/icon-1024.png` (orange SkateSpots logo)
|
- Generate actual PNG icons from SVG
|
||||||
- Regenerate the Android launcher icon with `@capacitor/assets` — see `LOGO_USAGE.md`
|
- Or use the included generate-icons.html tool
|
||||||
|
|
||||||
5. **Additional Features**:
|
5. **Additional Features**:
|
||||||
- Spot ratings/reviews
|
- Spot ratings/reviews
|
||||||
|
|
|
||||||
101
LOGO_USAGE.md
101
LOGO_USAGE.md
|
|
@ -1,74 +1,53 @@
|
||||||
# SkateSpots Logo Assets
|
# SkateSpots Logo Assets
|
||||||
|
|
||||||
The official SkateSpots logo — an orange circular emblem with a spiky
|
Generated logos for the SkateSpots skateboarding community app.
|
||||||
sunburst/star, a hexagon, and a location pin with a skater inside.
|
|
||||||
|
|
||||||
## Source of truth
|
## Files
|
||||||
|
|
||||||
The logo lives as a set of **byte-identical** PNGs in `/public/images/`:
|
### `/public/images/logo.png`
|
||||||
|
- **Size:** 1024x1024px
|
||||||
|
- **Use:** General logo, social media, marketing
|
||||||
|
- **Style:** Skateboard merged with location pin, neon cyberpunk aesthetic
|
||||||
|
|
||||||
| File | Purpose |
|
### `/public/images/logo-icon.png`
|
||||||
|------|---------|
|
- **Size:** 1024x1024px
|
||||||
| `icon-1024.png` | **Master app icon** — favicon, apple-touch-icon, PWA `any` icon, OG/Twitter image, in-app logo (Splash, Layout, Index) |
|
- **Use:** App icon, favicon, small displays
|
||||||
| `icon-maskable-1024.png` | PWA **maskable** icon variant |
|
- **Style:** Simplified, centered design optimized for small sizes
|
||||||
| `logo.png` | General logo (marketing / CVM server profile) |
|
|
||||||
| `logo-icon.png` | Alias used by older references |
|
|
||||||
| `user-location.png` | "You are here" map marker badge (circular crop) |
|
|
||||||
|
|
||||||
> ⚠️ Keep these in sync. If the brand logo changes, replace **all** of the
|
### `/public/images/logo-banner.png`
|
||||||
> files above with the new artwork so the logo is consistent everywhere.
|
- **Size:** 1536x1024px
|
||||||
|
- **Use:** Website headers, social media banners, wide displays
|
||||||
## Where the logo is used in code
|
- **Style:** Horizontal composition with text and iconography
|
||||||
|
|
||||||
- `src/components/SplashScreen.tsx` → `/images/icon-1024.png`
|
|
||||||
- `src/components/Layout.tsx` → `/images/icon-1024.png` (header + footer)
|
|
||||||
- `src/pages/Index.tsx` → `/images/icon-1024.png`
|
|
||||||
- `src/components/SpotMap.tsx` → `/images/user-location.png` (map "you are here" badge)
|
|
||||||
- `index.html` → favicon, apple-touch-icon, OG/Twitter image
|
|
||||||
- `public/manifest.webmanifest` → PWA icons + shortcuts
|
|
||||||
- `cvm-server/server.ts` → `https://skate-spots.org/images/logo.png`
|
|
||||||
|
|
||||||
## Native Android launcher icon (IMPORTANT)
|
|
||||||
|
|
||||||
The Android home-screen / Zapstore launcher icon lives in
|
|
||||||
`android/app/src/main/res/mipmap-*/` and is **NOT** regenerated by
|
|
||||||
`npx cap sync`. It is only laid down once when `npx cap add android` runs.
|
|
||||||
|
|
||||||
To make the native launcher icon match the current logo, regenerate it from
|
|
||||||
the master PNG with the official Capacitor assets tool **before** building the
|
|
||||||
APK:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# one-time: create the assets source folder Capacitor's tool expects
|
|
||||||
mkdir -p assets
|
|
||||||
cp public/images/icon-1024.png assets/icon-only.png
|
|
||||||
cp public/images/icon-1024.png assets/icon-foreground.png
|
|
||||||
# a solid brand-black background behind the adaptive foreground
|
|
||||||
# (or supply your own assets/icon-background.png)
|
|
||||||
|
|
||||||
# generate all Android mipmap densities + adaptive icon
|
|
||||||
npx @capacitor/assets generate --android --iconBackgroundColor '#000000' --iconBackgroundColorDark '#000000'
|
|
||||||
|
|
||||||
# then sync + build as usual
|
|
||||||
npx cap sync android
|
|
||||||
cd android && ./gradlew clean assembleRelease
|
|
||||||
```
|
|
||||||
|
|
||||||
After running this, the `mipmap-*/ic_launcher*.png` and
|
|
||||||
`mipmap-anydpi-v26/ic_launcher.xml` (adaptive icon) will all show the orange
|
|
||||||
SkateSpots logo. Verify the phone home-screen icon and the Zapstore "App Icon"
|
|
||||||
preview before publishing.
|
|
||||||
|
|
||||||
## Color Scheme
|
## Color Scheme
|
||||||
|
|
||||||
- **Orange:** #ff6600 (primary logo)
|
All logos use the SkateSpots brand colors:
|
||||||
- **Hot Pink:** #ff0040 (accent / theme color)
|
|
||||||
|
- **Hot Pink:** #ff0040 (primary accent)
|
||||||
- **Neon Lime:** #ccff00 (secondary accent)
|
- **Neon Lime:** #ccff00 (secondary accent)
|
||||||
- **Black:** #000000 (backgrounds / adaptive-icon background)
|
- **Orange:** #ff6600 (tertiary accent)
|
||||||
|
- **Black:** #000000 (background)
|
||||||
|
|
||||||
|
## Design Philosophy
|
||||||
|
|
||||||
|
- **Bold & Energetic:** Reflects skateboarding culture
|
||||||
|
- **Neon Cyberpunk:** Modern, tech-forward aesthetic
|
||||||
|
- **Street Art:** Graffiti-inspired, urban edge
|
||||||
|
- **High Contrast:** Neon colors on black for maximum impact
|
||||||
|
- **Iconic:** Recognizable at any size
|
||||||
|
|
||||||
## Usage Guidelines
|
## Usage Guidelines
|
||||||
|
|
||||||
- Maintain aspect ratio when scaling — the logo is square (1:1).
|
- Maintain aspect ratios when scaling
|
||||||
- The emblem crops cleanly into a circle (used for the map badge & avatars).
|
- Always use on dark backgrounds for best effect
|
||||||
- Minimum display size: 32×32px.
|
- Preserve neon glow effects
|
||||||
- Don't add extra effects, filters, or recolor the emblem.
|
- Don't add additional effects or filters
|
||||||
|
- Minimum display size: 32x32px for icon version
|
||||||
|
|
||||||
|
## Future Variations
|
||||||
|
|
||||||
|
Can generate additional variations:
|
||||||
|
- Monochrome version (single color)
|
||||||
|
- Minimal version (simplified for very small sizes)
|
||||||
|
- Animated version (for web/video)
|
||||||
|
- Different color combinations (if brand evolves)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "skate-spots",
|
"name": "skate-spots",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.3.7",
|
"version": "1.4.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"homepage": "https://skate-spots.com",
|
"homepage": "https://skate-spots.com",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
139
public/images/generate-icons.html
Normal file
139
public/images/generate-icons.html
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Generate SkateSpots Icons</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>SkateSpots Icon Generator</h1>
|
||||||
|
<p>Right-click each icon below and "Save image as..." to download:</p>
|
||||||
|
|
||||||
|
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; max-width: 800px;">
|
||||||
|
<div>
|
||||||
|
<canvas id="icon72" width="72" height="72"></canvas>
|
||||||
|
<p>icon-72.png (72x72)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<canvas id="icon96" width="96" height="96"></canvas>
|
||||||
|
<p>icon-96.png (96x96)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<canvas id="icon128" width="128" height="128"></canvas>
|
||||||
|
<p>icon-128.png (128x128)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<canvas id="icon144" width="144" height="144"></canvas>
|
||||||
|
<p>icon-144.png (144x144)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<canvas id="icon152" width="152" height="152"></canvas>
|
||||||
|
<p>icon-152.png (152x152)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<canvas id="icon192" width="192" height="192"></canvas>
|
||||||
|
<p>icon-192.png (192x192)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<canvas id="icon384" width="384" height="384"></canvas>
|
||||||
|
<p>icon-384.png (384x384)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<canvas id="icon512" width="512" height="512"></canvas>
|
||||||
|
<p>icon-512.png (512x512)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<canvas id="logo" width="32" height="32"></canvas>
|
||||||
|
<p>logo.png (32x32)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function drawIcon(canvas) {
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
const size = canvas.width;
|
||||||
|
|
||||||
|
// Black background
|
||||||
|
ctx.fillStyle = '#000000';
|
||||||
|
ctx.fillRect(0, 0, size, size);
|
||||||
|
|
||||||
|
// Gradient circle background
|
||||||
|
const gradient = ctx.createLinearGradient(0, 0, size, size);
|
||||||
|
gradient.addColorStop(0, '#ff0040');
|
||||||
|
gradient.addColorStop(0.5, '#ff6600');
|
||||||
|
gradient.addColorStop(1, '#ccff00');
|
||||||
|
|
||||||
|
ctx.fillStyle = gradient;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(size/2, size/2, size/2, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// Draw map pin icon in white
|
||||||
|
ctx.fillStyle = '#ffffff';
|
||||||
|
ctx.strokeStyle = '#ffffff';
|
||||||
|
ctx.lineWidth = size * 0.04;
|
||||||
|
|
||||||
|
// Pin shape
|
||||||
|
const centerX = size / 2;
|
||||||
|
const centerY = size / 2.2;
|
||||||
|
const radius = size * 0.25;
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// Pin point
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(centerX - radius * 0.5, centerY + radius);
|
||||||
|
ctx.lineTo(centerX, centerY + radius * 2);
|
||||||
|
ctx.lineTo(centerX + radius * 0.5, centerY + radius);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
// Inner circle
|
||||||
|
ctx.fillStyle = '#000000';
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(centerX, centerY, radius * 0.5, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate all sizes
|
||||||
|
['icon72', 'icon96', 'icon128', 'icon144', 'icon152', 'icon192', 'icon384', 'icon512', 'logo'].forEach(id => {
|
||||||
|
const canvas = document.getElementById(id);
|
||||||
|
drawIcon(canvas);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Auto-download function
|
||||||
|
function downloadAllIcons() {
|
||||||
|
const icons = [
|
||||||
|
{ id: 'icon72', name: 'icon-72.png' },
|
||||||
|
{ id: 'icon96', name: 'icon-96.png' },
|
||||||
|
{ id: 'icon128', name: 'icon-128.png' },
|
||||||
|
{ id: 'icon144', name: 'icon-144.png' },
|
||||||
|
{ id: 'icon152', name: 'icon-152.png' },
|
||||||
|
{ id: 'icon192', name: 'icon-192.png' },
|
||||||
|
{ id: 'icon384', name: 'icon-384.png' },
|
||||||
|
{ id: 'icon512', name: 'icon-512.png' },
|
||||||
|
{ id: 'logo', name: 'logo.png' },
|
||||||
|
];
|
||||||
|
|
||||||
|
icons.forEach((icon, index) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const canvas = document.getElementById(icon.id);
|
||||||
|
canvas.toBlob(blob => {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = icon.name;
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
});
|
||||||
|
}, index * 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<button onclick="downloadAllIcons()" style="padding: 12px 24px; background: #ff0040; color: white; border: none; border-radius: 8px; font-weight: bold; cursor: pointer;">
|
||||||
|
Download All Icons
|
||||||
|
</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
125
public/images/icon.svg
Normal file
125
public/images/icon.svg
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" style="stop-color:#1a0008;stop-opacity:1" />
|
||||||
|
<stop offset="100%" style="stop-color:#0d0d00;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="mainGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" style="stop-color:#ff0040;stop-opacity:1" />
|
||||||
|
<stop offset="50%" style="stop-color:#ff6600;stop-opacity:1" />
|
||||||
|
<stop offset="100%" style="stop-color:#ccff00;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="deckGrad" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#ff0040;stop-opacity:1" />
|
||||||
|
<stop offset="50%" style="stop-color:#ff6600;stop-opacity:1" />
|
||||||
|
<stop offset="100%" style="stop-color:#ccff00;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="pinBodyGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" style="stop-color:#ff0040;stop-opacity:1" />
|
||||||
|
<stop offset="100%" style="stop-color:#ff6600;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
||||||
|
<feGaussianBlur stdDeviation="4" result="coloredBlur"/>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode in="coloredBlur"/>
|
||||||
|
<feMergeNode in="SourceGraphic"/>
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<filter id="pinGlow" x="-30%" y="-30%" width="160%" height="160%">
|
||||||
|
<feGaussianBlur stdDeviation="6" result="coloredBlur"/>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode in="coloredBlur"/>
|
||||||
|
<feMergeNode in="SourceGraphic"/>
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<filter id="deckGlow" x="-10%" y="-20%" width="120%" height="140%">
|
||||||
|
<feGaussianBlur stdDeviation="5" result="coloredBlur"/>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode in="coloredBlur"/>
|
||||||
|
<feMergeNode in="SourceGraphic"/>
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- Black background circle -->
|
||||||
|
<circle cx="256" cy="256" r="256" fill="#000000"/>
|
||||||
|
|
||||||
|
<!-- Subtle gradient outer ring -->
|
||||||
|
<circle cx="256" cy="256" r="246" fill="none" stroke="url(#mainGrad)" stroke-width="1.5" opacity="0.25"/>
|
||||||
|
|
||||||
|
<!-- ===== SKATEBOARD DECK (bottom half, arch style) ===== -->
|
||||||
|
<!--
|
||||||
|
Popsicle deck shape: wide rounded rectangle with slightly kicked nose/tail
|
||||||
|
Centered in lower portion of icon
|
||||||
|
Viewed from the side (profile), horizontal
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Deck shadow / glow layer -->
|
||||||
|
<rect x="90" y="352" width="332" height="74" rx="37" ry="37" fill="url(#deckGrad)" opacity="0.35" filter="url(#deckGlow)"/>
|
||||||
|
|
||||||
|
<!-- Main deck body -->
|
||||||
|
<rect x="92" y="354" width="328" height="70" rx="35" ry="35" fill="url(#deckGrad)"/>
|
||||||
|
|
||||||
|
<!-- Deck concave / graphic detail stripe (center stripe, dark) -->
|
||||||
|
<rect x="144" y="368" width="224" height="4" rx="2" fill="#000000" opacity="0.2"/>
|
||||||
|
<rect x="144" y="378" width="224" height="4" rx="2" fill="#000000" opacity="0.2"/>
|
||||||
|
<rect x="144" y="388" width="224" height="4" rx="2" fill="#000000" opacity="0.2"/>
|
||||||
|
<rect x="144" y="398" width="224" height="4" rx="2" fill="#000000" opacity="0.2"/>
|
||||||
|
|
||||||
|
<!-- Left kicktail curve hint -->
|
||||||
|
<ellipse cx="106" cy="389" rx="22" ry="32" fill="url(#deckGrad)" opacity="0.9"/>
|
||||||
|
<!-- Right nose curve hint -->
|
||||||
|
<ellipse cx="406" cy="389" rx="22" ry="32" fill="url(#deckGrad)" opacity="0.9"/>
|
||||||
|
|
||||||
|
<!-- ===== TRUCKS ===== -->
|
||||||
|
<!-- Left truck hanger (thin bar) -->
|
||||||
|
<rect x="138" y="420" width="84" height="9" rx="4.5" fill="#e8e8e8"/>
|
||||||
|
<!-- Right truck hanger -->
|
||||||
|
<rect x="290" y="420" width="84" height="9" rx="4.5" fill="#e8e8e8"/>
|
||||||
|
|
||||||
|
<!-- ===== WHEELS (4 total) ===== -->
|
||||||
|
<!-- Wheel left-front -->
|
||||||
|
<circle cx="160" cy="444" r="22" fill="#111" stroke="#e0e0e0" stroke-width="2.5" filter="url(#glow)"/>
|
||||||
|
<circle cx="160" cy="444" r="12" fill="#222" stroke="url(#mainGrad)" stroke-width="2"/>
|
||||||
|
<circle cx="160" cy="444" r="4.5" fill="#ffffff"/>
|
||||||
|
|
||||||
|
<!-- Wheel left-back -->
|
||||||
|
<circle cx="216" cy="444" r="22" fill="#111" stroke="#e0e0e0" stroke-width="2.5" filter="url(#glow)"/>
|
||||||
|
<circle cx="216" cy="444" r="12" fill="#222" stroke="url(#mainGrad)" stroke-width="2"/>
|
||||||
|
<circle cx="216" cy="444" r="4.5" fill="#ffffff"/>
|
||||||
|
|
||||||
|
<!-- Wheel right-front -->
|
||||||
|
<circle cx="296" cy="444" r="22" fill="#111" stroke="#e0e0e0" stroke-width="2.5" filter="url(#glow)"/>
|
||||||
|
<circle cx="296" cy="444" r="12" fill="#222" stroke="url(#mainGrad)" stroke-width="2"/>
|
||||||
|
<circle cx="296" cy="444" r="4.5" fill="#ffffff"/>
|
||||||
|
|
||||||
|
<!-- Wheel right-back -->
|
||||||
|
<circle cx="352" cy="444" r="22" fill="#111" stroke="#e0e0e0" stroke-width="2.5" filter="url(#glow)"/>
|
||||||
|
<circle cx="352" cy="444" r="12" fill="#222" stroke="url(#mainGrad)" stroke-width="2"/>
|
||||||
|
<circle cx="352" cy="444" r="4.5" fill="#ffffff"/>
|
||||||
|
|
||||||
|
<!-- ===== LOCATION PIN (top, centered) ===== -->
|
||||||
|
<!--
|
||||||
|
Classic location pin:
|
||||||
|
- Circle head at top
|
||||||
|
- Teardrop tail pointing down toward deck center
|
||||||
|
The pin tip lands roughly at y=340, just above the deck
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Pin glow / shadow -->
|
||||||
|
<g filter="url(#pinGlow)" opacity="0.6">
|
||||||
|
<circle cx="256" cy="190" r="72" fill="#ff0040"/>
|
||||||
|
<path d="M 210 242 L 256 340 L 302 242 Z" fill="#ff0040"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Pin body (filled teardrop) -->
|
||||||
|
<circle cx="256" cy="188" r="70" fill="url(#pinBodyGrad)"/>
|
||||||
|
<path d="M 212 242 Q 236 295 256 340 Q 276 295 300 242 Z" fill="url(#pinBodyGrad)"/>
|
||||||
|
|
||||||
|
<!-- Pin inner ring (white) -->
|
||||||
|
<circle cx="256" cy="185" r="40" fill="#000000"/>
|
||||||
|
<!-- Pin inner center dot (gradient) -->
|
||||||
|
<circle cx="256" cy="185" r="22" fill="url(#mainGrad)"/>
|
||||||
|
<!-- Pin center highlight -->
|
||||||
|
<circle cx="248" cy="177" r="7" fill="#ffffff" opacity="0.35"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 2.8 MiB |
Loading…
Reference in a new issue