From 86061c72e7ce8121b44a5379d3388ac378c6f8ce Mon Sep 17 00:00:00 2001 From: Tickbase Date: Sat, 11 Jul 2026 12:18:45 +0200 Subject: [PATCH] new spinner --- src/components/buttons/Button.tsx | 3 ++- src/components/common/LoadingIndicator.tsx | 25 +++++------------- src/components/common/Spinner.tsx | 17 ++++++++++++ src/components/common/index.ts | 5 +++- src/components/dialogs/DlcSelectionDialog.tsx | 3 ++- .../layout/InitialLoadingScreen.tsx | 4 +-- src/components/layout/UpdateScreen.tsx | 26 +++++++++++-------- 7 files changed, 48 insertions(+), 35 deletions(-) create mode 100644 src/components/common/Spinner.tsx diff --git a/src/components/buttons/Button.tsx b/src/components/buttons/Button.tsx index 8cbbf49..20f5a32 100644 --- a/src/components/buttons/Button.tsx +++ b/src/components/buttons/Button.tsx @@ -1,4 +1,5 @@ import { FC, ButtonHTMLAttributes } from 'react' +import Spinner from '@/components/common/Spinner' export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'success' | 'warning' export type ButtonSize = 'small' | 'medium' | 'large' @@ -58,7 +59,7 @@ const Button: FC = ({ > {isLoading && ( - + )} diff --git a/src/components/common/LoadingIndicator.tsx b/src/components/common/LoadingIndicator.tsx index 5087786..b64f885 100644 --- a/src/components/common/LoadingIndicator.tsx +++ b/src/components/common/LoadingIndicator.tsx @@ -1,25 +1,25 @@ import { ReactNode } from 'react' +import Spinner from './Spinner' -export type LoadingType = 'spinner' | 'dots' | 'progress' +export type LoadingType = 'spinner' | 'dots' export type LoadingSize = 'small' | 'medium' | 'large' interface LoadingIndicatorProps { size?: LoadingSize type?: LoadingType message?: string - progress?: number className?: string } /** * Versatile loading indicator component - * Supports multiple visual styles and sizes + * Supports multiple visual styles and sizes. + * For a progress bar, use ProgressBar or ProgressDialog's progress bar instead. */ const LoadingIndicator = ({ size = 'medium', type = 'spinner', message, - progress = 0, className = '', }: LoadingIndicatorProps) => { // Size class mapping @@ -33,7 +33,7 @@ const LoadingIndicator = ({ const renderLoadingIndicator = (): ReactNode => { switch (type) { case 'spinner': - return
+ return case 'dots': return ( @@ -44,21 +44,8 @@ const LoadingIndicator = ({ ) - case 'progress': - return ( -
-
-
-
- {progress > 0 &&
{Math.round(progress)}%
} -
- ) - default: - return
+ return } } diff --git a/src/components/common/Spinner.tsx b/src/components/common/Spinner.tsx new file mode 100644 index 0000000..165d7d1 --- /dev/null +++ b/src/components/common/Spinner.tsx @@ -0,0 +1,17 @@ +interface SpinnerProps { + className?: string +} + +/** + * Windows/Fluent-style indeterminate ring spinner an SVG circle whose + * stroke-dasharray and rotation are animated (see .spinner-ring in + * _loading.scss), rather than a CSS conic-gradient mask. Size and color + * come from whatever wrapping className/context is passed in. + */ +const Spinner = ({ className = '' }: SpinnerProps) => ( + + + +) + +export default Spinner diff --git a/src/components/common/index.ts b/src/components/common/index.ts index 2f8ba08..af670db 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -2,7 +2,10 @@ export { default as LoadingIndicator } from './LoadingIndicator' export { default as ProgressBar } from './ProgressBar' export { default as Dropdown } from './Dropdown' export { default as VotesDisplay } from './VotesDisplay' +export { default as EntryList } from './EntryList' +export { default as Spinner } from './Spinner' export type { LoadingSize, LoadingType } from './LoadingIndicator' export type { DropdownOption } from './Dropdown' -export type { GameVotes } from './VotesDisplay' \ No newline at end of file +export type { GameVotes } from './VotesDisplay' +export type { EntryListProps } from './EntryList' \ No newline at end of file diff --git a/src/components/dialogs/DlcSelectionDialog.tsx b/src/components/dialogs/DlcSelectionDialog.tsx index 1afc12c..2109f0d 100644 --- a/src/components/dialogs/DlcSelectionDialog.tsx +++ b/src/components/dialogs/DlcSelectionDialog.tsx @@ -6,6 +6,7 @@ import DialogFooter from './DialogFooter' import DialogActions from './DialogActions' import AddDlcDialog from './AddDlcDialog' import { Button, AnimatedCheckbox } from '@/components/buttons' +import { Spinner } from '@/components/common' import { DlcInfo } from '@/types' import { Icon, check, info } from '@/components/icons' @@ -223,7 +224,7 @@ const DlcSelectionDialog = ({ ) : (
-
+

Loading DLC information...

)} diff --git a/src/components/layout/InitialLoadingScreen.tsx b/src/components/layout/InitialLoadingScreen.tsx index 981c42a..546a9fe 100644 --- a/src/components/layout/InitialLoadingScreen.tsx +++ b/src/components/layout/InitialLoadingScreen.tsx @@ -1,4 +1,5 @@ import { useEffect, useState } from 'react' +import { Spinner } from '@/components/common' interface InitialLoadingScreenProps { message: string @@ -38,8 +39,7 @@ const InitialLoadingScreen = ({ message, progress }: InitialLoadingScreenProps)

CreamLinux

- {/* Spinner animation */} -
+

{message}

diff --git a/src/components/layout/UpdateScreen.tsx b/src/components/layout/UpdateScreen.tsx index 7cbd8b4..3f2823d 100644 --- a/src/components/layout/UpdateScreen.tsx +++ b/src/components/layout/UpdateScreen.tsx @@ -1,7 +1,7 @@ -import { useState, useEffect, useCallback } from 'react' +import { useState, useEffect, useCallback, useRef } from 'react' import { check } from '@tauri-apps/plugin-updater' import { relaunch } from '@tauri-apps/plugin-process' -import { ProgressBar } from '@/components/common' +import { ProgressBar, Spinner } from '@/components/common' interface UpdateScreenProps { onComplete: () => void @@ -16,6 +16,8 @@ const UpdateScreen = ({ onComplete }: UpdateScreenProps) => { const [downloading, setDownloading] = useState(false) const [progress, setProgress] = useState(0) const [version, setVersion] = useState('') + const totalBytesRef = useRef(0) + const downloadedBytesRef = useRef(0) const checkForUpdates = useCallback(async () => { try { @@ -29,20 +31,22 @@ const UpdateScreen = ({ onComplete }: UpdateScreenProps) => { setVersion(update.version) // Download and install the update + totalBytesRef.current = 0 + downloadedBytesRef.current = 0 + await update.downloadAndInstall((event) => { switch (event.event) { case 'Started': { - const contentLength = event.data.contentLength - console.log(`Started downloading ${contentLength} bytes`) + totalBytesRef.current = event.data.contentLength ?? 0 + console.log(`Started downloading ${totalBytesRef.current} bytes`) break } case 'Progress': { - const { chunkLength } = event.data - // Calculate cumulative progress - setProgress((prev) => { - const newProgress = prev + chunkLength - return Math.min(newProgress, 100) - }) + downloadedBytesRef.current += event.data.chunkLength + // Percentage of total bytes downloaded so far (0 if the server + // didn't report a content length) + const total = totalBytesRef.current + setProgress(total > 0 ? Math.min((downloadedBytesRef.current / total) * 100, 100) : 0) break } case 'Finished': @@ -77,7 +81,7 @@ const UpdateScreen = ({ onComplete }: UpdateScreenProps) => {

CreamLinux

- {checking &&
} + {checking && }