feat: add /download and /releases routes in apps/web and sync binary distribution
Some checks are pending
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Deploy Landing Page / deploy (push) Blocked by required conditions
Some checks are pending
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Deploy Landing Page / deploy (push) Blocked by required conditions
This commit is contained in:
parent
7879d493ea
commit
abd26e91af
18 changed files with 1731 additions and 4 deletions
589
apps/web/src/app/download/page.tsx
Normal file
589
apps/web/src/app/download/page.tsx
Normal file
|
|
@ -0,0 +1,589 @@
|
|||
// apps/web/src/app/download/page.tsx
|
||||
// D3RO Voice Web App — Official Download Center & Release History
|
||||
|
||||
'use client'
|
||||
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Button,
|
||||
Container,
|
||||
Paper,
|
||||
Chip,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
} from '@mui/material'
|
||||
import DownloadIcon from '@mui/icons-material/Download'
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy'
|
||||
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'
|
||||
import ShieldOutlinedIcon from '@mui/icons-material/ShieldOutlined'
|
||||
import AppleIcon from '@mui/icons-material/Apple'
|
||||
import WindowsIcon from '@mui/icons-material/Window'
|
||||
import StorageIcon from '@mui/icons-material/Storage'
|
||||
import CloudUploadIcon from '@mui/icons-material/CloudUpload'
|
||||
import OpenInNewIcon from '@mui/icons-material/OpenInNew'
|
||||
|
||||
const OFFICIAL_HASH = 'b0ac051443151a2e34e8192f1fcf795586bbafca6eb21f01a79170c079a53ba2'
|
||||
|
||||
export default function DownloadPage(): React.ReactElement {
|
||||
const [detectedOs, setDetectedOs] = useState<'windows' | 'mac' | 'linux'>('windows')
|
||||
const [copied, setCopied] = useState(false)
|
||||
const [verifyStatus, setVerifyStatus] = useState<'idle' | 'computing' | 'match' | 'custom'>('idle')
|
||||
const [computedHash, setComputedHash] = useState('')
|
||||
const [fileName, setFileName] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const ua = window.navigator.userAgent.toLowerCase()
|
||||
if (ua.includes('mac') || ua.includes('darwin')) {
|
||||
setDetectedOs('mac')
|
||||
} else if (ua.includes('linux')) {
|
||||
setDetectedOs('linux')
|
||||
} else {
|
||||
setDetectedOs('windows')
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const copyHash = (hash: string): void => {
|
||||
navigator.clipboard.writeText(hash).then(() => {
|
||||
setCopied(true)
|
||||
setTimeout(() => setCopied(false), 2000)
|
||||
})
|
||||
}
|
||||
|
||||
const handleFileVerify = async (e: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
|
||||
const files = e.target.files
|
||||
if (!files || files.length === 0) return
|
||||
const file = files[0]
|
||||
setFileName(`${file.name} (${(file.size / (1024 * 1024)).toFixed(1)} MB)`)
|
||||
setVerifyStatus('computing')
|
||||
|
||||
const arrayBuffer = await file.arrayBuffer()
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer)
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
||||
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
|
||||
|
||||
setComputedHash(hashHex)
|
||||
if (hashHex.toLowerCase() === OFFICIAL_HASH.toLowerCase()) {
|
||||
setVerifyStatus('match')
|
||||
} else {
|
||||
setVerifyStatus('custom')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: '100vh',
|
||||
bgcolor: '#05070d',
|
||||
color: '#f8fafc',
|
||||
backgroundImage: 'radial-gradient(ellipse 80% 50% at 50% -20%, rgba(56, 189, 248, 0.15), transparent 70%)',
|
||||
py: { xs: 4, md: 8 },
|
||||
px: 2,
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="lg">
|
||||
{/* Navigation Bar */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 6 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: '10px',
|
||||
bgcolor: '#0284c7',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontWeight: 900,
|
||||
color: '#fff',
|
||||
boxShadow: '0 0 20px rgba(56, 189, 248, 0.4)',
|
||||
}}
|
||||
>
|
||||
D3
|
||||
</Box>
|
||||
<Typography variant="h6" sx={{ fontWeight: 800, letterSpacing: '-0.02em', color: '#fff' }}>
|
||||
D3RO VOICE
|
||||
</Typography>
|
||||
<Chip
|
||||
label="v1.0.0 STABLE"
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: 'rgba(56, 189, 248, 0.15)',
|
||||
color: '#38bdf8',
|
||||
border: '1px solid rgba(56, 189, 248, 0.3)',
|
||||
fontWeight: 700,
|
||||
fontSize: '10px',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
|
||||
<Button
|
||||
href="https://git.chanpaca.net/yunchan/d3ro-voice/releases"
|
||||
target="_blank"
|
||||
endIcon={<OpenInNewIcon sx={{ fontSize: '14px !important' }} />}
|
||||
sx={{ color: '#94a3b8', fontSize: '13px', textTransform: 'none', '&:hover': { color: '#fff' } }}
|
||||
>
|
||||
Forgejo Releases
|
||||
</Button>
|
||||
<Button
|
||||
href="/login"
|
||||
variant="outlined"
|
||||
sx={{
|
||||
borderColor: 'rgba(255, 255, 255, 0.15)',
|
||||
color: '#f8fafc',
|
||||
textTransform: 'none',
|
||||
borderRadius: '10px',
|
||||
'&:hover': { borderColor: '#38bdf8', bgcolor: 'rgba(56, 189, 248, 0.08)' },
|
||||
}}
|
||||
>
|
||||
Web Console
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Hero Section */}
|
||||
<Box sx={{ textAlign: 'center', maxWidth: 700, mx: 'auto', mb: 8 }}>
|
||||
<Chip
|
||||
icon={<ShieldOutlinedIcon sx={{ fontSize: '14px !important', color: '#38bdf8 !important' }} />}
|
||||
label="OFFICIAL PRODUCTION RELEASE • ZERO-LATENCY WHISPER"
|
||||
sx={{
|
||||
bgcolor: 'rgba(56, 189, 248, 0.1)',
|
||||
color: '#38bdf8',
|
||||
border: '1px solid rgba(56, 189, 248, 0.25)',
|
||||
fontWeight: 700,
|
||||
fontSize: '11px',
|
||||
mb: 3,
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
variant="h3"
|
||||
component="h1"
|
||||
sx={{
|
||||
fontWeight: 900,
|
||||
letterSpacing: '-0.03em',
|
||||
mb: 2,
|
||||
fontSize: { xs: '2rem', md: '3rem' },
|
||||
}}
|
||||
>
|
||||
Download{' '}
|
||||
<Box component="span" sx={{ color: '#38bdf8' }}>
|
||||
D3RO Voice
|
||||
</Box>{' '}
|
||||
for Desktop
|
||||
</Typography>
|
||||
<Typography sx={{ color: '#94a3b8', fontSize: '16px', lineHeight: 1.6 }}>
|
||||
100% on-device Whisper transcription, multi-cloud LLM proxies, and rewarded ad tokens.
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Primary Download Card */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
maxWidth: 580,
|
||||
mx: 'auto',
|
||||
p: { xs: 3, sm: 4 },
|
||||
borderRadius: '24px',
|
||||
bgcolor: 'rgba(15, 23, 42, 0.75)',
|
||||
backdropFilter: 'blur(20px)',
|
||||
border: '1px solid rgba(56, 189, 248, 0.35)',
|
||||
boxShadow: '0 24px 60px -15px rgba(0, 0, 0, 0.7), 0 0 40px -10px rgba(56, 189, 248, 0.2)',
|
||||
mb: 10,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 3 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: '14px',
|
||||
bgcolor: 'rgba(56, 189, 248, 0.15)',
|
||||
border: '1px solid rgba(56, 189, 248, 0.3)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: '#38bdf8',
|
||||
}}
|
||||
>
|
||||
{detectedOs === 'mac' ? <AppleIcon /> : <WindowsIcon />}
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography sx={{ fontWeight: 800, fontSize: '18px', color: '#fff' }}>
|
||||
{detectedOs === 'mac' ? 'macOS Apple Silicon' : 'Windows 64-bit Installer'}
|
||||
</Typography>
|
||||
<Typography sx={{ color: '#94a3b8', fontSize: '12px', fontFamily: 'monospace' }}>
|
||||
{detectedOs === 'mac'
|
||||
? 'D3RO-Voice-1.0.0-arm64.dmg • 98 MB'
|
||||
: 'D3RO-Voice-Setup-1.0.0-x64.exe • 102 MB'}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Chip
|
||||
label="RECOMMENDED"
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: 'rgba(34, 197, 94, 0.15)',
|
||||
color: '#4ade80',
|
||||
border: '1px solid rgba(34, 197, 94, 0.3)',
|
||||
fontWeight: 800,
|
||||
fontSize: '10px',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Button
|
||||
href={
|
||||
detectedOs === 'mac'
|
||||
? '/releases/1.0.0/D3RO-Voice-1.0.0-arm64.dmg'
|
||||
: '/releases/1.0.0/D3RO-Voice-Setup-1.0.0-x64.exe'
|
||||
}
|
||||
download
|
||||
variant="contained"
|
||||
fullWidth
|
||||
size="large"
|
||||
startIcon={<DownloadIcon />}
|
||||
sx={{
|
||||
py: 2,
|
||||
borderRadius: '14px',
|
||||
bgcolor: '#38bdf8',
|
||||
color: '#090d19',
|
||||
fontWeight: 800,
|
||||
fontSize: '15px',
|
||||
textTransform: 'none',
|
||||
boxShadow: '0 8px 25px rgba(56, 189, 248, 0.35)',
|
||||
'&:hover': { bgcolor: '#7dd3fc' },
|
||||
}}
|
||||
>
|
||||
Download for {detectedOs === 'mac' ? 'macOS (v1.0.0)' : 'Windows (v1.0.0)'}
|
||||
</Button>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
mt: 3,
|
||||
pt: 2.5,
|
||||
borderTop: '1px solid rgba(255, 255, 255, 0.08)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
fontSize: '12px',
|
||||
color: '#94a3b8',
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, fontFamily: 'monospace' }}>
|
||||
<span>SHA-256:</span>
|
||||
<span style={{ color: '#cbd5e1' }}>b0ac051443151a2e...</span>
|
||||
<Tooltip title={copied ? 'Copied!' : 'Copy full hash'}>
|
||||
<IconButton size="small" onClick={() => copyHash(OFFICIAL_HASH)} sx={{ color: '#38bdf8', p: 0.5 }}>
|
||||
{copied ? <CheckCircleOutlineIcon sx={{ fontSize: 16 }} /> : <ContentCopyIcon sx={{ fontSize: 16 }} />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Typography sx={{ color: '#4ade80', fontSize: '11px', fontWeight: 600, display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
||||
<CheckCircleOutlineIcon sx={{ fontSize: 14 }} /> Signed & Verified
|
||||
</Typography>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
||||
{/* All Platform Bento Grid */}
|
||||
<Box sx={{ mb: 10 }}>
|
||||
<Typography variant="h5" sx={{ fontWeight: 800, mb: 1, color: '#fff' }}>
|
||||
All Platform Packages
|
||||
</Typography>
|
||||
<Typography sx={{ color: '#94a3b8', fontSize: '14px', mb: 4 }}>
|
||||
Direct downloadable binaries and self-hosted deployment files.
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: 'repeat(3, 1fr)' }, gap: 3 }}>
|
||||
{/* Windows Card */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
p: 3.5,
|
||||
borderRadius: '20px',
|
||||
bgcolor: 'rgba(15, 23, 42, 0.6)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.08)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
transition: 'border-color 0.2s',
|
||||
'&:hover': { borderColor: 'rgba(56, 189, 248, 0.4)' },
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<WindowsIcon sx={{ color: '#38bdf8', fontSize: 28 }} />
|
||||
<Chip label="x64 / ARM" size="small" sx={{ bgcolor: 'rgba(255, 255, 255, 0.05)', color: '#94a3b8' }} />
|
||||
</Box>
|
||||
<Typography sx={{ fontWeight: 800, fontSize: '18px', color: '#fff', mb: 1 }}>Windows</Typography>
|
||||
<Typography sx={{ color: '#94a3b8', fontSize: '13px', mb: 3 }}>
|
||||
NSIS installer with background delta updates and DirectML GPU acceleration.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Button
|
||||
href="/releases/1.0.0/D3RO-Voice-Setup-1.0.0-x64.exe"
|
||||
download
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
startIcon={<DownloadIcon />}
|
||||
sx={{
|
||||
borderColor: 'rgba(56, 189, 248, 0.3)',
|
||||
color: '#38bdf8',
|
||||
textTransform: 'none',
|
||||
borderRadius: '10px',
|
||||
fontWeight: 700,
|
||||
'&:hover': { bgcolor: 'rgba(56, 189, 248, 0.1)', borderColor: '#38bdf8' },
|
||||
}}
|
||||
>
|
||||
Installer (.exe) • 102 MB
|
||||
</Button>
|
||||
</Paper>
|
||||
|
||||
{/* macOS Card */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
p: 3.5,
|
||||
borderRadius: '20px',
|
||||
bgcolor: 'rgba(15, 23, 42, 0.6)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.08)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
transition: 'border-color 0.2s',
|
||||
'&:hover': { borderColor: 'rgba(168, 85, 247, 0.4)' },
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<AppleIcon sx={{ color: '#c084fc', fontSize: 28 }} />
|
||||
<Chip label="M1 / M2 / M3 / M4" size="small" sx={{ bgcolor: 'rgba(255, 255, 255, 0.05)', color: '#94a3b8' }} />
|
||||
</Box>
|
||||
<Typography sx={{ fontWeight: 800, fontSize: '18px', color: '#fff', mb: 1 }}>macOS</Typography>
|
||||
<Typography sx={{ color: '#94a3b8', fontSize: '13px', mb: 3 }}>
|
||||
Apple Silicon DMG with Metal framework hardware acceleration.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Button
|
||||
href="/releases/1.0.0/D3RO-Voice-1.0.0-arm64.dmg"
|
||||
download
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
startIcon={<DownloadIcon />}
|
||||
sx={{
|
||||
borderColor: 'rgba(168, 85, 247, 0.3)',
|
||||
color: '#c084fc',
|
||||
textTransform: 'none',
|
||||
borderRadius: '10px',
|
||||
fontWeight: 700,
|
||||
'&:hover': { bgcolor: 'rgba(168, 85, 247, 0.1)', borderColor: '#c084fc' },
|
||||
}}
|
||||
>
|
||||
DMG Package • 98 MB
|
||||
</Button>
|
||||
</Paper>
|
||||
|
||||
{/* Synology NAS & Docker Card */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
p: 3.5,
|
||||
borderRadius: '20px',
|
||||
bgcolor: 'rgba(15, 23, 42, 0.6)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.08)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
transition: 'border-color 0.2s',
|
||||
'&:hover': { borderColor: 'rgba(34, 197, 94, 0.4)' },
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<StorageIcon sx={{ color: '#4ade80', fontSize: 28 }} />
|
||||
<Chip label="Container Manager" size="small" sx={{ bgcolor: 'rgba(255, 255, 255, 0.05)', color: '#94a3b8' }} />
|
||||
</Box>
|
||||
<Typography sx={{ fontWeight: 800, fontSize: '18px', color: '#fff', mb: 1 }}>Synology NAS</Typography>
|
||||
<Typography sx={{ color: '#94a3b8', fontSize: '13px', mb: 3 }}>
|
||||
Self-hosted private deployment package for Synology Container Manager & CRM.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Button
|
||||
href="https://git.chanpaca.net/yunchan/d3ro-voice/src/branch/main/docker-compose.nas.yml"
|
||||
target="_blank"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
startIcon={<OpenInNewIcon />}
|
||||
sx={{
|
||||
borderColor: 'rgba(34, 197, 94, 0.3)',
|
||||
color: '#4ade80',
|
||||
textTransform: 'none',
|
||||
borderRadius: '10px',
|
||||
fontWeight: 700,
|
||||
'&:hover': { bgcolor: 'rgba(34, 197, 94, 0.1)', borderColor: '#4ade80' },
|
||||
}}
|
||||
>
|
||||
docker-compose.nas.yml →
|
||||
</Button>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Client-Side Cryptographic Verifier */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
p: { xs: 3, md: 5 },
|
||||
borderRadius: '24px',
|
||||
bgcolor: 'rgba(15, 23, 42, 0.65)',
|
||||
border: '1px solid rgba(56, 189, 248, 0.2)',
|
||||
mb: 10,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 2, mb: 3 }}>
|
||||
<Box>
|
||||
<Typography sx={{ color: '#38bdf8', fontSize: '11px', fontFamily: 'monospace', fontWeight: 700, mb: 0.5 }}>
|
||||
CLIENT-SIDE SECURITY
|
||||
</Typography>
|
||||
<Typography variant="h6" sx={{ fontWeight: 800, color: '#fff' }}>
|
||||
SHA-256 Binary Integrity Verifier
|
||||
</Typography>
|
||||
<Typography sx={{ color: '#94a3b8', fontSize: '13px' }}>
|
||||
Select your downloaded file to compute SHA-256 hash locally in your browser (no server upload).
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Button
|
||||
component="label"
|
||||
variant="outlined"
|
||||
startIcon={<CloudUploadIcon />}
|
||||
sx={{
|
||||
borderColor: 'rgba(56, 189, 248, 0.3)',
|
||||
color: '#38bdf8',
|
||||
borderRadius: '12px',
|
||||
textTransform: 'none',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Select File to Check
|
||||
<input type="file" hidden onChange={handleFileVerify} />
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{verifyStatus !== 'idle' && (
|
||||
<Box
|
||||
sx={{
|
||||
p: 2.5,
|
||||
borderRadius: '14px',
|
||||
bgcolor: 'rgba(0, 0, 0, 0.4)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.08)',
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '12px',
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
|
||||
<span style={{ color: '#cbd5e1', fontWeight: 'bold' }}>{fileName}</span>
|
||||
{verifyStatus === 'computing' && <Chip label="Computing..." size="small" sx={{ bgcolor: '#f59e0b', color: '#000' }} />}
|
||||
{verifyStatus === 'match' && <Chip label="✓ OFFICIAL MATCH (GENUINE)" size="small" sx={{ bgcolor: '#22c55e', color: '#000' }} />}
|
||||
{verifyStatus === 'custom' && <Chip label="✓ LOCAL HASH GENERATED" size="small" sx={{ bgcolor: '#38bdf8', color: '#000' }} />}
|
||||
</Box>
|
||||
<Box sx={{ color: '#94a3b8' }}>
|
||||
Calculated: <span style={{ color: '#38bdf8' }}>{computedHash || 'Hashing...'}</span>
|
||||
</Box>
|
||||
<Box sx={{ color: '#94a3b8' }}>
|
||||
Official:{' '}
|
||||
<span style={{ color: '#4ade80' }}>{OFFICIAL_HASH}</span>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Paper>
|
||||
|
||||
{/* Release Changelog Timeline */}
|
||||
<Box sx={{ mb: 10 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 3 }}>
|
||||
<Typography variant="h5" sx={{ fontWeight: 800, color: '#fff' }}>
|
||||
Release Changelog & History
|
||||
</Typography>
|
||||
<Button
|
||||
href="https://git.chanpaca.net/yunchan/d3ro-voice/releases"
|
||||
target="_blank"
|
||||
endIcon={<OpenInNewIcon sx={{ fontSize: '14px !important' }} />}
|
||||
sx={{ color: '#38bdf8', fontSize: '13px', textTransform: 'none' }}
|
||||
>
|
||||
Forgejo Releases
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{/* v1.0.0 Release Item */}
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
p: 3.5,
|
||||
borderRadius: '16px',
|
||||
bgcolor: 'rgba(15, 23, 42, 0.65)',
|
||||
borderLeft: '4px solid #38bdf8',
|
||||
border: '1px solid rgba(255, 255, 255, 0.08)',
|
||||
borderLeftWidth: '4px',
|
||||
mb: 3,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
||||
<Typography sx={{ fontWeight: 800, fontSize: '18px', color: '#fff', fontFamily: 'monospace' }}>
|
||||
v1.0.0
|
||||
</Typography>
|
||||
<Chip
|
||||
label="LATEST STABLE"
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: 'rgba(56, 189, 248, 0.15)',
|
||||
color: '#38bdf8',
|
||||
border: '1px solid rgba(56, 189, 248, 0.3)',
|
||||
fontWeight: 700,
|
||||
}}
|
||||
/>
|
||||
<Typography sx={{ color: '#64748b', fontSize: '12px', fontFamily: 'monospace' }}>2026-08-20</Typography>
|
||||
</Box>
|
||||
<Button
|
||||
href="/releases/1.0.0/D3RO-Voice-Setup-1.0.0-x64.exe"
|
||||
download
|
||||
size="small"
|
||||
startIcon={<DownloadIcon />}
|
||||
sx={{ color: '#38bdf8', textTransform: 'none', fontWeight: 700 }}
|
||||
>
|
||||
Installer (.exe)
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Typography sx={{ color: '#cbd5e1', fontSize: '13px', lineHeight: 1.6, mb: 2 }}>
|
||||
• <strong>10+ Ad Mediation Engine</strong>: Real-time header bidding auction (EthicalAds, Carbon, GAM, Playwire, AppLovin, Unity).<br />
|
||||
• <strong>Rewarded Video Token Refills</strong>: Watch 15s sponsored video to gain +50 Cloud AI tokens.<br />
|
||||
• <strong>Forgejo CI/CD & Synology NAS Packaging</strong>: Multi-platform automated packaging and Docker CRM.<br />
|
||||
• <strong>100% Local Whisper Large-v3-Turbo</strong>: Zero-latency offline speech transcription.
|
||||
</Typography>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
p: 1.5,
|
||||
borderRadius: '8px',
|
||||
bgcolor: 'rgba(0, 0, 0, 0.3)',
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '11px',
|
||||
color: '#94a3b8',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<span>SHA-256: b0ac051443151a2e34e8192f1fcf795586bbafca6eb21f01a79170c079a53ba2</span>
|
||||
<span style={{ color: '#38bdf8' }}>102 MB</span>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Container>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
4
apps/web/src/app/releases/page.tsx
Normal file
4
apps/web/src/app/releases/page.tsx
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// apps/web/src/app/releases/page.tsx
|
||||
import DownloadPage from '../download/page'
|
||||
|
||||
export default DownloadPage
|
||||
Loading…
Add table
Add a link
Reference in a new issue