mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-17 05:38:04 +00:00
feat: updates
This commit is contained in:
parent
950f72d4e8
commit
f54d2ded5c
26 changed files with 361 additions and 166 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
* @see https://www.electron.build/configuration/configuration
|
* @see https://www.electron.build/configuration/configuration
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
appId: 'yesplaymusic',
|
appId: 'com.qier222.yesplaymusic',
|
||||||
productName: 'YesPlayMusic',
|
productName: 'YesPlayMusic',
|
||||||
copyright: 'Copyright © 2022 ${author}',
|
copyright: 'Copyright © 2022 ${author}',
|
||||||
asar: true,
|
asar: true,
|
||||||
|
|
@ -43,4 +43,19 @@ module.exports = {
|
||||||
target: ['AppImage'],
|
target: ['AppImage'],
|
||||||
artifactName: '${productName}-${version}-Installer.${ext}',
|
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
3
.gitignore
vendored
|
|
@ -86,3 +86,6 @@ release
|
||||||
dist-ssr
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
|
bundle-stats-main.html
|
||||||
|
bundle-stats-preload.html
|
||||||
|
bundle-stats-renderer.html
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
"main": "dist/main/index.cjs",
|
"main": "dist/main/index.cjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node scripts/watch.mjs",
|
"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",
|
"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\"",
|
"debug": "cross-env-shell NODE_ENV=debug \"npm run typecheck && node scripts/build.mjs && vite ./packages/renderer\"",
|
||||||
"eslint": "eslint --ext .ts,.js ./",
|
"eslint": "eslint --ext .ts,.js ./",
|
||||||
|
|
@ -26,11 +26,12 @@
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"electron-log": "^4.4.6",
|
"electron-log": "^4.4.6",
|
||||||
"electron-store": "^8.0.1",
|
"electron-store": "^8.0.1",
|
||||||
"express": "^4.17.3",
|
"realm": "^10.13.0",
|
||||||
"realm": "^10.13.0"
|
"express": "^4.17.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@trivago/prettier-plugin-sort-imports": "^3.2.0",
|
"@trivago/prettier-plugin-sort-imports": "^3.2.0",
|
||||||
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
"@types/howler": "^2.2.6",
|
"@types/howler": "^2.2.6",
|
||||||
"@types/js-cookie": "^3.0.1",
|
"@types/js-cookie": "^3.0.1",
|
||||||
|
|
|
||||||
82
packages/main/database.ts
Normal file
82
packages/main/database.ts
Normal 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: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,16 +4,12 @@ import {
|
||||||
app,
|
app,
|
||||||
shell,
|
shell,
|
||||||
} from 'electron'
|
} from 'electron'
|
||||||
import installExtension, {
|
|
||||||
REACT_DEVELOPER_TOOLS,
|
|
||||||
REDUX_DEVTOOLS,
|
|
||||||
} from 'electron-devtools-installer'
|
|
||||||
import Store from 'electron-store'
|
import Store from 'electron-store'
|
||||||
import { release } from 'os'
|
import { release } from 'os'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import Realm from 'realm'
|
|
||||||
import logger from './logger'
|
import logger from './logger'
|
||||||
import './server'
|
import './server'
|
||||||
|
import './database'
|
||||||
|
|
||||||
const isWindows = process.platform === 'win32'
|
const isWindows = process.platform === 'win32'
|
||||||
const isMac = process.platform === 'darwin'
|
const isMac = process.platform === 'darwin'
|
||||||
|
|
@ -104,6 +100,12 @@ app.whenReady().then(async () => {
|
||||||
|
|
||||||
// Install devtool extension
|
// Install devtool extension
|
||||||
if (isDev) {
|
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 =>
|
installExtension(REACT_DEVELOPER_TOOLS.id).catch(err =>
|
||||||
console.log('An error occurred: ', err)
|
console.log('An error occurred: ', err)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,42 +2,44 @@ import { pathCase } from 'change-case'
|
||||||
import cookieParser from 'cookie-parser'
|
import cookieParser from 'cookie-parser'
|
||||||
import express, { Request, Response } from 'express'
|
import express, { Request, Response } from 'express'
|
||||||
import logger from './logger'
|
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()
|
const app = express()
|
||||||
app.use(cookieParser())
|
app.use(cookieParser())
|
||||||
const port = Number(process.env['ELECTRON_DEV_NETEASE_API_PORT'] ?? 3000)
|
const port = Number(process.env['ELECTRON_DEV_NETEASE_API_PORT'] ?? 3000)
|
||||||
|
|
||||||
Object.entries(neteaseApi).forEach(([name, handler]) => {
|
Object.entries(neteaseApi).forEach(([name, handler]) => {
|
||||||
if (['serveNcmApi', 'getModulesDefinitions'].includes(name)) {
|
if (['serveNcmApi', 'getModulesDefinitions'].includes(name)) return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const wrappedHandler = async (req: Request, res: Response) => {
|
const wrappedHandler = async (req: Request, res: Response) => {
|
||||||
logger.info(`[server] Handling request: ${req.path}`)
|
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 {
|
try {
|
||||||
const result = await handler({
|
const result = await handler({
|
||||||
...req.query,
|
...req.query,
|
||||||
// cookie:
|
|
||||||
// 'MUSIC_U=1239b6c1217d8cd240df9c8fa15e99a62f9aaac86baa7a8aa3166acbad267cd8a237494327fc3ec043124f3fcebe94e446b14e3f0c3f8af9fe5c85647582a507',
|
|
||||||
// cookie: req.headers.cookie,
|
|
||||||
cookie: `MUSIC_U=${req.cookies['MUSIC_U']}`,
|
cookie: `MUSIC_U=${req.cookies['MUSIC_U']}`,
|
||||||
})
|
})
|
||||||
res.send(result.body)
|
res.send(result.body)
|
||||||
|
setCache(name, result.body)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).send(error)
|
res.status(500).send(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get(
|
const neteasePath = `/netease/${pathCase(name)}`
|
||||||
`/netease/${pathCase(name)}`,
|
app.get(neteasePath, wrappedHandler)
|
||||||
async (req: Request, res: Response) => await wrappedHandler(req, res)
|
app.post(neteasePath, wrappedHandler)
|
||||||
)
|
|
||||||
app.post(
|
|
||||||
`/netease/${pathCase(name)}`,
|
|
||||||
async (req: Request, res: Response) => await wrappedHandler(req, res)
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import dotenv from 'dotenv'
|
import dotenv from 'dotenv'
|
||||||
import { builtinModules } from 'module'
|
import { builtinModules } from 'module'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import pkg from '../../package.json'
|
import pkg from '../../package.json'
|
||||||
import esm2cjs from '../../scripts/vite-plugin-esm2cjs'
|
import esm2cjs from '../../scripts/vite-plugin-esm2cjs'
|
||||||
|
|
@ -27,6 +28,13 @@ export default defineConfig({
|
||||||
...builtinModules,
|
...builtinModules,
|
||||||
...Object.keys(pkg.dependencies || {}),
|
...Object.keys(pkg.dependencies || {}),
|
||||||
],
|
],
|
||||||
|
plugins: [
|
||||||
|
visualizer({
|
||||||
|
filename: './bundle-stats-main.html',
|
||||||
|
gzipSize: true,
|
||||||
|
projectRoot: 'packages/main',
|
||||||
|
}),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { builtinModules } from 'module'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import pkg from '../../package.json'
|
import pkg from '../../package.json'
|
||||||
|
import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
|
|
||||||
dotenv.config({
|
dotenv.config({
|
||||||
path: path.resolve(process.cwd(), '.env'),
|
path: path.resolve(process.cwd(), '.env'),
|
||||||
|
|
@ -25,6 +26,13 @@ export default defineConfig({
|
||||||
...builtinModules,
|
...builtinModules,
|
||||||
...Object.keys(pkg.dependencies || {}),
|
...Object.keys(pkg.dependencies || {}),
|
||||||
],
|
],
|
||||||
|
plugins: [
|
||||||
|
visualizer({
|
||||||
|
filename: './bundle-stats-preload.html',
|
||||||
|
gzipSize: true,
|
||||||
|
projectRoot: 'packages/preload',
|
||||||
|
}),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export enum TrackApiNames {
|
||||||
export interface FetchTracksParams {
|
export interface FetchTracksParams {
|
||||||
ids: number[]
|
ids: number[]
|
||||||
}
|
}
|
||||||
interface FetchTracksResponse {
|
export interface FetchTracksResponse {
|
||||||
code: number
|
code: number
|
||||||
songs: Track[]
|
songs: Track[]
|
||||||
privileges: {
|
privileges: {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export enum UserApiNames {
|
||||||
* - uid : 用户 id
|
* - uid : 用户 id
|
||||||
* @param {number} uid
|
* @param {number} uid
|
||||||
*/
|
*/
|
||||||
export function userDetail(uid) {
|
export function userDetail(uid: number) {
|
||||||
return request({
|
return request({
|
||||||
url: '/user/detail',
|
url: '/user/detail',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
|
@ -160,68 +160,68 @@ export function dailySignin(type = 0) {
|
||||||
* @param {number} params.limit
|
* @param {number} params.limit
|
||||||
* @param {number=} params.offset
|
* @param {number=} params.offset
|
||||||
*/
|
*/
|
||||||
export function likedAlbums(params) {
|
// export function likedAlbums(params) {
|
||||||
return request({
|
// return request({
|
||||||
url: '/album/sublist',
|
// url: '/album/sublist',
|
||||||
method: 'get',
|
// method: 'get',
|
||||||
params: {
|
// params: {
|
||||||
limit: params.limit,
|
// limit: params.limit,
|
||||||
timestamp: new Date().getTime(),
|
// timestamp: new Date().getTime(),
|
||||||
},
|
// },
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取收藏的歌手(需要登录)
|
* 获取收藏的歌手(需要登录)
|
||||||
* 说明 : 调用此接口可获取到用户收藏的歌手
|
* 说明 : 调用此接口可获取到用户收藏的歌手
|
||||||
*/
|
*/
|
||||||
export function likedArtists(params) {
|
// export function likedArtists(params) {
|
||||||
return request({
|
// return request({
|
||||||
url: '/artist/sublist',
|
// url: '/artist/sublist',
|
||||||
method: 'get',
|
// method: 'get',
|
||||||
params: {
|
// params: {
|
||||||
limit: params.limit,
|
// limit: params.limit,
|
||||||
timestamp: new Date().getTime(),
|
// timestamp: new Date().getTime(),
|
||||||
},
|
// },
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取收藏的MV(需要登录)
|
* 获取收藏的MV(需要登录)
|
||||||
* 说明 : 调用此接口可获取到用户收藏的MV
|
* 说明 : 调用此接口可获取到用户收藏的MV
|
||||||
*/
|
*/
|
||||||
export function likedMVs(params) {
|
// export function likedMVs(params) {
|
||||||
return request({
|
// return request({
|
||||||
url: '/mv/sublist',
|
// url: '/mv/sublist',
|
||||||
method: 'get',
|
// method: 'get',
|
||||||
params: {
|
// params: {
|
||||||
limit: params.limit,
|
// limit: params.limit,
|
||||||
timestamp: new Date().getTime(),
|
// timestamp: new Date().getTime(),
|
||||||
},
|
// },
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传歌曲到云盘(需要登录)
|
* 上传歌曲到云盘(需要登录)
|
||||||
*/
|
*/
|
||||||
export function uploadSong(file) {
|
// export function uploadSong(file) {
|
||||||
let formData = new FormData()
|
// let formData = new FormData()
|
||||||
formData.append('songFile', file)
|
// formData.append('songFile', file)
|
||||||
return request({
|
// return request({
|
||||||
url: '/cloud',
|
// url: '/cloud',
|
||||||
method: 'post',
|
// method: 'post',
|
||||||
params: {
|
// params: {
|
||||||
timestamp: new Date().getTime(),
|
// timestamp: new Date().getTime(),
|
||||||
},
|
// },
|
||||||
data: formData,
|
// data: formData,
|
||||||
headers: {
|
// headers: {
|
||||||
'Content-Type': 'multipart/form-data',
|
// 'Content-Type': 'multipart/form-data',
|
||||||
},
|
// },
|
||||||
timeout: 200000,
|
// timeout: 200000,
|
||||||
}).catch(error => {
|
// }).catch(error => {
|
||||||
alert(`上传失败,Error: ${error}`)
|
// alert(`上传失败,Error: ${error}`)
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取云盘歌曲(需要登录)
|
* 获取云盘歌曲(需要登录)
|
||||||
|
|
@ -232,40 +232,40 @@ export function uploadSong(file) {
|
||||||
* @param {number} params.limit
|
* @param {number} params.limit
|
||||||
* @param {number=} params.offset
|
* @param {number=} params.offset
|
||||||
*/
|
*/
|
||||||
export function cloudDisk(params = {}) {
|
// export function cloudDisk(params = {}) {
|
||||||
params.timestamp = new Date().getTime()
|
// params.timestamp = new Date().getTime()
|
||||||
return request({
|
// return request({
|
||||||
url: '/user/cloud',
|
// url: '/user/cloud',
|
||||||
method: 'get',
|
// method: 'get',
|
||||||
params,
|
// params,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取云盘歌曲详情(需要登录)
|
* 获取云盘歌曲详情(需要登录)
|
||||||
*/
|
*/
|
||||||
export function cloudDiskTrackDetail(id) {
|
// export function cloudDiskTrackDetail(id) {
|
||||||
return request({
|
// return request({
|
||||||
url: '/user/cloud/detail',
|
// url: '/user/cloud/detail',
|
||||||
method: 'get',
|
// method: 'get',
|
||||||
params: {
|
// params: {
|
||||||
timestamp: new Date().getTime(),
|
// timestamp: new Date().getTime(),
|
||||||
id,
|
// id,
|
||||||
},
|
// },
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除云盘歌曲(需要登录)
|
* 删除云盘歌曲(需要登录)
|
||||||
* @param {Array} id
|
* @param {Array} id
|
||||||
*/
|
*/
|
||||||
export function cloudDiskTrackDelete(id) {
|
// export function cloudDiskTrackDelete(id) {
|
||||||
return request({
|
// return request({
|
||||||
url: '/user/cloud/del',
|
// url: '/user/cloud/del',
|
||||||
method: 'get',
|
// method: 'get',
|
||||||
params: {
|
// params: {
|
||||||
timestamp: new Date().getTime(),
|
// timestamp: new Date().getTime(),
|
||||||
id,
|
// id,
|
||||||
},
|
// },
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,11 @@ const Button = ({
|
||||||
{
|
{
|
||||||
'px-4 py-1.5': shape === Shape.Default,
|
'px-4 py-1.5': shape === Shape.Default,
|
||||||
'px-3 py-1.5': shape === Shape.Square,
|
'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,
|
'text-brand-500 dark:text-white': iconColor === Color.Primary,
|
||||||
'bg-gray-100 dark:bg-gray-700': color === Color.Gray,
|
'bg-gray-100 dark:bg-gray-700': color === Color.Gray,
|
||||||
'text-gray-900 dark:text-gray-400': iconColor === 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,
|
isSkelton,
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,14 @@ const getSubtitleText = (
|
||||||
subtitle: Subtitle
|
subtitle: Subtitle
|
||||||
) => {
|
) => {
|
||||||
const nickname = 'creator' in item ? item.creator.nickname : 'someone'
|
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 =
|
const releaseYear =
|
||||||
'publishTime' in item
|
('publishTime' in item &&
|
||||||
? formatDate(item.publishTime ?? 0, 'en', 'YYYY')
|
formatDate(item.publishTime ?? 0, 'en', 'YYYY')) ||
|
||||||
: 'unknown'
|
'unknown'
|
||||||
const types = {
|
|
||||||
|
const type = {
|
||||||
playlist: 'playlist',
|
playlist: 'playlist',
|
||||||
album: 'Album',
|
album: 'Album',
|
||||||
专辑: 'Album',
|
专辑: 'Album',
|
||||||
|
|
@ -50,16 +53,17 @@ const getSubtitleText = (
|
||||||
'EP/Single': 'EP',
|
'EP/Single': 'EP',
|
||||||
EP: 'EP',
|
EP: 'EP',
|
||||||
unknown: 'unknown',
|
unknown: 'unknown',
|
||||||
}
|
精选集: 'Collection',
|
||||||
const type = 'type' in item ? item.type || 'unknown' : 'unknown'
|
}[('type' in item && typeof item.type !== 'number' && item.type) || 'unknown']
|
||||||
const artist = 'artist' in item ? item.artist.name : 'unknown'
|
|
||||||
|
|
||||||
const table = {
|
const table = {
|
||||||
[Subtitle.CREATOR]: `by ${nickname}`,
|
[Subtitle.CREATOR]: `by ${nickname}`,
|
||||||
[Subtitle.TYPE_RELEASE_YEAR]: `${types[type]} · ${releaseYear}`,
|
[Subtitle.TYPE_RELEASE_YEAR]: `${type} · ${releaseYear}`,
|
||||||
[Subtitle.ARTIST]: artist,
|
[Subtitle.ARTIST]: artist,
|
||||||
|
[Subtitle.COPYWRITER]: copywriter,
|
||||||
}
|
}
|
||||||
return table[subtitle] ?? item[subtitle]
|
|
||||||
|
return table[subtitle]
|
||||||
}
|
}
|
||||||
|
|
||||||
const getImageUrl = (item: Album | Playlist | Artist) => {
|
const getImageUrl = (item: Album | Playlist | Artist) => {
|
||||||
|
|
@ -162,7 +166,7 @@ const CoverRow = ({
|
||||||
)}
|
)}
|
||||||
<span
|
<span
|
||||||
onClick={() => goTo(item.id)}
|
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}
|
{item.name}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ const IconButton = ({
|
||||||
className,
|
className,
|
||||||
'relative transform cursor-default p-2 transition duration-200',
|
'relative transform cursor-default p-2 transition duration-200',
|
||||||
!disabled &&
|
!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'
|
disabled && 'opacity-30'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ const PlayingTrack = () => {
|
||||||
<div className="flex flex-col justify-center leading-tight">
|
<div className="flex flex-col justify-center leading-tight">
|
||||||
<div
|
<div
|
||||||
onClick={toTrackListSource}
|
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}
|
{track?.name}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -58,7 +58,7 @@ const PlayingTrack = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<IconButton>
|
<IconButton onClick={() => toast('Work in progress')}>
|
||||||
<SvgIcon
|
<SvgIcon
|
||||||
className="h-4 w-4 text-black dark:text-white"
|
className="h-4 w-4 text-black dark:text-white"
|
||||||
name="heart-outline"
|
name="heart-outline"
|
||||||
|
|
@ -100,19 +100,19 @@ const MediaControls = () => {
|
||||||
const Others = () => {
|
const Others = () => {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-end gap-2 pr-2 text-black dark:text-white">
|
<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" />
|
<SvgIcon className="h-4 w-4" name="playlist" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton>
|
<IconButton onClick={() => toast('Work in progress')}>
|
||||||
<SvgIcon className="h-4 w-4" name="repeat" />
|
<SvgIcon className="h-4 w-4" name="repeat" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton>
|
<IconButton onClick={() => toast('Work in progress')}>
|
||||||
<SvgIcon className="h-4 w-4" name="shuffle" />
|
<SvgIcon className="h-4 w-4" name="shuffle" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton>
|
<IconButton onClick={() => toast('Work in progress')}>
|
||||||
<SvgIcon className="h-4 w-4" name="volume" />
|
<SvgIcon className="h-4 w-4" name="volume" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton>
|
<IconButton onClick={() => toast('Work in progress')}>
|
||||||
<SvgIcon className="h-4 w-4" name="chevron-up" />
|
<SvgIcon className="h-4 w-4" name="chevron-up" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -149,7 +149,7 @@ const Progress = () => {
|
||||||
|
|
||||||
const Player = () => {
|
const Player = () => {
|
||||||
return (
|
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 />
|
<Progress />
|
||||||
|
|
||||||
<PlayingTrack />
|
<PlayingTrack />
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ const PrimaryTabs = () => {
|
||||||
</NavLink>
|
</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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +65,7 @@ const Playlists = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-auto pb-[4.6rem]">
|
<div className="mb-16 overflow-auto pb-2">
|
||||||
{playlists?.playlist?.map(playlist => (
|
{playlists?.playlist?.map(playlist => (
|
||||||
<NavLink
|
<NavLink
|
||||||
key={playlist.id}
|
key={playlist.id}
|
||||||
|
|
@ -89,7 +89,7 @@ const Sidebar = () => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="sidebar"
|
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 />
|
<PrimaryTabs />
|
||||||
<Playlists />
|
<Playlists />
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ const Topbar = () => {
|
||||||
className={classNames(
|
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',
|
'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 &&
|
!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">
|
<div className="flex gap-2">
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,9 @@ const useScroll = (
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ref) return
|
if (!ref) return
|
||||||
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
const handleScroll = (e: Event) => {
|
||||||
if (!e.currentTarget && !e.target) return
|
if (!e.target) return
|
||||||
const target = e.currentTarget || e.target
|
const target = e.target as HTMLElement
|
||||||
|
|
||||||
const arrivedState: ArrivedState = {
|
const arrivedState: ArrivedState = {
|
||||||
left: target.scrollLeft <= 0 + (offset?.left || 0),
|
left: target.scrollLeft <= 0 + (offset?.left || 0),
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,53 @@ import TracksAlbum from '@/components/TracksAlbum'
|
||||||
import useAlbum from '@/hooks/useAlbum'
|
import useAlbum from '@/hooks/useAlbum'
|
||||||
import useArtistAlbums from '@/hooks/useArtistAlbums'
|
import useArtistAlbums from '@/hooks/useArtistAlbums'
|
||||||
import { player } from '@/store'
|
import { player } from '@/store'
|
||||||
|
import { State as PlayerState } from '@/utils/player'
|
||||||
import { formatDate, formatDuration, resizeImage } from '@/utils/common'
|
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 = ({
|
const Header = ({
|
||||||
album,
|
album,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -37,11 +82,11 @@ const Header = ({
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<img
|
<img
|
||||||
src={coverUrl}
|
src={coverUrl}
|
||||||
className="absolute top-[-50%] w-full blur-[100px]"
|
className="absolute -top-full w-full blur-[100px]"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
src={coverUrl}
|
src={coverUrl}
|
||||||
className="absolute top-[-50%] w-full blur-[100px]"
|
className="absolute -top-full w-full blur-[100px]"
|
||||||
/>
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
|
|
@ -81,17 +126,18 @@ const Header = ({
|
||||||
{/* Info */}
|
{/* Info */}
|
||||||
<div className="z-10 flex h-full flex-col justify-between">
|
<div className="z-10 flex h-full flex-col justify-between">
|
||||||
{/* Name */}
|
{/* Name */}
|
||||||
{!isLoading && (
|
{isLoading ? (
|
||||||
|
<Skeleton className="w-3/4 text-6xl">PLACEHOLDER</Skeleton>
|
||||||
|
) : (
|
||||||
<div className="text-6xl font-bold dark:text-white">
|
<div className="text-6xl font-bold dark:text-white">
|
||||||
{album?.name}
|
{album?.name}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isLoading && (
|
|
||||||
<Skeleton className="w-3/4 text-6xl">PLACEHOLDER</Skeleton>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Artist */}
|
{/* 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">
|
<div className="mt-5 text-lg font-medium text-gray-800 dark:text-gray-300">
|
||||||
Album by{' '}
|
Album by{' '}
|
||||||
<NavLink
|
<NavLink
|
||||||
|
|
@ -102,43 +148,39 @@ const Header = ({
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isLoading && (
|
|
||||||
<Skeleton className="mt-5 w-64 text-lg">PLACEHOLDER</Skeleton>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Release date & track count & album duration */}
|
{/* 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">
|
<div className="text-sm font-thin text-gray-500 dark:text-gray-400">
|
||||||
{dayjs(album?.publishTime || 0).year()} · {album?.size} Songs,{' '}
|
{dayjs(album?.publishTime || 0).year()} · {album?.size} Songs,{' '}
|
||||||
{albumDuration}
|
{albumDuration}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isLoading && (
|
|
||||||
<Skeleton className="w-72 translate-y-px text-sm">
|
|
||||||
PLACEHOLDER
|
|
||||||
</Skeleton>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Description */}
|
{/* 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">
|
<div className="line-clamp-2 mt-5 min-h-[2.5rem] text-sm text-gray-500 dark:text-gray-400">
|
||||||
{album?.description}
|
{album?.description}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isLoading && (
|
|
||||||
<Skeleton className="mt-5 min-h-[2.5rem] w-1/2 text-sm">
|
|
||||||
PLACEHOLDER
|
|
||||||
</Skeleton>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Buttons */}
|
{/* Buttons */}
|
||||||
<div className="mt-5 flex gap-4">
|
<div className="mt-5 flex gap-4">
|
||||||
<Button onClick={() => handlePlay()} isSkelton={isLoading}>
|
<PlayButton {...{ album, handlePlay, isLoading }} />
|
||||||
<SvgIcon name="play" className="mr-2 h-4 w-4" />
|
|
||||||
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" />
|
<SvgIcon name="heart" className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|
@ -146,6 +188,7 @@ const Header = ({
|
||||||
color={ButtonColor.Gray}
|
color={ButtonColor.Gray}
|
||||||
iconColor={ButtonColor.Gray}
|
iconColor={ButtonColor.Gray}
|
||||||
isSkelton={isLoading}
|
isSkelton={isLoading}
|
||||||
|
onClick={() => toast('Work in progress')}
|
||||||
>
|
>
|
||||||
<SvgIcon name="more" className="h-4 w-4" />
|
<SvgIcon name="more" className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ const LoginWithEmail = () => {
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<EmailInput {...{ email, setEmail }} />
|
<EmailInput {...{ email, setEmail }} />
|
||||||
<PasswordInput {...{ password, setPassword }} />
|
<PasswordInput {...{ password, setPassword }} />
|
||||||
<LoginButton />
|
<LoginButton onClick={() => toast('Work in progress')} disabled={true} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,11 @@ const Header = memo(
|
||||||
PLAY
|
PLAY
|
||||||
</Button>
|
</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" />
|
<SvgIcon name="heart" className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|
@ -123,6 +127,7 @@ const Header = memo(
|
||||||
color={ButtonColor.Gray}
|
color={ButtonColor.Gray}
|
||||||
iconColor={ButtonColor.Gray}
|
iconColor={ButtonColor.Gray}
|
||||||
isSkelton={isLoading}
|
isSkelton={isLoading}
|
||||||
|
onClick={() => toast('Work in progress')}
|
||||||
>
|
>
|
||||||
<SvgIcon name="more" className="h-4 w-4" />
|
<SvgIcon name="more" className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ export class Player {
|
||||||
repeatMode: RepeatMode = RepeatMode.OFF
|
repeatMode: RepeatMode = RepeatMode.OFF
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
window.player = this
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,13 @@ import dotenv from 'dotenv'
|
||||||
import { builtinModules } from 'module'
|
import { builtinModules } from 'module'
|
||||||
import path, { join } from 'path'
|
import path, { join } from 'path'
|
||||||
import AutoImport from 'unplugin-auto-import/vite'
|
import AutoImport from 'unplugin-auto-import/vite'
|
||||||
import { Plugin, defineConfig } from 'vite'
|
import { defineConfig, Plugin } from 'vite'
|
||||||
import resolve from 'vite-plugin-resolve'
|
import resolve from 'vite-plugin-resolve'
|
||||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||||
|
import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
|
|
||||||
dotenv.config({ path: path.resolve(process.cwd(), '.env') })
|
dotenv.config({ path: path.resolve(process.cwd(), '.env') })
|
||||||
|
|
||||||
console.log(join(__dirname, '../../.eslintrc.js'))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://vitejs.dev/config/
|
* @see https://vitejs.dev/config/
|
||||||
*/
|
*/
|
||||||
|
|
@ -60,6 +59,16 @@ export default defineConfig({
|
||||||
build: {
|
build: {
|
||||||
sourcemap: process.env.NODE_ENV === 'debug',
|
sourcemap: process.env.NODE_ENV === 'debug',
|
||||||
outDir: '../../dist/renderer',
|
outDir: '../../dist/renderer',
|
||||||
|
rollupOptions: {
|
||||||
|
plugins: [
|
||||||
|
visualizer({
|
||||||
|
filename: './bundle-stats-renderer.html',
|
||||||
|
gzipSize: true,
|
||||||
|
projectRoot: 'packages/renderer',
|
||||||
|
template: 'treemap',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ module.exports = {
|
||||||
tabWidth: 2,
|
tabWidth: 2,
|
||||||
useTabs: false,
|
useTabs: false,
|
||||||
semi: false,
|
semi: false,
|
||||||
jsxBracketSameLine: false,
|
bracketSameLine: false,
|
||||||
arrowParens: 'avoid',
|
arrowParens: 'avoid',
|
||||||
endOfLine: 'lf',
|
endOfLine: 'lf',
|
||||||
bracketSpacing: true,
|
bracketSpacing: true,
|
||||||
|
|
|
||||||
|
|
@ -86,9 +86,14 @@ const color = (hex, text) => {
|
||||||
|
|
||||||
// bootstrap
|
// bootstrap
|
||||||
logPrefix(color('#eab308', '[vite] '))
|
logPrefix(color('#eab308', '[vite] '))
|
||||||
|
console.log('building renderer')
|
||||||
const server = await createServer({
|
const server = await createServer({
|
||||||
configFile: 'packages/renderer/vite.config.ts',
|
configFile: 'packages/renderer/vite.config.ts',
|
||||||
})
|
})
|
||||||
await server.listen()
|
await server.listen()
|
||||||
|
|
||||||
|
console.log('building preload')
|
||||||
await watchPreload(server)
|
await watchPreload(server)
|
||||||
|
|
||||||
|
console.log('building main')
|
||||||
await watchMain(server)
|
await watchMain(server)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
const colors = require('tailwindcss/colors')
|
const colors = require('tailwindcss/colors')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
||||||
11
yarn.lock
11
yarn.lock
|
|
@ -565,6 +565,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@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":
|
"@types/debug@^4.1.6":
|
||||||
version "4.1.7"
|
version "4.1.7"
|
||||||
resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz"
|
resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz"
|
||||||
|
|
@ -581,7 +588,7 @@
|
||||||
"@types/qs" "*"
|
"@types/qs" "*"
|
||||||
"@types/range-parser" "*"
|
"@types/range-parser" "*"
|
||||||
|
|
||||||
"@types/express@^4.17.13":
|
"@types/express@*", "@types/express@^4.17.13":
|
||||||
version "4.17.13"
|
version "4.17.13"
|
||||||
resolved "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz"
|
resolved "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz"
|
||||||
integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
|
integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
|
||||||
|
|
@ -5934,7 +5941,7 @@ roarr@^2.15.3:
|
||||||
|
|
||||||
rollup-plugin-visualizer@^5.6.0:
|
rollup-plugin-visualizer@^5.6.0:
|
||||||
version "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==
|
integrity sha512-CKcc8GTUZjC+LsMytU8ocRr/cGZIfMR7+mdy4YnlyetlmIl/dM8BMnOEpD4JPIGt+ZVW7Db9ZtSsbgyeBH3uTA==
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^3.1.32"
|
nanoid "^3.1.32"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue