mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-19 21:46:11 +05:00
refactor
This commit is contained in:
@@ -10,7 +10,6 @@
|
|||||||
"fontsource-roboto": "^4.0.0",
|
"fontsource-roboto": "^4.0.0",
|
||||||
"i18next": "^20.3.1",
|
"i18next": "^20.3.1",
|
||||||
"i18next-browser-languagedetector": "^6.1.1",
|
"i18next-browser-languagedetector": "^6.1.1",
|
||||||
"konva": "^8.0.1",
|
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"material-ui-image": "^3.3.2",
|
"material-ui-image": "^3.3.2",
|
||||||
"parse-torrent": "^9.1.3",
|
"parse-torrent": "^9.1.3",
|
||||||
@@ -21,7 +20,6 @@
|
|||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-dropzone": "^11.3.2",
|
"react-dropzone": "^11.3.2",
|
||||||
"react-i18next": "^11.10.0",
|
"react-i18next": "^11.10.0",
|
||||||
"react-konva": "^17.0.2-4",
|
|
||||||
"react-measure": "^2.5.2",
|
"react-measure": "^2.5.2",
|
||||||
"react-query": "^3.17.0",
|
"react-query": "^3.17.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react'
|
|
||||||
import DialogContent from '@material-ui/core/DialogContent'
|
|
||||||
import { Stage, Layer } from 'react-konva'
|
|
||||||
import Measure from 'react-measure'
|
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
|
||||||
import styled from 'styled-components'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
|
|
||||||
import SingleBlock from './SingleBlock'
|
|
||||||
import getShortCacheMap from './getShortCacheMap'
|
|
||||||
|
|
||||||
const ScrollNotification = styled.div`
|
|
||||||
margin-top: 10px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: rgba(0, 0, 0, 0.5);
|
|
||||||
align-self: center;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default function DefaultSnake({ isMini, cacheMap, preloadPiecesAmount }) {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
|
|
||||||
const [stageSettings, setStageSettings] = useState({
|
|
||||||
boxHeight: null,
|
|
||||||
strokeWidth: null,
|
|
||||||
marginBetweenBlocks: null,
|
|
||||||
stageOffset: null,
|
|
||||||
})
|
|
||||||
const updateStageSettings = (boxHeight, strokeWidth) => {
|
|
||||||
setStageSettings({
|
|
||||||
boxHeight,
|
|
||||||
strokeWidth,
|
|
||||||
marginBetweenBlocks: strokeWidth,
|
|
||||||
stageOffset: strokeWidth * 2,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// initializing stageSettings
|
|
||||||
if (isMini) return dimensions.width < 500 ? updateStageSettings(20, 3) : updateStageSettings(24, 4)
|
|
||||||
updateStageSettings(12, 2)
|
|
||||||
}, [isMini, dimensions.width])
|
|
||||||
|
|
||||||
const miniCacheMaxHeight = 340
|
|
||||||
|
|
||||||
const { boxHeight, strokeWidth, marginBetweenBlocks, stageOffset } = stageSettings
|
|
||||||
|
|
||||||
const blockSizeWithMargin = boxHeight + strokeWidth + marginBetweenBlocks
|
|
||||||
const piecesInOneRow = Math.floor((dimensions.width * 0.9) / blockSizeWithMargin)
|
|
||||||
|
|
||||||
const shortCacheMap = isMini ? getShortCacheMap({ cacheMap, preloadPiecesAmount, piecesInOneRow }) : []
|
|
||||||
|
|
||||||
const amountOfRows = Math.ceil((isMini ? shortCacheMap.length : cacheMap.length) / piecesInOneRow)
|
|
||||||
|
|
||||||
const getItemCoordinates = blockOrder => {
|
|
||||||
const currentRow = Math.floor(blockOrder / piecesInOneRow)
|
|
||||||
const x = (blockOrder % piecesInOneRow) * blockSizeWithMargin || 0
|
|
||||||
const y = currentRow * blockSizeWithMargin || 0
|
|
||||||
|
|
||||||
return { x, y }
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Measure bounds onResize={({ bounds }) => setDimensions(bounds)}>
|
|
||||||
{({ measureRef }) => (
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
||||||
<DialogContent
|
|
||||||
ref={measureRef}
|
|
||||||
{...(isMini
|
|
||||||
? { style: { padding: 0, maxHeight: `${miniCacheMaxHeight}px`, overflow: 'auto' } }
|
|
||||||
: { style: { padding: 0 } })}
|
|
||||||
>
|
|
||||||
<Stage
|
|
||||||
style={{ display: 'flex', justifyContent: 'center' }}
|
|
||||||
offset={{ x: -stageOffset, y: -stageOffset }}
|
|
||||||
width={stageOffset + blockSizeWithMargin * piecesInOneRow || 0}
|
|
||||||
height={stageOffset + blockSizeWithMargin * amountOfRows || 0}
|
|
||||||
>
|
|
||||||
<Layer>
|
|
||||||
{isMini
|
|
||||||
? shortCacheMap.map(({ percentage, isComplete, inProgress, isActive, isReaderRange }, i) => {
|
|
||||||
const { x, y } = getItemCoordinates(i)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SingleBlock
|
|
||||||
key={uuidv4()}
|
|
||||||
x={x}
|
|
||||||
y={y}
|
|
||||||
percentage={percentage}
|
|
||||||
inProgress={inProgress}
|
|
||||||
isComplete={isComplete}
|
|
||||||
isReaderRange={isReaderRange}
|
|
||||||
isActive={isActive}
|
|
||||||
boxHeight={boxHeight}
|
|
||||||
strokeWidth={strokeWidth}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
: cacheMap.map(({ id, percentage, isComplete, inProgress, isActive, isReaderRange }) => {
|
|
||||||
const { x, y } = getItemCoordinates(id)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SingleBlock
|
|
||||||
key={uuidv4()}
|
|
||||||
x={x}
|
|
||||||
y={y}
|
|
||||||
percentage={percentage}
|
|
||||||
inProgress={inProgress}
|
|
||||||
isComplete={isComplete}
|
|
||||||
isReaderRange={isReaderRange}
|
|
||||||
isActive={isActive}
|
|
||||||
boxHeight={boxHeight}
|
|
||||||
strokeWidth={strokeWidth}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Layer>
|
|
||||||
</Stage>
|
|
||||||
</DialogContent>
|
|
||||||
|
|
||||||
{isMini &&
|
|
||||||
(stageOffset + blockSizeWithMargin * amountOfRows || 0) >= miniCacheMaxHeight &&
|
|
||||||
dimensions.height >= miniCacheMaxHeight && <ScrollNotification>{t('ScrollDown')}</ScrollNotification>}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Measure>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
import styled, { css } from 'styled-components'
|
|
||||||
import Measure from 'react-measure'
|
|
||||||
import { useState } from 'react'
|
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
|
|
||||||
import {
|
|
||||||
defaultBackgroundColor,
|
|
||||||
defaultBorderColor,
|
|
||||||
progressColor,
|
|
||||||
completeColor,
|
|
||||||
activeColor,
|
|
||||||
rangeColor,
|
|
||||||
} from './colors'
|
|
||||||
import getShortCacheMap from './getShortCacheMap'
|
|
||||||
|
|
||||||
const borderWidth = 1
|
|
||||||
const defaultPieceSize = 14
|
|
||||||
const pieceSizeForMiniMap = 23
|
|
||||||
const gapBetweenPieces = 3
|
|
||||||
const miniCacheMaxHeight = 340
|
|
||||||
|
|
||||||
const ScrollNotification = styled.div`
|
|
||||||
margin-top: 10px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
color: rgba(0, 0, 0, 0.5);
|
|
||||||
align-self: center;
|
|
||||||
`
|
|
||||||
|
|
||||||
const SnakeWrapper = styled.div`
|
|
||||||
${({ pieceSize, piecesInOneRow }) => css`
|
|
||||||
display: grid;
|
|
||||||
gap: ${gapBetweenPieces}px;
|
|
||||||
grid-template-columns: repeat(${piecesInOneRow || 'auto-fit'}, ${pieceSize}px);
|
|
||||||
grid-auto-rows: max-content;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
${piecesInOneRow &&
|
|
||||||
css`
|
|
||||||
max-height: ${miniCacheMaxHeight}px;
|
|
||||||
overflow: auto;
|
|
||||||
`}
|
|
||||||
|
|
||||||
.piece {
|
|
||||||
width: ${pieceSize}px;
|
|
||||||
height: ${pieceSize}px;
|
|
||||||
background: ${defaultBackgroundColor};
|
|
||||||
border: ${borderWidth}px solid ${defaultBorderColor};
|
|
||||||
display: grid;
|
|
||||||
align-items: end;
|
|
||||||
|
|
||||||
&-loading {
|
|
||||||
background: ${progressColor};
|
|
||||||
border-color: ${progressColor};
|
|
||||||
}
|
|
||||||
&-complete {
|
|
||||||
background: ${completeColor};
|
|
||||||
border-color: ${completeColor};
|
|
||||||
}
|
|
||||||
&-reader {
|
|
||||||
border-color: ${activeColor};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.reader-range {
|
|
||||||
border-color: ${rangeColor};
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
`
|
|
||||||
|
|
||||||
const PercentagePiece = styled.div`
|
|
||||||
background: ${completeColor};
|
|
||||||
height: ${({ percentage }) => (percentage / 100) * 12}px;
|
|
||||||
`
|
|
||||||
|
|
||||||
export default function LargeSnake({ cacheMap, isMini, preloadPiecesAmount }) {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
|
|
||||||
const pieceSize = isMini ? pieceSizeForMiniMap : defaultPieceSize
|
|
||||||
|
|
||||||
let piecesInOneRow
|
|
||||||
let shotCacheMap
|
|
||||||
if (isMini) {
|
|
||||||
const pieceSizeWithGap = pieceSize + gapBetweenPieces
|
|
||||||
piecesInOneRow = Math.floor((dimensions.width * 0.95) / pieceSizeWithGap)
|
|
||||||
shotCacheMap = isMini && getShortCacheMap({ cacheMap, preloadPiecesAmount, piecesInOneRow })
|
|
||||||
}
|
|
||||||
|
|
||||||
return isMini ? (
|
|
||||||
<Measure bounds onResize={({ bounds }) => setDimensions(bounds)}>
|
|
||||||
{({ measureRef }) => (
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
||||||
<SnakeWrapper ref={measureRef} pieceSize={pieceSize} piecesInOneRow={piecesInOneRow}>
|
|
||||||
{shotCacheMap.map(({ className, id, percentage }) => (
|
|
||||||
<span key={id || uuidv4()} className={className}>
|
|
||||||
{percentage > 0 && percentage <= 100 && <PercentagePiece percentage={percentage} />}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</SnakeWrapper>
|
|
||||||
|
|
||||||
{dimensions.height >= miniCacheMaxHeight && <ScrollNotification>{t('ScrollDown')}</ScrollNotification>}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Measure>
|
|
||||||
) : (
|
|
||||||
<SnakeWrapper pieceSize={pieceSize}>
|
|
||||||
{cacheMap.map(({ className, id, percentage }) => (
|
|
||||||
<span key={id || uuidv4()} className={className}>
|
|
||||||
{percentage > 0 && percentage <= 100 && <PercentagePiece percentage={percentage} />}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</SnakeWrapper>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
import { Rect } from 'react-konva'
|
|
||||||
|
|
||||||
import { activeColor, completeColor, defaultBorderColor, progressColor, rangeColor } from './colors'
|
|
||||||
|
|
||||||
export default function SingleBlock({
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
percentage,
|
|
||||||
isActive = false,
|
|
||||||
inProgress = false,
|
|
||||||
isReaderRange = false,
|
|
||||||
isComplete = false,
|
|
||||||
boxHeight,
|
|
||||||
strokeWidth,
|
|
||||||
}) {
|
|
||||||
const strokeColor = isActive
|
|
||||||
? activeColor
|
|
||||||
: isComplete
|
|
||||||
? completeColor
|
|
||||||
: inProgress
|
|
||||||
? progressColor
|
|
||||||
: isReaderRange
|
|
||||||
? rangeColor
|
|
||||||
: defaultBorderColor
|
|
||||||
const backgroundColor = inProgress ? progressColor : defaultBorderColor
|
|
||||||
const percentageProgressColor = completeColor
|
|
||||||
const processCompletedColor = completeColor
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Rect
|
|
||||||
x={x}
|
|
||||||
y={y}
|
|
||||||
stroke={strokeColor}
|
|
||||||
strokeWidth={strokeWidth}
|
|
||||||
height={boxHeight}
|
|
||||||
width={boxHeight}
|
|
||||||
fillAfterStrokeEnabled
|
|
||||||
preventDefault={false}
|
|
||||||
{...(isComplete
|
|
||||||
? { fill: processCompletedColor }
|
|
||||||
: inProgress && {
|
|
||||||
fillLinearGradientStartPointY: boxHeight,
|
|
||||||
fillLinearGradientEndPointY: 0,
|
|
||||||
fillLinearGradientColorStops: [
|
|
||||||
0,
|
|
||||||
percentageProgressColor,
|
|
||||||
percentage,
|
|
||||||
percentageProgressColor,
|
|
||||||
percentage,
|
|
||||||
backgroundColor,
|
|
||||||
],
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
export const defaultBorderColor = '#eef2f4'
|
|
||||||
export const defaultBackgroundColor = '#fff'
|
|
||||||
export const completeColor = '#00a572'
|
|
||||||
export const progressColor = '#ffa724'
|
|
||||||
export const activeColor = '#000'
|
|
||||||
export const rangeColor = '#9a9aff'
|
|
||||||
|
|
||||||
export const getLargeSnakeColors = ({ isActive, isComplete, inProgress, isReaderRange, percentage }) => {
|
|
||||||
const gradientBackgroundColor = inProgress ? progressColor : defaultBackgroundColor
|
|
||||||
const gradient = `linear-gradient(to top, ${completeColor} 0%, ${completeColor} ${
|
|
||||||
percentage * 100
|
|
||||||
}%, ${gradientBackgroundColor} ${percentage * 100}%, ${gradientBackgroundColor} 100%)`
|
|
||||||
|
|
||||||
const borderColor = isActive
|
|
||||||
? activeColor
|
|
||||||
: isComplete
|
|
||||||
? completeColor
|
|
||||||
: inProgress
|
|
||||||
? progressColor
|
|
||||||
: isReaderRange
|
|
||||||
? rangeColor
|
|
||||||
: defaultBorderColor
|
|
||||||
const backgroundColor = isComplete ? completeColor : inProgress ? gradient : defaultBackgroundColor
|
|
||||||
|
|
||||||
return { borderColor, backgroundColor }
|
|
||||||
}
|
|
||||||
@@ -1,18 +1,59 @@
|
|||||||
import { memo } from 'react'
|
import Measure from 'react-measure'
|
||||||
|
import { useState, memo } from 'react'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import isEqual from 'lodash/isEqual'
|
import isEqual from 'lodash/isEqual'
|
||||||
|
|
||||||
import { useCreateCacheMap } from '../customHooks'
|
import { useCreateCacheMap } from '../customHooks'
|
||||||
import LargeSnake from './LargeSnake'
|
import { gapBetweenPieces, miniCacheMaxHeight, pieceSizeForMiniMap, defaultPieceSize } from './snakeSettings'
|
||||||
|
import getShortCacheMap from './getShortCacheMap'
|
||||||
|
import { SnakeWrapper, PercentagePiece, ScrollNotification } from './style'
|
||||||
|
|
||||||
const TorrentCache = memo(
|
const TorrentCache = ({ cache, isMini }) => {
|
||||||
({ cache, isMini }) => {
|
const { t } = useTranslation()
|
||||||
const cacheMap = useCreateCacheMap(cache)
|
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
|
||||||
|
const cacheMap = useCreateCacheMap(cache)
|
||||||
|
|
||||||
const preloadPiecesAmount = Math.round(cache.Capacity / cache.PiecesLength - 1)
|
const preloadPiecesAmount = Math.round(cache.Capacity / cache.PiecesLength - 1)
|
||||||
|
|
||||||
return <LargeSnake isMini={isMini} cacheMap={cacheMap} preloadPiecesAmount={preloadPiecesAmount} />
|
const pieceSize = isMini ? pieceSizeForMiniMap : defaultPieceSize
|
||||||
},
|
|
||||||
|
let piecesInOneRow
|
||||||
|
let shotCacheMap
|
||||||
|
if (isMini) {
|
||||||
|
const pieceSizeWithGap = pieceSize + gapBetweenPieces
|
||||||
|
piecesInOneRow = Math.floor((dimensions.width * 0.95) / pieceSizeWithGap)
|
||||||
|
shotCacheMap = isMini && getShortCacheMap({ cacheMap, preloadPiecesAmount, piecesInOneRow })
|
||||||
|
}
|
||||||
|
|
||||||
|
return isMini ? (
|
||||||
|
<Measure bounds onResize={({ bounds }) => setDimensions(bounds)}>
|
||||||
|
{({ measureRef }) => (
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
|
<SnakeWrapper ref={measureRef} pieceSize={pieceSize} piecesInOneRow={piecesInOneRow}>
|
||||||
|
{shotCacheMap.map(({ className, id, percentage }) => (
|
||||||
|
<span key={id || uuidv4()} className={className}>
|
||||||
|
{percentage > 0 && percentage <= 100 && <PercentagePiece percentage={percentage} />}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</SnakeWrapper>
|
||||||
|
|
||||||
|
{dimensions.height >= miniCacheMaxHeight && <ScrollNotification>{t('ScrollDown')}</ScrollNotification>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Measure>
|
||||||
|
) : (
|
||||||
|
<SnakeWrapper pieceSize={pieceSize}>
|
||||||
|
{cacheMap.map(({ className, id, percentage }) => (
|
||||||
|
<span key={id || uuidv4()} className={className}>
|
||||||
|
{percentage > 0 && percentage <= 100 && <PercentagePiece percentage={percentage} />}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</SnakeWrapper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(
|
||||||
|
TorrentCache,
|
||||||
(prev, next) => isEqual(prev.cache.Pieces, next.cache.Pieces) && isEqual(prev.cache.Readers, next.cache.Readers),
|
(prev, next) => isEqual(prev.cache.Pieces, next.cache.Pieces) && isEqual(prev.cache.Readers, next.cache.Readers),
|
||||||
)
|
)
|
||||||
|
|
||||||
export default TorrentCache
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export const borderWidth = 1
|
||||||
|
export const defaultPieceSize = 14
|
||||||
|
export const pieceSizeForMiniMap = 23
|
||||||
|
export const gapBetweenPieces = 3
|
||||||
|
export const miniCacheMaxHeight = 340
|
||||||
|
|
||||||
|
export const defaultBorderColor = '#eef2f4'
|
||||||
|
export const defaultBackgroundColor = '#fff'
|
||||||
|
export const completeColor = '#00a572'
|
||||||
|
export const progressColor = '#ffa724'
|
||||||
|
export const activeColor = '#000'
|
||||||
|
export const rangeColor = '#9a9aff'
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import styled, { css } from 'styled-components'
|
||||||
|
|
||||||
|
import {
|
||||||
|
defaultBackgroundColor,
|
||||||
|
defaultBorderColor,
|
||||||
|
progressColor,
|
||||||
|
completeColor,
|
||||||
|
activeColor,
|
||||||
|
rangeColor,
|
||||||
|
gapBetweenPieces,
|
||||||
|
miniCacheMaxHeight,
|
||||||
|
borderWidth,
|
||||||
|
} from './snakeSettings'
|
||||||
|
|
||||||
|
export const ScrollNotification = styled.div`
|
||||||
|
margin-top: 10px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
align-self: center;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const SnakeWrapper = styled.div`
|
||||||
|
${({ pieceSize, piecesInOneRow }) => css`
|
||||||
|
display: grid;
|
||||||
|
gap: ${gapBetweenPieces}px;
|
||||||
|
grid-template-columns: repeat(${piecesInOneRow || 'auto-fit'}, ${pieceSize}px);
|
||||||
|
grid-auto-rows: max-content;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
${piecesInOneRow &&
|
||||||
|
css`
|
||||||
|
max-height: ${miniCacheMaxHeight}px;
|
||||||
|
overflow: auto;
|
||||||
|
`}
|
||||||
|
|
||||||
|
.piece {
|
||||||
|
width: ${pieceSize}px;
|
||||||
|
height: ${pieceSize}px;
|
||||||
|
background: ${defaultBackgroundColor};
|
||||||
|
border: ${borderWidth}px solid ${defaultBorderColor};
|
||||||
|
display: grid;
|
||||||
|
align-items: end;
|
||||||
|
|
||||||
|
&-loading {
|
||||||
|
background: ${progressColor};
|
||||||
|
border-color: ${progressColor};
|
||||||
|
}
|
||||||
|
&-complete {
|
||||||
|
background: ${completeColor};
|
||||||
|
border-color: ${completeColor};
|
||||||
|
}
|
||||||
|
&-reader {
|
||||||
|
border-color: ${activeColor};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reader-range {
|
||||||
|
border-color: ${rangeColor};
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const PercentagePiece = styled.div`
|
||||||
|
background: ${completeColor};
|
||||||
|
height: ${({ percentage }) => (percentage / 100) * 12}px;
|
||||||
|
`
|
||||||
@@ -7938,11 +7938,6 @@ klona@^2.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
|
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
|
||||||
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
|
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
|
||||||
|
|
||||||
konva@^8.0.1:
|
|
||||||
version "8.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/konva/-/konva-8.0.1.tgz#f34f483cdf62c36f966addc1a7484ed694313c2b"
|
|
||||||
integrity sha512-QDppGS1L5Dhod1zjwy9GVVjeyfPBHnPncL5oRh1NyjR1mEvhrLjzflrkdW+p73uFIW9hwCDZVLGxzzjQre9izw==
|
|
||||||
|
|
||||||
language-subtag-registry@~0.3.2:
|
language-subtag-registry@~0.3.2:
|
||||||
version "0.3.21"
|
version "0.3.21"
|
||||||
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
|
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
|
||||||
@@ -10472,14 +10467,6 @@ react-is@^16.7.0, react-is@^16.8.1:
|
|||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||||
|
|
||||||
react-konva@^17.0.2-4:
|
|
||||||
version "17.0.2-4"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-konva/-/react-konva-17.0.2-4.tgz#afd0968e1295b624bf2a7a154ba294e0d5be55cd"
|
|
||||||
integrity sha512-YvRVPT81y8sMQV1SY1/tIDetGxBK+7Rk86u4LmiyDBLLE17vD78F01b8EC3AuP3nI3hUaTblfBugUF35cm6Etg==
|
|
||||||
dependencies:
|
|
||||||
react-reconciler "~0.26.2"
|
|
||||||
scheduler "^0.20.2"
|
|
||||||
|
|
||||||
react-measure@^2.5.2:
|
react-measure@^2.5.2:
|
||||||
version "2.5.2"
|
version "2.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-2.5.2.tgz#4ffc410e8b9cb836d9455a9ff18fc1f0fca67f89"
|
resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-2.5.2.tgz#4ffc410e8b9cb836d9455a9ff18fc1f0fca67f89"
|
||||||
@@ -10499,15 +10486,6 @@ react-query@^3.17.0:
|
|||||||
broadcast-channel "^3.4.1"
|
broadcast-channel "^3.4.1"
|
||||||
match-sorter "^6.0.2"
|
match-sorter "^6.0.2"
|
||||||
|
|
||||||
react-reconciler@~0.26.2:
|
|
||||||
version "0.26.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.26.2.tgz#bbad0e2d1309423f76cf3c3309ac6c96e05e9d91"
|
|
||||||
integrity sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
scheduler "^0.20.2"
|
|
||||||
|
|
||||||
react-refresh@^0.8.3:
|
react-refresh@^0.8.3:
|
||||||
version "0.8.3"
|
version "0.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
|
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
|
||||||
|
|||||||
Reference in New Issue
Block a user