feat: Implement foundational UI styling, shared components, and web platform structure.
All checks were successful
Build and Release / build-and-release (push) Successful in 14m40s

This commit is contained in:
Bryan1029384756
2026-02-19 16:03:54 -06:00
parent 65fa715fdf
commit 0e1b7f868a
4 changed files with 153 additions and 12 deletions

View File

@@ -35,9 +35,31 @@ export function UpdateProvider({ children }) {
}
function ForcedUpdateModal({ latestVersion }) {
const { links } = usePlatform();
const handleDownload = () => {
links.openExternal(RELEASE_URL);
const { links, updates } = usePlatform();
const [downloading, setDownloading] = useState(false);
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);
useEffect(() => {
if (!downloading || !updates?.onDownloadProgress) return;
updates.onDownloadProgress(({ percent }) => {
setProgress(percent);
});
}, [downloading]);
const handleDownload = async () => {
if (updates?.installUpdate) {
setDownloading(true);
setError(null);
try {
await updates.installUpdate();
} catch (e) {
setError('Download failed. Please try again.');
setDownloading(false);
}
} else {
links.openExternal(RELEASE_URL);
}
};
return (
@@ -47,30 +69,65 @@ function ForcedUpdateModal({ latestVersion }) {
<p>
A new version (v{latestVersion}) is available. This update is required to continue using the app.
</p>
<button className="forced-update-btn" onClick={handleDownload}>
Download Update
</button>
{downloading ? (
<div className="update-progress">
<div className="update-progress-bar-bg">
<div
className="update-progress-bar-fill"
style={{ width: `${progress}%` }}
/>
</div>
<span className="update-progress-text">Downloading... {progress}%</span>
</div>
) : (
<button className="forced-update-btn" onClick={handleDownload}>
Download Update
</button>
)}
{error && <p className="update-error-text">{error}</p>}
</div>
</div>
);
}
export function TitleBarUpdateIcon() {
const { links } = usePlatform();
const { links, updates } = usePlatform();
const update = useUpdateCheck();
const [downloading, setDownloading] = useState(false);
const [progress, setProgress] = useState(0);
useEffect(() => {
if (!downloading || !updates?.onDownloadProgress) return;
updates.onDownloadProgress(({ percent }) => {
setProgress(percent);
});
}, [downloading]);
if (!update) return null;
const handleClick = () => {
links.openExternal(RELEASE_URL);
const handleClick = async () => {
if (updates?.installUpdate && !downloading) {
setDownloading(true);
try {
await updates.installUpdate();
} catch {
setDownloading(false);
}
} else if (!downloading) {
links.openExternal(RELEASE_URL);
}
};
const label = downloading
? `Downloading update... ${progress}%`
: `Update available: v${update.latestVersion}`;
return (
<button
className="titlebar-btn"
onClick={handleClick}
aria-label={`Update available: v${update.latestVersion}`}
title={`Update available: v${update.latestVersion}`}
aria-label={label}
title={label}
style={{ borderRight: '1px solid var(--app-frame-border)' }}
>
<div style={{ marginRight: '12px' }}>
@@ -79,4 +136,3 @@ export function TitleBarUpdateIcon() {
</button>
);
}

View File

@@ -3173,6 +3173,40 @@ body {
background-color: var(--brand-experiment-hover);
}
.update-progress {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
width: 100%;
}
.update-progress-bar-bg {
width: 100%;
height: 8px;
background-color: var(--bg-tertiary);
border-radius: 4px;
overflow: hidden;
}
.update-progress-bar-fill {
height: 100%;
background-color: var(--brand-experiment);
border-radius: 4px;
transition: width 0.2s ease;
}
.update-progress-text {
color: var(--header-secondary);
font-size: 13px;
}
.update-error-text {
color: var(--text-danger, #ed4245);
font-size: 13px;
margin: 8px 0 0;
}
/* ============================================
VOICE USER ITEM (sidebar)
============================================ */

View File

@@ -55,6 +55,8 @@
/**
* @typedef {Object} PlatformUpdates
* @property {() => Promise<object>} checkUpdate
* @property {() => Promise<void>} [installUpdate] - Download and install APK (Android only)
* @property {(callback: function) => void} [onDownloadProgress] - Listen for download progress events (Android only)
*/
/**