feat: updates

This commit is contained in:
qier222 2022-03-17 14:45:04 +08:00
parent 950f72d4e8
commit f54d2ded5c
No known key found for this signature in database
GPG Key ID: 9C85007ED905F14D
26 changed files with 361 additions and 166 deletions

View File

@ -3,7 +3,7 @@
* @see https://www.electron.build/configuration/configuration
*/
module.exports = {
appId: 'yesplaymusic',
appId: 'com.qier222.yesplaymusic',
productName: 'YesPlayMusic',
copyright: 'Copyright © 2022 ${author}',
asar: true,
@ -43,4 +43,19 @@ module.exports = {
target: ['AppImage'],
artifactName: '${productName}-${version}-Installer.${ext}',
},
files: [
'**/*',
'!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}',
'!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}',
'!**/node_modules/*.d.ts',
'!**/node_modules/.bin',
'!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}',
'!.editorconfig',
'!**/._*',
'!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}',
'!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}',
'!**/{appveyor.yml,.travis.yml,circle.yml}',
'!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json}',
'!**/node_modules/realm/react-native/**/*',
],
}

3
.gitignore vendored
View File

@ -86,3 +86,6 @@ release
dist-ssr
*.local
.vscode/settings.json
bundle-stats-main.html
bundle-stats-preload.html
bundle-stats-renderer.html

View File

@ -11,7 +11,7 @@
"main": "dist/main/index.cjs",
"scripts": {
"dev": "node scripts/watch.mjs",
"build": "npm run typecheck && node scripts/build.mjs && electron-builder --config .electron-builder.config.js",
"build": "npm run typecheck && node scripts/build.mjs && electron-builder --config .electron-builder.config.js --dir",
"typecheck": "tsc --noEmit --project packages/renderer/tsconfig.json",
"debug": "cross-env-shell NODE_ENV=debug \"npm run typecheck && node scripts/build.mjs && vite ./packages/renderer\"",
"eslint": "eslint --ext .ts,.js ./",
@ -26,11 +26,12 @@
"cookie-parser": "^1.4.6",
"electron-log": "^4.4.6",
"electron-store": "^8.0.1",
"express": "^4.17.3",
"realm": "^10.13.0"
"realm": "^10.13.0",
"express": "^4.17.3"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^3.2.0",
"@types/cookie-parser": "^1.4.2",
"@types/express": "^4.17.13",
"@types/howler": "^2.2.6",
"@types/js-cookie": "^3.0.1",

82
packages/main/database.ts Normal file
View File

@ -0,0 +1,82 @@
import Realm from 'realm'
import type { FetchTracksResponse } from '../renderer/src/api/track'
enum ModelNames {
TRACK = 'Track',
}
const TrackSchema = {
name: ModelNames.TRACK,
properties: {
id: 'int',
json: 'string',
updateAt: 'int',
},
primaryKey: 'id',
}
const realm = new Realm({
path: './dist/db.realm',
schema: [TrackSchema],
})
export const database = {
get: (model: ModelNames, key: number) => {
return realm.objectForPrimaryKey(model, key)
},
set: (model: ModelNames, key: number, value: any) => {
realm.create(
model,
{
id: key,
updateAt: ~~(Date.now() / 1000),
json: JSON.stringify(value),
},
'modified'
)
},
delete: (model: ModelNames, key: number) => {
realm.delete(realm.objectForPrimaryKey(model, key))
},
}
export function setTracks(data: FetchTracksResponse) {
const tracks = data.songs
if (!data.songs) return
const write = async () =>
realm.write(() => {
tracks.forEach(track => {
database.set(ModelNames.TRACK, track.id, track)
})
})
write()
}
export async function setCache(api: string, data: any) {
switch (api) {
case 'song_detail':
setTracks(data)
}
}
export function getCache(api: string, query: any) {
switch (api) {
case 'song_detail': {
const ids: string[] = query.ids.split(',')
const idsQuery = ids.map(id => `id = ${id}`).join(' OR ')
const tracksRaw = realm
.objects(ModelNames.TRACK)
.filtered(`(${idsQuery})`)
if (tracksRaw.length !== ids.length) {
return
}
const tracks = tracksRaw.map(track => JSON.parse(track.json))
return {
code: 200,
songs: tracks,
privileges: {},
}
}
}
}

View File

@ -4,16 +4,12 @@ import {
app,
shell,
} from 'electron'
import installExtension, {
REACT_DEVELOPER_TOOLS,
REDUX_DEVTOOLS,
} from 'electron-devtools-installer'
import Store from 'electron-store'
import { release } from 'os'
import { join } from 'path'
import Realm from 'realm'
import logger from './logger'
import './server'
import './database'
const isWindows = process.platform === 'win32'
const isMac = process.platform === 'darwin'
@ -104,6 +100,12 @@ app.whenReady().then(async () => {
// Install devtool extension
if (isDev) {
const {
default: installExtension,
REACT_DEVELOPER_TOOLS,
REDUX_DEVTOOLS,
// eslint-disable-next-line @typescript-eslint/no-var-requires
} = require('electron-devtools-installer')
installExtension(REACT_DEVELOPER_TOOLS.id).catch(err =>
console.log('An error occurred: ', err)
)

View File

@ -2,42 +2,44 @@ import { pathCase } from 'change-case'
import cookieParser from 'cookie-parser'
import express, { Request, Response } from 'express'
import logger from './logger'
import { getCache, setCache } from './database'
const neteaseApi = require('NeteaseCloudMusicApi')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const neteaseApi = require('NeteaseCloudMusicApi') as (params: any) => any[]
const app = express()
app.use(cookieParser())
const port = Number(process.env['ELECTRON_DEV_NETEASE_API_PORT'] ?? 3000)
Object.entries(neteaseApi).forEach(([name, handler]) => {
if (['serveNcmApi', 'getModulesDefinitions'].includes(name)) {
return
}
if (['serveNcmApi', 'getModulesDefinitions'].includes(name)) return
const wrappedHandler = async (req: Request, res: Response) => {
logger.info(`[server] Handling request: ${req.path}`)
// Get from cache
const cacheResult = getCache(name, req.query)
if (cacheResult) {
logger.info(`[server] Cache hit for ${req.path}`)
return res.json(cacheResult)
}
// Request netease api
try {
const result = await handler({
...req.query,
// cookie:
// 'MUSIC_U=1239b6c1217d8cd240df9c8fa15e99a62f9aaac86baa7a8aa3166acbad267cd8a237494327fc3ec043124f3fcebe94e446b14e3f0c3f8af9fe5c85647582a507',
// cookie: req.headers.cookie,
cookie: `MUSIC_U=${req.cookies['MUSIC_U']}`,
})
res.send(result.body)
setCache(name, result.body)
} catch (error) {
res.status(500).send(error)
}
}
app.get(
`/netease/${pathCase(name)}`,
async (req: Request, res: Response) => await wrappedHandler(req, res)
)
app.post(
`/netease/${pathCase(name)}`,
async (req: Request, res: Response) => await wrappedHandler(req, res)
)
const neteasePath = `/netease/${pathCase(name)}`
app.get(neteasePath, wrappedHandler)
app.post(neteasePath, wrappedHandler)
})
app.listen(port, () => {

View File

@ -1,6 +1,7 @@
import dotenv from 'dotenv'
import { builtinModules } from 'module'
import path from 'path'
import { visualizer } from 'rollup-plugin-visualizer'
import { defineConfig } from 'vite'
import pkg from '../../package.json'
import esm2cjs from '../../scripts/vite-plugin-esm2cjs'
@ -27,6 +28,13 @@ export default defineConfig({
...builtinModules,
...Object.keys(pkg.dependencies || {}),
],
plugins: [
visualizer({
filename: './bundle-stats-main.html',
gzipSize: true,
projectRoot: 'packages/main',
}),
],
},
},
})

View File

@ -3,6 +3,7 @@ import { builtinModules } from 'module'
import path from 'path'
import { defineConfig } from 'vite'
import pkg from '../../package.json'
import { visualizer } from 'rollup-plugin-visualizer'
dotenv.config({
path: path.resolve(process.cwd(), '.env'),
@ -25,6 +26,13 @@ export default defineConfig({
...builtinModules,
...Object.keys(pkg.dependencies || {}),
],
plugins: [
visualizer({
filename: './bundle-stats-preload.html',
gzipSize: true,
projectRoot: 'packages/preload',
}),
],
},
},
})

View File

@ -9,7 +9,7 @@ export enum TrackApiNames {
export interface FetchTracksParams {
ids: number[]
}
interface FetchTracksResponse {
export interface FetchTracksResponse {
code: number
songs: Track[]
privileges: {

View File

@ -12,7 +12,7 @@ export enum UserApiNames {
* - uid : 用户 id
* @param {number} uid
*/
export function userDetail(uid) {
export function userDetail(uid: number) {
return request({
url: '/user/detail',
method: 'get',
@ -160,68 +160,68 @@ export function dailySignin(type = 0) {
* @param {number} params.limit
* @param {number=} params.offset
*/
export function likedAlbums(params) {
return request({
url: '/album/sublist',
method: 'get',
params: {
limit: params.limit,
timestamp: new Date().getTime(),
},
})
}
// export function likedAlbums(params) {
// return request({
// url: '/album/sublist',
// method: 'get',
// params: {
// limit: params.limit,
// timestamp: new Date().getTime(),
// },
// })
// }
/**
*
* 说明 : 调用此接口可获取到用户收藏的歌手
*/
export function likedArtists(params) {
return request({
url: '/artist/sublist',
method: 'get',
params: {
limit: params.limit,
timestamp: new Date().getTime(),
},
})
}
// export function likedArtists(params) {
// return request({
// url: '/artist/sublist',
// method: 'get',
// params: {
// limit: params.limit,
// timestamp: new Date().getTime(),
// },
// })
// }
/**
* MV
* 说明 : 调用此接口可获取到用户收藏的MV
*/
export function likedMVs(params) {
return request({
url: '/mv/sublist',
method: 'get',
params: {
limit: params.limit,
timestamp: new Date().getTime(),
},
})
}
// export function likedMVs(params) {
// return request({
// url: '/mv/sublist',
// method: 'get',
// params: {
// limit: params.limit,
// timestamp: new Date().getTime(),
// },
// })
// }
/**
*
*/
export function uploadSong(file) {
let formData = new FormData()
formData.append('songFile', file)
return request({
url: '/cloud',
method: 'post',
params: {
timestamp: new Date().getTime(),
},
data: formData,
headers: {
'Content-Type': 'multipart/form-data',
},
timeout: 200000,
}).catch(error => {
alert(`上传失败Error: ${error}`)
})
}
// export function uploadSong(file) {
// let formData = new FormData()
// formData.append('songFile', file)
// return request({
// url: '/cloud',
// method: 'post',
// params: {
// timestamp: new Date().getTime(),
// },
// data: formData,
// headers: {
// 'Content-Type': 'multipart/form-data',
// },
// timeout: 200000,
// }).catch(error => {
// alert(`上传失败Error: ${error}`)
// })
// }
/**
*
@ -232,40 +232,40 @@ export function uploadSong(file) {
* @param {number} params.limit
* @param {number=} params.offset
*/
export function cloudDisk(params = {}) {
params.timestamp = new Date().getTime()
return request({
url: '/user/cloud',
method: 'get',
params,
})
}
// export function cloudDisk(params = {}) {
// params.timestamp = new Date().getTime()
// return request({
// url: '/user/cloud',
// method: 'get',
// params,
// })
// }
/**
*
*/
export function cloudDiskTrackDetail(id) {
return request({
url: '/user/cloud/detail',
method: 'get',
params: {
timestamp: new Date().getTime(),
id,
},
})
}
// export function cloudDiskTrackDetail(id) {
// return request({
// url: '/user/cloud/detail',
// method: 'get',
// params: {
// timestamp: new Date().getTime(),
// id,
// },
// })
// }
/**
*
* @param {Array} id
*/
export function cloudDiskTrackDelete(id) {
return request({
url: '/user/cloud/del',
method: 'get',
params: {
timestamp: new Date().getTime(),
id,
},
})
}
// export function cloudDiskTrackDelete(id) {
// return request({
// url: '/user/cloud/del',
// method: 'get',
// params: {
// timestamp: new Date().getTime(),
// id,
// },
// })
// }

View File

@ -36,11 +36,11 @@ const Button = ({
{
'px-4 py-1.5': shape === Shape.Default,
'px-3 py-1.5': shape === Shape.Square,
'bg-brand-100 dark:bg-brand-700': color === Color.Primary,
'bg-brand-100 dark:bg-brand-600': color === Color.Primary,
'text-brand-500 dark:text-white': iconColor === Color.Primary,
'bg-gray-100 dark:bg-gray-700': color === Color.Gray,
'text-gray-900 dark:text-gray-400': iconColor === Color.Gray,
'animate-pulse bg-gray-100 text-transparent dark:bg-gray-800':
'animate-pulse bg-gray-100 !text-transparent dark:bg-gray-800':
isSkelton,
}
)}

View File

@ -38,11 +38,14 @@ const getSubtitleText = (
subtitle: Subtitle
) => {
const nickname = 'creator' in item ? item.creator.nickname : 'someone'
const artist = 'artist' in item ? item.artist.name : 'unknown'
const copywriter = 'copywriter' in item ? item.copywriter : 'unknown'
const releaseYear =
'publishTime' in item
? formatDate(item.publishTime ?? 0, 'en', 'YYYY')
: 'unknown'
const types = {
('publishTime' in item &&
formatDate(item.publishTime ?? 0, 'en', 'YYYY')) ||
'unknown'
const type = {
playlist: 'playlist',
album: 'Album',
: 'Album',
@ -50,16 +53,17 @@ const getSubtitleText = (
'EP/Single': 'EP',
EP: 'EP',
unknown: 'unknown',
}
const type = 'type' in item ? item.type || 'unknown' : 'unknown'
const artist = 'artist' in item ? item.artist.name : 'unknown'
: 'Collection',
}[('type' in item && typeof item.type !== 'number' && item.type) || 'unknown']
const table = {
[Subtitle.CREATOR]: `by ${nickname}`,
[Subtitle.TYPE_RELEASE_YEAR]: `${types[type]} · ${releaseYear}`,
[Subtitle.TYPE_RELEASE_YEAR]: `${type} · ${releaseYear}`,
[Subtitle.ARTIST]: artist,
[Subtitle.COPYWRITER]: copywriter,
}
return table[subtitle] ?? item[subtitle]
return table[subtitle]
}
const getImageUrl = (item: Album | Playlist | Artist) => {
@ -162,7 +166,7 @@ const CoverRow = ({
)}
<span
onClick={() => goTo(item.id)}
className="decoration-gray-600 decoration-2 hover:underline dark:text-white"
className="decoration-gray-600 decoration-2 hover:underline dark:text-white dark:decoration-gray-200"
>
{item.name}
</span>

View File

@ -18,7 +18,7 @@ const IconButton = ({
className,
'relative transform cursor-default p-2 transition duration-200',
!disabled &&
'btn-pressed-animation btn-hover-animation after:bg-black/[.06]',
'btn-pressed-animation btn-hover-animation after:bg-black/[.06] dark:after:bg-white/10',
disabled && 'opacity-30'
)}
>

View File

@ -49,7 +49,7 @@ const PlayingTrack = () => {
<div className="flex flex-col justify-center leading-tight">
<div
onClick={toTrackListSource}
className="line-clamp-1 font-semibold text-black decoration-gray-600 decoration-2 hover:underline dark:text-white"
className="line-clamp-1 font-semibold text-black decoration-gray-600 decoration-2 hover:underline dark:text-white dark:decoration-gray-300"
>
{track?.name}
</div>
@ -58,7 +58,7 @@ const PlayingTrack = () => {
</div>
</div>
<IconButton>
<IconButton onClick={() => toast('Work in progress')}>
<SvgIcon
className="h-4 w-4 text-black dark:text-white"
name="heart-outline"
@ -100,19 +100,19 @@ const MediaControls = () => {
const Others = () => {
return (
<div className="flex items-center justify-end gap-2 pr-2 text-black dark:text-white">
<IconButton>
<IconButton onClick={() => toast('Work in progress')}>
<SvgIcon className="h-4 w-4" name="playlist" />
</IconButton>
<IconButton>
<IconButton onClick={() => toast('Work in progress')}>
<SvgIcon className="h-4 w-4" name="repeat" />
</IconButton>
<IconButton>
<IconButton onClick={() => toast('Work in progress')}>
<SvgIcon className="h-4 w-4" name="shuffle" />
</IconButton>
<IconButton>
<IconButton onClick={() => toast('Work in progress')}>
<SvgIcon className="h-4 w-4" name="volume" />
</IconButton>
<IconButton>
<IconButton onClick={() => toast('Work in progress')}>
<SvgIcon className="h-4 w-4" name="chevron-up" />
</IconButton>
</div>
@ -149,7 +149,7 @@ const Progress = () => {
const Player = () => {
return (
<div className="fixed bottom-0 left-0 right-0 grid h-16 grid-cols-3 grid-rows-1 bg-white bg-opacity-[.86] py-2.5 px-5 backdrop-blur-xl backdrop-saturate-[1.8] dark:bg-[#222]">
<div className="fixed bottom-0 left-0 right-0 grid h-16 grid-cols-3 grid-rows-1 bg-white bg-opacity-[.86] py-2.5 px-5 backdrop-blur-xl backdrop-saturate-[1.8] dark:bg-[#222] dark:bg-opacity-[.86]">
<Progress />
<PlayingTrack />

View File

@ -52,7 +52,7 @@ const PrimaryTabs = () => {
</NavLink>
))}
<div className="mx-5 my-2 h-px bg-black opacity-5 dark:bg-white dark:opacity-20"></div>
<div className="mx-5 my-2 h-px bg-black opacity-5 dark:bg-white dark:opacity-10"></div>
</div>
)
}
@ -65,7 +65,7 @@ const Playlists = () => {
})
return (
<div className="overflow-auto pb-[4.6rem]">
<div className="mb-16 overflow-auto pb-2">
{playlists?.playlist?.map(playlist => (
<NavLink
key={playlist.id}
@ -89,7 +89,7 @@ const Sidebar = () => {
return (
<div
id="sidebar"
className="grid h-screen max-w-sm grid-rows-[12rem_auto] border-r border-gray-300/10 bg-gray-50 bg-opacity-[.85] dark:bg-black dark:bg-opacity-70"
className="grid h-screen max-w-sm grid-rows-[12rem_auto] border-r border-gray-300/10 bg-gray-50 bg-opacity-[.85] dark:border-gray-500/10 dark:bg-gray-900 dark:bg-opacity-80"
>
<PrimaryTabs />
<Playlists />

View File

@ -80,7 +80,7 @@ const Topbar = () => {
className={classNames(
'app-region-drag sticky top-0 z-30 flex h-16 min-h-[4rem] w-full cursor-default items-center justify-between px-8 transition duration-300',
!scroll.arrivedState.top &&
'bg-white bg-opacity-[.86] backdrop-blur-xl backdrop-saturate-[1.8] dark:bg-[#222]'
'bg-white bg-opacity-[.86] backdrop-blur-xl backdrop-saturate-[1.8] dark:bg-[#222] dark:bg-opacity-[.86]'
)}
>
<div className="flex gap-2">

View File

@ -36,9 +36,9 @@ const useScroll = (
useEffect(() => {
if (!ref) return
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
if (!e.currentTarget && !e.target) return
const target = e.currentTarget || e.target
const handleScroll = (e: Event) => {
if (!e.target) return
const target = e.target as HTMLElement
const arrivedState: ArrivedState = {
left: target.scrollLeft <= 0 + (offset?.left || 0),

View File

@ -9,8 +9,53 @@ import TracksAlbum from '@/components/TracksAlbum'
import useAlbum from '@/hooks/useAlbum'
import useArtistAlbums from '@/hooks/useArtistAlbums'
import { player } from '@/store'
import { State as PlayerState } from '@/utils/player'
import { formatDate, formatDuration, resizeImage } from '@/utils/common'
const PlayButton = ({
album,
handlePlay,
isLoading,
}: {
album: Album | undefined
isLoading: boolean
handlePlay: () => void
}) => {
const playerSnapshot = useSnapshot(player)
const isPlaying = useMemo(
() => playerSnapshot.state === PlayerState.PLAYING,
[playerSnapshot.state]
)
const isThisAlbumPlaying = useMemo(
() =>
playerSnapshot.trackListSource?.type === 'album' &&
playerSnapshot.trackListSource?.id === album?.id,
[playerSnapshot.trackListSource, album?.id]
)
const wrappedHandlePlay = () => {
if (isPlaying && isThisAlbumPlaying) {
player.pause()
return
}
if (!isPlaying && isThisAlbumPlaying) {
player.play()
return
}
handlePlay()
}
return (
<Button onClick={wrappedHandlePlay} isSkelton={isLoading}>
<SvgIcon
name={isPlaying && isThisAlbumPlaying ? 'pause' : 'play'}
className="mr-2 h-4 w-4"
/>
{isPlaying && isThisAlbumPlaying ? '暂停' : '播放'}
</Button>
)
}
const Header = ({
album,
isLoading,
@ -37,11 +82,11 @@ const Header = ({
<Fragment>
<img
src={coverUrl}
className="absolute top-[-50%] w-full blur-[100px]"
className="absolute -top-full w-full blur-[100px]"
/>
<img
src={coverUrl}
className="absolute top-[-50%] w-full blur-[100px]"
className="absolute -top-full w-full blur-[100px]"
/>
</Fragment>
)}
@ -81,17 +126,18 @@ const Header = ({
{/* Info */}
<div className="z-10 flex h-full flex-col justify-between">
{/* Name */}
{!isLoading && (
{isLoading ? (
<Skeleton className="w-3/4 text-6xl">PLACEHOLDER</Skeleton>
) : (
<div className="text-6xl font-bold dark:text-white">
{album?.name}
</div>
)}
{isLoading && (
<Skeleton className="w-3/4 text-6xl">PLACEHOLDER</Skeleton>
)}
{/* Artist */}
{!isLoading && (
{isLoading ? (
<Skeleton className="mt-5 w-64 text-lg">PLACEHOLDER</Skeleton>
) : (
<div className="mt-5 text-lg font-medium text-gray-800 dark:text-gray-300">
Album by{' '}
<NavLink
@ -102,43 +148,39 @@ const Header = ({
</NavLink>
</div>
)}
{isLoading && (
<Skeleton className="mt-5 w-64 text-lg">PLACEHOLDER</Skeleton>
)}
{/* Release date & track count & album duration */}
{!isLoading && (
{isLoading ? (
<Skeleton className="w-72 translate-y-px text-sm">
PLACEHOLDER
</Skeleton>
) : (
<div className="text-sm font-thin text-gray-500 dark:text-gray-400">
{dayjs(album?.publishTime || 0).year()} · {album?.size} Songs,{' '}
{albumDuration}
</div>
)}
{isLoading && (
<Skeleton className="w-72 translate-y-px text-sm">
PLACEHOLDER
</Skeleton>
)}
{/* Description */}
{!isLoading && (
{isLoading ? (
<Skeleton className="mt-5 min-h-[2.5rem] w-1/2 text-sm">
PLACEHOLDER
</Skeleton>
) : (
<div className="line-clamp-2 mt-5 min-h-[2.5rem] text-sm text-gray-500 dark:text-gray-400">
{album?.description}
</div>
)}
{isLoading && (
<Skeleton className="mt-5 min-h-[2.5rem] w-1/2 text-sm">
PLACEHOLDER
</Skeleton>
)}
{/* Buttons */}
<div className="mt-5 flex gap-4">
<Button onClick={() => handlePlay()} isSkelton={isLoading}>
<SvgIcon name="play" className="mr-2 h-4 w-4" />
PLAY
</Button>
<PlayButton {...{ album, handlePlay, isLoading }} />
<Button color={ButtonColor.Gray} isSkelton={isLoading}>
<Button
color={ButtonColor.Gray}
isSkelton={isLoading}
onClick={() => toast('Work in progress')}
>
<SvgIcon name="heart" className="h-4 w-4" />
</Button>
@ -146,6 +188,7 @@ const Header = ({
color={ButtonColor.Gray}
iconColor={ButtonColor.Gray}
isSkelton={isLoading}
onClick={() => toast('Work in progress')}
>
<SvgIcon name="more" className="h-4 w-4" />
</Button>

View File

@ -189,7 +189,7 @@ const LoginWithEmail = () => {
<Fragment>
<EmailInput {...{ email, setEmail }} />
<PasswordInput {...{ password, setPassword }} />
<LoginButton />
<LoginButton onClick={() => toast('Work in progress')} disabled={true} />
</Fragment>
)
}

View File

@ -115,7 +115,11 @@ const Header = memo(
PLAY
</Button>
<Button color={ButtonColor.Gray} isSkelton={isLoading}>
<Button
color={ButtonColor.Gray}
isSkelton={isLoading}
onClick={() => toast('Work in progress')}
>
<SvgIcon name="heart" className="h-4 w-4" />
</Button>
@ -123,6 +127,7 @@ const Header = memo(
color={ButtonColor.Gray}
iconColor={ButtonColor.Gray}
isSkelton={isLoading}
onClick={() => toast('Work in progress')}
>
<SvgIcon name="more" className="h-4 w-4" />
</Button>

View File

@ -44,7 +44,7 @@ export class Player {
repeatMode: RepeatMode = RepeatMode.OFF
constructor() {
window.player = this
//
}
/**

View File

@ -3,14 +3,13 @@ import dotenv from 'dotenv'
import { builtinModules } from 'module'
import path, { join } from 'path'
import AutoImport from 'unplugin-auto-import/vite'
import { Plugin, defineConfig } from 'vite'
import { defineConfig, Plugin } from 'vite'
import resolve from 'vite-plugin-resolve'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import { visualizer } from 'rollup-plugin-visualizer'
dotenv.config({ path: path.resolve(process.cwd(), '.env') })
console.log(join(__dirname, '../../.eslintrc.js'))
/**
* @see https://vitejs.dev/config/
*/
@ -60,6 +59,16 @@ export default defineConfig({
build: {
sourcemap: process.env.NODE_ENV === 'debug',
outDir: '../../dist/renderer',
rollupOptions: {
plugins: [
visualizer({
filename: './bundle-stats-renderer.html',
gzipSize: true,
projectRoot: 'packages/renderer',
template: 'treemap',
}),
],
},
},
resolve: {
alias: {

View File

@ -3,7 +3,7 @@ module.exports = {
tabWidth: 2,
useTabs: false,
semi: false,
jsxBracketSameLine: false,
bracketSameLine: false,
arrowParens: 'avoid',
endOfLine: 'lf',
bracketSpacing: true,

View File

@ -86,9 +86,14 @@ const color = (hex, text) => {
// bootstrap
logPrefix(color('#eab308', '[vite] '))
console.log('building renderer')
const server = await createServer({
configFile: 'packages/renderer/vite.config.ts',
})
await server.listen()
console.log('building preload')
await watchPreload(server)
console.log('building main')
await watchMain(server)

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const colors = require('tailwindcss/colors')
module.exports = {

View File

@ -565,6 +565,13 @@
dependencies:
"@types/node" "*"
"@types/cookie-parser@^1.4.2":
version "1.4.2"
resolved "https://registry.yarnpkg.com/@types/cookie-parser/-/cookie-parser-1.4.2.tgz#e4d5c5ffda82b80672a88a4281aaceefb1bd9df5"
integrity sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==
dependencies:
"@types/express" "*"
"@types/debug@^4.1.6":
version "4.1.7"
resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz"
@ -581,7 +588,7 @@
"@types/qs" "*"
"@types/range-parser" "*"
"@types/express@^4.17.13":
"@types/express@*", "@types/express@^4.17.13":
version "4.17.13"
resolved "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz"
integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
@ -5934,7 +5941,7 @@ roarr@^2.15.3:
rollup-plugin-visualizer@^5.6.0:
version "5.6.0"
resolved "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.6.0.tgz"
resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.6.0.tgz#06aa7cf3fd504a29d404335700f2a3f28ebb33f3"
integrity sha512-CKcc8GTUZjC+LsMytU8ocRr/cGZIfMR7+mdy4YnlyetlmIl/dM8BMnOEpD4JPIGt+ZVW7Db9ZtSsbgyeBH3uTA==
dependencies:
nanoid "^3.1.32"