Compare commits

...

14 Commits
master ... ui

  1. 1
      .gitignore
  2. 11
      a.md
  3. 62
      backup/Home/Dialog.tsx
  4. 31
      backup/Home/dialog.module.scss
  5. 10
      backup/Home/index.module.scss
  6. 152
      backup/Home/index.tsx
  7. 7
      backup/Home/useLocation.ts
  8. 34
      dist/package-lock.json
  9. 4
      dist/package.json
  10. 5
      jest.config.js
  11. 2657
      package-lock.json
  12. 21
      package.json
  13. 35
      plugins/md.ts
  14. 6
      script/code/runElectron.ts
  15. 8
      script/code/runVite.ts
  16. 6
      script/dev-runner.ts
  17. 8
      script/log.ts
  18. 2
      script/run.js
  19. 78
      script/webpack/runMain.js
  20. 23
      src/main/facilities/clock/index.ts
  21. 2
      src/main/facilities/float/index.ts
  22. 3
      src/main/facilities/index.ts
  23. 20
      src/main/facilities/main/index.ts
  24. 6
      src/render/AppRouter.tsx
  25. 23
      src/render/assets/style/common.scss
  26. 2
      src/render/index.html
  27. 10
      src/render/main.tsx
  28. 3
      src/render/plugins/electron/index.ts
  29. 50
      src/render/plugins/useRoute/index.ts
  30. 23
      src/render/route.tsx
  31. 16
      src/render/views/About/a.md
  32. 3
      src/render/views/About/index.module.scss
  33. 27
      src/render/views/About/index.tsx
  34. 3
      src/render/views/Float/index.module.scss
  35. 72
      src/render/views/Home/index.module.scss
  36. 58
      src/render/views/Home/index.tsx
  37. 32
      src/render/views/Home/usePositionElectron.ts
  38. 55
      src/render/views/Home/useTime.ts
  39. 54
      src/render/views/Layout/index.module.scss
  40. 69
      src/render/views/Layout/index.tsx
  41. 0
      te22st.js
  42. 2
      tsconfig.json
  43. 4
      types/global.d.ts
  44. 7
      vite.config.ts

1
.gitignore

@ -4,3 +4,4 @@ out
.vscode
dist/electron
计划.md
coverage

11
a.md

@ -16,4 +16,13 @@ https://www.jianshu.com/p/4699b825d285
https://www.npmjs.com/package/node-schedule
https://www.electronjs.org/community
https://www.electronjs.org/community
https://blueprintjs.com/
https://chakra-ui.com/
https://www.npmjs.com/package/node-fetch
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
react-desktop
考虑使用谷歌的材料ui
https://www.framer.com/docs/animation/

62
backup/Home/Dialog.tsx

@ -0,0 +1,62 @@
import { Button, ButtonGroup, Card, FormGroup, InputGroup, Overlay, TextArea } from "@blueprintjs/core"
import cs from "classnames"
import React, { useEffect, useState } from "react"
import style from "./dialog.module.scss"
export default function Dialog(props: any) {
const { isOpen, setIsOpen } = props
const [title, setTitle] = useState<string>("")
const [time, setTime] = useState<string>("")
const [desc, setDesc] = useState<string>("")
function clickConfrim(){
props.onConfrim&&props.onConfrim(title,time,desc)
}
function clickCancel(){
setIsOpen(false)
props.onCancel&&props.onCancel()
}
useEffect(()=>{
if(isOpen){
setTitle("")
setTime("")
setDesc("")
}
}, [isOpen])
return (
<Overlay
isOpen={isOpen}
onClose={() => {
setIsOpen(false)
}}
>
<div className={cs(style.dialog)}>
<Card>
<form className="addClock clearfix">
<FormGroup label="标题" labelFor="title-input" labelInfo="(required)">
<InputGroup value={title} onChange={e => setTitle(e.target.value)} id="title-input" placeholder="请输入标题"/>
</FormGroup>
<FormGroup helperText="一个通用的时间表示法" label="时间区间" labelFor="time-input" labelInfo="(required)">
<InputGroup value={time} onChange={e => setTime(e.target.value)} id="time-input" placeholder="请输入时间区间"/>
</FormGroup>
<FormGroup label="描述" labelFor="desc-input">
<TextArea value={desc} onChange={e => setDesc(e.target.value)} id="desc-input" style={{ width: "100%" }}
growVertically={true} large={true} intent="primary"/>
</FormGroup>
<ButtonGroup style={{ float: "right" }}>
<Button
intent="primary"
onClick={()=>clickConfrim()}
>
</Button>
<Button intent="danger" onClick={()=>clickCancel()}></Button>
</ButtonGroup>
</form>
</Card>
</div>
</Overlay>
)
}

31
backup/Home/dialog.module.scss

@ -0,0 +1,31 @@
.dialog {
left: calc(50vw - 200px);
width: 400px;
margin: 10vh 0;
top: 0;
&:global(.bp3-overlay-appear),
&:global(.bp3-overlay-enter) {
transform: translateY(-50vh) rotate(-10deg);
}
&:global(.bp3-overlay-appear-active),
&:global(.bp3-overlay-enter-active) {
transform: translateY(0) rotate(0deg);
transition-delay: 0;
transition-duration: 0.3s;
transition-property: transform;
transition-timing-function: cubic-bezier(0.54, 1.12, 0.38, 1.11);
}
&:global(.bp3-overlay-exit) {
transform: translateY(0) rotate(0deg);
}
&:global(.bp3-overlay-exit-active) {
transform: translateY(150vh) rotate(-20deg);
transition-delay: 0;
transition-duration: 0.5s;
transition-property: transform;
transition-timing-function: cubic-bezier(0.4, 1, 0.75, 0.9);
}
}

10
backup/Home/index.module.scss

@ -0,0 +1,10 @@
.container {
padding: 20px;
.title {
font-size: 25px;
font-weight: bolder;
}
.opeation {
margin: 20px 0;
}
}

152
backup/Home/index.tsx

@ -0,0 +1,152 @@
import electron from "@/plugins/electron"
import { addTodo, removeTodo } from "@/store/action/todo"
import { Button, ButtonGroup, ControlGroup, FormGroup, HotkeysProvider, InputGroup } from "@blueprintjs/core"
import { Cell, Column, Table2 } from "@blueprintjs/table"
import cs from "classnames"
import _ from "lodash"
import React, { useEffect, useRef, useState } from "react"
import { connect } from "react-redux"
import Dialog from "./Dialog"
import style from "./index.module.scss"
import useLocation from "./useLocation"
export interface HomeProps {
add(text: string): void
todo: ITodo[]
remove(id: number): void
}
let keyGen = 0
function Home(props: HomeProps) {
const [isOpen, setIsOpen] = useState<boolean>(false)
const keyRef = useRef<HTMLInputElement>(null)
function delItem() {
let key = keyRef.current?.value
if (key) {
let index = _.findIndex(clockList, { key: +key })
if (index != -1) {
var list = [...clockList]
list.splice(index, 1)
setClockList(list)
keyRef.current!.value = ""
}
}
}
const { save, get } = useLocation()
const [clockList, setClockList] = useState<Record<string, any>[]>([])
const keyList = _.map(clockList, "key")
const titleList = _.map(clockList, "title")
const timeList = _.map(clockList, "time")
const descList = _.map(clockList, "desc")
function onConfrim(title: string, time: string, desc: string) {
if (title && time) {
const value = {
key: ++keyGen,
title: title,
time: time,
desc: desc,
}
setClockList([...clockList, value])
setIsOpen(false)
}
}
useEffect(() => {
;(async () => {
let list = await electron.ipcRenderer.invoke("@func:clock:getData")
if (list) {
setClockList(list)
const keyList = _.map(list, "key")
if (keyList.length) {
keyGen = Math.max(...keyList)
}
}
})()
}, [])
useEffect(() => {
electron.ipcRenderer.send("@func:clock:saveData", clockList)
}, [clockList])
return (
<div className={cs(style.container, "container")}>
<div className={style.title}></div>
<div className={style.opeation}>
<ButtonGroup>
<Button
icon="insert"
onClick={() => {
setIsOpen(true)
}}
>
</Button>
<Button icon="refresh"></Button>
</ButtonGroup>
</div>
<table>
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<tfoot>
<tr>
<td>Sum</td>
<td>$180</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<td>February</td>
<td>$80</td>
</tr>
</tbody>
</table>
{/* <HotkeysProvider>
<Table2 numRows={titleList.length}>
<Column name="KEY" cellRenderer={index => <Cell>{keyList[index]}</Cell>}></Column>
<Column name="标题" cellRenderer={index => <Cell>{titleList[index]}</Cell>}></Column>
<Column name="时间" cellRenderer={index => <Cell>{timeList[index]}</Cell>}></Column>
<Column name="描述" cellRenderer={index => <Cell>{descList[index]}</Cell>}></Column>
</Table2>
</HotkeysProvider> */}
<div style={{ margin: "10px 0" }}>
<FormGroup helperText="需要填入指定的闹钟进行删除" label="Key" labelFor="text-input" labelInfo="(required)">
<ControlGroup fill={false} vertical={false}>
<InputGroup inputRef={keyRef} id="text-input" placeholder="请输入Key值进行删除" />
<Button onClick={() => delItem()} icon="trash" intent="danger" type="submit">
</Button>
</ControlGroup>
</FormGroup>
</div>
<Dialog isOpen={isOpen} setIsOpen={setIsOpen} onConfrim={onConfrim}></Dialog>
</div>
)
}
const mapStateToProps = (state: any) => {
return {
todo: state.todo,
}
}
const mapDispatchToProps = (dispatch: any) => ({
add: (text: string) => dispatch(addTodo(text)),
remove: (id: string | number) => dispatch(removeTodo(id)),
})
export default connect(mapStateToProps, mapDispatchToProps)(Home)

7
backup/Home/useLocation.ts

@ -0,0 +1,7 @@
export default function useLocation() {
return {
save: localStorage.setItem.bind(localStorage),
remove: localStorage.removeItem.bind(localStorage),
get: localStorage.getItem.bind(localStorage),
}
}

34
dist/package-lock.json

@ -1,5 +1,37 @@
{
"name": "my-electron-app",
"version": "1.0.0",
"lockfileVersion": 1
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"fs-extra": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
"integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
}
},
"graceful-fs": {
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
"integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
},
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
}
},
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
}
}
}

4
dist/package.json

@ -8,5 +8,7 @@
"author": "TopOne",
"license": "ISC",
"devDependencies": {},
"dependencies": {}
"dependencies": {
"fs-extra": "^10.0.0"
}
}

5
jest.config.js

@ -0,0 +1,5 @@
/** @type {import('@ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};

2657
package-lock.json

File diff suppressed because it is too large

21
package.json

@ -19,7 +19,8 @@
"packageaaa": "electron-forge package",
"make": "electron-forge make",
"build:vite": "vite build",
"serve": "vite preview"
"serve": "vite preview",
"test": "jest"
},
"keywords": [],
"author": "TopOne",
@ -36,6 +37,9 @@
"@rollup/plugin-node-resolve": "^13.0.4",
"@rollup/plugin-replace": "^3.0.0",
"@rollup/plugin-typescript": "^8.2.3",
"@types/jest": "^26.0.24",
"@types/lodash": "^4.14.172",
"@types/markdown-it": "^12.0.3",
"@types/minimist": "^1.2.2",
"@types/node": "^15.14.3",
"@types/react": "^17.0.0",
@ -59,6 +63,9 @@
"execa": "^5.1.1",
"i18next": "^20.3.4",
"i18next-browser-languagedetector": "^6.1.2",
"jest": "^27.0.6",
"lodash": "^4.17.21",
"markdown-it": "^12.2.0",
"node-loader": "^2.0.0",
"react": "^17.0.0",
"react-dom": "^17.0.0",
@ -70,6 +77,7 @@
"redux-saga": "^1.1.3",
"sass": "^1.35.1",
"styled-jsx": "^3.4.4",
"ts-jest": "^27.0.4",
"ts-loader": "^9.2.4",
"ts-node": "^10.1.0",
"tsconfig-paths": "^3.10.1",
@ -80,10 +88,15 @@
"vitejs-plugin-electron": "^0.1.3",
"webpack": "^5.47.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2",
"windicss": "^3.1.3"
"webpack-dev-server": "^3.11.2"
},
"dependencies": {
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2",
"framer-motion": "^4.1.17",
"fs-extra": "^10.0.0",
"normalize.css": "^8.0.1"
},
"dependencies": {},
"build": {
"productName": "my-project",
"appId": "com.example.yourapp",

35
plugins/md.ts

@ -0,0 +1,35 @@
import MarkdownIt from "markdown-it"
const mark = new MarkdownIt()
const mdToHtml = (str: string) => {
const content = mark.render(str)
return `
import React from "react"
export default React.createElement('div', {dangerouslySetInnerHTML:{__html: \`${content}\`} })`
}
export default function md(): any {
return {
name: "vite-plugin-md",
enforce: "pre",
transform(raw: any, id: any) {
if (!/\.md/g.test(id))
return
try {
return mdToHtml(raw)
} catch (e) {
this.error(e)
return ""
}
},
async handleHotUpdate(ctx: any) {
if (!/\.md/g.test(ctx.file))
return
const defaultRead = ctx.read
ctx.read = async function() {
return mdToHtml(await defaultRead())
}
}
}
}

6
script/code/runElectron.ts

@ -3,6 +3,7 @@ import { exec, spawn, ChildProcess } from "child_process"
import { join } from "path"
import * as electron from "electron"
import { main } from "../../package.json"
import { electronLog } from "../log"
export function devElectron() {
return new Promise((resolve, reject) => {
@ -11,8 +12,11 @@ export function devElectron() {
// env: Object.assign(process.env, { NODE_ENV: argv.env }),
})
if (electronProcess) {
electronProcess.stderr.on("data", data => {
electronLog(`${data}`, "red")
})
electronProcess.stdout.on("data", data => {
console.log(`${data}`)
electronLog(`${data}`, "yellow")
})
resolve(electronProcess)
} else {

8
script/code/runVite.ts

@ -1,6 +1,7 @@
// @ts-nocheck
import { exec, spawn, ChildProcess } from "child_process"
import { join } from "path"
import {logStats} from "../log"
export function devVite() {
return new Promise((resolve, reject) => {
@ -10,20 +11,23 @@ export function devVite() {
})
if (viteProcess) {
let isReady = false
let str = ""
viteProcess.stdout.on("data", data => {
str+=data
console.log(`${data}`)
if (!isReady && data.indexOf("ready") != -1) {
logStats("vite", str)
resolve(viteProcess)
}
})
viteProcess.stderr.on("data", data => {
console.error(`[vite err]: ${data}`)
logStats("vite err", data.toString())
reject()
})
viteProcess.on("close", code => {
console.log(`[vite close]: exited with code ${code}`)
logStats("vite close", code)
reject()
})
} else {

6
script/dev-runner.ts

@ -2,7 +2,7 @@
import * as chalk from "chalk"
import { devVite } from "./code/runVite"
import { devElectron } from "./code/runElectron"
import {logStats,electronLog} from "./log"
import { ChildProcess } from "child_process"
import { watch } from "rollup"
import options from "./rollup.config"
@ -10,7 +10,7 @@ const { startMain } = require("./webpack/runMain")
;(async () => {
let vitePorcess = await devVite()
console.log("[vite]", chalk.green(`vite ready.`))
logStats("vite","vite ready.")
let child: ChildProcess | null
let manualRestart = false
@ -25,7 +25,7 @@ const { startMain } = require("./webpack/runMain")
}
try {
child = await devElectron()
console.log("[electron]", chalk.green(`electron ready.`))
electronLog("electron ready.","green")
child.on("close", () => {
if (!manualRestart) {
// https://juejin.cn/post/6844904071682326535

8
script/log.ts

@ -1,7 +1,7 @@
const { say } = require("cfonts")
const chalk = require("chalk")
export function logStats(proc, data) {
export function logStats(proc:any, data:any) {
let log = ""
log += chalk.yellow.bold(`${proc} Process ${new Array(19 - proc.length + 1).join("-")}`)
@ -14,7 +14,7 @@ export function logStats(proc, data) {
chunks: false,
})
.split(/\r?\n/)
.forEach(line => {
.forEach((line:any) => {
log += " " + line + "\n"
})
} else {
@ -26,10 +26,10 @@ export function logStats(proc, data) {
console.log(log)
}
export function electronLog(data, color) {
export function electronLog(data:any, color:any) {
let log = ""
data = data.toString().split(/\r?\n/)
data.forEach(line => {
data.forEach((line:any) => {
log += ` ${line}\n`
})
if (/[0-9A-z]+/.test(log)) {

2
script/run.js

@ -15,5 +15,5 @@ if (argv.build) {
"PORT=3344",
"NODE_ENV=development",
"ts-node -r tsconfig-paths/register script/dev-runner --watch"
])
], { shell: true })
}

78
script/webpack/runMain.js

@ -6,7 +6,6 @@ const { spawn } = require('child_process')
const webpack = require('webpack')
// const WebpackDevServer = require('webpack-dev-server')
// const webpackHotMiddleware = require('webpack-hot-middleware')
const mainConfig = require('./webpack.main.config')
// const rendererConfig = require('./webpack.renderer.config')
@ -14,24 +13,27 @@ let electronProcess = null
let manualRestart = false
// let hotMiddleware
function logStats (proc, data) {
let log = ''
log += chalk.yellow.bold(`${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`)
log += '\n\n'
if (typeof data === 'object') {
data.toString({
colors: true,
chunks: false
}).split(/\r?\n/).forEach(line => {
log += ' ' + line + '\n'
})
function logStats(proc, data) {
let log = ""
log += chalk.yellow.bold(`${proc} Process ${new Array(19 - proc.length + 1).join("-")}`)
log += "\n\n"
if (typeof data === "object") {
data
.toString({
colors: true,
chunks: false,
})
.split(/\r?\n/)
.forEach((line) => {
log += " " + line + "\n"
})
} else {
log += ` ${data}\n`
}
log += '\n' + chalk.yellow.bold(`${new Array(28 + 1).join('-')}`) + '\n'
log += "\n" + chalk.yellow.bold(`${new Array(28 + 1).join("-")}`) + "\n"
console.log(log)
}
@ -40,8 +42,10 @@ function buildMain () {
return new Promise((resolve, reject) => {
mainConfig.mode = 'production'
webpack(mainConfig, (err, stats) => {
if (err) reject(err.stack || err)
else if (stats.hasErrors()) {
if (err) {
logStats('Main', chalk.red.bold(err))
reject(err.stack || err)
}else if (stats.hasErrors()) {
let err = ''
stats.toString({
chunks: false,
@ -51,7 +55,7 @@ function buildMain () {
.forEach(line => {
err += ` ${line}\n`
})
logStats('Main', chalk.red.bold(err))
reject(err)
}
else {
@ -77,7 +81,7 @@ function startMain (callback) {
compiler.watch({}, (err, stats) => {
if (err) {
console.log(err)
logStats('Main', chalk.red.bold(err))
return
}
@ -95,42 +99,6 @@ module.exports = {
}
function electronLog (data, color) {
let log = ''
data = data.toString().split(/\r?\n/)
data.forEach(line => {
log += ` ${line}\n`
})
if (/[0-9A-z]+/.test(log)) {
console.log(
chalk[color].bold('┏ Electron -------------------') +
'\n\n' +
log +
chalk[color].bold('┗ ----------------------------') +
'\n'
)
}
}
function greeting () {
const cols = process.stdout.columns
let text = ''
if (cols > 104) text = 'electron-vue'
else if (cols > 76) text = 'electron-|vue'
else text = false
if (text) {
say(text, {
colors: ['yellow'],
font: 'simple3d',
space: false
})
} else console.log(chalk.yellow.bold('\n electron-vue'))
console.log(chalk.blue(' getting ready...') + '\n')
}
// function init () {
// greeting()
// startMain()

23
src/main/facilities/clock/index.ts

@ -0,0 +1,23 @@
import { ipcMain } from "electron"
import fs from "fs-extra"
import path from "path"
const homeDir = require("os").homedir()
const clockJsonPath = path.resolve(homeDir, ".forceClock/clock.json")
fs.ensureFileSync(clockJsonPath)
try {
console.log("--->",fs.readJSONSync(clockJsonPath))
// const job = schedule.scheduleJob('42 * * * *', function(){
// console.log('The answer to life, the universe, and everything!');
// });
} catch (e) {
console.log(e)
// 读取JSON文件失败
}
ipcMain.on("@func:clock:saveData", function(event, data) {
fs.writeJson(clockJsonPath, data)
})
ipcMain.handle("@func:clock:getData", function() {
return fs.readJSONSync(clockJsonPath)
})

2
src/main/facilities/float/index.ts

@ -82,7 +82,7 @@ ipcMain.on("@func:float:showRightMenu", e => {
function createSuspensionWindow() {
Shared.data.floatWindow = new BrowserWindow({
width: 260, // 悬浮窗口的宽度 比实际DIV的宽度要多2px 因为有1px的边框
height: 95, // 悬浮窗口的高度 比实际DIV的高度要多2px 因为有1px的边框
height: 105, // 悬浮窗口的高度 比实际DIV的高度要多2px 因为有1px的边框
type: "toolbar", // 创建的窗口类型为工具栏窗口
frame: false, // 要创建无边框窗口
resizable: false, // 禁止窗口大小缩放

3
src/main/facilities/index.ts

@ -1,4 +1,5 @@
import Shared from "@main/share"
import "@main/facilities/clock"
import setTray from "@main/facilities/tray"
import { app, dialog, ipcMain } from "electron"
import Share from "../share"
@ -52,5 +53,5 @@ ipcMain.on("@func:buildin:quit", event => {
})
ipcMain.on("@func:render:addClock", (event, x, y) => {
ipcMain.emit("@func:main:show", event , "about")
ipcMain.emit("@func:main:show", event , "about/test")
})

20
src/main/facilities/main/index.ts

@ -14,23 +14,23 @@ ipcMain.on("@func:main:hide", () => {
}
})
let cur:string|null = null
export default function showWindow(url?: string) {
if (!Shared.data.mainWindow || Shared.data.mainWindow?.isDestroyed()) {
/**
* Initial window options
*/
Shared.data.mainWindow = new BrowserWindow({
height: 95,
height: 600,
useContentSize: true,
width: 260,
width: 800,
resizable: true,
minWidth: 260,
minHeight: 95,
minWidth: 800,
minHeight: 600,
icon: __static + "/icon.png",
// show: false,
// frame: false, // 去除原生的菜单
// transparent: true, // 背景透明
alwaysOnTop: true,
alwaysOnTop: false,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
@ -73,10 +73,16 @@ export default function showWindow(url?: string) {
} else {
Shared.data.mainWindow?.showInactive()
}
url = url === undefined ? '': url
if (cur === url){
return
}
if(!url){
cur = ""
Shared.data.mainWindow.loadURL(getFileUrl(""))
}else{
cur = url
Shared.data.mainWindow.loadURL(getFileUrl(url))
}
console.log(cur)
}

6
src/render/AppRouter.tsx

@ -47,12 +47,12 @@ function RouteMap(props: any) {
export default function () {
return (
<Router>
<RouteMap routes={routes}></RouteMap>
{/* <Layout
{/* <RouteMap routes={routes}></RouteMap> */}
<Layout
render={() => {
return <RouteMap routes={routes}></RouteMap>
}}
></Layout> */}
></Layout>
</Router>
)
}

23
src/render/assets/style/common.scss

@ -1,6 +1,11 @@
@import "./reset.scss";
@import "./_font.scss";
:focus {
// 去除按钮点击时的蓝色边框
outline: 0;
}
body,
button,
input,
@ -9,13 +14,14 @@ textarea {
font: 12px/1.5 tahoma, arial, "Hiragino Sans GB", "\5b8b\4f53", sans-serif;
}
body{
body {
// background-image: url("@/assets/images/0.jpg");
// background-attachment: fixed;
// background-position: center top 36px;
// background-repeat: no-repeat;
// background-size: cover;
}
a {
// color: initial;
display: inline-block;
@ -26,3 +32,18 @@ a {
.clearfix {
@include clearfix;
}
.container {
max-width: 900px;
margin: 0 auto;
}
.a-shadow {
//-moz-box-shadow: 3px 3px 4px #000;
//-webkit-box-shadow: 3px 3px 4px #000;
box-shadow: 0 0 4px #898989;
/* For IE 8 */
-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4,Direction=135, Color='#000000)";
/* For IE 5.5 - 7 */
filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#000000');
}

2
src/render/index.html

@ -7,6 +7,8 @@
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self' https: 'unsafe-inline'; style-src * 'unsafe-inline'; font-src * data:;"> -->
<!-- <meta http-equiv="X-Content-Security-Policy" content="default-src 'self' https: 'unsafe-inline'; style-src * 'unsafe-inline'; font-src * data:;"> -->
<!-- -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<title><%- title %></title>
</head>
<body>

10
src/render/main.tsx

@ -4,21 +4,19 @@ import React from "react";
import ReactDOM from "react-dom";
import "@/plugins/i18n"
import {Provider} from 'react-redux'
import electron from "@/plugins/electron"
import Router from "./AppRouter";
// 静态资源地址变量请用"__static",在html中使用请用__static
console.log(electron);
console.log(__staticVar);
console.log(__staticVar);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<Router></Router>
</Provider>
<Provider store={store}>
<Router></Router>
</Provider>
</React.StrictMode>,
document.getElementById("root")
);

3
src/render/plugins/electron/index.ts

@ -1,3 +1,4 @@
const electron = require("electron") // 只能用require
const electron = require("electron") // 只能用require ,而且不能用那个import转require的插件,否则样式懒加载样式打包有问题
export default electron

50
src/render/plugins/useRoute/index.ts

@ -0,0 +1,50 @@
import { useLocation } from "react-router-dom"
export function foundRoute(route: any, name: string, arrIndex?: number[]): any {
if (!arrIndex) {
arrIndex = []
}
for (let i = 0; i < route.length; i++) {
const element = route[i]
if (element.root) {
arrIndex = []
}
arrIndex.push(i)
let lena = element.path.split("/").length
let lenb = name.split("/").length
if (element.path == name && lena == lenb) {
return arrIndex
} else if (element.children) {
let a = foundRoute(element.children, name, arrIndex)
if (a) {
return a
}
}
}
}
export default function useRoute(routes:any){
const { pathname } = useLocation()
let oroute = JSON.parse(JSON.stringify(routes))
let index = foundRoute(routes, pathname)
let isLayout = true
let curA = null
let curB = null
if (index && index.length) {
let res = oroute[index[0]]
let cur = res
for (let i = 1; i < index.length; i++) {
const element = index[i]
cur.children = [cur.children[element]]
cur = cur.children[element]
}
if (cur) {
cur.children = []
}
if (cur.layout != undefined) {
isLayout = !!cur.layout
}
curA = cur
curB = res
}
return [curA,curB]
}

23
src/render/route.tsx

@ -1,6 +1,9 @@
import Page404 from "@/views/Auth/Page404"
import Home from "@/views/Home"
import Login from "@/views/Login"
import React, { lazy } from "react"
import useRouter from "@render/plugins/useRoute"
export const Loading = (props: any) => <div style={{ color: props.color }}>Lodeing.22..</div>
@ -21,11 +24,12 @@ let delay =
})
)
export default [
const routesArray = [
{
path: "/about",
component: lazy(() => import("@/views/About")),
exact: false,
root: true,
meta: {
auth: false,
},
@ -34,6 +38,7 @@ export default [
{
path: "/about/test",
exact: true,
layout:false,
meta: {
auth: false,
},
@ -46,16 +51,19 @@ export default [
path: "/float",
component: lazy(() => import("@/views/Float")),
exact: true,
root: true,
layout:false,
meta: {
auth: false,
},
children: [],
},
{
path: "/home",
component: lazy(() => import("@/views/Home")),
path: "/home", // Home,//
component: lazy(delay(() => import("@/views/Home"), 2000)),
exact: true,
loading: () => <Loading color="blue"></Loading>,
// loading: () => <Loading color="blue"></Loading>,
root: true,
meta: {
auth: false,
},
@ -64,15 +72,22 @@ export default [
{
path: "/",
exact: true,
root: true,
redirect: "/home",
},
{
path: "/login",
root: true,
component: Login //lazy(() => import("@/views/Login")),
},
{
path: "*",
exact: false,
root: true,
component: Page404,
},
]
export const useRoute = useRouter.bind(null, routesArray)
export default routesArray

16
src/render/views/About/a.md

@ -0,0 +1,16 @@
# 天涯路远,只争朝夕
时间如白驹过隙,一晃而过,在茫茫中,我仿佛已经丢失了很多,曾经的路已不见痕迹,前方的海无涯无际。
回首望去,过去的岁月如梦幻泡影,伸手一触,四散分离。
你还记得自己的梦想是什么吗?你还记得自己曾想过要干什么吗?如今的自己是否活成了当初讨厌的样子?
在冰冷的白色灯管下,我写下了这一段话,我也将深度思考,回答。这一切是否是自己期望的。
> 今天是2021-08-04 00:26:00,昨天是我**25岁**生日。
```javascript
console.log("时间会检验出答案"); // 请带上分号,给一切一个结束
```
## 曾经
阿松大

3
src/render/views/About/index.module.scss

@ -0,0 +1,3 @@
.about{
padding: 20px;
}

27
src/render/views/About/index.tsx

@ -1,5 +1,7 @@
import React from "react"
import style from "./index.module.scss"
import { useLocation, Route, Switch, useHistory } from "react-router-dom"
import html from "./a.md"
function Test() {
return <div>test</div>
@ -10,18 +12,23 @@ export default function About(props: any) {
// let location = useLocation()
function back(){
console.log(1231);
history.goBack()
history.replace("/about")
}
// console.log(html)
return (
<div className="">
<div onClick={() =>back()}> asdasd</div>
<div>22{props.children}{location.href}</div>
<p>sadsa</p>
<p>sadsa</p>
<Route path="/about/aa" exact={true}>
<Test></Test>
</Route>
<div className={`container ${style.about}`}>
<div className={"bp3-running-text bp3-text-large"}>
{html}
</div>
{/*<div onClick={() =>back()}>阿萨 阿松大asdasd</div>*/}
{/*<div>22{props.children}{location.href}</div>*/}
{/*<p>sadsa</p>*/}
{/*<p>sadsa</p>*/}
{/*<Route path="/about/aa" exact={true}>*/}
{/* <Test></Test>*/}
{/*</Route>*/}
</div>
)
}

3
src/render/views/Float/index.module.scss

@ -2,8 +2,9 @@
position: fixed;
left: 0;
top: 0;
transform: translate(-50% -50%);
right: 0;
font-size: 40px;
text-align: center;
font-weight: bolder;
text-align: center;
line-height: 1.3;

72
src/render/views/Home/index.module.scss

@ -1,14 +1,60 @@
.clock {
position: fixed;
left: 0;
top: 0;
transform: translate(-50% -50%);
font-size: 40px;
font-weight: bolder;
text-align: center;
line-height: 1.3;
color: #CD1110;
font-family: "pixi";
user-select: none;
pointer-events: none;
.container {
padding: 20px;
.title {
font-size: 25px;
font-weight: bolder;
}
.opeation {
margin: 20px 0;
}
.panel {
padding: 10px 20px;
border-radius: 6px;
.panelTitle {
cursor: pointer;
margin-bottom: 10px;
.panelTitleName {
display: inline-block;
font-size: 25px;
font-weight: bolder;
position: relative;
&:before {
font-size: 20px;
content: "#";
opacity: 0;
position: absolute;
color: red;
right: 100%;
top: 50%;
transform: translateY(-50%);
transition: opacity .3s linear;
}
&:hover:before {
opacity: 1;
}
}
.panelTitleDesc {
display: inline-block;
font-size: 14px;
margin-left: 8px;
}
}
.cell {
border: 1px solid #999999;
padding: 5px 15px;
font-size: 14px;
border-radius: 5px;
cursor: pointer;
user-select: none;
}
}
}

58
src/render/views/Home/index.tsx

@ -1,35 +1,41 @@
import { addTodo, removeTodo } from "@/store/action/todo"
import { Grid, Paper } from "@material-ui/core"
import cs from "classnames"
import { motion } from "framer-motion"
import React from "react"
import { connect } from "react-redux"
import style from "./index.module.scss"
import useTime from "./useTime"
import usePositionElectron from "./usePositionElectron"
export interface HomeProps {
add(text: string): void
todo: ITodo[]
remove(id: number): void
}
function Home(props: HomeProps) {
const MyComponent = ({ children }: any) => {
return (
<div className={style.clock}>
asdsadasdsdasad
</div>
<motion.div initial="hidden" animate="visible" variants={{
visible: { opacity: 1 },
hidden: { opacity: 0 }
}}>
{children}
</motion.div>
)
}
const mapStateToProps = (state: any) => {
return {
todo: state.todo
}
function Home() {
return (
<MyComponent>
<div className={cs(style.container, "container")}>
<Paper className={cs(style.panel)} elevation={3} variant="outlined">
<div className={style.panelTitle}>
<div className={style.panelTitleName}></div>
<div className={style.panelTitleDesc}>便</div>
</div>
<Grid container style={{ textAlign: "center" }} spacing={2}>
<Grid item xs={12} sm={6} md={2}>
<div className={style.cell}>Base64</div>
</Grid>
<Grid item xs={12} sm={6} md={2}>
<div className={style.cell}></div>
</Grid>
</Grid>
</Paper>
</div>
</MyComponent>
)
}
const mapDispatchToProps = (dispatch: any) => ({
add: (text: string) => dispatch(addTodo(text)),
remove: (id: string | number) => dispatch(removeTodo(id))
})
export default connect(mapStateToProps, mapDispatchToProps)(Home)
export default Home

32
src/render/views/Home/usePositionElectron.ts

@ -1,32 +0,0 @@
import electron from "@/plugins/electron"
import { useEffect } from "react"
export default function() {
useEffect(() => {
let biasX = 0
let biasY = 0
document.addEventListener("mousedown", function(e) {
switch (e.button) {
case 0:
biasX = e.x
biasY = e.y
document.addEventListener("mousemove", moveEvent)
break
case 2:
electron.ipcRenderer.send("@func:float:showRightMenu")
break
}
})
document.addEventListener("mouseup", function() {
biasX = 0
biasY = 0
document.removeEventListener("mousemove", moveEvent)
})
function moveEvent(e: any) {
electron.ipcRenderer.send("@func:buildin:setPosition", e.screenX - biasX, e.screenY - biasY)
}
}, [])
}

55
src/render/views/Home/useTime.ts

@ -1,55 +0,0 @@
import { Dispatch, SetStateAction, useEffect, useState } from "react"
type ITime<T = string | number> = {
year?: T;
month?: T;
day?: T;
hour?: T;
minute?: T;
second?: T;
}
function isLow10(value:string | number) {
if (+value< 10){
return "0"+value
}
return value
}
export default function(isUpdate = true): [ITime, Dispatch<SetStateAction<ITime>>] {
let [nowDate, setNowDate] = useState<ITime>({})
function updateTime() {
let date: ITime = {}
let newDate = new Date()
date.year = isLow10(newDate.getFullYear())
date.month = isLow10(newDate.getMonth() + 1)
date.day = isLow10(newDate.getDate())
date.hour = isLow10(newDate.getHours())
date.minute = isLow10(newDate.getMinutes())
date.second = isLow10(newDate.getSeconds())
setNowDate(date)
return newDate.getMilliseconds()
}
if (isUpdate) {
useEffect(() => {
function cicleCall(millis: number): NodeJS.Timeout {
let timeID = setTimeout(() => {
let millis = 1000 - updateTime()
cicleCall(millis)
}, millis)
return timeID
}
let millis = 1000 - updateTime()
let timeID = cicleCall(millis)
return () => {
clearTimeout(timeID)
}
}, [])
}
return [nowDate, setNowDate]
}

54
src/render/views/Layout/index.module.scss

@ -0,0 +1,54 @@
.Layout {
height: 100vh;
position: relative;
transform:scale(1,1);
&.NoLayout{
.left {
display: none;
width: 0;
}
.right{
margin-left: 0;
}
}
.left {
position: fixed;
left: 0;
top: 0;
bottom: 0;
background-color: #2c2c2c;
width: 55px;
display: flex;
flex-direction: column;
overflow: hidden;
.leftList,.leftListBottom {
width: 100%;
.leftItem {
text-align: center;
padding: 10px 0;
color: #808080;
cursor: pointer;
&:hover {
color: #f8ffff;
}
position: relative;
.activeLine{
position: absolute;
left: 0;
top: 6px;
bottom: 6px;
width: 3px;
background-color: white;
}
}
}
.leftList{
flex-grow: 1;
flex-shrink: 0;
}
}
.right{
margin-left: 55px;
}
}

69
src/render/views/Layout/index.tsx

@ -1,14 +1,67 @@
import React, { ReactElement } from "react"
import { useLocation } from "react-router-dom"
import * as Icon from "@material-ui/icons"
import { useRoute } from "@render/route"
import cs from "classnames"
import React from "react"
import { NavLink } from "react-router-dom"
import style from "./index.module.scss"
// interface IProps {
// render(): ReactElement
// }
function ActionItem() {
}
export default function Layout(props: any) {
let isLayout = true
let [curRoute, routeList] = useRoute()
if (curRoute.layout != undefined) {
isLayout = !!curRoute.layout
}
interface TList {
icon: any
path: string
title: string
text: string
}
const list: TList[] = [
{
path: "/home",
icon: Icon.Home,
title: "首页",
text: "首页"
},
{
path: "/about",
icon: Icon.Home,
title: "添加闹钟",
text: "关于"
}
]
export default function (props: any) {
return (
<div>
<div className="content">
<div className={cs(style.Layout, !isLayout ? style.NoLayout : "")}>
<div className={style.left}>
<div className={style.leftList}>
{list.map((v, i) => (
<NavLink key={i} replace to={v.path} style={{ display: "block" }}>
<div className={style.leftItem} title={v.title}>
<v.icon style={{ fontSize: 22 }}/>
<div>{v.text}</div>
{v.path == curRoute.path && <div className={style.activeLine}></div>}
</div>
</NavLink>
))}
</div>
<div className={style.leftListBottom}>
<div className={style.leftItem} title={"设置"}>
<Icon.Home style={{ fontSize: 22 }}/>
</div>
<div className={style.leftItem} title={"设置"}>
<Icon.Home style={{ fontSize: 22 }}/>
</div>
</div>
</div>
<div className={style.right}>
<props.render></props.render>
</div>
</div>

0
test.js → te22st.js

2
tsconfig.json

@ -23,7 +23,7 @@
"@main/*": ["src/main/*"],
"@src/*": ["src/*"],
"@root/*": ["./*"]
},
}
},
"include": ["src", "types"],
"exclude": ["node_modules"],

4
types/global.d.ts

@ -10,3 +10,7 @@ interface IAction extends IAny{
declare const __static: string;
declare const __staticVar: string;
declare module "*.md"
declare module 'react-desktop/macOs';

7
vite.config.ts

@ -2,16 +2,18 @@ import { defineConfig } from "vite"
import reactRefresh from "@vitejs/plugin-react-refresh"
// import WindiCSS from "vite-plugin-windicss"
const { resolve, join } = require("path")
import electron from "vitejs-plugin-electron"
// import electron from "vitejs-plugin-electron"
import { minifyHtml, injectHtml } from "vite-plugin-html"
import replace from '@rollup/plugin-replace';
import md from './plugins/md';
let isDev = process.env.NODE_ENV === "development"
let plugins = []
let staticPath = isDev? '/static': 'static'
plugins.push(
// electron(),
md(),
replace({
preventAssignment: true,
"__static": staticPath,
@ -32,6 +34,7 @@ export default defineConfig({
},
},
server: {
// @ts-ignore
port: +process.env.PORT,
},
build: {

Loading…
Cancel
Save