mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-08 04:50:12 +02:00
Update player/shared components
This commit is contained in:
+28
-34
@@ -1,20 +1,14 @@
|
||||
import { ReactNode, useEffect } from 'react';
|
||||
import {
|
||||
DndContext,
|
||||
MouseSensor,
|
||||
TouchSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from '@dnd-kit/core';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import { useLocalStorage } from '@mantine/hooks';
|
||||
import { ModalsProvider } from '@mantine/modals';
|
||||
import { NotificationsProvider } from '@mantine/notifications';
|
||||
import isElectron from 'is-electron';
|
||||
import { BrowserRouter, HashRouter } from 'react-router-dom';
|
||||
import { useDefaultSettings } from './features/settings';
|
||||
import { AppRouter } from './router/AppRouter';
|
||||
import { AppRouter } from './router/app-router';
|
||||
import './styles/global.scss';
|
||||
import 'ag-grid-community/styles/ag-grid.css';
|
||||
import './styles/ag-grid.scss';
|
||||
|
||||
const SelectRouter = ({ children }: { children: ReactNode }) => {
|
||||
if (isElectron()) {
|
||||
@@ -36,27 +30,16 @@ export const App = () => {
|
||||
document.body.setAttribute('data-theme', theme);
|
||||
}, [theme]);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(MouseSensor, {
|
||||
activationConstraint: {
|
||||
delay: 200,
|
||||
tolerance: 100,
|
||||
},
|
||||
}),
|
||||
useSensor(TouchSensor, {
|
||||
activationConstraint: {
|
||||
delay: 500,
|
||||
tolerance: 10,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
return (
|
||||
<MantineProvider
|
||||
withGlobalStyles
|
||||
withNormalizeCSS
|
||||
theme={{
|
||||
colorScheme: 'dark',
|
||||
defaultRadius: 'xs',
|
||||
focusRing: 'auto',
|
||||
dir: 'ltr',
|
||||
focusRing: 'never',
|
||||
fontFamily: 'Poppins, sans-serif',
|
||||
fontSizes: {
|
||||
lg: 16,
|
||||
md: 14,
|
||||
@@ -64,22 +47,33 @@ export const App = () => {
|
||||
xl: 18,
|
||||
xs: 10,
|
||||
},
|
||||
|
||||
other: {},
|
||||
spacing: {
|
||||
lg: 12,
|
||||
md: 8,
|
||||
sm: 4,
|
||||
xl: 16,
|
||||
xs: 2,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
onDragEnd={() => console.log('drag end')}
|
||||
onDragStart={() => console.log('drag start')}
|
||||
<NotificationsProvider
|
||||
autoClose={1500}
|
||||
position="bottom-right"
|
||||
style={{
|
||||
marginBottom: '90px',
|
||||
opacity: '.8',
|
||||
userSelect: 'none',
|
||||
width: '250px',
|
||||
}}
|
||||
transitionDuration={200}
|
||||
>
|
||||
<SelectRouter>
|
||||
<AppRouter />
|
||||
</SelectRouter>
|
||||
</DndContext>
|
||||
<ModalsProvider>
|
||||
<SelectRouter>
|
||||
<AppRouter />
|
||||
</SelectRouter>
|
||||
</ModalsProvider>
|
||||
</NotificationsProvider>
|
||||
</MantineProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Ref, useMemo } from 'react';
|
||||
import { FixedSizeList, FixedSizeListProps } from 'react-window';
|
||||
import { GridCard } from '@/renderer/components/virtual-grid/grid-card';
|
||||
import { usePlayQueueHandler } from '@/renderer/features/player/hooks/usePlayQueueHandler';
|
||||
import { usePlayQueueHandler } from '@/renderer/features/player/hooks/use-playqueue-handler';
|
||||
import { CardRow } from '@/renderer/types';
|
||||
|
||||
export const VirtualGridWrapper = ({
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useRef } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import styled from '@emotion/styled';
|
||||
import { PlaybackType } from '../../../../types';
|
||||
import { AudioPlayer } from '../../../components';
|
||||
import { usePlayerStore } from '../../../store';
|
||||
import { CenterControls } from './CenterControls';
|
||||
import { LeftControls } from './LeftControls';
|
||||
import { RightControls } from './RightControls';
|
||||
import { CenterControls } from './center-controls';
|
||||
import { LeftControls } from './left-controls';
|
||||
import { RightControls } from './right-controls';
|
||||
|
||||
const PlayerbarContainer = styled.div`
|
||||
width: 100%;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import format from 'format-duration';
|
||||
import ReactSlider, { ReactSliderProps } from 'react-slider';
|
||||
import styled from 'styled-components';
|
||||
|
||||
interface SliderProps extends ReactSliderProps {
|
||||
hasTooltip?: boolean;
|
||||
|
||||
+17
-19
@@ -1,22 +1,22 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import format from 'format-duration';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
RiPauseLine,
|
||||
RiPlayFill,
|
||||
RiRewindFill,
|
||||
RiRepeat2Fill,
|
||||
RiShuffleFill,
|
||||
RiSkipBackFill,
|
||||
RiSkipForwardFill,
|
||||
RiSpeedFill,
|
||||
} from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
import { PlaybackType, PlayerStatus } from '../../../../types';
|
||||
import { Text } from '../../../components';
|
||||
import { usePlayerStore } from '../../../store';
|
||||
import { Font } from '../../../styles';
|
||||
import { useCenterControls } from '../hooks/useCenterControls';
|
||||
import { PlayerButton } from './PlayerButton';
|
||||
import { Slider } from './Slider';
|
||||
import { useCenterControls } from '../hooks/use-center-controls';
|
||||
import { PlayerButton } from './player-button';
|
||||
import { Slider } from './slider';
|
||||
|
||||
interface CenterControlsProps {
|
||||
playersRef: any;
|
||||
@@ -67,8 +67,6 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
||||
handlePlayPause,
|
||||
handlePrevTrack,
|
||||
handleSeekSlider,
|
||||
handleSkipBackward,
|
||||
handleSkipForward,
|
||||
} = useCenterControls({ playersRef });
|
||||
|
||||
const currentTime = usePlayerStore((state) => state.current.time);
|
||||
@@ -106,16 +104,16 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
||||
<ControlsContainer onScroll={(e) => console.log(e)}>
|
||||
<ButtonsContainer>
|
||||
<PlayerButton
|
||||
icon={<RiSkipBackFill size={15} />}
|
||||
tooltip={{ label: `${t('player.prev')}` }}
|
||||
icon={<RiShuffleFill size={15} />}
|
||||
tooltip={{ label: `${t('player.shuffle')}` }}
|
||||
variant="secondary"
|
||||
onClick={handlePrevTrack}
|
||||
/>
|
||||
<PlayerButton
|
||||
icon={<RiRewindFill size={15} />}
|
||||
tooltip={{ label: `${t('player.skipBack')}` }}
|
||||
icon={<RiSkipBackFill size={15} />}
|
||||
tooltip={{ label: `${t('player.previous')}` }}
|
||||
variant="secondary"
|
||||
onClick={handleSkipBackward}
|
||||
onClick={handlePrevTrack}
|
||||
/>
|
||||
<PlayerButton
|
||||
icon={
|
||||
@@ -134,18 +132,18 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
||||
variant="main"
|
||||
onClick={handlePlayPause}
|
||||
/>
|
||||
<PlayerButton
|
||||
icon={<RiSpeedFill size={15} />}
|
||||
tooltip={{ label: `${t('player.skipForward')}` }}
|
||||
variant="secondary"
|
||||
onClick={handleSkipForward}
|
||||
/>
|
||||
<PlayerButton
|
||||
icon={<RiSkipForwardFill size={15} />}
|
||||
tooltip={{ label: `${t('player.next')}` }}
|
||||
variant="secondary"
|
||||
onClick={handleNextTrack}
|
||||
/>
|
||||
<PlayerButton
|
||||
icon={<RiRepeat2Fill size={15} />}
|
||||
tooltip={{ label: `${t('player.repeat')}` }}
|
||||
variant="secondary"
|
||||
onClick={handleNextTrack}
|
||||
/>
|
||||
</ButtonsContainer>
|
||||
</ControlsContainer>
|
||||
<SliderContainer>
|
||||
+4
-2
@@ -1,4 +1,4 @@
|
||||
import styled from 'styled-components';
|
||||
import styled from '@emotion/styled';
|
||||
import { Text } from '../../../components';
|
||||
import { usePlayerStore } from '../../../store';
|
||||
import { Font } from '../../../styles';
|
||||
@@ -34,7 +34,9 @@ export const LeftControls = () => {
|
||||
return (
|
||||
<LeftControlsContainer>
|
||||
<ImageWrapper>
|
||||
<img alt="img" height={60} src={song?.imageUrl} width={60} />
|
||||
{song?.imageUrl && (
|
||||
<img alt="img" height={60} src={song?.imageUrl} width={60} />
|
||||
)}
|
||||
</ImageWrapper>
|
||||
<MetadataStack>
|
||||
<Text
|
||||
+11
-12
@@ -1,11 +1,12 @@
|
||||
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
TooltipProps,
|
||||
UnstyledButton,
|
||||
UnstyledButtonProps,
|
||||
} from '@mantine/core';
|
||||
import { motion } from 'framer-motion';
|
||||
import styled, { css } from 'styled-components';
|
||||
import { Tooltip } from '../../../components';
|
||||
|
||||
type MantineButtonProps = UnstyledButtonProps &
|
||||
@@ -32,17 +33,11 @@ const MotionWrapper = styled(motion.div)<MotionWrapperProps>`
|
||||
|
||||
const ButtonMainVariant = css`
|
||||
padding: 0.5rem;
|
||||
background: var(--playerbar-btn-color);
|
||||
border: 2px solid var(--playerbar-btn-color);
|
||||
border-radius: 50%;
|
||||
|
||||
svg {
|
||||
display: flex;
|
||||
fill: black;
|
||||
stroke: black;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--playerbar-btn-color-hover);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
@@ -109,13 +104,17 @@ export const PlayerButton = ({
|
||||
}: PlayerButtonProps) => {
|
||||
if (tooltip) {
|
||||
return (
|
||||
<MotionWrapper variant={variant}>
|
||||
<Tooltip {...tooltip}>
|
||||
<Tooltip {...tooltip}>
|
||||
<MotionWrapper
|
||||
variant={variant}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
<StyledPlayerButton variant={variant} {...rest}>
|
||||
{icon}
|
||||
</StyledPlayerButton>
|
||||
</Tooltip>
|
||||
</MotionWrapper>
|
||||
</MotionWrapper>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
+9
-11
@@ -1,9 +1,9 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { RiVolumeUpFill, RiVolumeMuteFill } from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
import { IconButton } from '../../../components';
|
||||
import { usePlayerStore } from '../../../store';
|
||||
import { useRightControls } from '../hooks/useRightControls';
|
||||
import { Slider } from './Slider';
|
||||
import { useRightControls } from '../hooks/use-right-controls';
|
||||
import { PlayerButton } from './player-button';
|
||||
import { Slider } from './slider';
|
||||
|
||||
const RightControlsContainer = styled.div`
|
||||
display: flex;
|
||||
@@ -39,23 +39,21 @@ export const RightControls = () => {
|
||||
<RightControlsContainer>
|
||||
<MetadataStack>
|
||||
<VolumeSliderWrapper>
|
||||
<IconButton
|
||||
<PlayerButton
|
||||
icon={
|
||||
muted ? (
|
||||
<RiVolumeMuteFill size={20} />
|
||||
<RiVolumeMuteFill size={15} />
|
||||
) : (
|
||||
<RiVolumeUpFill size={20} />
|
||||
<RiVolumeUpFill size={15} />
|
||||
)
|
||||
}
|
||||
size={20}
|
||||
tooltip={{ label: muted ? 'Muted' : volume }}
|
||||
variant="transparent"
|
||||
variant="secondary"
|
||||
onClick={handleMute}
|
||||
/>
|
||||
|
||||
<Slider
|
||||
hasTooltip
|
||||
height="100%"
|
||||
height="60%"
|
||||
max={100}
|
||||
min={0}
|
||||
value={volume}
|
||||
+9
-9
@@ -42,7 +42,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
||||
};
|
||||
|
||||
const handlePlay = useCallback(() => {
|
||||
if (settings.type === PlaybackType.Local) {
|
||||
if (settings.type === PlaybackType.LOCAL) {
|
||||
mpvPlayer.play();
|
||||
} else {
|
||||
currentPlayerRef.getInternalPlayer().play();
|
||||
@@ -52,7 +52,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
||||
}, [currentPlayerRef, play, settings]);
|
||||
|
||||
const handlePause = useCallback(() => {
|
||||
if (settings.type === PlaybackType.Local) {
|
||||
if (settings.type === PlaybackType.LOCAL) {
|
||||
mpvPlayer.pause();
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
||||
}, [pause, settings]);
|
||||
|
||||
const handleStop = () => {
|
||||
if (settings.type === PlaybackType.Local) {
|
||||
if (settings.type === PlaybackType.LOCAL) {
|
||||
mpvPlayer.stop();
|
||||
} else {
|
||||
stopPlayback();
|
||||
@@ -73,7 +73,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
||||
const handleNextTrack = useCallback(() => {
|
||||
const playerData = next();
|
||||
|
||||
if (settings.type === PlaybackType.Local) {
|
||||
if (settings.type === PlaybackType.LOCAL) {
|
||||
mpvPlayer.setQueue(playerData);
|
||||
mpvPlayer.next();
|
||||
} else {
|
||||
@@ -86,7 +86,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
||||
const handlePrevTrack = useCallback(() => {
|
||||
const playerData = prev();
|
||||
|
||||
if (settings.type === PlaybackType.Local) {
|
||||
if (settings.type === PlaybackType.LOCAL) {
|
||||
mpvPlayer.setQueue(playerData);
|
||||
mpvPlayer.previous();
|
||||
} else {
|
||||
@@ -98,7 +98,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
||||
|
||||
const handlePlayPause = useCallback(() => {
|
||||
if (queue) {
|
||||
if (playerStatus === PlayerStatus.Paused) {
|
||||
if (playerStatus === PlayerStatus.PAUSED) {
|
||||
return handlePlay();
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
||||
const handleSkipBackward = () => {
|
||||
const skipBackwardSec = 5;
|
||||
|
||||
if (settings.type === PlaybackType.Local) {
|
||||
if (settings.type === PlaybackType.LOCAL) {
|
||||
const newTime = currentTime - skipBackwardSec;
|
||||
mpvPlayer.seek(-skipBackwardSec);
|
||||
setCurrentTime(newTime < 0 ? 0 : newTime);
|
||||
@@ -126,7 +126,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
||||
const handleSkipForward = () => {
|
||||
const skipForwardSec = 5;
|
||||
|
||||
if (settings.type === PlaybackType.Local) {
|
||||
if (settings.type === PlaybackType.LOCAL) {
|
||||
const newTime = currentTime + skipForwardSec;
|
||||
mpvPlayer.seek(skipForwardSec);
|
||||
setCurrentTime(newTime);
|
||||
@@ -147,7 +147,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
||||
(e: number | any) => {
|
||||
setCurrentTime(e);
|
||||
|
||||
if (settings.type === PlaybackType.Local) {
|
||||
if (settings.type === PlaybackType.LOCAL) {
|
||||
mpvPlayer.seekTo(e);
|
||||
} else {
|
||||
currentPlayerRef.seekTo(e);
|
||||
+28
-26
@@ -1,23 +1,19 @@
|
||||
import { api } from '@/renderer/api';
|
||||
import { Item, Play } from '../../../../types';
|
||||
import { albumsApi } from '../../../api/albumsApi';
|
||||
import { usePlayerStore } from '../../../store';
|
||||
import {
|
||||
getJellyfinStreamUrl,
|
||||
getServerFolderAuth,
|
||||
getSubsonicStreamUrl,
|
||||
} from '../../../utils';
|
||||
import { useAuthStore, usePlayerStore } from '../../../store';
|
||||
import { mpvPlayer } from '../utils/mpvPlayer';
|
||||
|
||||
const getEndpointByItemType = (item: Item) => {
|
||||
switch (item) {
|
||||
case Item.ALBUM:
|
||||
return albumsApi.getAlbum;
|
||||
return api.albums.getAlbumDetail;
|
||||
default:
|
||||
return albumsApi.getAlbum;
|
||||
return api.albums.getAlbumDetail;
|
||||
}
|
||||
};
|
||||
|
||||
export const usePlayQueueHandler = () => {
|
||||
const serverId = useAuthStore((state) => state.currentServer?.id) || '';
|
||||
const addToQueue = usePlayerStore((state) => state.addToQueue);
|
||||
|
||||
const handlePlayQueueAdd = async (options: {
|
||||
@@ -35,36 +31,42 @@ export const usePlayQueueHandler = () => {
|
||||
|
||||
if (options.byItemType) {
|
||||
const deviceId = localStorage.getItem('device_id');
|
||||
const { serverUrl } = JSON.parse(
|
||||
localStorage.getItem('authentication') || '{}'
|
||||
);
|
||||
// const { state } = JSON.parse(
|
||||
// localStorage.getItem('authentication') || '{}'
|
||||
// );
|
||||
|
||||
if (deviceId) {
|
||||
const endpoint = getEndpointByItemType(options.byItemType.type);
|
||||
|
||||
const { data } = await endpoint({
|
||||
id: options.byItemType.id,
|
||||
albumId: options.byItemType.id,
|
||||
serverId,
|
||||
});
|
||||
|
||||
const songs = data.songs.map((song) => {
|
||||
const auth = getServerFolderAuth(serverUrl, song.serverFolderId);
|
||||
const songs = data.songs?.map((song) => {
|
||||
// const auth = getServerFolderAuth(
|
||||
// state.serverUrl,
|
||||
// song.serverFolderId
|
||||
// );
|
||||
|
||||
if (auth) {
|
||||
const streamUrl =
|
||||
auth.type === 'jellyfin'
|
||||
? getJellyfinStreamUrl(auth, song, deviceId)
|
||||
: getSubsonicStreamUrl(auth, song, deviceId);
|
||||
// if (auth) {
|
||||
// const streamUrl =
|
||||
// auth.type === 'jellyfin'
|
||||
// ? getJellyfinStreamUrl(auth, song, deviceId)
|
||||
// : getSubsonicStreamUrl(auth, song, deviceId);
|
||||
|
||||
return {
|
||||
...song,
|
||||
streamUrl,
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// ...song,
|
||||
// streamUrl,
|
||||
// };
|
||||
// }
|
||||
|
||||
return song;
|
||||
});
|
||||
|
||||
const playerData = addToQueue(songs, options.play);
|
||||
const playerData = addToQueue(songs || [], options.play);
|
||||
|
||||
console.log('playerData', playerData);
|
||||
|
||||
if (options.play === Play.NEXT || options.play === Play.LAST) {
|
||||
mpvPlayer.setQueueNext(playerData);
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from './components/CenterControls';
|
||||
export * from './components/LeftControls';
|
||||
export * from './components/Playerbar';
|
||||
export * from './components/Slider';
|
||||
export * from './components/center-controls';
|
||||
export * from './components/left-controls';
|
||||
export * from './components/playerbar';
|
||||
export * from './components/slider';
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { ReactNode } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { motion } from 'framer-motion';
|
||||
import styled from 'styled-components';
|
||||
|
||||
interface AnimatedPageProps {
|
||||
children: ReactNode;
|
||||
@@ -0,0 +1,22 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useAuthStore } from '@/renderer/store';
|
||||
|
||||
export const usePermissions = () => {
|
||||
const permissions = useAuthStore((state) => state.permissions);
|
||||
|
||||
const permissionSet = useMemo(() => {
|
||||
const set = {
|
||||
createServer: permissions.isAdmin,
|
||||
createServerCredential: true,
|
||||
createServerUrl: permissions.isAdmin,
|
||||
deleteServer: permissions.isAdmin,
|
||||
deleteServerCredential: true,
|
||||
deleteServerUrl: permissions.isAdmin,
|
||||
editServer: permissions.isAdmin,
|
||||
};
|
||||
|
||||
return set;
|
||||
}, [permissions]);
|
||||
|
||||
return permissionSet;
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './components/animated-page';
|
||||
export * from './hooks/use-permissions';
|
||||
@@ -1,11 +1,11 @@
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
RiDashboardFill,
|
||||
RiFileList2Fill,
|
||||
RiSearch2Fill,
|
||||
RiSearch2Line,
|
||||
} from 'react-icons/ri';
|
||||
import styled from 'styled-components';
|
||||
import { AppRoute } from '../../../router/utils/routes';
|
||||
import { ListItem } from './ListItem';
|
||||
import { AppRoute } from '../../../router/routes';
|
||||
import { ListItem } from './list-item';
|
||||
|
||||
const StyledSidebar = styled.div``;
|
||||
|
||||
@@ -19,15 +19,15 @@ export const Sidebar = () => {
|
||||
</ListItem.Link>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItem.Link to={AppRoute.SEARCH}>
|
||||
<RiSearch2Fill size={20} />
|
||||
Search
|
||||
<ListItem.Link to={AppRoute.LIBRARY}>
|
||||
<RiFileList2Fill size={20} />
|
||||
Library
|
||||
</ListItem.Link>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItem.Link to={AppRoute.LIBRARY}>
|
||||
<RiFileList2Fill size={20} />
|
||||
Your Library
|
||||
<ListItem.Link to={AppRoute.SEARCH}>
|
||||
<RiSearch2Line size={20} />
|
||||
Search
|
||||
</ListItem.Link>
|
||||
</ListItem>
|
||||
</StyledSidebar>
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Link, LinkProps } from 'react-router-dom';
|
||||
import styled, { css } from 'styled-components';
|
||||
import { fontInter } from '../../../styles';
|
||||
|
||||
interface ListItemProps {
|
||||
@@ -1 +1 @@
|
||||
export * from './components/Sidebar';
|
||||
export * from './components/sidebar';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { QueryClientProvider } from 'react-query';
|
||||
import { queryClient } from '@/renderer/lib/react-query';
|
||||
import i18n from '../i18n/i18n';
|
||||
import { App } from './app';
|
||||
import { queryClient } from './lib';
|
||||
|
||||
const container = document.getElementById('root')!;
|
||||
const root = createRoot(container);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AppRoute } from './router/utils/routes';
|
||||
import { AppRoute } from './router/routes';
|
||||
|
||||
export interface CardRow {
|
||||
align?: 'left' | 'center' | 'right';
|
||||
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
import '@emotion/react';
|
||||
import type { MantineTheme } from '@mantine/core';
|
||||
|
||||
declare module '@emotion/react' {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface GREY extends MantineTheme {}
|
||||
}
|
||||
Reference in New Issue
Block a user