Skip to content

Commit 2803227

Browse files
committed
feat(website): add release info and direct download to website
- Add releases.json with version, changelog, and download URLs - Create DownloadSection component with categorized changelog display - Update Hero with version badge and direct DMG download link - Update build-release workflow to auto-update releases.json on release - Website now shows release info without requiring GitHub visit
1 parent b670942 commit 2803227

File tree

5 files changed

+332
-8
lines changed

5 files changed

+332
-8
lines changed

.github/workflows/build-release.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,69 @@ jobs:
282282
env:
283283
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
284284

285+
- name: Update Website releases.json
286+
run: |
287+
VERSION="${{ steps.version.outputs.version }}"
288+
DATE=$(date +%Y-%m-%d)
289+
DMG_SIZE=$(ls -lh "build/${{ env.APP_NAME }}-v${VERSION}.dmg" | awk '{print $5}')
290+
291+
# Update releases.json using Python
292+
python3 << PYTHON_SCRIPT
293+
import json
294+
import os
295+
296+
version = "${VERSION}"
297+
date = "${DATE}"
298+
dmg_size = "${DMG_SIZE}"
299+
repo = "${{ github.repository }}"
300+
301+
with open("website/public/data/releases.json", "r") as f:
302+
data = json.load(f)
303+
304+
# Mark all existing releases as not latest
305+
for release in data["releases"]:
306+
release["latest"] = False
307+
308+
# Create new release entry
309+
new_release = {
310+
"version": version,
311+
"date": date,
312+
"latest": True,
313+
"minOS": "macOS 14.0+",
314+
"architecture": "Universal (Apple Silicon + Intel)",
315+
"downloads": {
316+
"dmg": {
317+
"url": f"https://github.com/{repo}/releases/download/v{version}/MyMacCleaner-v{version}.dmg",
318+
"size": dmg_size
319+
}
320+
},
321+
"changelog": [
322+
{"type": "added", "description": "See GitHub release notes for full changelog"}
323+
]
324+
}
325+
326+
# Insert at beginning
327+
data["releases"].insert(0, new_release)
328+
329+
# Keep only last 5 releases
330+
data["releases"] = data["releases"][:5]
331+
332+
with open("website/public/data/releases.json", "w") as f:
333+
json.dump(data, f, indent=2)
334+
335+
print(f"Updated releases.json with v{version}")
336+
PYTHON_SCRIPT
337+
338+
- name: Commit and Push Website Update
339+
run: |
340+
git config --local user.email "github-actions[bot]@users.noreply.github.com"
341+
git config --local user.name "github-actions[bot]"
342+
git add website/public/data/releases.json
343+
git commit -m "chore: update website releases.json for v${{ steps.version.outputs.version }}" || echo "No changes to commit"
344+
git push origin HEAD:main
345+
env:
346+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
347+
285348
- name: Cleanup Keychain
286349
if: always()
287350
run: |

website/public/data/releases.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"releases": [
3+
{
4+
"version": "1.1.0",
5+
"date": "2025-01-15",
6+
"latest": true,
7+
"minOS": "macOS 14.0+",
8+
"architecture": "Universal (Apple Silicon + Intel)",
9+
"downloads": {
10+
"dmg": {
11+
"url": "https://github.com/Prot10/MyMacCleaner/releases/download/v1.1.0/MyMacCleaner-v1.1.0.dmg",
12+
"size": "4.6 MB"
13+
}
14+
},
15+
"changelog": [
16+
{ "type": "added", "description": "Browser Privacy Cleaner - Clear data from Safari, Chrome, Firefox, and Edge" },
17+
{ "type": "added", "description": "Orphaned Files Scanner - Detect leftover files from uninstalled applications" },
18+
{ "type": "added", "description": "Duplicate File Finder - Find duplicate files with SHA256 hashing" },
19+
{ "type": "added", "description": "Menu Bar Monitor - Real-time CPU/RAM/Disk stats with 4 display modes" },
20+
{ "type": "added", "description": "Permissions Management - Manage FDA and folder access permissions" },
21+
{ "type": "added", "description": "Empty Trash functionality with confirmation dialog" },
22+
{ "type": "changed", "description": "Complete Theme system with consistent typography, spacing, and corner radius" },
23+
{ "type": "changed", "description": "Enhanced UI with standardized glass styling across all views" },
24+
{ "type": "changed", "description": "Improved app initialization to avoid unnecessary TCC permission prompts" },
25+
{ "type": "changed", "description": "Better localization support with runtime language switching" },
26+
{ "type": "fixed", "description": "FDA detection with multiple fallback methods" },
27+
{ "type": "fixed", "description": "Async update checking and command escaping" },
28+
{ "type": "fixed", "description": "Thread safety in file scanning operations" }
29+
]
30+
},
31+
{
32+
"version": "1.0.0",
33+
"date": "2025-01-06",
34+
"latest": false,
35+
"minOS": "macOS 14.0+",
36+
"architecture": "Universal (Apple Silicon + Intel)",
37+
"downloads": {
38+
"dmg": {
39+
"url": "https://github.com/Prot10/MyMacCleaner/releases/download/v1.0.0/MyMacCleaner-v1.0.0.dmg",
40+
"size": "3.7 MB"
41+
}
42+
},
43+
"changelog": [
44+
{ "type": "added", "description": "Initial release with Liquid Glass UI design" },
45+
{ "type": "added", "description": "Smart Scan for quick system cleanup" },
46+
{ "type": "added", "description": "Disk Cleaner with category-based file management" },
47+
{ "type": "added", "description": "Space Lens with treemap visualization" },
48+
{ "type": "added", "description": "Performance monitoring and maintenance tools" },
49+
{ "type": "added", "description": "Applications manager with Homebrew integration" },
50+
{ "type": "added", "description": "Startup items and port management" },
51+
{ "type": "added", "description": "System health dashboard" },
52+
{ "type": "added", "description": "Multi-language support (English, Italian, Spanish)" }
53+
]
54+
}
55+
]
56+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
---
2+
// Fetch releases data at build time
3+
import releases from '../../public/data/releases.json';
4+
5+
const latestRelease = releases.releases.find(r => r.latest) || releases.releases[0];
6+
const olderReleases = releases.releases.filter(r => !r.latest);
7+
8+
// Changelog type icons and colors
9+
const changelogIcons: Record<string, { icon: string; color: string; label: string }> = {
10+
added: { icon: '+', color: 'text-green-400', label: 'Added' },
11+
changed: { icon: '~', color: 'text-blue-400', label: 'Changed' },
12+
fixed: { icon: '', color: 'text-yellow-400', label: 'Fixed' },
13+
removed: { icon: '-', color: 'text-red-400', label: 'Removed' },
14+
security: { icon: '!', color: 'text-orange-400', label: 'Security' },
15+
};
16+
---
17+
18+
<section id="download" class="py-24 relative overflow-hidden">
19+
<!-- Background -->
20+
<div class="absolute inset-0 -z-10">
21+
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] h-[600px] bg-primary/10 rounded-full blur-3xl"></div>
22+
</div>
23+
24+
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
25+
<div class="text-center mb-12">
26+
<h2 class="text-3xl sm:text-4xl font-bold text-white mb-4">
27+
Download MyMacCleaner
28+
</h2>
29+
<p class="text-lg text-gray-400 max-w-2xl mx-auto">
30+
Free and open source. No sign-up required.
31+
</p>
32+
</div>
33+
34+
<!-- Latest Release Card -->
35+
<div class="glass-card p-8 max-w-2xl mx-auto mb-8">
36+
<!-- Header -->
37+
<div class="flex items-center justify-between mb-6">
38+
<div class="flex items-center gap-4">
39+
<img
40+
src="/MyMacCleaner/icon-192.png"
41+
alt="MyMacCleaner"
42+
class="w-16 h-16 rounded-2xl shadow-lg"
43+
/>
44+
<div>
45+
<h3 class="text-xl font-semibold text-white">MyMacCleaner</h3>
46+
<div class="flex items-center gap-2 mt-1">
47+
<span class="px-2 py-0.5 bg-primary/20 text-primary text-sm font-medium rounded-full">
48+
v{latestRelease.version}
49+
</span>
50+
<span class="text-sm text-gray-500">
51+
{new Date(latestRelease.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
52+
</span>
53+
</div>
54+
</div>
55+
</div>
56+
<span class="hidden sm:inline-flex items-center gap-1 px-3 py-1 bg-green-500/20 text-green-400 text-xs font-medium rounded-full">
57+
<span class="w-1.5 h-1.5 bg-green-400 rounded-full"></span>
58+
Latest
59+
</span>
60+
</div>
61+
62+
<!-- Download Button -->
63+
<a
64+
href={latestRelease.downloads.dmg.url}
65+
class="glass-button w-full flex items-center justify-center gap-2 mb-4"
66+
>
67+
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
68+
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
69+
</svg>
70+
Download DMG
71+
<span class="text-sm text-white/60">({latestRelease.downloads.dmg.size})</span>
72+
</a>
73+
74+
<!-- System Requirements -->
75+
<p class="text-xs text-gray-500 text-center mb-6">
76+
{latestRelease.minOS} · {latestRelease.architecture}
77+
</p>
78+
79+
<!-- Changelog -->
80+
<div class="border-t border-white/10 pt-6">
81+
<details class="group" open>
82+
<summary class="flex items-center justify-between cursor-pointer text-sm font-medium text-white mb-4">
83+
<span>What's New</span>
84+
<svg class="w-4 h-4 text-gray-400 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
85+
<path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />
86+
</svg>
87+
</summary>
88+
<div class="space-y-2 max-h-64 overflow-y-auto pr-2">
89+
{latestRelease.changelog.map((item) => {
90+
const config = changelogIcons[item.type] || changelogIcons.added;
91+
return (
92+
<div class="flex items-start gap-3 text-sm">
93+
<span class={`${config.color} font-mono w-5 flex-shrink-0 text-center`}>{config.icon}</span>
94+
<span class="text-gray-300">{item.description}</span>
95+
</div>
96+
);
97+
})}
98+
</div>
99+
</details>
100+
</div>
101+
102+
<!-- Gatekeeper Warning -->
103+
<div class="border-t border-white/10 pt-6 mt-6">
104+
<div class="flex items-start gap-3 text-left">
105+
<div class="w-8 h-8 rounded-lg bg-green-500/20 flex items-center justify-center flex-shrink-0 mt-0.5">
106+
<svg class="w-5 h-5 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
107+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
108+
</svg>
109+
</div>
110+
<div>
111+
<h4 class="text-sm font-semibold text-white mb-1">Signed & Notarized</h4>
112+
<p class="text-xs text-gray-400">
113+
This app is code-signed and notarized by Apple. No security warnings on launch.
114+
</p>
115+
</div>
116+
</div>
117+
</div>
118+
</div>
119+
120+
<!-- Older Releases -->
121+
{olderReleases.length > 0 && (
122+
<div class="max-w-2xl mx-auto">
123+
<details class="group">
124+
<summary class="flex items-center justify-center gap-2 cursor-pointer text-sm text-gray-400 hover:text-gray-300 transition-colors py-4">
125+
<span>Previous Releases</span>
126+
<svg class="w-4 h-4 transition-transform group-open:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
127+
<path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />
128+
</svg>
129+
</summary>
130+
<div class="space-y-4 mt-4">
131+
{olderReleases.map((release) => (
132+
<div class="glass-card p-6">
133+
<div class="flex items-center justify-between mb-4">
134+
<div class="flex items-center gap-3">
135+
<span class="px-2 py-0.5 bg-gray-500/20 text-gray-400 text-sm font-medium rounded-full">
136+
v{release.version}
137+
</span>
138+
<span class="text-sm text-gray-500">
139+
{new Date(release.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
140+
</span>
141+
</div>
142+
<a
143+
href={release.downloads.dmg.url}
144+
class="text-sm text-primary hover:text-primary-400 transition-colors flex items-center gap-1"
145+
>
146+
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
147+
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
148+
</svg>
149+
Download ({release.downloads.dmg.size})
150+
</a>
151+
</div>
152+
<details class="group/changelog">
153+
<summary class="flex items-center gap-2 cursor-pointer text-xs text-gray-500 hover:text-gray-400 transition-colors">
154+
<span>View changelog</span>
155+
<svg class="w-3 h-3 transition-transform group-open/changelog:rotate-180" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
156+
<path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />
157+
</svg>
158+
</summary>
159+
<div class="mt-3 space-y-1.5 pl-2 border-l border-white/10">
160+
{release.changelog.slice(0, 5).map((item) => {
161+
const config = changelogIcons[item.type] || changelogIcons.added;
162+
return (
163+
<div class="flex items-start gap-2 text-xs">
164+
<span class={`${config.color} font-mono w-4 flex-shrink-0 text-center`}>{config.icon}</span>
165+
<span class="text-gray-400">{item.description}</span>
166+
</div>
167+
);
168+
})}
169+
{release.changelog.length > 5 && (
170+
<p class="text-xs text-gray-500 pl-6">
171+
+{release.changelog.length - 5} more changes
172+
</p>
173+
)}
174+
</div>
175+
</details>
176+
</div>
177+
))}
178+
</div>
179+
</details>
180+
</div>
181+
)}
182+
183+
<!-- Alternative Options -->
184+
<div class="mt-8 flex flex-col sm:flex-row items-center justify-center gap-4 text-sm text-gray-400">
185+
<span>Or build from source:</span>
186+
<a
187+
href="https://github.com/Prot10/MyMacCleaner"
188+
target="_blank"
189+
rel="noopener noreferrer"
190+
class="flex items-center gap-2 text-primary hover:text-primary-400 transition-colors"
191+
>
192+
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
193+
<path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" />
194+
</svg>
195+
View on GitHub
196+
</a>
197+
</div>
198+
</div>
199+
</section>

website/src/components/Hero.astro

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
---
2+
// Fetch releases data at build time
3+
import releases from '../../public/data/releases.json';
24
5+
const latestRelease = releases.releases.find(r => r.latest) || releases.releases[0];
36
---
47

58
<section class="relative pt-32 pb-20 overflow-hidden">
@@ -12,9 +15,13 @@
1215
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
1316
<div class="text-center max-w-3xl mx-auto">
1417
<!-- Badge -->
15-
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/5 border border-white/10 text-sm text-gray-300 mb-8 animate-fade-in">
16-
<span class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></span>
17-
Free & Open Source
18+
<div class="inline-flex items-center gap-3 px-4 py-2 rounded-full bg-white/5 border border-white/10 text-sm text-gray-300 mb-8 animate-fade-in">
19+
<span class="inline-flex items-center gap-1.5">
20+
<span class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></span>
21+
Free & Open Source
22+
</span>
23+
<span class="w-px h-4 bg-white/20"></span>
24+
<span class="text-primary font-medium">v{latestRelease.version}</span>
1825
</div>
1926

2027
<!-- Heading -->
@@ -32,15 +39,14 @@
3239
<!-- CTA Buttons -->
3340
<div class="flex flex-col sm:flex-row items-center justify-center gap-4 animate-slide-up" style="animation-delay: 0.2s;">
3441
<a
35-
href="https://github.com/Prot10/MyMacCleaner/releases/latest"
36-
target="_blank"
37-
rel="noopener noreferrer"
42+
href={latestRelease.downloads.dmg.url}
3843
class="glass-button flex items-center gap-2"
3944
>
4045
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
4146
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
4247
</svg>
4348
Download for macOS
49+
<span class="text-sm text-white/60">({latestRelease.downloads.dmg.size})</span>
4450
</a>
4551
<a
4652
href="/MyMacCleaner/docs/"

website/src/pages/index.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
import BaseLayout from '../layouts/BaseLayout.astro';
33
import Hero from '../components/Hero.astro';
44
import Features from '../components/Features.astro';
5-
import Download from '../components/Download.astro';
5+
import DownloadSection from '../components/DownloadSection.astro';
66
import OpenSource from '../components/OpenSource.astro';
77
---
88

99
<BaseLayout title="MyMacCleaner - Free Mac Cleaning App">
1010
<Hero />
1111
<Features />
12-
<Download />
12+
<DownloadSection />
1313
<OpenSource />
1414
</BaseLayout>

0 commit comments

Comments
 (0)