mirror of
https://github.com/Novattz/creamlinux-installer.git
synced 2026-08-01 19:18:25 -04:00
new spinner
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { FC, ButtonHTMLAttributes } from 'react'
|
import { FC, ButtonHTMLAttributes } from 'react'
|
||||||
|
import Spinner from '@/components/common/Spinner'
|
||||||
|
|
||||||
export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'success' | 'warning'
|
export type ButtonVariant = 'primary' | 'secondary' | 'danger' | 'success' | 'warning'
|
||||||
export type ButtonSize = 'small' | 'medium' | 'large'
|
export type ButtonSize = 'small' | 'medium' | 'large'
|
||||||
@@ -58,7 +59,7 @@ const Button: FC<ButtonProps> = ({
|
|||||||
>
|
>
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<span className="btn-spinner">
|
<span className="btn-spinner">
|
||||||
<span className="spinner"></span>
|
<Spinner />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import { ReactNode } from 'react'
|
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'
|
export type LoadingSize = 'small' | 'medium' | 'large'
|
||||||
|
|
||||||
interface LoadingIndicatorProps {
|
interface LoadingIndicatorProps {
|
||||||
size?: LoadingSize
|
size?: LoadingSize
|
||||||
type?: LoadingType
|
type?: LoadingType
|
||||||
message?: string
|
message?: string
|
||||||
progress?: number
|
|
||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Versatile loading indicator component
|
* 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 = ({
|
const LoadingIndicator = ({
|
||||||
size = 'medium',
|
size = 'medium',
|
||||||
type = 'spinner',
|
type = 'spinner',
|
||||||
message,
|
message,
|
||||||
progress = 0,
|
|
||||||
className = '',
|
className = '',
|
||||||
}: LoadingIndicatorProps) => {
|
}: LoadingIndicatorProps) => {
|
||||||
// Size class mapping
|
// Size class mapping
|
||||||
@@ -33,7 +33,7 @@ const LoadingIndicator = ({
|
|||||||
const renderLoadingIndicator = (): ReactNode => {
|
const renderLoadingIndicator = (): ReactNode => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'spinner':
|
case 'spinner':
|
||||||
return <div className="loading-spinner"></div>
|
return <Spinner />
|
||||||
|
|
||||||
case 'dots':
|
case 'dots':
|
||||||
return (
|
return (
|
||||||
@@ -44,21 +44,8 @@ const LoadingIndicator = ({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
case 'progress':
|
|
||||||
return (
|
|
||||||
<div className="loading-progress">
|
|
||||||
<div className="progress-bar-container">
|
|
||||||
<div
|
|
||||||
className="progress-bar"
|
|
||||||
style={{ width: `${Math.min(Math.max(progress, 0), 100)}%` }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
{progress > 0 && <div className="progress-percentage">{Math.round(progress)}%</div>}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return <div className="loading-spinner"></div>
|
return <Spinner />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) => (
|
||||||
|
<svg viewBox="0 0 16 16" className={`spinner-ring ${className}`}>
|
||||||
|
<circle cx="8" cy="8" r="7" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Spinner
|
||||||
@@ -2,7 +2,10 @@ export { default as LoadingIndicator } from './LoadingIndicator'
|
|||||||
export { default as ProgressBar } from './ProgressBar'
|
export { default as ProgressBar } from './ProgressBar'
|
||||||
export { default as Dropdown } from './Dropdown'
|
export { default as Dropdown } from './Dropdown'
|
||||||
export { default as VotesDisplay } from './VotesDisplay'
|
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 { LoadingSize, LoadingType } from './LoadingIndicator'
|
||||||
export type { DropdownOption } from './Dropdown'
|
export type { DropdownOption } from './Dropdown'
|
||||||
export type { GameVotes } from './VotesDisplay'
|
export type { GameVotes } from './VotesDisplay'
|
||||||
|
export type { EntryListProps } from './EntryList'
|
||||||
@@ -6,6 +6,7 @@ import DialogFooter from './DialogFooter'
|
|||||||
import DialogActions from './DialogActions'
|
import DialogActions from './DialogActions'
|
||||||
import AddDlcDialog from './AddDlcDialog'
|
import AddDlcDialog from './AddDlcDialog'
|
||||||
import { Button, AnimatedCheckbox } from '@/components/buttons'
|
import { Button, AnimatedCheckbox } from '@/components/buttons'
|
||||||
|
import { Spinner } from '@/components/common'
|
||||||
import { DlcInfo } from '@/types'
|
import { DlcInfo } from '@/types'
|
||||||
import { Icon, check, info } from '@/components/icons'
|
import { Icon, check, info } from '@/components/icons'
|
||||||
|
|
||||||
@@ -223,7 +224,7 @@ const DlcSelectionDialog = ({
|
|||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
<div className="dlc-loading">
|
<div className="dlc-loading">
|
||||||
<div className="loading-spinner"></div>
|
<Spinner />
|
||||||
<p>Loading DLC information...</p>
|
<p>Loading DLC information...</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { Spinner } from '@/components/common'
|
||||||
|
|
||||||
interface InitialLoadingScreenProps {
|
interface InitialLoadingScreenProps {
|
||||||
message: string
|
message: string
|
||||||
@@ -38,8 +39,7 @@ const InitialLoadingScreen = ({ message, progress }: InitialLoadingScreenProps)
|
|||||||
<h1>CreamLinux</h1>
|
<h1>CreamLinux</h1>
|
||||||
|
|
||||||
<div className="loading-animation">
|
<div className="loading-animation">
|
||||||
{/* Spinner animation */}
|
<Spinner />
|
||||||
<div className="loading-spinner"></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="loading-message">{message}</p>
|
<p className="loading-message">{message}</p>
|
||||||
|
|||||||
@@ -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 { check } from '@tauri-apps/plugin-updater'
|
||||||
import { relaunch } from '@tauri-apps/plugin-process'
|
import { relaunch } from '@tauri-apps/plugin-process'
|
||||||
import { ProgressBar } from '@/components/common'
|
import { ProgressBar, Spinner } from '@/components/common'
|
||||||
|
|
||||||
interface UpdateScreenProps {
|
interface UpdateScreenProps {
|
||||||
onComplete: () => void
|
onComplete: () => void
|
||||||
@@ -16,6 +16,8 @@ const UpdateScreen = ({ onComplete }: UpdateScreenProps) => {
|
|||||||
const [downloading, setDownloading] = useState(false)
|
const [downloading, setDownloading] = useState(false)
|
||||||
const [progress, setProgress] = useState(0)
|
const [progress, setProgress] = useState(0)
|
||||||
const [version, setVersion] = useState('')
|
const [version, setVersion] = useState('')
|
||||||
|
const totalBytesRef = useRef(0)
|
||||||
|
const downloadedBytesRef = useRef(0)
|
||||||
|
|
||||||
const checkForUpdates = useCallback(async () => {
|
const checkForUpdates = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -29,20 +31,22 @@ const UpdateScreen = ({ onComplete }: UpdateScreenProps) => {
|
|||||||
setVersion(update.version)
|
setVersion(update.version)
|
||||||
|
|
||||||
// Download and install the update
|
// Download and install the update
|
||||||
|
totalBytesRef.current = 0
|
||||||
|
downloadedBytesRef.current = 0
|
||||||
|
|
||||||
await update.downloadAndInstall((event) => {
|
await update.downloadAndInstall((event) => {
|
||||||
switch (event.event) {
|
switch (event.event) {
|
||||||
case 'Started': {
|
case 'Started': {
|
||||||
const contentLength = event.data.contentLength
|
totalBytesRef.current = event.data.contentLength ?? 0
|
||||||
console.log(`Started downloading ${contentLength} bytes`)
|
console.log(`Started downloading ${totalBytesRef.current} bytes`)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'Progress': {
|
case 'Progress': {
|
||||||
const { chunkLength } = event.data
|
downloadedBytesRef.current += event.data.chunkLength
|
||||||
// Calculate cumulative progress
|
// Percentage of total bytes downloaded so far (0 if the server
|
||||||
setProgress((prev) => {
|
// didn't report a content length)
|
||||||
const newProgress = prev + chunkLength
|
const total = totalBytesRef.current
|
||||||
return Math.min(newProgress, 100)
|
setProgress(total > 0 ? Math.min((downloadedBytesRef.current / total) * 100, 100) : 0)
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'Finished':
|
case 'Finished':
|
||||||
@@ -77,7 +81,7 @@ const UpdateScreen = ({ onComplete }: UpdateScreenProps) => {
|
|||||||
<h1>CreamLinux</h1>
|
<h1>CreamLinux</h1>
|
||||||
|
|
||||||
<div className="loading-animation">
|
<div className="loading-animation">
|
||||||
{checking && <div className="loading-spinner"></div>}
|
{checking && <Spinner />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="loading-message">
|
<p className="loading-message">
|
||||||
|
|||||||
Reference in New Issue
Block a user