├── .DS_Store
├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── public
├── banner.png
├── demo1.jpg
├── demo2.jpg
├── demo3.jpg
├── demo4.jpg
├── index.html
├── logo128.png
├── manifest.json
├── news.js
└── robots.txt
└── src
├── App.css
├── App.js
├── AppIcons
├── Bilibili.svg
├── Bytedance.svg
├── Douban.svg
├── Douyin.svg
├── Github.svg
├── Juejin.svg
├── Leetcode.svg
├── NewTabIcon.svg
├── Toutiao.svg
├── Web.svg
├── Weibo.svg
└── Xigua.svg
├── asset
├── Tomato.png
├── astronaut.json
├── motorbike.json
├── rest.mp3
├── solar-system.json
├── solarsystem.json
├── tick.mp3
├── woodenfish.mp3
├── woodenfish.png
└── work.mp3
├── components
├── Account
│ ├── Account.css
│ └── Account.js
├── Apps
│ ├── AppFolder
│ │ ├── AppFolder.css
│ │ └── AppFolder.js
│ ├── Apps.css
│ ├── Apps.js
│ └── SetApp
│ │ ├── SetApp.css
│ │ └── SetApp.js
├── Calendar
│ ├── CalComponent.css
│ └── CalComponent.js
├── ChatRoom
│ ├── ChatRoom.css
│ └── ChatRoom.js
├── ClickMenu
│ ├── ClickMenu.css
│ └── ClickMenu.js
├── Clock
│ ├── Clock.css
│ ├── Clock.js
│ └── SetClock
│ │ ├── SetClock.css
│ │ └── SetClock.js
├── Competition
│ ├── Competition.css
│ └── Competition.js
├── CountDown
│ ├── CountDown.css
│ └── CountDown.js
├── Demos
│ ├── Demos.css
│ └── Demos.js
├── FormHabit
│ └── FormHabit.js
├── FuncCard
│ ├── FuncCard.css
│ ├── FuncCard.js
│ └── SetFuncCard
│ │ ├── SetFuncCard.css
│ │ └── SetFuncCard.js
├── FuncModal
│ ├── FuncModal.css
│ └── FuncModal.js
├── FunctionAera
│ ├── FunctionAera.css
│ ├── FunctionAera.js
│ └── SetFunctionAera
│ │ ├── SetFunctionArea.css
│ │ └── SetFunctionArea.js
├── MottoFooter
│ ├── MottoFooter.css
│ └── MottoFooter.js
├── News
│ ├── News.css
│ └── News.js
├── Notes
│ ├── index.css
│ ├── index.js
│ ├── markdown-notes
│ │ ├── index.css
│ │ └── index.js
│ └── noesTabs.js
├── Pictures
│ ├── index.js
│ └── style.css
├── Search
│ ├── Search.css
│ └── Search.js
├── ServerMonitor
│ ├── ServerMonitor.css
│ └── ServerMonitor.js
├── SetBackground
│ ├── SetBackground.css
│ └── SetBackground.js
├── Setting
│ └── Setting.js
├── Snippets
│ ├── Snippets.css
│ └── Snippets.js
├── StockMarket
│ ├── StockMarket.css
│ └── StockMarket.js
├── SwiperAera
│ ├── SwiperAera.css
│ └── SwiperAera.js
├── Todo
│ ├── AddItemInput
│ │ ├── index.css
│ │ └── index.js
│ ├── EditItemInput.js
│ ├── Todo.js
│ ├── TodoItems
│ │ ├── index.css
│ │ └── index.js
│ ├── TodoModal.css
│ └── TodoModal.js
├── TomatoClock
│ ├── TomatoClock.css
│ └── TomatoClock.js
├── ToolKit
│ ├── ToolKit.css
│ └── ToolKit.js
├── TopNav
│ ├── TopNav.css
│ └── TopNav.js
├── Weather
│ ├── Weather.js
│ ├── plugin.js
│ └── style.css
└── WoodenFish
│ ├── WoodenFish.css
│ └── WoodenFish.js
├── config
└── index.js
├── font
├── DS-Digital Bold.ttf
├── UnidreamLED.eot
├── UnidreamLED.woff
├── iconfont.css
├── iconfont.js
├── iconfont.json
└── iconfont.ttf
├── hooks
├── useLocalStorage.js
└── useScript.js
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
├── service
└── getCookie.js
├── setupProxy.js
├── setupTests.js
└── store
├── index.js
└── reducer.js
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/.DS_Store
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | # VScode需要安装插件支持
3 | root = true
4 |
5 | [*]
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
16 | [Makefile]
17 | indent_style = tab
18 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/.eslintignore
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true
5 | },
6 | "extends": ["eslint:recommended", "plugin:react/recommended"],
7 | "overrides": [],
8 | "parserOptions": {
9 | "ecmaVersion": "latest",
10 | "sourceType": "module"
11 | },
12 | "plugins": ["react"],
13 | "rules": {
14 | "quotes": 1,
15 | "semi": 1,
16 | "no-console": 1,
17 | "no-undef": "off",
18 | "no-restricted-globals": "off",
19 | "no-unused-vars": 1,
20 | "react/react-in-jsx-scope":"off",
21 | "react/prop-types":"off",
22 | "react/display-name": 1,
23 | "react/jsx-key": 1
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Build app and deploy to Aliyun
4 | # 将CI设置为false,不然会把warning当error
5 | env:
6 | CI: false
7 | on:
8 | #监听push操作
9 | push:
10 | branches:
11 | # mian分支,你也可以改成其他分支
12 | - main
13 | jobs:
14 | # 任务ID
15 | build:
16 | # 运行环境
17 | runs-on: ubuntu-latest
18 | # 步骤
19 | steps:
20 | # 使用别人的action
21 | - uses: actions/checkout@v2
22 | # 步骤名称
23 | - name: npm install
24 | # 步骤执行指令
25 | run: npm install -legacy-peer-deps
26 | - name: npm run build
27 | run: npm run build
28 | # 命名这个任务为发布Deploy
29 | - name: Deploy
30 | # 因为构建之后,需要把代码上传到服务器上,所以需要连接到ssh,并且做一个拷贝操作
31 | uses: appleboy/scp-action@v0.1.7
32 | env:
33 | WELCOME: "ssh scp ssh pipelines"
34 | LASTSSH: "Doing something after copying"
35 | with:
36 | host: ${{ secrets.USER_HOST }}
37 | username: ${{ secrets.USER_NAME }}
38 | # pass: ${{ secrets.USER_PASS }}
39 | key: ${{ secrets.USER_KEY }}
40 | source: "./build/*"
41 | target: /home/www/newtab.wisdompanda
42 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | #scripts
26 | *.sh
27 | *.py
28 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "avoid",
3 | "bracketSameLine": false,
4 | "bracketSpacing": true,
5 | "embeddedLanguageFormatting": "auto",
6 | "htmlWhitespaceSensitivity": "css",
7 | "insertPragma": false,
8 | "jsxSingleQuote": true,
9 | "printWidth": 80,
10 | "proseWrap": "preserve",
11 | "quoteProps": "as-needed",
12 | "requirePragma": false,
13 | "semi": true,
14 | "singleQuote": false,
15 | "tabWidth": 2,
16 | "trailingComma": "es5",
17 | "useTabs": false,
18 | "vueIndentScriptAndStyle": false
19 | }
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 wisdompandamaster
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "newtab",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@ant-design/icons": "^4.7.0",
7 | "@ant-design/pro-components": "^1.1.3",
8 | "@ant-design/pro-form": "^1.69.1",
9 | "@ant-design/pro-table": "^2.76.1",
10 | "@ant-design/pro-utils": "^1.42.0",
11 | "@babel/runtime": "^7.18.3",
12 | "@testing-library/jest-dom": "^5.16.2",
13 | "@testing-library/react": "^12.1.2",
14 | "@testing-library/user-event": "^13.5.0",
15 | "antd": "^4.18.6",
16 | "array-move": "^4.0.0",
17 | "axios": "^0.26.1",
18 | "babel": "^6.23.0",
19 | "braft-editor": "^2.3.9",
20 | "braft-extensions": "^0.1.1",
21 | "canvas-confetti": "^1.6.0",
22 | "draft-js-prism": "^1.0.6",
23 | "fetch-jsonp": "^1.2.1",
24 | "highlight.js": "^11.4.0",
25 | "immutability-helper": "^3.1.1",
26 | "js-md5": "^0.7.3",
27 | "jsonp": "^0.2.1",
28 | "lunar-javascript": "^1.2.37",
29 | "markdown-it": "^12.3.2",
30 | "memfs": "^4.2.0",
31 | "minio": "^7.0.26",
32 | "prismjs": "^1.29.0",
33 | "react": "^17.0.2",
34 | "react-activity-calendar": "^1.6.0",
35 | "react-calendar": "^3.7.0",
36 | "react-cookies": "^0.1.1",
37 | "react-datepicker": "^4.6.0",
38 | "react-dnd": "^15.1.1",
39 | "react-dnd-html5-backend": "^15.1.2",
40 | "react-dom": "^17.0.2",
41 | "react-draggable": "^4.4.5",
42 | "react-github-calendar": "^3.3.1",
43 | "react-lottie": "^1.2.3",
44 | "react-markdown-editor-lite": "^1.3.2",
45 | "react-scripts": "5.0.0",
46 | "react-sortable-hoc": "^2.0.0",
47 | "swiper": "^8.1.6",
48 | "web-vitals": "^2.1.4"
49 | },
50 | "scripts": {
51 | "start": "react-scripts start",
52 | "build": "CI=false && react-scripts build",
53 | "test": "react-scripts test",
54 | "eject": "react-scripts eject"
55 | },
56 | "eslintConfig": {
57 | "extends": [
58 | "react-app",
59 | "react-app/jest"
60 | ]
61 | },
62 | "browserslist": {
63 | "production": [
64 | ">0.2%",
65 | "not dead",
66 | "not op_mini all"
67 | ],
68 | "development": [
69 | "last 1 chrome version",
70 | "last 1 firefox version",
71 | "last 1 safari version"
72 | ]
73 | },
74 | "devDependencies": {
75 | "eslint": "^8.26.0",
76 | "eslint-plugin-react": "^7.31.10",
77 | "prettier": "^2.7.1",
78 | "react-redux": "^7.2.6",
79 | "redux": "^4.1.2"
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/public/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/public/banner.png
--------------------------------------------------------------------------------
/public/demo1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/public/demo1.jpg
--------------------------------------------------------------------------------
/public/demo2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/public/demo2.jpg
--------------------------------------------------------------------------------
/public/demo3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/public/demo3.jpg
--------------------------------------------------------------------------------
/public/demo4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/public/demo4.jpg
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
21 |
22 |
31 | NewTab 标签页
32 |
33 |
34 |
35 |
36 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/public/logo128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/public/logo128.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo512.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | @import "~antd/dist/antd.css";
2 |
3 | /* 全局CSS样式 */
4 |
5 | :root {
6 | /* 定义CSS变量,之后设置简单模式,浅色或深色模式的时候可以用*/
7 | --dark-color: #0000004d;
8 | }
9 | body {
10 | line-height: normal;
11 | min-width: 800px;
12 | }
13 | .App {
14 | position: absolute;
15 | width: 100vw;
16 | height: 100vh;
17 | /* background-color: #59887c4d; */
18 | }
19 | .mask {
20 | width: 100vw;
21 | height: 100vh;
22 | position: fixed;
23 | background-color: #000;
24 | }
25 | .background {
26 | width: 100vw;
27 | height: 100vh;
28 | position: fixed;
29 | transition: background-image 0.3s ease-in-out;
30 | /*通过缩放来去掉白边 */
31 | }
32 | .clockSearch {
33 | display: flex;
34 | justify-content: center;
35 | }
36 |
37 | /* -------------更改的antd modal组件样式--------- */
38 | .ant-modal-header {
39 | border-radius: 10px;
40 | }
41 | .ant-modal-content {
42 | border-radius: 10px;
43 | }
44 | .ant-modal-close-x:hover {
45 | background-color: #0000004d;
46 | border-radius: 0 10px 0 0;
47 | }
48 | .ant-collapse > .ant-collapse-item:last-child,
49 | .ant-collapse-borderless > .ant-collapse-item:last-child .ant-collapse-header {
50 | border-radius: 10px;
51 | }
52 |
53 | /* Todo组件的css */
54 | #todo-app {
55 | /* position: absolute; */
56 | display: inline-block;
57 | /* width: 18vw;
58 | height: 8.5vw; */
59 | width: 352px;
60 | height: 165px;
61 | /* left: 392px;
62 | top: 20px; */
63 | /* left:20px;
64 | top:205px; */
65 | padding-bottom: 10px;
66 | /* font-family: ; */
67 | padding-top: 10px;
68 | background: #ffffff;
69 | border: 0px solid #ffffff;
70 | border-radius: 20px;
71 | transition: 0.1s ease-in;
72 | }
73 | #todo-app:active {
74 | transform: scale(0.95);
75 | }
76 |
77 | #todo-container {
78 | display: flex;
79 | height: 100%;
80 | max-height: 165px;
81 | border-radius: 20px;
82 | justify-content: space-between;
83 | }
84 |
85 | #side-container {
86 | width: 40%;
87 | border-radius: 20px;
88 | }
89 |
90 | #todo-header {
91 | height: 20%;
92 | border-radius: 20px;
93 | }
94 |
95 | #app-icon {
96 | position: relative;
97 | width: 6px;
98 | height: 14px;
99 | left: 18px;
100 | top: 12px;
101 | background: linear-gradient(180deg, #b1ff64 0%, #11f2af 100%);
102 | box-shadow: 0px 3px 6px rgba(71, 255, 55, 0.8);
103 | border-radius: 20px;
104 | }
105 |
106 | /* #app-title {
107 | position: relative;
108 | width: 100px;
109 | left: 36px;
110 | top:-7px;
111 | font-style: normal;
112 | font-weight: bold;
113 | font-size: 18px;
114 | line-height: 22px;
115 | letter-spacing: 0.2rem;
116 | color: rgba(0, 0, 0, 0.85);
117 | cursor: pointer;
118 | } */
119 |
120 | #todo-count {
121 | height: 90%;
122 | border-radius: 20px;
123 | display: flex;
124 | align-items: center;
125 | justify-content: space-evenly;
126 | cursor: pointer;
127 | }
128 |
129 | .count {
130 | display: flex;
131 | flex-direction: column;
132 | align-items: center;
133 | justify-content: space-evenly;
134 | }
135 |
136 | .count h1 {
137 | font-style: normal;
138 | font-weight: 400;
139 | font-size: 35px;
140 | line-height: 35px;
141 | }
142 |
143 | #count-completed {
144 | color: #63ff3c;
145 | }
146 |
147 | .count p {
148 | font-style: normal;
149 | font-weight: 500;
150 | font-size: 15px;
151 | line-height: 20px;
152 | letter-spacing: 0.05em;
153 | }
154 |
155 | #p-completed {
156 | color: rgba(0, 0, 0, 0.5);
157 | }
158 |
159 | #items-container {
160 | width: 60%;
161 | height: 145px;
162 | display: flex;
163 | margin-top: -25px;
164 | flex-direction: column;
165 | overflow-x: hidden;
166 | overflow-y: scroll;
167 | justify-items: space-evenly;
168 | }
169 |
170 | #items-container::-webkit-scrollbar {
171 | width: 0;
172 | height: 0;
173 | color: transparent;
174 | }
175 |
176 | .todo-item {
177 | display: flex;
178 | cursor: pointer;
179 | user-select: none;
180 | font-size: 18px;
181 | }
182 |
183 | .item-icon {
184 | height: 1em;
185 | width: 1em;
186 | margin-top: 0.1em;
187 | margin-right: 1em;
188 | }
189 |
190 | .item-text {
191 | width: 100%;
192 | font-style: normal;
193 | font-weight: normal;
194 | font-size: 18px;
195 | line-height: 18px;
196 | margin-right: 1em;
197 | font-weight: 600;
198 | white-space: nowrap;
199 | overflow: hidden;
200 | text-overflow: ellipsis;
201 | }
202 |
203 | .item-completed {
204 | /* text-decoration: line-through; */
205 | opacity: 0.2;
206 | }
207 |
208 | #items-completed-header {
209 | color: gray;
210 | font-size: 1em;
211 | font-weight: 400;
212 | }
213 |
214 | hr {
215 | width: 90%;
216 | height: 0px;
217 | border: 0.5px solid rgba(0, 0, 0, 0.1);
218 | margin: 0.3em 0;
219 | }
220 |
221 | #modal-button {
222 | border: 0;
223 | background-color: #ffffff;
224 | color: gray;
225 | text-align: right;
226 | position: absolute;
227 | right: 10px;
228 | height: 24px;
229 | top: 10px;
230 | text-decoration: underline;
231 | margin-right: 1em;
232 | margin-top: 0em;
233 | }
234 |
235 | #modal-button:hover {
236 | color: #63ff3c;
237 | }
238 |
239 | .ant-modal {
240 | padding-bottom: 0;
241 | max-width: 100vw;
242 | }
243 |
244 | .ant-modal-content {
245 | border-radius: 10px;
246 | }
247 |
248 | .ant-modal-header {
249 | border-radius: 10px;
250 | }
251 |
252 | .ant-modal-body {
253 | border-radius: 10px;
254 | overflow: scroll;
255 | padding: 1.5% 1.5% 1.5% 1.5%;
256 | }
257 |
258 | .ant-modal-body::-webkit-scrollbar {
259 | width: 0;
260 | height: 0;
261 | color: transparent;
262 | }
263 |
264 | .ant-modal-footer {
265 | display: none;
266 | }
267 |
268 | #items-completed-header {
269 | height: 2em;
270 | text-align: center;
271 | }
272 |
273 | #items-completed-header h1 {
274 | color: gray;
275 | font-size: 1em;
276 | font-weight: 400;
277 | }
278 |
279 | hr.todo-hr {
280 | width: auto;
281 | border: 0.5px solid rgb(211, 211, 211);
282 | }
283 |
284 | .react-datepicker__input-container {
285 | top: -11px;
286 | }
287 |
288 | /* 天气组件的CSS */
289 | #Weather {
290 | position: absolute;
291 | width: 352px;
292 | height: 165px;
293 | left: 183px;
294 | top: 390px;
295 | background: #ffffff;
296 | border: 1px solid #ffffff;
297 | border-radius: 20px;
298 | }
299 |
300 | .snippets-container {
301 | position: absolute;
302 | z-index: 2;
303 | top: 100px;
304 | left: 200px;
305 | }
306 |
307 | /* 设置新闻里的列表背景颜色 */
308 | .ant-tabs-content-holder {
309 | background-color: rgba(255, 255, 255, 0.8);
310 | }
311 |
--------------------------------------------------------------------------------
/src/AppIcons/Bilibili.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/AppIcons/Bytedance.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/AppIcons/Douban.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/AppIcons/Douyin.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/AppIcons/Github.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/AppIcons/Leetcode.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/AppIcons/NewTabIcon.svg:
--------------------------------------------------------------------------------
1 |
86 |
--------------------------------------------------------------------------------
/src/AppIcons/Toutiao.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/AppIcons/Web.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/AppIcons/Weibo.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/AppIcons/Xigua.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/asset/Tomato.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/asset/Tomato.png
--------------------------------------------------------------------------------
/src/asset/rest.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/asset/rest.mp3
--------------------------------------------------------------------------------
/src/asset/tick.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/asset/tick.mp3
--------------------------------------------------------------------------------
/src/asset/woodenfish.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/asset/woodenfish.mp3
--------------------------------------------------------------------------------
/src/asset/woodenfish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/asset/woodenfish.png
--------------------------------------------------------------------------------
/src/asset/work.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/asset/work.mp3
--------------------------------------------------------------------------------
/src/components/Account/Account.css:
--------------------------------------------------------------------------------
1 | .login_form {
2 | display: flex;
3 | flex-wrap: wrap;
4 | width: 271px;
5 | margin: 0 auto;
6 | font-size: 14px;
7 | line-height: 20px;
8 | font-weight: 700;
9 | }
10 | .login_form label {
11 | width: 100%;
12 | margin: 5px auto;
13 | }
14 | .login_form input {
15 | display: block;
16 | width: 100%;
17 | height: 30px;
18 | margin-top: 5px;
19 | border: 1px solid #000000;
20 | box-sizing: border-box;
21 | border-radius: 10px;
22 | padding-left: 10px;
23 | line-height: 30px;
24 | outline: none;
25 | }
26 | .login_form input:nth-child(3) {
27 | background: linear-gradient(180deg, #6cdcff 0%, #3355ff 100%);
28 | box-shadow: 0px 4px 10px rgba(17, 84, 255, 0.6);
29 | border: none;
30 | margin-top: 20px;
31 | margin-bottom: 20px;
32 | letter-spacing: 0.5em;
33 | color: #ffffff;
34 | transition: 0.3s ease-in;
35 | cursor: pointer;
36 | }
37 | .login_form input:nth-child(3):active {
38 | transform: scale(0.9);
39 | }
40 | form.login_form + div {
41 | width: 274px;
42 | border: 1px solid rgba(0, 0, 0, 0.2);
43 | margin: 10px auto 0 auto;
44 | }
45 | .noaccount {
46 | position: relative;
47 | width: 120px;
48 | text-align: center;
49 | height: 17px;
50 | margin: 10px auto -15px auto;
51 | top: -20px;
52 | background-color: #ffffff;
53 | line-height: 17px;
54 | }
55 |
56 | .onsignin {
57 | display: flex;
58 | justify-content: space-around;
59 | align-items: center;
60 | font-size: 20px;
61 | line-height: 20px;
62 | font-weight: 700;
63 | }
64 |
--------------------------------------------------------------------------------
/src/components/Account/Account.js:
--------------------------------------------------------------------------------
1 | import { Button, message } from "antd";
2 | import { useState } from "react";
3 | import "./Account.css";
4 | import cookie from "react-cookies";
5 |
6 | export default function Account() {
7 | const [username, setUsername] = useState("");
8 | const [password, setPassword] = useState("");
9 |
10 | const handleSubmit = e => {
11 | e.preventDefault();
12 | let data = new FormData();
13 | data.append("username", username);
14 | data.append("password", password);
15 | fetch("/api/account/signin/", {
16 | method: "post",
17 | body: data,
18 | credentials: "include",
19 | })
20 | .then(function (res) {
21 | return res.json();
22 | })
23 | .then(function (data) {
24 | if (data.code === "200") {
25 | //message.success(data.msg)
26 | window.location.reload();
27 | } else if (data.code === "201") {
28 | message.error(data.msg);
29 | }
30 | });
31 | };
32 |
33 | const onSignOut = e => {
34 | e.preventDefault();
35 | fetch("/api/account/signout/", {
36 | method: "get",
37 | credentials: "include",
38 | })
39 | .then(function (res) {
40 | return res.json();
41 | })
42 | .then(function (data) {
43 | // message.success(data.msg)
44 | localStorage.clear();
45 | // cookie.remove('status')
46 | // console.log('remove cookie')
47 | // cookie.remove('username')
48 | window.location.reload();
49 | });
50 | };
51 |
52 | if (cookie.load("status") === "200") {
53 | //如果已经登录
54 | return (
55 |
56 | {cookie.load("username")}
57 |
60 |
61 | );
62 | } else
63 | return (
64 |
93 | );
94 | }
95 |
--------------------------------------------------------------------------------
/src/components/Apps/AppFolder/AppFolder.css:
--------------------------------------------------------------------------------
1 | .app-folder {
2 | width: 4.5vw;
3 | height: 4.5vw;
4 | min-height: 60px;
5 | min-width: 60px;
6 | border: 2px solid white;
7 | background: rgba(255, 255, 255, 0.5);
8 | border-radius: 20px;
9 | transition: 0.5s;
10 | cursor: pointer;
11 | }
12 | .app-contents {
13 | width: 90%;
14 | height: 88%;
15 | margin: 6% auto 0 auto;
16 | display: grid;
17 | grid-template-columns: repeat(3, 1fr);
18 | grid-template-rows: repeat(3, 1fr);
19 | align-items: center;
20 | justify-items: center;
21 | }
22 | .app-contents img {
23 | width: 0.9vw;
24 | border-radius: 5px;
25 | }
26 | .app-folder-modal {
27 | display: grid;
28 | width: 100%;
29 | height: 100%;
30 | grid-template-columns: repeat(4, 1fr);
31 | grid-template-rows: repeat(4, 1fr);
32 | align-items: center;
33 | justify-items: center;
34 | }
35 | .app-folder-modal img {
36 | border-radius: 20px;
37 | }
38 | .folder-name {
39 | position: fixed;
40 | font-size: 2rem;
41 | letter-spacing: 0.5rem;
42 | font-weight: 600;
43 | top: -4rem;
44 | text-align: center;
45 | color: azure;
46 | width: 96%;
47 | user-select: none;
48 | cursor: pointer;
49 | }
50 | .folder-name-input {
51 | position: fixed;
52 | font-size: 2rem;
53 | letter-spacing: 0.5rem;
54 | font-weight: 600;
55 | top: -4rem;
56 | text-align: center;
57 | color: azure;
58 | width: 95%;
59 | border: 0;
60 | background: rgba(255, 255, 255, 0);
61 | outline: none;
62 | }
63 | .folder-name-input:focus {
64 | outline: none;
65 | /* border-bottom: 2px solid whitesmoke; */
66 | box-shadow: 0px 2px 0px 0px rgba(255, 255, 255, 0.8);
67 | user-select: none;
68 | }
69 |
--------------------------------------------------------------------------------
/src/components/Apps/AppFolder/AppFolder.js:
--------------------------------------------------------------------------------
1 | import FuncModal from "../../FuncModal/FuncModal";
2 | import { memo, useEffect, useState } from "react";
3 | import { useSelector, useDispatch } from "react-redux";
4 | import "./AppFolder.css";
5 |
6 | function AppFolder(props) {
7 | // modal组件控制函数
8 | const [isModalVisible, setIsModalVisible] = useState(false);
9 | const [ediable, setEdiable] = useState(false);
10 | const { contents, name, folderId } = props;
11 | const [nameinput, setNameInput] = useState(name);
12 | const myApps = useSelector(state => state.myApps);
13 | // 文件夹位置
14 | let folderIndex = myApps.findIndex(i => i.id === folderId);
15 |
16 | const dispatch = useDispatch();
17 |
18 | useEffect(() => {
19 | // () => {
20 | // let node = document.querySelector("div.app-folder");
21 | // node.style.transform = "scale(0)";
22 | // };
23 | }, []);
24 |
25 | const showModal = () => {
26 | // openNotification();
27 | setIsModalVisible(true);
28 | };
29 | const handleOk = () => {
30 | setIsModalVisible(false);
31 | };
32 | const handleCancel = () => {
33 | setIsModalVisible(false);
34 | };
35 |
36 | const onDragEnd = (e, item) => {
37 | e.stopPropagation();
38 | e.preventDefault();
39 |
40 | let foldernode = e.target.parentNode.parentNode.parentNode.parentNode;
41 | let region = foldernode.getBoundingClientRect();
42 | if (
43 | e.clientY >= region.top &&
44 | e.clientY <= region.bottom &&
45 | e.clientX >= region.left &&
46 | e.clientX <= region.right
47 | ) {
48 | console.log("in");
49 | } else {
50 | // 去除文件夹内图标
51 | myApps[folderIndex].children.splice(
52 | myApps[folderIndex].children.findIndex(i => i.id === item.id),
53 | 1
54 | );
55 |
56 | // dispatch时就移除文件夹,没有动画
57 | if (myApps[folderIndex].children.length === 0) {
58 | // let node = document.querySelector("div.app-folder");
59 | // node.style.transform = "scale(0)";
60 | myApps.splice(folderIndex, 1);
61 | }
62 | // console.log(myApps);
63 | const apps = [...myApps, item];
64 | dispatch({
65 | type: "CHANGE_APPS",
66 | myApps: apps,
67 | });
68 | localStorage.setItem("apps", JSON.stringify(apps));
69 | }
70 | };
71 |
72 | const OnDrag = (e, item) => {
73 | e.stopPropagation();
74 | e.preventDefault();
75 | let region =
76 | e.target.parentNode.parentNode.parentNode.parentNode.getBoundingClientRect();
77 | if (
78 | !(
79 | e.clientY >= region.top &&
80 | e.clientY <= region.bottom &&
81 | e.clientX >= region.left &&
82 | e.clientX <= region.right
83 | )
84 | ) {
85 | setIsModalVisible(false);
86 | }
87 | };
88 |
89 | const editFolderName = (e, name) => {
90 | e.preventDefault();
91 | e.stopPropagation();
92 | setEdiable(true);
93 | };
94 |
95 | const onKeyDown = e => {
96 | // console.log(e);
97 | if (e.key == "Enter") {
98 | setEdiable(false);
99 |
100 | myApps[folderIndex].name = nameinput || "文件夹";
101 | dispatch({
102 | type: "CHANGE_APPS",
103 | myApps: myApps,
104 | });
105 | localStorage.setItem("apps", JSON.stringify(myApps));
106 | // console.log(e);
107 | }
108 | };
109 | const addFolder = () => {};
110 |
111 | // document.addEventListener("dragenter", function (event) {
112 | // event.preventDefault();
113 | // // console.log("enter");
114 | // if (event.target.className == "app-folder") {
115 | // event.target.style.boxShadow = "0 0 0 4px #007ACC";
116 | // }
117 | // });
118 |
119 | // const dragEnterIn = () => {
120 | // console.log("drag enter");
121 | // // if (e.target.className === "apps_sortableItem") {
122 | // // e.target.style.transform = "scale(1.2)";
123 | // // }
124 | // };
125 |
126 | return (
127 | <>
128 |
133 |
134 | {contents.map((item, index) => (
135 |

136 | ))}
137 |
138 |
139 |
151 |
174 | setNameInput(e.target.value)}
180 | />
181 | editFolderName(e, name)}
185 | >
186 | {nameinput || "文件夹"}
187 |
188 |
189 | >
190 | );
191 | }
192 |
193 | export default memo(AppFolder);
194 |
--------------------------------------------------------------------------------
/src/components/Apps/Apps.css:
--------------------------------------------------------------------------------
1 | .Apps {
2 | display: flex;
3 | flex-wrap: wrap;
4 | justify-content: center;
5 | border: 0px solid #000000;
6 | position: relative;
7 | /* z-index:999; */
8 | bottom: 0vh;
9 | margin: 0 auto 20px auto;
10 | width: 84vw;
11 | /* height: 20vw; */
12 | border-radius: 20px;
13 | overflow-y: scroll;
14 | overflow-x: hidden;
15 | font-size: small;
16 | text-align: center;
17 | background-color: #ffffff00;
18 | transition: 0.3s ease-in-out;
19 | }
20 | .apps_sortableItem a img:hover {
21 | box-shadow: 0 0 25px rgb(255, 255, 255), 0 0 10px rgb(255, 255, 255) inset;
22 | }
23 |
24 | .apps_sortableItem a {
25 | transition: 0.2s ease-out;
26 | position: relative;
27 | width: 60px;
28 | min-height: 60px;
29 | /* 这个transition挺重要,和事件执行有关,这个时间要比外面的慢,才先执行,待弄懂 */
30 | }
31 |
32 | .apps_sortableItem a img {
33 | width: 4.5vw;
34 | min-width: 60px;
35 | max-width: 4.5vw;
36 | border-radius: 20px;
37 | transition: 0.2s ease-in-out;
38 | }
39 | .apps_sortable {
40 | display: grid;
41 | grid-template-columns: repeat(8, calc(100% / 8));
42 | grid-template-rows: none;
43 | justify-content: center;
44 | justify-items: center;
45 | overflow-x: hidden;
46 | width: 70%;
47 | position: relative;
48 | }
49 | /* .delete{
50 | transform: scale(0);
51 | transition:2s ease-in-out;
52 | } */
53 | .apps_sortableItem {
54 | width: 100%;
55 | height: 100%;
56 | display: flex;
57 | align-items: center;
58 | position: relative;
59 | z-index: 2;
60 | }
61 | .shake {
62 | animation: icon_shake 0.2s infinite;
63 | }
64 | .apps_sortableItem button {
65 | position: relative;
66 | margin-top: -50%;
67 | left: 66%;
68 | z-index: 1;
69 | }
70 | /* .Apps:active {
71 | transform: scale(0.8);
72 | } */
73 | @keyframes icon_shake {
74 | 0% {
75 | transform: rotate(3deg);
76 | }
77 | 25% {
78 | transform: rotate(0);
79 | }
80 | 50% {
81 | transform: rotate(-3deg);
82 | }
83 | 75% {
84 | transform: rotate(0deg);
85 | }
86 | 100% {
87 | transform: rotate(3deg);
88 | }
89 | }
90 |
91 | .apps_sortable::-webkit-scrollbar,
92 | .Apps::-webkit-scrollbar {
93 | width: 0px;
94 | }
95 | /* div::-webkit-scrollbar-thumb {
96 | border-radius: 10px;
97 | box-shadow: inset 0 0 4px #00000033;
98 | background: rgba(0,0,0,0.2);
99 | }
100 | div::-webkit-scrollbar-track {
101 | box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
102 | border-radius: 10px;
103 | background: rgba(0,0,0,0.1);
104 | } */
105 |
--------------------------------------------------------------------------------
/src/components/Apps/Apps.js:
--------------------------------------------------------------------------------
1 | import "./Apps.css";
2 | import "../../font/iconfont.css";
3 | import { SortableContainer, SortableElement } from "react-sortable-hoc";
4 | import { arrayMoveImmutable } from "array-move";
5 | import { useSelector, useDispatch } from "react-redux";
6 | import React, { useState, useEffect } from "react";
7 | import { Button } from "antd";
8 | import { CloseOutlined } from "@ant-design/icons";
9 | import AppFolder from "./AppFolder/AppFolder";
10 | // import ClickMenu from "../ClickMenu/ClickMenu";
11 |
12 | export default function Apps() {
13 | const dispatch = useDispatch();
14 | const deleteMode = useSelector(state => state.deleteApp);
15 | const myApps = useSelector(state => state.myApps);
16 | const [items, setItems] = useState(myApps);
17 | // let timePos = useSelector(state => state.timePos);
18 |
19 | let height = "30vw";
20 |
21 | useEffect(() => {
22 | //这一行让Apps SetApps 拖拽时可以同步变换
23 | setItems(myApps);
24 | }, [myApps]);
25 |
26 | const deleteApp = id => {
27 | // e.target.parentNode.classList.add('delete')
28 | // console.log('deleteAPP')
29 | let updatemyApps = myApps.filter(item => item.id !== id);
30 | localStorage.setItem("apps", JSON.stringify(updatemyApps));
31 | setItems(updatemyApps);
32 | dispatch({
33 | type: "CHANGE_APPS",
34 | myApps: updatemyApps,
35 | });
36 | };
37 |
38 | const handleContextMenu = (e, b) => {
39 | e.preventDefault();
40 | e.stopPropagation();
41 | dispatch({
42 | type: "CHANGE_DELETEAPP",
43 | deleteApp: !b,
44 | });
45 | };
46 |
47 | const renderItem = item => {
48 | const shake = deleteMode ? " shake" : "";
49 | const app = (
50 |
51 |
handleContextMenu(e, deleteMode)}
53 | alt={item.name}
54 | src={item.imgPath}
55 | />
56 |
57 | );
58 | const folder = (
59 |
66 | );
67 |
68 | return (
69 |
70 | }
74 | size='small'
75 | onMouseDown={() => deleteApp(item.id)}
76 | />
77 | {item.type ? folder : app}
78 |
79 | );
80 | };
81 |
82 | //拖拽排序插件-----------------------------------
83 | const SortableItem = SortableElement(({ value }) => renderItem(value));
84 | const SortableList = SortableContainer(({ items }) => {
85 | return (
86 |
87 | {items.map((value, index) => (
88 |
89 | ))}
90 |
91 | );
92 | });
93 |
94 | const onSortEnd = ({ oldIndex, newIndex }) => {
95 | setItems(arrayMoveImmutable(items, oldIndex, newIndex));
96 | localStorage.setItem(
97 | "apps",
98 | JSON.stringify(arrayMoveImmutable(items, oldIndex, newIndex))
99 | ); //这里更改了,但是还不能同步
100 | dispatch({
101 | type: "CHANGE_APPS",
102 | myApps: arrayMoveImmutable(items, oldIndex, newIndex),
103 | });
104 | };
105 |
106 | // const onSortOver = (
107 | // // { index, oldIndex, newIndex, collection, isKeySorting },
108 | // e
109 | // ) => {
110 | // e.helper.querySelector("div").style.transform = "scale(0.8)";
111 | // };
112 | //-------------------------------------------------
113 |
114 | // const renderCard = (item)=>{
115 | // return ( //因为click事件会引发拖动,所以这里click没有生效,设置transition解决了
116 | //
117 | // )
118 | // }
119 |
120 | return (
121 | // {myApps.map((item, i) => renderItem(item))}
122 | //通过给SortableList 设置最小拖动距离来激活点击事件(distance 单位px)
123 |
124 |
131 | {/* {apps.map((app, i) => renderCard(app, i))} */}
132 |
133 | );
134 | }
135 |
--------------------------------------------------------------------------------
/src/components/Apps/SetApp/SetApp.css:
--------------------------------------------------------------------------------
1 | .set_apps {
2 | display: flex;
3 | }
4 | .icon_list {
5 | height: 89%;
6 | overflow-y: scroll;
7 | display: grid;
8 | grid-template-columns: repeat(3, calc(96% / 3));
9 | grid-column-gap: 2%;
10 | justify-items: center;
11 | margin-top: 3%;
12 | }
13 | .icon_list_item {
14 | width: 100%;
15 | height: 150px;
16 | overflow: hidden;
17 | position: relative;
18 | margin-bottom: 5%;
19 | background-color: #ffffff66;
20 | /* background-image: linear-gradient( 135deg, #3C8CE7 10%, #00EAFF 100%); */
21 | border-radius: 25px;
22 | }
23 |
24 | .icon_list_item span {
25 | margin-left: 5%;
26 | color: white;
27 | font-size: 15px;
28 | /* white-space: nowrap; */
29 | display: inline-block;
30 | width: 60%;
31 | position: relative;
32 | top: 5%;
33 | overflow-x: hidden;
34 | white-space: nowrap;
35 | text-overflow: ellipsis;
36 | }
37 | .icon_list_item div {
38 | margin: 5% 5% 5% 5%;
39 | overflow-x: hidden;
40 | white-space: nowrap;
41 | text-overflow: ellipsis;
42 | }
43 | .icon_list_item div.cover {
44 | position: absolute;
45 | width: 100%;
46 | height: 100%;
47 | margin: 0;
48 | transition: 0.3s ease-in-out;
49 | }
50 | .icon_list_item div.cover:hover {
51 | background-color: #00000066;
52 | }
53 | .icon_list_item button {
54 | position: absolute;
55 | top: 50%;
56 | left: 50%;
57 | transform: translate(-50%, -50%);
58 | opacity: 0;
59 | }
60 | .icon_list_item div.cover:hover button {
61 | opacity: 1;
62 | background-color: #fff3;
63 | }
64 |
--------------------------------------------------------------------------------
/src/components/Calendar/CalComponent.css:
--------------------------------------------------------------------------------
1 | /* .cal{
2 |
3 | width: 352px;
4 | height: 165px;
5 |
6 | padding: 16px;
7 | background: #FFFFFF;
8 | box-sizing: border-box;
9 | border-radius: 20px;
10 | display: inline-flex;
11 | justify-content: space-between;
12 | transition: .1s ease-in;
13 | } */
14 | .cal-left {
15 | width: 40%;
16 | flex-direction: column;
17 | position: absolute;
18 | top: 55px;
19 | left: 0;
20 | }
21 | .cal-right {
22 | height: 100%;
23 | width: 60%;
24 | display: flex;
25 | position: absolute;
26 | right: 13px;
27 | top: 0;
28 | align-items: center;
29 | justify-content: center;
30 | }
31 |
32 | .cal-header {
33 | display: flex;
34 | flex-direction: row;
35 | align-items: center;
36 | justify-content: flex-start;
37 | }
38 |
39 | .cal-title {
40 | font-style: normal;
41 | font-weight: bold;
42 | font-size: 18px;
43 | line-height: 22px;
44 | letter-spacing: 0.2rem;
45 | margin-left: 0.6em;
46 | color: rgba(0, 0, 0, 0.85);
47 | cursor: pointer;
48 | }
49 |
50 | .cal-icon {
51 | width: 6px;
52 | height: 14px;
53 | left: 18px;
54 | top: 17px;
55 | background: linear-gradient(180deg, #ff6d90 14.58%, #ff3131 100%);
56 | box-shadow: 0px 3px 6px rgba(255, 55, 55, 0.8);
57 | border-radius: 20px;
58 | }
59 |
60 | .cal-date-container {
61 | width: 100%;
62 | height: calc(100% - 18px);
63 | display: flex;
64 | flex-direction: column;
65 | align-items: center;
66 | justify-content: center;
67 | }
68 |
69 | .cal-todo-container {
70 | width: 80%;
71 | display: flex;
72 | flex-direction: row;
73 | align-items: center;
74 | justify-content: center;
75 | margin: 0 auto;
76 | text-overflow: ellipsis;
77 | overflow: hidden;
78 | }
79 |
80 | .cal-weekday {
81 | font-size: 1rem;
82 | color: #ff4848;
83 | }
84 |
85 | .cal-date {
86 | font-size: 2.4rem;
87 | font-weight: lighter;
88 | color: #1d1d1d;
89 | }
90 |
91 | .cal-icon2 {
92 | width: 10px;
93 | height: 10px;
94 | border-radius: 50%;
95 | margin-right: 5px;
96 | /* background: #64C2F7; */
97 | background-color: rgb(243, 104, 104);
98 | }
99 |
100 | .cal-todo-exist {
101 | color: rgba(0, 0, 0, 0.8);
102 | }
103 |
104 | .cal-todo-none {
105 | font-size: 0.9em;
106 | color: rgba(0, 0, 0, 0.5);
107 | }
108 |
109 | .react-calendar {
110 | width: 280px;
111 | background-color: #fff0;
112 | color: #222;
113 | border-radius: 8px;
114 | font-family: Arial, Helvetica, sans-serif;
115 | line-height: 1.125em;
116 | }
117 | .react-calendar__navigation {
118 | display: flex;
119 | justify-content: center;
120 | align-items: center;
121 | }
122 | .react-calendar__navigation__label {
123 | width: 80%;
124 | }
125 | .react-calendar__navigation button {
126 | min-width: 16px;
127 | background: none;
128 | font-size: 14px;
129 | margin-top: 8px;
130 | border: #fff;
131 | }
132 | .react-calendar__month-view__weekdays__weekday {
133 | color: rgba(0, 0, 0, 0.5);
134 | display: flex;
135 | justify-content: center;
136 | align-items: center;
137 | font-size: 12px;
138 | }
139 | .react-calendar__month-view__days__day {
140 | font-size: 12px;
141 | border: #fff;
142 | background-color: #fff;
143 | }
144 | .react-calendar__navigation button:enabled:hover,
145 | .react-calendar__navigation button:enabled:focus {
146 | background-color: #f8f8fa;
147 | }
148 | .react-calendar__navigation button[disabled] {
149 | background-color: #f0f0f0;
150 | }
151 | abbr[title] {
152 | text-decoration: none;
153 | }
154 | .react-calendar__tile {
155 | border-radius: 2px;
156 | border: 0;
157 | background-color: #fff0;
158 | }
159 | .react-calendar__tile:enabled:hover,
160 | .react-calendar__tile:enabled:focus {
161 | background: #f8f8fa;
162 | color: #6f48eb;
163 | border-radius: 6px;
164 | }
165 | .react-calendar__tile--now {
166 | background: #6f48eb33;
167 | border-radius: 6px;
168 | font-weight: bold;
169 | color: #6f48eb;
170 | }
171 | .react-calendar__tile--now:enabled:hover,
172 | .react-calendar__tile--now:enabled:focus {
173 | background: #6f48eb33;
174 | border-radius: 6px;
175 | font-weight: bold;
176 | color: #6f48eb;
177 | }
178 | .react-calendar__tile--hasActive:enabled:hover,
179 | .react-calendar__tile--hasActive:enabled:focus {
180 | background: #f8f8fa;
181 | }
182 | .react-calendar__tile--active {
183 | background: #6f48eb;
184 | border-radius: 6px;
185 | font-weight: bold;
186 | color: white;
187 | }
188 | .react-calendar__tile--active:enabled:hover,
189 | .react-calendar__tile--active:enabled:focus {
190 | background: #6f48eb;
191 | color: white;
192 | }
193 | .react-calendar--selectRange .react-calendar__tile--hover {
194 | background-color: #f8f8fa;
195 | }
196 | .react-calendar__tile--range {
197 | background: #f8f8fa;
198 | color: #6f48eb;
199 | border-radius: 0;
200 | }
201 | .react-calendar__tile--rangeStart {
202 | border-radius: 6px;
203 | background: #6f48eb;
204 | color: white;
205 | }
206 | .react-calendar__tile--rangeEnd {
207 | border-radius: 6px;
208 | background: #6f48eb;
209 | color: white;
210 | }
211 |
212 | div.todo {
213 | width: 90%;
214 | height: 2px;
215 | margin-top: -2px;
216 | border-radius: 1rem;
217 | background-color: #ff4848;
218 | }
219 | .cal-item {
220 | height: 20px;
221 | display: flex;
222 | justify-content: center;
223 | flex-direction: column;
224 | align-items: center;
225 | }
226 | .cal-detail {
227 | width: 60%;
228 | /* margin-bottom: 2%; */
229 | margin-right: 1%;
230 | padding: 5px;
231 | background-color: #f0f0f088;
232 | font-size: 25px;
233 | /* border: 1px solid grey; */
234 | }
235 | .cal-detail-item {
236 | height: 60px;
237 | font-weight: 700;
238 | font-size: 25px;
239 | display: flex;
240 | flex-direction: column;
241 | align-items: center;
242 | justify-content: center;
243 | position: relative;
244 | }
245 | .is-work {
246 | position: absolute;
247 | width: 20px;
248 | height: 20px;
249 | font-size: 12px;
250 | text-align: center;
251 | line-height: 20px;
252 | font-weight: 700;
253 | color: #fff;
254 | background: #4ed5f7;
255 | right: 0;
256 | top: 3px;
257 | }
258 | .work {
259 | background: #f74e4e;
260 | }
261 | .date-order {
262 | font-size: 20px;
263 | font-weight: 700;
264 | text-align: center;
265 | margin: 2% 0;
266 | }
267 | .date-order span {
268 | color: #6f48eb;
269 | font-size: 25px;
270 | margin: 0 5px;
271 | }
272 | .date-info {
273 | margin: 2% 0 2% 8%;
274 | width: 98%;
275 | font-size: 18px;
276 | }
277 | .date-info > span {
278 | padding: 2px 4px;
279 | color: #222;
280 | text-align: center;
281 | font-weight: 800;
282 | letter-spacing: 2px;
283 | margin-right: 1%;
284 | }
285 | .date-info > span:nth-child(1) {
286 | border: 1px solid red;
287 | background: #f74e4e55;
288 | font-size: 15px;
289 | margin-right: 3%;
290 | border-radius: 8px;
291 | }
292 |
--------------------------------------------------------------------------------
/src/components/ChatRoom/ChatRoom.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/components/ChatRoom/ChatRoom.css
--------------------------------------------------------------------------------
/src/components/ChatRoom/ChatRoom.js:
--------------------------------------------------------------------------------
1 | import "./ChatRoom.css";
2 | import FuncModal from "../FuncModal/FuncModal";
3 | import { useState } from "react";
4 | import { Button } from "antd";
5 | import { memo } from "react";
6 |
7 | function ChatRoom() {
8 | // modal组件控制函数
9 | const [isModalVisible, setIsModalVisible] = useState(false);
10 | const showModal = () => {
11 | // openNotification();
12 | setIsModalVisible(true);
13 | };
14 | const handleOk = () => {
15 | setIsModalVisible(false);
16 | };
17 | const handleCancel = () => {
18 | setIsModalVisible(false);
19 | };
20 |
21 | return (
22 | <>
23 |
26 |
33 |
46 | 建造中 ...
47 |
48 |
49 | >
50 | );
51 | }
52 |
53 | export default memo(ChatRoom);
54 |
--------------------------------------------------------------------------------
/src/components/ClickMenu/ClickMenu.css:
--------------------------------------------------------------------------------
1 | .menu-wrapper {
2 | width: 120px;
3 | background: #fffd;
4 | border-radius: 10px;
5 | position: absolute;
6 | z-index: 4;
7 | }
8 | .menu-wrapper ul {
9 | padding-inline-start: 0;
10 | margin-bottom: 0;
11 | font-family: "SimHei";
12 | }
13 | .menu-wrapper i {
14 | font-style: normal;
15 | font-size: 1rem;
16 | font-weight: 600;
17 | letter-spacing: 1px;
18 | user-select: none;
19 | }
20 | .menu-wrapper .menu {
21 | padding: 3px 5px;
22 | }
23 | .menu-content .menu-item {
24 | list-style: none;
25 | /* font-size: 10px; */
26 | height: 30px;
27 | display: flex;
28 | /* padding:0 5px; */
29 | align-items: center;
30 | border-radius: 5px;
31 | margin-bottom: 2px;
32 | /* background: #0003; */
33 | }
34 | .menu-item > div {
35 | height: 100%;
36 | width: 100%;
37 | display: flex;
38 | align-items: center;
39 | cursor: pointer;
40 | }
41 | .menu-content .menu-item:hover {
42 | background: #0002;
43 | }
44 | .menu-content .menu-item span {
45 | /* font-size: 10px; */
46 | margin-left: 8px;
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/ClickMenu/ClickMenu.js:
--------------------------------------------------------------------------------
1 | import "./ClickMenu.css";
2 | import {
3 | DownloadOutlined,
4 | SwapOutlined,
5 | CodeOutlined,
6 | } from "@ant-design/icons";
7 | import { memo, useState } from "react";
8 | import { useSelector, useDispatch } from "react-redux";
9 | import { SetFunctionArea } from "../FunctionAera/SetFunctionAera/SetFunctionArea";
10 | import SetApp from "../Apps/SetApp/SetApp";
11 | import { SnippetsInMenu } from "../Snippets/Snippets";
12 |
13 | function ClickMenu() {
14 | const currentbg = useSelector(state => state.currentbg);
15 | const bgType = useSelector(state => state.bgtype);
16 | const clear = useSelector(state => state.clear);
17 |
18 | const dispatch = useDispatch();
19 |
20 | const downloadWallPaper = e => {
21 | // e.stopPropagation();
22 | //创造 a 标签来下载
23 | // 方法一:利用a标签下载,但是当跨域时,会跳转而不是下载
24 | const a = document.createElement("a");
25 | a.style.display = "none";
26 | a.href = currentbg;
27 | a.target = "_blank";
28 | a.download = "bg.jpg";
29 | document.body.appendChild(a);
30 | a.click(); // 自动触发点击a标签的click事件
31 | document.body.removeChild(a);
32 | // 方法二:获取文件二进制数据然后创建a标签下载
33 | // fetch(currentbg).then(res => {
34 | // res.blob().then(blob => {
35 | // const blobUrl = window.URL.createObjectURL(blob);
36 | // // 这里的文件名根据实际情况从响应头或者url里获取
37 | // // const filename = 'user.txt';
38 | // const a = document.createElement("a");
39 | // a.href = blobUrl;
40 | // a.download = "a.jpg";
41 | // a.click();
42 | // window.URL.revokeObjectURL(blobUrl);
43 | // });
44 | // });
45 | // 方法三:利用canvas编辑base64下载
46 | // let imgsrc = currentbg;
47 | // let image = new Image();
48 | // image.crossOrigin = "anonymous";
49 | // image.src = imgsrc;
50 | // // 解决跨域canvas污染问题
51 | // image.onload = () => {
52 | // let canvas = document.createElement("canvas");
53 | // canvas.width = image.width;
54 | // canvas.height = image.height;
55 | // let context = canvas.getContext("2d");
56 | // context.drawImage(image, 0, 0, image.width, image.height);
57 | // let url = canvas.toDataURL("image/png"); // 得到图片的base64编码数据
58 | // let a = document.createElement("a");
59 | // a.download = "download";
60 | // a.href = url;
61 | // a.click();
62 | // };
63 | };
64 |
65 | function onChangeClear() {
66 | let value = clear ? 0 : 1;
67 | dispatch({
68 | type: "CHANGE_CLEAR",
69 | clear: value,
70 | });
71 | }
72 |
73 | return (
74 |
105 | );
106 | }
107 |
108 | export default memo(ClickMenu);
109 |
--------------------------------------------------------------------------------
/src/components/Clock/Clock.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "UnidreamLED";
3 | src: url(../../font/UnidreamLED.eot); /***兼容ie9***/
4 | src: url(../../font/UnidreamLED.eot?#iefix) format("embedded-opentype"),
5 | /***兼容ie6-ie8***/ url("../../font/UnidreamLED.woff") format("woff"),
6 | local("UnidreamLED"), url("../../font/UnidreamLED.woff"); /***默认使用本地的***/
7 | }
8 | @font-face {
9 | font-family: "DS-Digital";
10 | /* 这个是定义字体的名称 */
11 | src: url("../../font/DS-Digital\ Bold.ttf");
12 | }
13 |
14 | .clock {
15 | position: absolute;
16 | left: 50%;
17 | transform: translateX(-50%);
18 | display: flex;
19 | flex-direction: column;
20 | justify-content: center;
21 | /* height: 20vh; */
22 | padding: 0 3%;
23 | text-align: center;
24 | border-radius: 20px;
25 | /* align-items: center; */
26 | font-size: 6.5rem;
27 | font-weight: 200;
28 | color: white;
29 | /* display: block; */
30 | cursor: pointer;
31 | user-select: none;
32 | transition: 0.3s ease-in-out;
33 | height: 13rem;
34 | /* padding: 1%; */
35 | }
36 | .clock:hover {
37 | background-color: #00000055;
38 | border-radius: 20px;
39 | }
40 | .clock-setting {
41 | font-size: 1.5rem;
42 | visibility: hidden;
43 | position: absolute;
44 | font-weight: 700;
45 | color: aqua;
46 | top: 5%;
47 | right: 3%;
48 | }
49 | .clock-day {
50 | /* position:absolute; */
51 | font-size: 1.5rem;
52 | }
53 | .clock:hover .clock-setting {
54 | visibility: visible;
55 | }
56 | .digitalfont {
57 | font-family: "DS-Digital";
58 | font-size: 8.5rem;
59 | }
60 | .h,
61 | .m {
62 | display: inline-block;
63 | /* line-height: 12rem; */
64 | /* font-family: 'DS-Digital'; */
65 | /* font-size: 100px; */
66 | width: 9rem;
67 | }
68 | .h {
69 | text-align: right;
70 | margin-right: 2rem;
71 | }
72 | .m {
73 | text-align: left;
74 | margin-left: 2rem;
75 | }
76 |
77 | /* 倒计时 */
78 | .countdown_content_clock {
79 | /* overflow-y: scroll; */
80 | height: 10rem;
81 | /* margin-top: 2rem; */
82 | /* position: relative;
83 | top:1rem; */
84 | /* border:1px solid red; */
85 | display: flex;
86 | flex-direction: column;
87 | justify-content: space-around;
88 | /* margin-top:10px; */
89 | /* scroll-snap-type: y mandatory; */
90 | /* scrollbar-width:none; */
91 | }
92 | .countdown_content_clock > div {
93 | /* height:120px; */
94 | /* margin-top: 30px; */
95 | scroll-snap-align: end;
96 | }
97 |
98 | .countdown_content_clock > div div:nth-child(1) {
99 | text-align: center;
100 | font-size: 2rem;
101 | font-weight: 800;
102 | letter-spacing: 5px;
103 | color: #19bbfc;
104 | }
105 | .countdown_content_clock > div div:nth-child(2) {
106 | text-align: center;
107 | /* margin-top: 5px; */
108 | font-size: 8rem;
109 | font-weight: 900;
110 | letter-spacing: 8px;
111 | }
112 | .countdown_content_clock span {
113 | font-size: 2rem;
114 | letter-spacing: 0px;
115 | }
116 | /* .countdown_inclock_item{
117 | position: relative;
118 | top:0rem;
119 | }
120 | .countdown_slidein{
121 | animation: countdown_slidin 1s;
122 | }
123 | @keyframes countdown_slidein {
124 | 0% {
125 | opacity: 0;
126 | top:3rem;
127 | }
128 | 100% {
129 | opacity: 1;
130 | top:0rem;
131 | }
132 | } */
133 |
134 | /* 滚动条样式 */
135 | .countdown_content_clock::-webkit-scrollbar {
136 | width: 0px;
137 | }
138 | /* .top-clock > div {
139 | position: absolute;
140 | left: -85%;
141 | z-index: 4;
142 | display: none;
143 | background-color: #0009;
144 | margin-top: 0.5vh;
145 | border-radius: 16px;
146 | padding: 5px 16px;
147 | width: 14vw;
148 | }
149 | .top-clock:hover > div {
150 | display: flex;
151 | justify-content: center;
152 | flex-direction: column;
153 | }
154 | .top-clock > div > div {
155 | display: flex;
156 | justify-content: space-between;
157 | } */
158 |
159 | .top-clock > div {
160 | position: absolute;
161 | left: -85%;
162 | z-index: 4;
163 | display: none;
164 | background-color: #0009;
165 | margin-top: 0.5vh;
166 | border-radius: 16px;
167 | padding: 5px 16px;
168 | width: 14vw;
169 | }
170 | .top-clock:hover > div {
171 | display: flex;
172 | justify-content: center;
173 | flex-direction: column;
174 | }
175 | .city-time {
176 | display: flex;
177 | justify-content: space-between;
178 | }
179 |
--------------------------------------------------------------------------------
/src/components/Clock/SetClock/SetClock.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/components/Clock/SetClock/SetClock.css
--------------------------------------------------------------------------------
/src/components/Clock/SetClock/SetClock.js:
--------------------------------------------------------------------------------
1 | import "./SetClock.css";
2 | import { Radio } from "antd";
3 | import { React } from "react";
4 | import { useDispatch, useSelector } from "react-redux";
5 | import useLocalStorage from "../../../hooks/useLocalStorage";
6 |
7 | export default function SetClock() {
8 | const dispatch = useDispatch();
9 | // const [value, setValue] = useState(1);
10 | const [, setTimeFont] = useLocalStorage("timefont");
11 | const TimeFont = useSelector(state => state.timefont);
12 |
13 | const onChange = e => {
14 | // setValue(e.target.value);
15 | dispatch({
16 | type: "CHANGE_TIMEFONT",
17 | timefont: e.target.value,
18 | });
19 | setTimeFont(e.target.value);
20 | };
21 |
22 | return (
23 |
24 |
25 | 时间样式
26 |
27 |
28 | 普通
29 | 数码
30 |
31 |
32 |
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/Competition/Competition.css:
--------------------------------------------------------------------------------
1 | .competition {
2 | /* width: 18vw;
3 | height: 8.5vw; */
4 | width: 352px;
5 | height: 165px;
6 | /* margin:20px; */
7 | /* left:764px;
8 | top:20px; */
9 | display: inline-block;
10 | background: #ffffff;
11 | box-sizing: border-box;
12 | border-radius: 20px;
13 | transition: 0.1s ease-in;
14 | }
15 |
16 | /* .competition .com_left {
17 | display: inline-block;
18 | margin-top: 13px;
19 | }
20 | .competition .com_left p{
21 |
22 | font-style: normal;
23 | font-weight: bold;
24 | font-size: 18px;
25 | line-height: 22px;
26 | margin: 0;
27 | display: inline-block;
28 | letter-spacing: 0.2rem;
29 | cursor: pointer;
30 | margin-left: 12px;
31 | }
32 | .competition .com_left div{
33 | display: inline-block;
34 | margin-left: 18px;
35 | width: 6px;
36 | height: 14px;
37 | background: linear-gradient(180deg, #6d53b4 14.58%, #2a1086 100%);
38 | box-shadow: 0px 3px 6px rgba(7, 87, 119, 0.8);
39 | border-radius: 20px;
40 | }
41 | .competition .com_right{
42 | display: inline-flex;
43 | width: 150px;
44 | height: 25px;
45 | position: absolute;
46 | margin-top: 12px;
47 | margin-left: 65px;
48 | justify-content: space-around;
49 | }
50 | .com_right span{
51 | font-size: 15px;
52 | line-height: 25px;
53 | text-align: center;
54 | font-weight: 700;
55 | width: 50px;
56 | height: 25px;
57 | border-radius: 5px;
58 | cursor: pointer;
59 | } */
60 | /* .com_right span:hover{
61 | background-color:#00000022;
62 | } */
63 | .com_board {
64 | width: 95%;
65 | height: 120px;
66 | /* background-color:#00000011; */
67 | margin: 5px auto 0 auto;
68 | /* overflow-y: scroll; */
69 | border-radius: 20px;
70 | }
71 | .com_board::-webkit-scrollbar {
72 | width: 0px;
73 | }
74 | .com_board a {
75 | /* display: block; */
76 | color: #000000;
77 | }
78 | .com_board a > div {
79 | /* overflow-y: scroll; */
80 | height: 120px;
81 | /* scroll-snap-type: y mandatory; */
82 | /* 滚动贴合 */
83 | }
84 | .com_board a > div::-webkit-scrollbar {
85 | width: 0;
86 | }
87 | .nba {
88 | display: flex;
89 | width: 100%;
90 | height: 100%;
91 | margin-top: -1.5%;
92 | justify-content: space-around;
93 | /* scroll-snap-align: start; */
94 | }
95 | .nba_team {
96 | display: inline-flex;
97 | flex-direction: column;
98 | align-items: center;
99 | font-size: 20px;
100 | font-weight: 700;
101 | height: 120px;
102 | margin-top: 10px;
103 | overflow: hidden;
104 | word-wrap: normal;
105 | text-overflow: ellipsis;
106 | }
107 |
108 | .nba_team img {
109 | height: 80px;
110 | }
111 |
112 | .score_time {
113 | font-size: 30px;
114 | font-weight: 800;
115 | font-family: "SimHei, Serif";
116 | margin-top: 30px;
117 | text-align: center;
118 | }
119 | .score_time div {
120 | font-size: 15px;
121 | font-weight: 400;
122 | }
123 |
--------------------------------------------------------------------------------
/src/components/Competition/Competition.js:
--------------------------------------------------------------------------------
1 | import "./Competition.css";
2 | import { memo, useEffect, useState } from "react";
3 | import FuncCard from "../FuncCard/FuncCard";
4 |
5 | //无比赛页面
6 | const no_game = (
7 |
19 | 今日无赛程
20 |
21 | );
22 |
23 | function NBA(props) {
24 | //修复了一个bug,但是还没弄清原因,初步判断是state的更新问题
25 | //还差一个滚动贴合
26 | const [games, setGames] = useState([]);
27 | const [itemIndex, setItemIndex] = useState(0);
28 |
29 | //直接来自远程NBA网站的图片
30 | const remote_logo_img = "https://res.nba.cn/media/img/teams/logos/";
31 |
32 | let flag = []; //用来判断是否有比赛在进行中
33 |
34 | const handleWheelCapture = e => {
35 | if (games.length > 1) {
36 | e.stopPropagation();
37 | }
38 | if (e.deltaY > 0 && itemIndex < games.length - 1) {
39 | setItemIndex(itemIndex + 1);
40 | }
41 | if (e.deltaY < 0 && itemIndex >= 1) {
42 | setItemIndex(itemIndex - 1);
43 | }
44 | };
45 |
46 | useEffect(() => {
47 | let url = "https://api.nba.cn/sib/v2/game/schedule";
48 | async function getGameList() {
49 | fetch(url)
50 | .then(response => response.json())
51 | .then(
52 | data => {
53 | setGames(data.data.groups[0].games);
54 | flag = data.data.groups[0].games.map((item, index) => item.status);
55 | } //.next.games 表示下一天
56 | )
57 | .catch(e => console.log("error"));
58 | }
59 | getGameList();
60 |
61 | const t = setInterval(() => {
62 | // let flag = games.map((item,index)=>item.boxscore.status) //获取比赛状态数组,如果有比赛正在进行才请求 这个地方获取不行
63 | // console.log(games)
64 | if (flag.includes(2)) {
65 | console.log("比赛进行中");
66 | getGameList();
67 | }
68 | }, 10000); //10s更新一次
69 |
70 | return () => {
71 | clearTimeout(t);
72 | };
73 | }, []);
74 |
75 | const have_game = games.map((item, index) => {
76 | let awayTeam = item.awayTeamName;
77 | let homeTeam = item.homeTeamName;
78 | // let time = new Date(item.dateTimeUtc);
79 | // time = new Date(time.setHours(time.getHours() + 13));
80 | // time = time.getHours() + " : " + time.toLocaleTimeString().slice(3, 5);
81 | let time = item.startTime.slice(0, 2) + " : " + item.startTime.slice(3, 5);
82 | let score = item.awayTeamScore + " - " + item.homeTeamScore;
83 | let score_time = item.status !== 1 ? score : time;
84 | // 根据不同比赛状态显示不同文字
85 | let status =
86 | item.status == 2
87 | ? item.periodText + " " + item.gameClock
88 | : item.statusText;
89 | // 详细信息跳转链接
90 | let link =
91 | item.status == 1
92 | ? "https://china.nba.cn/preview/" + item.gameId + "/game-list"
93 | : "https://china.nba.cn/game/" + item.gameId + "/box-score";
94 | if (index === itemIndex)
95 | return (
96 |
128 | );
129 | });
130 |
131 | // const no_game = 今日无赛程
132 |
133 | return (
134 |
135 | {games.length === 0 ? no_game : have_game}
136 |
137 | );
138 | }
139 |
140 | const Competition = () => {
141 | const [type, setType] = useState(0); //比赛类型
142 | const [game, setGame] = useState([]);
143 |
144 | const handleChangeType = value => {
145 | setType(value);
146 | };
147 |
148 | return (
149 | <>
150 |
160 | {/* */}
161 | {/*
162 | setType(0)} style={{backgroundColor:(type===0? '#00000022':'#ffffff')}}>NBA
163 | setType(1)} style={{backgroundColor:(type===1? '#00000022':'#ffffff')}}>LOL
164 | setType(2)} style={{backgroundColor:(type===2? '#00000022':'#ffffff')}}>围棋
165 |
*/}
166 | {/*
167 | NBA官网: https://china.nba.cn/
168 | 腾讯视频: https://v.qq.com/channel/nba
169 | */}
170 |
199 |
200 | >
201 | );
202 | };
203 |
204 | export default memo(Competition);
205 |
--------------------------------------------------------------------------------
/src/components/CountDown/CountDown.css:
--------------------------------------------------------------------------------
1 | .CountDown {
2 | /* width: 18vw;
3 | height: 8.5vw; */
4 | width: 352px;
5 | height: 165px;
6 | background: #ffffff;
7 | box-sizing: border-box;
8 | border-radius: 20px;
9 | transition: 0.1s ease-in;
10 | }
11 | .countdown_content {
12 | overflow-y: scroll;
13 | height: 120px;
14 | /* margin-top:10px; */
15 | scroll-snap-type: y mandatory;
16 | /* scrollbar-width:none; */
17 | }
18 | .countdown_content > div {
19 | /* height:120px; */
20 | margin-top: 30px;
21 | scroll-snap-align: end;
22 | }
23 |
24 | .countdown_content > div div:nth-child(1) {
25 | text-align: center;
26 | font-size: 20px;
27 | font-weight: 800;
28 | letter-spacing: 3px;
29 | color: #31c5ff;
30 | }
31 | .countdown_content > div div:nth-child(2) {
32 | text-align: center;
33 | margin-top: 5px;
34 | font-size: 55px;
35 | font-family: "Microsoft Yahei";
36 | font-weight: 800;
37 | letter-spacing: 4px;
38 | }
39 | .countdown_content span {
40 | font-size: 30px;
41 | margin-left: 2%;
42 | letter-spacing: 0;
43 | }
44 |
45 | /* 滚动条样式 */
46 | .countdown_content::-webkit-scrollbar {
47 | width: 0px;
48 | }
49 | /* 设置滚动滑块 */
50 | /* .newsList::-webkit-scrollbar-thumb {
51 | border-radius: 10px;
52 | box-shadow: inset 0 0 4px #00000033;
53 | background: rgba(0,0,0,0.2);
54 | }
55 | .newsList::-webkit-scrollbar-track {
56 | box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
57 | border-radius: 10px;
58 | background: rgba(0,0,0,0.1);
59 | } */
60 |
61 | /* CSS实现滚动贴合 用在组件里面*/
62 | /* main{
63 | scroll-snap-type:y mandatory; 强制滚动
64 | scroll-padding: 80px; 贴合时的padding,如有粘滞元素的时候
65 | }
66 | section{
67 | scroll-snap-align: start; 贴合的位置,底部,center,或者顶部
68 | } */
69 |
--------------------------------------------------------------------------------
/src/components/Demos/Demos.css:
--------------------------------------------------------------------------------
1 | .demo {
2 | width: 300px;
3 | height: 150px;
4 | position: absolute;
5 | border-radius: 10px;
6 | background: #fff0;
7 | z-index: 1;
8 | transition: 0.3s ease-in-out;
9 | backdrop-filter: blur(10px) brightness(0.5);
10 | /* border: 1px solid blue; */
11 | }
12 | .demo:hover {
13 | /* background:#0008; */
14 | backdrop-filter: blur(0);
15 | }
16 | .demo > div {
17 | position: relative;
18 | left: 50%;
19 | top: 50%;
20 | transform: translate(-50%, -50%);
21 | opacity: 1;
22 | /* background-color: #fff0; */
23 | font-size: 40px;
24 | font-weight: 700;
25 | color: #fffb;
26 | text-align: center;
27 | letter-spacing: 2px;
28 | transition: 0.3s ease-in;
29 | }
30 | .demo:hover > div {
31 | opacity: 0;
32 | /* background-color: #000a; */
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/Demos/Demos.js:
--------------------------------------------------------------------------------
1 | import "./Demos.css";
2 | import { memo, useState } from "react";
3 | import FuncCard from "../FuncCard/FuncCard";
4 | import FuncModal from "../FuncModal/FuncModal";
5 | import Lottie from "react-lottie";
6 | import motorbike from "../../asset/motorbike.json";
7 | import GitHubCalendar from "react-github-calendar";
8 | // import astronaut from '../../asset/astronaut.json';
9 | // import solarsystem from '../../asset/solarsystem.json'
10 |
11 | const Demos = () => {
12 | const demoList = [
13 | {
14 | name: "parallax",
15 | imgPath:
16 | "https://minio.wisdompanda.com/newtabimg/demoimg/mydemo_parallax.png",
17 | src: "https://wisdompanda.com/demo/parallax/",
18 | },
19 | {
20 | name: "弹幕墙",
21 | imgPath:
22 | "https://minio.wisdompanda.com/newtabimg/demoimg/bulletscreen.png",
23 | src: "https://wisdompanda.com/demo/bulletscreen/",
24 | },
25 | {
26 | name: "parallax",
27 | imgPath:
28 | "https://minio.wisdompanda.com/newtabimg/demoimg/mydemo_parallax.png",
29 | src: "https://wisdompanda.com/demo/parallax/",
30 | },
31 | {
32 | name: "parallax",
33 | imgPath:
34 | "https://minio.wisdompanda.com/newtabimg/demoimg/mydemo_parallax.png",
35 | src: "https://wisdompanda.com/demo/parallax/",
36 | },
37 | ];
38 |
39 | // modal组件控制函数
40 | const [isModalVisible, setIsModalVisible] = useState(false);
41 | const showModal = () => {
42 | // openNotification();
43 | setIsModalVisible(true);
44 | };
45 | const handleOk = () => {
46 | setIsModalVisible(false);
47 | };
48 | const handleCancel = () => {
49 | setIsModalVisible(false);
50 | };
51 | // const [persistedTodoList] = us
52 |
53 | //lottie动画设定
54 | const defaultOptions = {
55 | loop: true,
56 | autoplay: true,
57 | animationData: motorbike,
58 | rendererSettings: {
59 | preserveAspectRatio: "xMidYMid slice",
60 | },
61 | };
62 |
63 | return (
64 |
65 |
80 |
90 |
91 |
92 |
108 | 前端练习
109 |
110 | }
111 | visible={isModalVisible}
112 | onOk={handleOk}
113 | onCancel={handleCancel}
114 | // width={"57vw"}
115 | >
116 |
129 | {demoList.map((item, index) => {
130 | return (
131 |
142 |
145 |
153 |
154 | );
155 | })}
156 |
157 |
173 |
174 |
175 |
176 |
177 | );
178 | };
179 |
180 | export default memo(Demos);
181 |
--------------------------------------------------------------------------------
/src/components/FormHabit/FormHabit.js:
--------------------------------------------------------------------------------
1 | import { memo } from "react";
2 | import FuncCard from "../FuncCard/FuncCard";
3 |
4 | function FormHabit() {
5 | return (
6 |
14 | );
15 | }
16 |
17 | export default memo(FormHabit);
18 |
--------------------------------------------------------------------------------
/src/components/FuncCard/FuncCard.css:
--------------------------------------------------------------------------------
1 | .funcCard {
2 | position: relative; /* 试运行 */
3 | /* width: 352px; */
4 | height: 165px;
5 | background: #ececec;
6 | border-radius: 20px;
7 | overflow: hidden;
8 | /* background-color: #FF5631; */
9 | /* display: flex;
10 | justify-content: center;
11 | align-items: center; */
12 | transition: 0.2s ease-in;
13 | /* backdrop-filter: blur(50px); */
14 | /* border: 1px solid red; */
15 | box-shadow: 0px 10px 15px -3px rgba(0, 0, 0, 0.1);
16 | cursor: pointer;
17 | }
18 | .filter {
19 | background: #ffffff55;
20 | backdrop-filter: blur(20px);
21 | /* backdrop-filter: blur(2px); */
22 | /* color: #FFFFFF; */
23 | }
24 | /* .dark,.dark span,.dark div{
25 | background-color: #000000;
26 | color: #FFFFFF;
27 | } */
28 |
29 | .no-title {
30 | display: flex;
31 | justify-content: center;
32 | align-items: center;
33 | }
34 | .cardTitle {
35 | display: inline-block;
36 | margin-top: 0.8rem;
37 | margin-left: 0.8rem;
38 | font-style: normal;
39 | font-weight: bold;
40 | font-size: 18px;
41 | /* width: 50%; */
42 | letter-spacing: 0.2rem;
43 | }
44 | .cardTitle div {
45 | display: inline-block;
46 | width: 6px;
47 | height: 14px;
48 | background: linear-gradient(180deg, #ffc531 14.58%, #ff5631 100%);
49 | box-shadow: 0px 3px 6px rgba(255, 141, 6, 0.8);
50 | /* box-shadow: 0px 3px 6px #000; */
51 | border-radius: 20px;
52 | margin-right: 15px;
53 | margin-left: 5px;
54 | }
55 | .cardKinds {
56 | display: inline-flex;
57 | width: 150px;
58 | height: 25px;
59 | position: absolute;
60 | right: 15px;
61 | margin-top: 12px;
62 | justify-content: space-around;
63 | }
64 | .cardKinds span {
65 | font-size: 15px;
66 | line-height: 25px;
67 | text-align: center;
68 | font-weight: 700;
69 | width: 50px;
70 | height: 25px;
71 | border-radius: 5px;
72 | cursor: pointer;
73 | }
74 |
--------------------------------------------------------------------------------
/src/components/FuncCard/FuncCard.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { memo, useState } from "react";
3 | import { useSelector } from "react-redux";
4 | import "./FuncCard.css";
5 |
6 | /**
7 | *
8 | * 组件可选参数:
9 | * title (Stirng)
10 | * iconStyle (CSS Style)
11 | * kinds ([])
12 | * width (String 没有就默认 352px)
13 | * changeType()
14 | * className
15 | *
16 | */
17 |
18 | //加入filter:blur
19 | const FuncCard = props => {
20 | const cardstyle = useSelector(state => state.cardstyle);
21 | const { title, iconStyle, kinds, width } = props;
22 |
23 | const [type, setType] = useState(0);
24 |
25 | const if_title = title ? "" : " no-title"; //判断是否有标题来确定内容的布局方式
26 |
27 | const classlist = props.className ? " " + props.className : ""; //原来的类名
28 |
29 | const cardstyles = ["", " filter"];
30 |
31 | useEffect(() => {
32 | // console.log("Effect " + title);
33 | // return () => {
34 | // console.log("destroy" + title);
35 | // };
36 | }, []);
37 |
38 | return (
39 |
43 | {title ? ( //标题
44 |
48 | ) : null}
49 | {kinds ? ( //右边种类标签
50 |
51 | {kinds.map((item, index) => {
52 | return (
53 | {
56 | setType(index);
57 | props.changeType(index);
58 | }}
59 | style={{
60 | backgroundColor: type === index ? "#00000022" : "#ffffff00",
61 | }}
62 | >
63 | {item}
64 |
65 | );
66 | })}
67 |
68 | ) : null}
69 | {props.children}
70 |
71 | );
72 | };
73 |
74 | export default memo(FuncCard);
75 |
--------------------------------------------------------------------------------
/src/components/FuncCard/SetFuncCard/SetFuncCard.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/components/FuncCard/SetFuncCard/SetFuncCard.css
--------------------------------------------------------------------------------
/src/components/FuncCard/SetFuncCard/SetFuncCard.js:
--------------------------------------------------------------------------------
1 | import "./SetFuncCard.css";
2 | import { Radio } from "antd";
3 | import { useState } from "react";
4 | import { useDispatch, useSelector } from "react-redux";
5 | import { Button } from "antd";
6 | import useLocalStorage from "../../../hooks/useLocalStorage";
7 | import FuncModal from "../../FuncModal/FuncModal";
8 |
9 | export function SetFuncCardStyle() {
10 | const [cardStyle, setCardStyle] = useLocalStorage("cardstyle");
11 | const cardstyle = useSelector(state => state.cardstyle);
12 | const dispatch = useDispatch();
13 |
14 | const onChange = e => {
15 | //console.log('radio checked', e.target.value);
16 | // setValue(e.target.value);
17 | dispatch({
18 | type: "CHANGE_CARDSTYLE",
19 | cardstyle: e.target.value,
20 | });
21 | setCardStyle(e.target.value);
22 | };
23 |
24 | return (
25 |
26 | 卡片样式
27 |
28 |
29 | 普通
30 | 磨砂
31 |
32 |
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/FuncModal/FuncModal.css:
--------------------------------------------------------------------------------
1 | /* Modal磨砂 */
2 | .react-draggable .ant-modal-content {
3 | background: #ffffff55;
4 | /* -webkit-backdrop-filter: blur(20px); */
5 | backdrop-filter: blur(20px);
6 | /* transition: all 2s ease-in-out; */
7 | }
8 | .react-draggable .ant-modal-header {
9 | background: #ffffff00;
10 | border-bottom: 0;
11 | /* -webkit-backdrop-filter: blur(20px); */
12 | backdrop-filter: blur(20px);
13 | /* transition: all 2s ease-in-out; */
14 | }
15 | /* News磨砂 */
16 | /* 修改tabpane的背景颜色 */
17 | .ant-tabs-card.ant-tabs-left > .ant-tabs-nav .ant-tabs-tab {
18 | background: #ffffff00;
19 | }
20 | .ant-tabs-card > .ant-tabs-nav .ant-tabs-tab {
21 | border: 0;
22 | }
23 | .ant-tabs-card.ant-tabs-left > .ant-tabs-nav .ant-tabs-tab-active {
24 | background: #ffffffaa;
25 | }
26 | .ant-tabs-dropdown-menu {
27 | background: #ffffffaa;
28 | }
29 | .ant-tabs-dropdown-menu::-webkit-scrollbar {
30 | width: 3px;
31 | }
32 | .ant-tabs-dropdown-menu::-webkit-scrollbar-thumb {
33 | border-radius: 10px;
34 | box-shadow: inset 0 0 4px #00000033;
35 | background: rgba(0, 0, 0, 0.2);
36 | }
37 | .ant-tabs-dropdown-menu::-webkit-scrollbar-track {
38 | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
39 | border-radius: 10px;
40 | background: rgba(0, 0, 0, 0.1);
41 | }
42 | /* Table磨砂 */
43 | .ant-table-thead > tr > th {
44 | background: #fafafa99;
45 | }
46 | .ant-table {
47 | background: #fff0;
48 | }
49 | .ant-table-tbody > tr.ant-table-row:hover > td,
50 | .ant-table-tbody > tr > td.ant-table-cell-row-hover {
51 | background: #fff5;
52 | }
53 | .ant-btn-dashed {
54 | background: #fff6;
55 | }
56 | .ant-btn-dashed:hover,
57 | .ant-btn-dashed:focus {
58 | background: #fff9;
59 | }
60 |
61 | .expand {
62 | border-radius: 0.1rem;
63 | position: absolute;
64 | padding: 3px 8px;
65 | z-index: 4;
66 | right: 1%;
67 | top: 0%;
68 | }
69 | .expand:hover {
70 | background-color: #0008;
71 | }
72 |
--------------------------------------------------------------------------------
/src/components/FuncModal/FuncModal.js:
--------------------------------------------------------------------------------
1 | import { Modal } from "antd";
2 | import { ExpandOutlined, CloseOutlined } from "@ant-design/icons";
3 | import "./FuncModal.css";
4 | import { useState, useRef, memo } from "react";
5 | import Draggable from "react-draggable";
6 |
7 | const FuncModal = props => {
8 | const [disabled, setDisabled] = useState(false);
9 | const [full, setFull] = useState(false);
10 | const [visible, setVisible] = useState(props.visible);
11 | const [bounds, setBounds] = useState({
12 | left: 0,
13 | top: 0,
14 | bottom: 0,
15 | right: 0,
16 | });
17 | const draggleRef = useRef(null);
18 |
19 | // 拖拽组件
20 | const onStart = (_event, uiData) => {
21 | const { clientWidth, clientHeight } = window.document.documentElement;
22 | const targetRect = draggleRef.current?.getBoundingClientRect();
23 |
24 | if (!targetRect) {
25 | return;
26 | }
27 |
28 | setBounds({
29 | left: -targetRect.left + uiData.x,
30 | right: clientWidth - (targetRect.right - uiData.x),
31 | top: -targetRect.top + uiData.y,
32 | bottom: clientHeight - (targetRect.bottom - uiData.y),
33 | });
34 | };
35 |
36 | const handleContextMenu = e => {
37 | e.stopPropagation();
38 | };
39 |
40 | return (
41 | handleContextMenu(e)}>
42 |
(
74 | onStart(event, uiData)}
78 | >
79 | {modal}
80 |
81 | )}
82 | >
83 | setFull(!full)}
87 | >
88 |
89 |
90 | {props.children}
91 |
92 |
93 | );
94 | };
95 |
96 | export default memo(FuncModal);
97 |
--------------------------------------------------------------------------------
/src/components/FunctionAera/FunctionAera.css:
--------------------------------------------------------------------------------
1 | .functionAera {
2 | position: relative;
3 | bottom: 0vh;
4 | margin: 0 auto 30px auto;
5 | width: 84vw;
6 | height: 20vw;
7 | border-radius: 20px;
8 | border: 0px solid black;
9 | /* overflow-y: scroll; */
10 | transition: 0.3s ease-in-out;
11 | /* transform: scale(0.95); */
12 | /* filter: blur(0px)!important */
13 | /* background-color: #ffffff4D; */
14 | }
15 | .sortable {
16 | /* position: relative;
17 | z-index: 1; */
18 | display: flex;
19 | flex-wrap: wrap;
20 | justify-content: center;
21 | /* display: inline-grid;
22 | grid-template-columns: repeat(4, 352px);
23 | grid-template-rows: repeat(auto-fill, 180px); */
24 | }
25 | .sortableItem {
26 | position: relative;
27 | z-index: 2;
28 | margin: 12px;
29 | border-radius: 20px;
30 | /* background-image: url(https://minio.wisdompanda.com/background/bg1.jpg);
31 | background-size: cover;
32 | background-repeat: no-repeat; */
33 | /* transform: scale(0.8); */
34 | /* display: inline-block; */
35 | /* transition: .5s ease-in; */
36 | }
37 | /* .sortableItem:active{
38 | transform: scale(0.95);
39 | } */
40 | .sortableItem > button {
41 | position: absolute;
42 | right: 0;
43 | z-index: 1;
44 | }
45 | .funcshake {
46 | animation: func_shake 0.2s infinite;
47 | }
48 | @keyframes func_shake {
49 | 0% {
50 | transform: rotate(1deg);
51 | }
52 | 25% {
53 | transform: rotate(0);
54 | }
55 | 50% {
56 | transform: rotate(-1deg);
57 | }
58 | 75% {
59 | transform: rotate(0deg);
60 | }
61 | 100% {
62 | transform: rotate(1deg);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/components/FunctionAera/FunctionAera.js:
--------------------------------------------------------------------------------
1 | import "./FunctionAera.css";
2 | import "../../font/iconfont.css";
3 | import News from "../News/News";
4 | import Todo from "../Todo/Todo";
5 | import Pictures from "../Pictures";
6 | import Notes from "../Notes";
7 | import Weather from "../Weather/Weather";
8 | import CalComponent from "../Calendar/CalComponent";
9 | import Competition from "../Competition/Competition";
10 | import CountDown from "../CountDown/CountDown";
11 | import ServerMonitor from "../ServerMonitor/ServerMonitor";
12 | import ToolKit from "../ToolKit/ToolKit";
13 | import Demos from "../Demos/Demos";
14 | // import Memo from '../Memo/Memo'
15 | // import YearToday from '../FuncModule/YearToday/YearToday'
16 | import TomatoClock from "../TomatoClock/TomatoClock";
17 |
18 | import { SortableContainer, SortableElement } from "react-sortable-hoc";
19 | import { arrayMoveImmutable } from "array-move";
20 | import { useSelector, useDispatch } from "react-redux";
21 | import { memo, useEffect, useState } from "react";
22 | import { Button } from "antd";
23 | import { CloseOutlined } from "@ant-design/icons";
24 | import { funcs } from "./SetFunctionAera/SetFunctionArea";
25 |
26 | //TODO: 1.服务器性能监控模块,2. 前端工具箱模块 3. 股票信息模块 4. 图片上传图床模块 5. 博客文章显示(改写笔记) 6. 日历添加打卡功能 7. 那年今日 8.桌面宠物或者人偶
27 |
28 | // type 0 为装饰类 1 为功能类
29 | // const funcs = [
30 | // { id: 0, node: , type: "1" },
31 | // { id: 1, node: , type: "1" },
32 | // { id: 2, node: , type: "0" },
33 | // { id: 3, node: , type: "1" },
34 | // { id: 4, node: , type: "1" },
35 | // { id: 5, node: , type: "1" },
36 | // { id: 6, node: , type: "1" },
37 | // { id: 7, node: , type: "1" },
38 | // { id: 8, node: , type: "1" },
39 | // { id: 9, node: , type: "1" },
40 | // { id: 10, node: , type: "0" },
41 | // // {id:11, node:},
42 | // // {id:11, node:},
43 | // { id: 11, node: , type: "1" },
44 | // ];
45 |
46 | //测试上传
47 | const FunctionAera = () => {
48 | //中间的功能组件,放在里面
49 |
50 | const funcdeleteMode = useSelector(state => state.deleteFunc);
51 | const functionList = useSelector(state => state.functionList);
52 | // let timePos = useSelector(state => state.timePos);
53 |
54 | //先重新排列这些组件,统一组件大小
55 | // let functionList = localStorage.getItem('functionList')? localStorage.getItem('functionList'):"[0,1,2,3,4,5,6,7]"
56 | //const functionList = useSelector(state=>state.functionList)
57 | const [items, setItems] = useState(functionList);
58 |
59 | const dispatch = useDispatch();
60 |
61 | const funcshake = funcdeleteMode ? " funcshake" : "";
62 |
63 | useEffect(() => {
64 | setItems(functionList);
65 | }, [functionList]);
66 |
67 | const handleContextMenu = (e, b) => {
68 | e.stopPropagation();
69 | e.preventDefault();
70 | dispatch({
71 | type: "CHANGE_DELETEFUNC",
72 | deleteFunc: !b,
73 | });
74 | };
75 |
76 | const SortableItem = SortableElement(({ value }) => (
77 | handleContextMenu(e, funcdeleteMode)}
81 | >
82 | {/* 删除模式按钮 */}
83 | }
87 | size='small'
88 | onMouseDown={e => deleteFunc(funcs[value].id)}
89 | />
90 | {funcs[value].node}
91 |
92 | ));
93 |
94 | const SortableList = SortableContainer(({ items }) => {
95 | return (
96 |
97 | {items.map((value, index) => (
98 | console.log(value)}
100 | key={index}
101 | index={index}
102 | value={value}
103 | />
104 | ))}
105 |
106 | );
107 | });
108 |
109 | const deleteFunc = id => {
110 | let newList = items;
111 | let cover = items.reduce((pre, cur) => {
112 | return pre + funcs[cur].cover;
113 | }, 0);
114 | // console.log(cover);
115 | //删除数组中指定元素
116 | // if (cover > 16) newList = newList.slice(0, 8);
117 | // console.log(newList);
118 | newList.splice(newList.indexOf(id), 1);
119 | setItems(newList);
120 | localStorage.setItem("functionList", JSON.stringify(newList));
121 | // let updatemyApps = myApps.filter((item) => item.id !== id);
122 | // localStorage.setItem('apps', JSON.stringify(updatemyApps))
123 | // setItems(updatemyApps);
124 | dispatch({
125 | type: "CHANGE_FUNCS",
126 | functionList: newList,
127 | });
128 | // console.log("deleteFunc")
129 | };
130 |
131 | const onSortEnd = ({ oldIndex, newIndex }) => {
132 | setItems(arrayMoveImmutable(items, oldIndex, newIndex));
133 | localStorage.setItem(
134 | "functionList",
135 | JSON.stringify(arrayMoveImmutable(items, oldIndex, newIndex))
136 | );
137 | };
138 |
139 | let height = "30vw";
140 |
141 | return (
142 |
143 |
149 |
150 | );
151 | };
152 |
153 | export default memo(FunctionAera);
154 |
--------------------------------------------------------------------------------
/src/components/FunctionAera/SetFunctionAera/SetFunctionArea.css:
--------------------------------------------------------------------------------
1 | .addfunc {
2 | height: 165px;
3 | position: absolute;
4 | border-radius: 20px;
5 | background: #fff0;
6 | z-index: 1;
7 | transition: 0.3s ease-in-out;
8 | }
9 | .addfunc:hover {
10 | background: #0005;
11 | }
12 | .addfunc > button {
13 | position: relative;
14 | left: 50%;
15 | top: 50%;
16 | transform: translate(-50%, -50%);
17 | opacity: 0;
18 | background-color: #fff0;
19 | }
20 | .addfunc:hover > button {
21 | opacity: 1;
22 | background-color: #fff8;
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/FunctionAera/SetFunctionAera/SetFunctionArea.js:
--------------------------------------------------------------------------------
1 | import "./SetFunctionArea.css";
2 | import { memo, useState } from "react";
3 | import { Button, message } from "antd";
4 | import { PlusOutlined, AppstoreAddOutlined } from "@ant-design/icons";
5 | import { useDispatch, useSelector } from "react-redux";
6 | import FuncModal from "../../FuncModal/FuncModal";
7 | import News from "../../News/News";
8 | import Todo from "../../Todo/Todo";
9 | import Pictures from "../../Pictures";
10 | import Notes from "../../Notes";
11 | import Weather from "../../Weather/Weather";
12 | import CalComponent from "../../Calendar/CalComponent";
13 | import Competition from "../../Competition/Competition";
14 | import CountDown from "../../CountDown/CountDown";
15 | import ServerMonitor from "../../ServerMonitor/ServerMonitor";
16 | import ToolKit from "../../ToolKit/ToolKit";
17 | import Demos from "../../Demos/Demos";
18 | // import Snippets from '../../Snippets/Snippets'
19 | // import YearToday from '../../FuncModule/YearToday/YearToday';
20 | import TomatoClock from "../../TomatoClock/TomatoClock";
21 | import { useEffect } from "react";
22 | import WoodenFish from "../../WoodenFish/WoodenFish";
23 | import FormHabit from "../../FormHabit/FormHabit";
24 | import StockMarket from "../../StockMarket/StockMarket";
25 |
26 | //FIXME:style have some problem
27 |
28 | const funcs = [
29 | { id: 0, node: , cover: 2 },
30 | { id: 1, node: , cover: 2 },
31 | { id: 2, node: , cover: 2 },
32 | { id: 3, node: , cover: 1 },
33 | { id: 4, node: , cover: 2 },
34 | { id: 5, node: , cover: 2 },
35 | { id: 6, node: , cover: 2 },
36 | { id: 7, node: , cover: 2 },
37 | { id: 8, node: , cover: 2 },
38 | { id: 9, node: , cover: 2 },
39 | { id: 10, node: , cover: 2 },
40 | // {id:11, node:},
41 | // {id:11, node:},
42 | { id: 11, node: , cover: 2 },
43 | { id: 12, node: , cover: 1 },
44 | { id: 13, node: , cover: 1 },
45 | { id: 14, node: , cover: 1 },
46 | ];
47 |
48 | const SetFunctionArea = memo(() => {
49 | const [isModalVisible, setIsModalVisible] = useState(false);
50 | let timePos = useSelector(state => state.timePos);
51 | const dispatch = useDispatch();
52 |
53 | const showModal = () => {
54 | setIsModalVisible(true);
55 | };
56 |
57 | const handleOk = () => {
58 | setIsModalVisible(false);
59 | };
60 |
61 | const handleCancel = () => {
62 | setIsModalVisible(false);
63 | };
64 |
65 | let funcNum = 24;
66 |
67 | const addFunc = id => {
68 | let newList = JSON.parse(localStorage.getItem("functionList"));
69 | let cover = newList.reduce((pre, cur) => {
70 | return pre + funcs[cur].cover;
71 | }, 0);
72 | // && cover + 目前要添加的组件cover <= funcNum 限制组件个数
73 | if (newList.indexOf(id) === -1 && cover + funcs[id].cover <= funcNum) {
74 | newList.push(id);
75 | localStorage.setItem("functionList", JSON.stringify(newList));
76 | dispatch({
77 | type: "CHANGE_FUNCS",
78 | functionList: newList,
79 | });
80 | } else {
81 | message.info("功能组件已存在 或 已超过最大放置组件数");
82 | }
83 | };
84 |
85 | return (
86 |
87 |
88 |
89 | 添加功能
90 |
91 |
101 | // 添加 Card
102 | //
103 | // }
104 | closable={false}
105 | visible={isModalVisible}
106 | onOk={handleOk}
107 | onCancel={handleCancel}
108 | >
109 |
119 | {funcs.map((item, index) => {
120 | return (
121 | //FIXME:天气应用无法显示
122 |
126 |
1 ? "352px" : "165px" }}
129 | >
130 | }
133 | size='large'
134 | onMouseDown={e => addFunc(item.id)}
135 | />
136 |
137 | {item.node}
138 |
139 | );
140 | })}
141 |
142 |
143 |
144 | );
145 | });
146 |
147 | export { SetFunctionArea, funcs };
148 |
--------------------------------------------------------------------------------
/src/components/MottoFooter/MottoFooter.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | position: absolute;
3 | font-size: 20px;
4 | font-weight: 600;
5 | text-align: center;
6 | left: 50%;
7 | bottom: 1vh;
8 | transform: translateX(-50%);
9 | /* background-color: #000000CC; */
10 | border-radius: 10px;
11 | padding: 10px 50px;
12 | color: white;
13 | cursor: pointer;
14 | }
15 | .footer:hover {
16 | background-color: #00000055;
17 | }
18 | .footer:hover span {
19 | visibility: visible;
20 | }
21 | .footer span {
22 | visibility: hidden;
23 | font-size: 18px;
24 | }
25 |
26 | .slidein {
27 | animation: slide 1s;
28 | }
29 |
30 | @keyframes slide {
31 | 0% {
32 | opacity: 0;
33 | }
34 | 100% {
35 | opacity: 1;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/News/News.css:
--------------------------------------------------------------------------------
1 | /* .news{
2 | position: absolute;
3 | display: inline-block;
4 | width: 352px;
5 | height: 165px;
6 | width: 18vw;
7 | height: 8.5vw;
8 | margin:20px;
9 | left:764px;
10 | top:20px;
11 | background: #FFFFFF;
12 | box-sizing: border-box;
13 | border-radius: 20px;
14 | transition: .1s ease-in;
15 | }
16 | .news:active{
17 | transform: scale(0.95);
18 | } */
19 | .briefNav .left {
20 | display: inline-block;
21 | margin-top: 13px;
22 | }
23 | /* .briefNav .left p{
24 |
25 | font-style: normal;
26 | font-weight: bold;
27 | font-size: 18px;
28 | line-height: 22px;
29 |
30 | margin: 0;
31 | display: inline-block;
32 | letter-spacing: 0.2rem;
33 | cursor: pointer;
34 | margin-left: 12px;
35 | }
36 | .briefNav .left div{
37 | display: inline-block;
38 | margin-left: 18px;
39 | width: 6px;
40 | height: 14px;
41 | background: linear-gradient(180deg, #FFC531 14.58%, #FF5631 100%);
42 | box-shadow: 0px 3px 6px rgba(255, 141, 6, 0.8);
43 | border-radius: 20px;
44 | } */
45 | .right {
46 | /* position: absolute; */
47 | display: inline-flex;
48 | align-items: center;
49 | justify-content: space-around;
50 | width: 120px;
51 | line-height: 18px;
52 | margin-left: 96px;
53 | cursor: pointer;
54 | }
55 | .right span {
56 | height: 22px;
57 | width: 22px;
58 | font-size: 22px;
59 | }
60 |
61 | .briefList {
62 | /* position: absolute; */
63 | display: flex;
64 | margin-top: 10px;
65 | flex-direction: column;
66 | flex-wrap: wrap;
67 | justify-content: space-around;
68 | align-content: space-between;
69 | width: 320px;
70 | height: 110px;
71 | margin-left: 21px;
72 | /* top: 40px;
73 | left:50%;
74 | transform:translateX(-50%); */
75 | }
76 | .briefList .briefListItem {
77 | width: 150px;
78 | height: 18px;
79 | line-height: 16px;
80 | /* font-size: 12px; */
81 | font-weight: 600;
82 | color: #00000066;
83 | margin: 3px 0;
84 | overflow: hidden;
85 | text-overflow: ellipsis;
86 | white-space: nowrap;
87 | letter-spacing: 1px;
88 | }
89 | .briefList .briefListItem a {
90 | color: #00000066;
91 | }
92 | .briefList .briefListItem a:hover {
93 | color: #000000;
94 | }
95 | .briefList .briefListItem span {
96 | font-size: 16px;
97 | font-weight: 700;
98 | margin-right: 10px;
99 | line-height: 18px;
100 | color: #00000066;
101 | cursor: pointer;
102 | }
103 | .briefList .briefListItem:nth-child(1) span {
104 | color: #ffdd2b;
105 | }
106 | .briefList .briefListItem:nth-child(2) span {
107 | color: #b2b2b2;
108 | }
109 | .briefList .briefListItem:nth-child(3) span {
110 | color: #d2a36c;
111 | }
112 | .line {
113 | margin-left: 123px;
114 | margin-top: -54px;
115 | width: 100px;
116 | height: 0px;
117 | border: 1px solid rgba(0, 0, 0, 0.1);
118 | transform: rotate(90deg);
119 | }
120 |
121 | span .newsItemNum {
122 | display: inline-block;
123 | line-height: 20px;
124 | text-align: center;
125 | border-radius: 3px;
126 | margin-right: 20px;
127 | font-size: 18px;
128 | font-weight: 600;
129 | width: 20px;
130 | height: 20px;
131 | background-color: #e4e0e0;
132 | position: relative;
133 | top: 1.5px;
134 | }
135 | .newsItem:nth-child(1) span .newsItemNum {
136 | background-color: #ffdd2b;
137 | }
138 | .newsItem:nth-child(2) span .newsItemNum {
139 | background-color: #b2b2b2;
140 | }
141 | .newsItem:nth-child(3) span .newsItemNum {
142 | background-color: #d2a36c;
143 | }
144 |
145 | .newsItem > span {
146 | overflow: hidden;
147 | text-overflow: ellipsis;
148 | white-space: nowrap;
149 | width: 450px;
150 | position: relative;
151 | }
152 |
153 | .newsItem:hover {
154 | background-color: #00000033;
155 | transition: 0.3s ease-out;
156 | }
157 | /* 滚动条样式 */
158 | .newsList::-webkit-scrollbar {
159 | width: 3px;
160 | }
161 | .newsList::-webkit-scrollbar-thumb {
162 | border-radius: 10px;
163 | box-shadow: inset 0 0 4px #00000033;
164 | background: rgba(0, 0, 0, 0.2);
165 | }
166 | .newsList::-webkit-scrollbar-track {
167 | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
168 | border-radius: 10px;
169 | background: rgba(0, 0, 0, 0.1);
170 | }
171 |
172 | .ant-tabs-dropdown {
173 | background-color: #fff;
174 | }
175 |
--------------------------------------------------------------------------------
/src/components/Notes/index.css:
--------------------------------------------------------------------------------
1 | @import "~antd/dist/antd.css";
2 | /* .ant-modal-body{
3 | padding-left: 5px;
4 | padding-right: 5px;
5 | } */
6 | .memorandum {
7 | display: flex;
8 | height: 100%;
9 | justify-content: space-between;
10 | }
11 | .notes-tabs {
12 | width: 100%;
13 | max-width: 200px;
14 | /* max-height: 500px; */
15 | height: 100%;
16 | display: flex;
17 | flex-direction: column;
18 | text-align: center;
19 | position: relative;
20 | }
21 | .notes-tabs-body {
22 | height: 100%;
23 | overflow: auto;
24 | background: #f0f1f4;
25 | }
26 | .wrapper {
27 | display: flex;
28 | flex-direction: column;
29 | align-items: center;
30 | justify-content: center;
31 | height: calc(100% - 55px);
32 | }
33 | .ant-card-body {
34 | padding: 24px 12px;
35 | }
36 | .notes-tabs-item {
37 | background: #f0f1f4;
38 | position: relative;
39 | font-size: 14px;
40 | }
41 | .notes-tabs-item:hover .ant-card-meta-title {
42 | color: #69c0ff;
43 | }
44 | .notes-tabs-checked {
45 | background: #fff;
46 | color: #222;
47 | }
48 |
49 | /* 笔记删除按钮 */
50 | .notes-del {
51 | position: absolute;
52 | top: 0;
53 | right: 0;
54 | }
55 | /* 笔记添加按钮 */
56 | .notes-add {
57 | position: absolute;
58 | bottom: 10px;
59 | right: 22px;
60 | }
61 |
--------------------------------------------------------------------------------
/src/components/Notes/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, memo } from "react";
2 | import { Button, message } from "antd";
3 | import MarkdownNotes from "./markdown-notes/index";
4 | import "./index.css";
5 | import { PlusOutlined } from "@ant-design/icons";
6 | import useLocalStorage from "../../hooks/useLocalStorage";
7 | import NoesTabs from "./noesTabs";
8 | import { nanoid } from "nanoid";
9 | import cookie from "react-cookies";
10 | import FuncCard from "../FuncCard/FuncCard";
11 | import FuncModal from "../FuncModal/FuncModal";
12 |
13 | const Notes = () => {
14 | const [notesList, setNotesList] = useLocalStorage("notesList", []);
15 | const [notesData, setNotesData] = useState(notesList); //笔记数据
16 | const [noteIndex, setNoteIndex] = useState(0); // 选中第几个
17 | const [isNotesVisible, setNotesVisible] = useState(false); // 弹框
18 |
19 | useEffect(() => {
20 | async function getNotes() {
21 | fetch("/api/functions/getmynotes/", {
22 | credentials: "include",
23 | })
24 | .then(response => response.json())
25 | .then(data => {
26 | setNotesData(JSON.parse(data.res));
27 | setNotesList(JSON.parse(data.res));
28 | })
29 | .catch(e => console.log(e.message));
30 | }
31 | if (cookie.load("status") === "200") {
32 | //获取数据
33 | getNotes();
34 | }
35 | }, []);
36 |
37 | // useEffect(()=>{
38 | // console.log('notes改变')
39 | // let url = defaultSetting.site + '/functions/savemynotes/'
40 | // async function saveNotes(){
41 | // fetch(url,{
42 | // method:'post',
43 | // body:JSON.stringify(notesData),
44 | // headers: {
45 | // 'Content-Type': 'application/json'
46 | // },
47 | // credentials:'include'
48 | // }).then((response)=>response.json())
49 | // .then((data)=>{ })
50 | // .catch((e)=>console.log("error"));
51 | // }
52 | // if(cookie.load('status')==='200'){ //保存到数据库
53 | // saveNotes()
54 | // }
55 | // },[notesData])
56 |
57 | // 是否显示弹框
58 | const isShowModal = () => {
59 | setNotesVisible(!isNotesVisible);
60 | async function saveNotes() {
61 | fetch("/api/functions/savemynotes/", {
62 | method: "post",
63 | body: JSON.stringify(notesData),
64 | headers: {
65 | "Content-Type": "application/json",
66 | },
67 | credentials: "include",
68 | })
69 | .then(response => response.json())
70 | .then(data => {})
71 | .catch(e => console.log("error"));
72 | }
73 | if (cookie.load("status") === "200" && isNotesVisible) {
74 | //保存到数据库
75 | saveNotes();
76 | message.success("笔记保存成功");
77 | }
78 | };
79 | // 添加笔记
80 | const isNoteAdd = () => {
81 | if (notesData.length === 0) setNoteIndex(0);
82 | const data = notesData.concat([
83 | { id: nanoid(), value: "无内容", text: "" },
84 | // 使用nanoid而不是uuid,引用nanoid包
85 | ]);
86 | setNotesData(data);
87 | setNotesList(data);
88 | };
89 |
90 | return (
91 | <>
92 |
101 | {/* */}
105 |
106 |
{notesData[0]?.value}
107 |
{notesData[1]?.value}
108 |
{notesData[2]?.value}
109 |
{notesData[3]?.value}
110 |
111 |
112 |
122 | 笔记
123 |
124 | }
125 | width={1000}
126 | footer={null}
127 | visible={isNotesVisible}
128 | onCancel={isShowModal}
129 | >
130 |
131 |
132 |
133 | {notesData.length !== 0 ? (
134 | notesData.map((item, index) => {
135 | return (
136 |
146 | );
147 | })
148 | ) : (
149 |
快来添加第一条笔记吧
150 | )}
151 |
152 |
}
158 | />
159 |
160 |
166 |
167 |
168 | >
169 | );
170 | };
171 |
172 | export default memo(Notes);
173 |
--------------------------------------------------------------------------------
/src/components/Notes/markdown-notes/index.css:
--------------------------------------------------------------------------------
1 | .button-type-image,
2 | .button-type-fullscreen {
3 | display: none !important;
4 | }
5 |
--------------------------------------------------------------------------------
/src/components/Notes/markdown-notes/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import MarkdownIt from "markdown-it";
3 | import MdEditor from "react-markdown-editor-lite";
4 | // 导入编辑器的样式
5 | import "react-markdown-editor-lite/lib/index.css";
6 | // markdown代码颜色
7 | import hljs from "highlight.js";
8 | import "highlight.js/styles/atom-one-light.css";
9 | // 编辑样式
10 | import "./index.css";
11 |
12 | // 初始化Markdown解析器
13 | const mdParser = new MarkdownIt({
14 | html: true,
15 | linkify: true,
16 | typographer: true,
17 | highlight: (str, lang) => {
18 | if (lang && hljs.getLanguage(lang)) {
19 | try {
20 | return hljs.highlight(lang, str).value;
21 | } catch (_) {
22 | console.log("出错了");
23 | }
24 | }
25 | return ""; // use external default escaping
26 | },
27 | });
28 |
29 | const MarkdownNotes = noteData => {
30 | const [notesValue, setIsCardDelete] = useState("");
31 |
32 | // 初始化更新
33 | React.useEffect(() => {
34 | const newNoteData = noteData?.notesData[noteData.noteIndex]
35 | ? noteData?.notesData[noteData.noteIndex]
36 | : noteData?.notesData[noteData.noteIndex - 1];
37 | setIsCardDelete(newNoteData);
38 | return () => {};
39 | }, [noteData.notesData, noteData.noteIndex]);
40 |
41 | // 使用正则表达式从字符串中删除 HTML/XML 标记。
42 | const stripHTMLTags = str => str.replace(/<[^>]*>/g, "");
43 |
44 | // 改变markdown笔记内容时触发
45 | const handleEditorChange = ({ html, text }) => {
46 | setIsCardDelete(text);
47 | const note = noteData.notesData;
48 | note[noteData.noteIndex].text = text;
49 | note[noteData.noteIndex].value = stripHTMLTags(html);
50 | noteData.setNotesData(note);
51 | noteData.setNotesList(note);
52 | };
53 |
54 | return (
55 | <>
56 | {noteData?.notesData.length !== 0 ? (
57 | mdParser.render(text)}
63 | onChange={handleEditorChange}
64 | />
65 | ) : (
66 |
81 | 暂无笔记
82 |
83 | )}
84 | >
85 | );
86 | };
87 |
88 | export default MarkdownNotes;
89 |
--------------------------------------------------------------------------------
/src/components/Notes/noesTabs.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { Button, Card, Modal } from "antd";
3 | import { DeleteOutlined, ExclamationCircleOutlined } from "@ant-design/icons";
4 | import Meta from "antd/es/card/Meta";
5 |
6 | const NoesTabs = data => {
7 | const [isCardDelete, setIsCardDelete] = useState(false); // 删除按钮
8 |
9 | // 是否显示删除按钮
10 | const handleMouse = flag => {
11 | setIsCardDelete(flag);
12 | };
13 | // 选中当前笔记
14 | const isShowNotes = (item, index) => {
15 | data.setNoteIndex(index);
16 | };
17 | // 删除笔记
18 | const isDelete = (item, index) => {
19 | Modal.confirm({
20 | title: "提示",
21 | icon: ,
22 | content: "删除这条笔记?",
23 | okText: "确认",
24 | cancelText: "取消",
25 | onOk: function () {
26 | const newNotesData = data.notesData.filter(i => i.id !== item.id);
27 | data.setNotesData(newNotesData);
28 | data.setNotesList(newNotesData);
29 | data.setNoteIndex(index - 1);
30 | },
31 | onCancel: function () {
32 | console.log("取消");
33 | },
34 | });
35 | };
36 | return (
37 | <>
38 | handleMouse(true)}
45 | onMouseLeave={() => handleMouse(false)}
46 | onClick={() => isShowNotes(data.item, data.index)}
47 | hoverable={true}
48 | >
49 |
50 |
59 | >
60 | );
61 | };
62 |
63 | export default NoesTabs;
64 |
--------------------------------------------------------------------------------
/src/components/Pictures/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, memo } from "react";
2 | import { Carousel, Table, Upload, Button, Image, message } from "antd";
3 | import { UploadOutlined } from "@ant-design/icons";
4 | // import data from './data';
5 | import "./style.css";
6 | import cookie from "react-cookies";
7 | import FuncCard from "../FuncCard/FuncCard";
8 | import FuncModal from "../FuncModal/FuncModal";
9 |
10 | const Pictures = () => {
11 | let initialList = localStorage.getItem("myimglist")
12 | ? JSON.parse(localStorage.getItem("myimglist"))
13 | : [""];
14 |
15 | const [modalVisible, setModalVisible] = useState(false);
16 |
17 | const [myimglist, setMyImgList] = useState(initialList);
18 |
19 | useEffect(() => {
20 | async function getList() {
21 | fetch("/api/img/getmyimglist/", {
22 | credentials: "include",
23 | })
24 | .then(response => response.json())
25 | .then(data => {
26 | localStorage.setItem("myimglist", JSON.stringify(data.objectList));
27 | setMyImgList(data.objectList);
28 | })
29 | .catch(e => console.log("error"));
30 | }
31 | getList();
32 | }, []);
33 |
34 | // 每当弹窗状态变化或图片数量变化时触发重新获取图片列表
35 | // useEffect(() => {
36 | // GET_PICS(userId).then((res) => {
37 | // // setPicData(res.data);
38 | // setPicNumber(res.data.length);
39 | // })
40 | // }, [modalVisible, picNumber, userId]);
41 |
42 | const showModal = () => {
43 | setModalVisible(true);
44 | // console.log("showmodel")
45 | };
46 |
47 | const deletePic = pic => {
48 | console.log("delete pic");
49 | let url = "/api/img/deletemyimg/?file_name=" + pic.split("/")[1];
50 | fetch(url, {
51 | credentials: "include",
52 | })
53 | .then(response => response.json())
54 | .then(data => {
55 | localStorage.setItem("myimglist", JSON.stringify(data.objectList));
56 | setMyImgList(data.objectList);
57 | })
58 | .catch(e => console.log("error"));
59 | };
60 |
61 | const columns = [
62 | {
63 | title: "图片",
64 | dataIndex: "",
65 | key: "",
66 | render: text => {
67 | let url = "/pic/" + text;
68 | return (
69 | <>
70 |
71 | >
72 | );
73 | },
74 | },
75 | {
76 | title: "操作",
77 | dataIndex: "",
78 | key: "",
79 | render: (text, index) => {
80 | return myimglist.length < 2 ? (
81 |
82 | ) : (
83 |
92 | );
93 | },
94 | },
95 | ];
96 |
97 | const settings = {
98 | dots: true,
99 | fade: true,
100 | speed: 500,
101 | autoplay: true,
102 | autoplaySpeed: 4000, //间隔
103 | };
104 |
105 | const props = {
106 | name: "file",
107 | withCredentials: true,
108 | action: "/api/img/uploadmyimg/",
109 | onChange(info) {
110 | const { status, response } = info.file;
111 | if (status !== "uploading") {
112 | console.log(info.file, info.fileList);
113 | }
114 | if (status === "done") {
115 | message.success(`${info.file.name} file uploaded successfully`);
116 | setMyImgList(response.objectList);
117 | localStorage.setItem("myimglist", JSON.stringify(response.objectList));
118 | } else if (info.file.status === "error") {
119 | message.error(`${info.file.name} file upload failed.`);
120 | }
121 | },
122 | };
123 |
124 | return (
125 | <>
126 |
127 |
128 |
129 | {
130 | // picData.map(() => { })
131 | myimglist.map((item, index) => {
132 | let url = "/pic/" + item;
133 | return (
134 |
135 |

143 |
144 | );
145 | })
146 | }
147 |
148 |
149 |
150 |
160 | 图片墙
161 |
162 | }
163 | visible={modalVisible}
164 | onCancel={() => {
165 | setModalVisible(false);
166 | }}
167 | footer={null}
168 | >
169 |
176 |
177 | }
180 | type='primary'
181 | style={{ marginTop: "10px" }}
182 | >
183 | 添加图片
184 |
185 |
186 |
187 | >
188 | );
189 | };
190 |
191 | export default memo(Pictures);
192 |
--------------------------------------------------------------------------------
/src/components/Pictures/style.css:
--------------------------------------------------------------------------------
1 | @import "~antd/dist/antd.css";
2 | /* .Picture{
3 | transition: all .5s ;
4 | } */
5 | .carousel {
6 | /* position: relative;
7 | z-index: 1; */
8 | /* top:20px;
9 | left: 1136px; */
10 | /* width: 18vw;
11 | height: 8.5vw; */
12 | width: 352px;
13 | height: 165px;
14 | border: 0 solid white;
15 | border-radius: 20px;
16 | overflow: hidden;
17 | /* transition: all .5s ; */
18 | }
19 | .carousel_func {
20 | background-color: #00000000;
21 | }
22 | .carousel:active {
23 | /* transform: scale(0.95); */
24 | }
25 |
26 | .panel {
27 | width: 100%;
28 | /* padding-bottom: 60%;
29 | height: 0; */
30 | /* position: relative;
31 | z-index: 100; */
32 | color: #ffffff;
33 | text-align: center;
34 | background: #364d79;
35 | }
36 |
37 | /* 滚动条样式 */
38 | div::-webkit-scrollbar {
39 | width: 3px;
40 | }
41 | div::-webkit-scrollbar-thumb {
42 | border-radius: 10px;
43 | box-shadow: inset 0 0 4px #00000033;
44 | background: rgba(0, 0, 0, 0.2);
45 | }
46 | div::-webkit-scrollbar-track {
47 | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
48 | border-radius: 10px;
49 | background: rgba(0, 0, 0, 0.1);
50 | }
51 |
--------------------------------------------------------------------------------
/src/components/Search/Search.css:
--------------------------------------------------------------------------------
1 | /* 搜索框 */
2 | .search {
3 | width: 40vw;
4 | height: 6vh;
5 | position: absolute;
6 | left: 50%;
7 | transform: translateX(-50%);
8 | /* border: 1px solid red; */
9 | z-index: 2;
10 | /* margin-top: 3vh; */
11 | min-width: 600px;
12 | min-height: 50px;
13 | background-color: #ffffffcc;
14 | border-radius: 50px;
15 | transition: 0.3s ease-in-out;
16 | }
17 | .engine {
18 | display: inline-flex;
19 | align-items: center;
20 | justify-content: space-evenly;
21 | padding: 0;
22 | outline: none;
23 | border: none;
24 | width: 4vw;
25 | min-width: 80px;
26 | height: 6vh;
27 | min-height: 50px;
28 | cursor: pointer;
29 | line-height: 6vh;
30 | border-radius: 50px 0 0 50px;
31 | background-color: #ffffffcc;
32 | /* transition:0.5s; */
33 | }
34 |
35 | .engine:hover {
36 | background-color: #00000026;
37 | }
38 | .engine:focus + .engineList {
39 | display: flex;
40 | }
41 | .engineList {
42 | display: none;
43 | position: absolute;
44 | z-index: 3;
45 | margin-top: 6px;
46 | padding: 5px;
47 | /* width:126px; */
48 | min-width: 96px;
49 | border-radius: 10px;
50 | background-color: #ffffffeb;
51 | box-shadow: 4px 6px 8px rgba(0, 0, 0, 0.32),
52 | inset 0px 4px 4px rgba(255, 255, 255, 0.2);
53 | transition: 0.2s;
54 | }
55 | .engineList li {
56 | display: flex;
57 | justify-content: space-around;
58 | align-items: center;
59 | height: 6vh;
60 | min-height: 36px;
61 | width: 100px;
62 | margin: 2px 2px;
63 | list-style: none;
64 | color: rgba(0, 0, 0, 0.6);
65 | line-height: 6vh;
66 | border-radius: 10px;
67 | font-size: 2vh;
68 | font-weight: 500;
69 | cursor: pointer;
70 | }
71 | .engineList li span {
72 | display: block;
73 | color: rgba(0, 0, 0, 0.6);
74 | }
75 | .engineList li:hover {
76 | background-color: #0000001a;
77 | }
78 | .search input {
79 | /* font-family: Microsoft YaHei ; */
80 | color: #0c0c0c;
81 | display: inline-block;
82 | position: absolute;
83 | font-size: 1.2rem;
84 | height: 6vh;
85 | min-height: 50px;
86 | width: 30vw;
87 | outline: none;
88 | border: none;
89 | padding: 0 0 0 10px;
90 | background-color: #ffffff00;
91 | }
92 | .search > span {
93 | display: inline-flex;
94 | position: absolute;
95 | justify-content: center;
96 | align-items: center;
97 | color: #302f2fcc;
98 | border-radius: 50%;
99 | height: 6vh;
100 | min-height: 50px;
101 | width: 6vh;
102 | min-width: 50px;
103 | right: 0;
104 | }
105 | .search > span:hover {
106 | background-color: #00000026;
107 | }
108 | .search input:focus + .presearch-list {
109 | display: block;
110 | }
111 | .presearch-list {
112 | width: 100%;
113 | background: #fffd;
114 | border-radius: 10px;
115 | display: none;
116 | position: absolute;
117 | /* backdrop-filter: blur(20px); */
118 | overflow: hidden;
119 | margin-top: 6px;
120 | transition: 0.3s ease-in-out;
121 | }
122 |
123 | .presearch-list div {
124 | font-size: 20px;
125 | padding: 2px;
126 | padding-left: 10px;
127 | font-weight: 600;
128 | transition: 0.3s ease-out;
129 | cursor: pointer;
130 | display: flex;
131 | align-items: center;
132 | overflow: hidden;
133 | text-overflow: ellipsis;
134 | white-space: nowrap;
135 | }
136 | .presearch-list > div div {
137 | width: 50%;
138 | /* overflow: hidden; */
139 | }
140 | .presearch-list > div:hover {
141 | background-color: #0003;
142 | }
143 | .pre-hover {
144 | background-color: #0003;
145 | }
146 | .pre-div-hover {
147 | margin-left: calc(50% - 20px);
148 | transform: translateX(-50%);
149 | display: inline-block;
150 | text-align: center;
151 | }
152 | .presearch-list div:hover div {
153 | margin-left: calc(50% - 20px);
154 | transform: translateX(-50%);
155 | display: inline-block;
156 | text-align: center;
157 | }
158 | .search-history-delete {
159 | position: absolute;
160 | color: #0008;
161 | font-size: 16px;
162 | right: 1%;
163 | opacity: 0;
164 | transition: 0.2s ease-in-out;
165 | }
166 | .presearch-list div:hover .search-history-delete {
167 | opacity: 1;
168 | }
169 |
--------------------------------------------------------------------------------
/src/components/ServerMonitor/ServerMonitor.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/components/ServerMonitor/ServerMonitor.css
--------------------------------------------------------------------------------
/src/components/ServerMonitor/ServerMonitor.js:
--------------------------------------------------------------------------------
1 | import "./ServerMonitor.css";
2 | import FuncCard from "../FuncCard/FuncCard";
3 | import { memo, useEffect, useState } from "react";
4 | import md5 from "js-md5";
5 |
6 | const ServerMonitor = () => {
7 | const [type, setType] = useState(0);
8 |
9 | const handleChangeType = value => {
10 | setType(value);
11 | };
12 |
13 | const request_time = new Date().getTime();
14 | const api_sk = "2tIiizP1DahyBmypN00hqdkdV9OaooI6";
15 | let request_token = md5(request_time.toString() + md5(api_sk));
16 | let args = {
17 | request_token: request_token,
18 | request_time: request_time,
19 | };
20 |
21 | useEffect(() => {
22 | // fetch("http://121.196.148.27:8899/system?action=GetNetWork",{
23 | // method:'POST',
24 | // body:args,
25 | // credentials:'include'
26 | // }).then((res)=>{
27 | // console.log(res.data)
28 | // })
29 | }, []);
30 |
31 | return (
32 |
41 |
53 | 待完成API接口
54 |
55 |
56 | );
57 | };
58 |
59 | export default memo(ServerMonitor);
60 |
--------------------------------------------------------------------------------
/src/components/SetBackground/SetBackground.css:
--------------------------------------------------------------------------------
1 | .backgroundImg {
2 | display: flex;
3 | background-size: cover;
4 | width: 100%;
5 | height: 180px;
6 | margin-bottom: 25px;
7 | justify-content: center;
8 | align-items: center;
9 | transition: background-image 0.3s ease-in-out;
10 | }
11 | .backgroundImg div {
12 | text-align: center;
13 | width: 100px;
14 | height: 50px;
15 | color: white;
16 | background-color: #00000088;
17 | border-radius: 10px;
18 | cursor: pointer;
19 | line-height: 50px;
20 | transition: 0.3s;
21 | }
22 | .backgroundImg div:hover {
23 | background-color: #000000dd;
24 | }
25 | .setBackground {
26 | user-select: none;
27 | }
28 | .setBackground span {
29 | margin-left: 10px;
30 | }
31 | .setBackground > div:nth-child(4) span {
32 | margin-left: 0px;
33 | }
34 | .backgroundCover,
35 | .backgroundBlur {
36 | width: 70%;
37 | display: inline-block;
38 | }
39 |
40 | .showBackground {
41 | font-size: 0;
42 | overflow-y: scroll;
43 | height: 550px;
44 | width: 748px;
45 | margin-bottom: 10px;
46 | }
47 |
48 | .showBackgroundItem {
49 | display: inline-flex;
50 | justify-content: center;
51 | align-items: center;
52 | position: relative;
53 | border-radius: 10px;
54 | margin-top: 10px;
55 | margin-bottom: 5px;
56 | margin-right: 5px;
57 | margin-left: 5px;
58 | width: 235px;
59 | height: 120px;
60 | }
61 | .showBackgroundItem div {
62 | position: relative;
63 | width: 50px;
64 | height: 50px;
65 | color: white;
66 | font-size: 20px;
67 | border-radius: 50%;
68 | text-align: center;
69 | opacity: 0;
70 | background-color: #000000cc;
71 | line-height: 50px;
72 | transition: 0.3s ease-in;
73 | cursor: pointer;
74 | }
75 | .showBackgroundItem::before {
76 | content: "hello";
77 | width: 235px;
78 | height: 120px;
79 | position: absolute;
80 | top: 0px;
81 | right: 0px;
82 | background-color: #00000000;
83 | border-radius: inherit;
84 | transition: 0.3s ease-in-out;
85 | }
86 | .showBackgroundItem:hover::before {
87 | background-color: #00000088;
88 | }
89 | .showBackgroundItem:hover div {
90 | opacity: 1;
91 | }
92 | .showBackgroundItem div:hover {
93 | background-color: rgba(145, 241, 145, 0.8);
94 | }
95 | .showBackgroundItem div:active {
96 | transform: scale(0.8);
97 | }
98 |
99 | .backTab {
100 | font-size: 18px;
101 | letter-spacing: 2px;
102 | font-weight: 700;
103 | line-height: 30px;
104 | display: inline-block;
105 | height: 30px;
106 | }
107 |
108 | /* 滚动条样式 */
109 | .showBackground::-webkit-scrollbar {
110 | width: 3px;
111 | }
112 | .showBackground::-webkit-scrollbar-thumb {
113 | border-radius: 10px;
114 | box-shadow: inset 0 0 4px #00000033;
115 | background: rgba(0, 0, 0, 0.2);
116 | }
117 | .showBackground::-webkit-scrollbar-track {
118 | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
119 | border-radius: 10px;
120 | background: rgba(0, 0, 0, 0.1);
121 | }
122 |
--------------------------------------------------------------------------------
/src/components/Snippets/Snippets.css:
--------------------------------------------------------------------------------
1 | .snippets {
2 | height: 200px;
3 | box-sizing: border-box;
4 | padding: 16px;
5 | border: none;
6 | border-radius: 10px;
7 | box-shadow: 0 0 7px rgba(0, 0, 0, 0.15);
8 | resize: none;
9 | background-color: #fffa;
10 | font-family: "SimHei";
11 | font-size: 16px;
12 | font-weight: 800;
13 | letter-spacing: 1.5px;
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/Snippets/Snippets.js:
--------------------------------------------------------------------------------
1 | import "./Snippets.css";
2 | import { memo } from "react";
3 | import React from "react";
4 | import { useSelector, useDispatch } from "react-redux";
5 | import { SnippetsOutlined } from "@ant-design/icons";
6 | import "braft-editor/dist/index.css";
7 | import BraftEditor from "braft-editor";
8 | // 富文本表情包扩展
9 | // import 'braft-extensions/dist/emoticon.css'
10 | // import Emoticon, { defaultEmoticons } from 'braft-extensions/dist/emoticon'
11 | // import 'braft-extensions/dist/code-highlighter.css'
12 | // import CodeHighlighter from 'braft-extensions/dist/code-highlighter'
13 |
14 | // BraftEditor.use(CodeHighlighter({
15 | // includeEditors: ['editor-with-code-highlighter'],
16 | // // theme: 'light' // 支持dark和light两种主题,默认为dark
17 | // }))
18 | // BraftEditor.use(CodeHighlighter({
19 | // includeEditors: ['editor-with-code-highlighter'],
20 | // }))
21 |
22 | const Snippets = memo(props => {
23 | const { id } = props;
24 | const dispatch = useDispatch();
25 | const snippets = useSelector(state => state.snippets);
26 | // const [editorState,setEditorState] = useState(BraftEditor.createEditorState(null))
27 |
28 | const deleteSnippet = () => {
29 | let new_snippets = snippets.reduce((pre, cur) => {
30 | if (cur.id !== id) {
31 | pre.push(cur);
32 | }
33 | return pre;
34 | }, []);
35 | dispatch({
36 | type: "CHANGE_SNIPPETS",
37 | snippets: new_snippets,
38 | });
39 | };
40 |
41 | //富文本编辑器
42 | // const handleChange = (editorState) => {
43 | // console.log(editorState)
44 | // setEditorState({ editorState })
45 | // }
46 | //自定义富文本控件
47 | //富选框参数
48 | // const controls = ['undo', 'redo', 'separator',
49 | // 'font-size', 'line-height', 'letter-spacing', 'separator',
50 | // 'text-color', 'blod', 'italic', 'underline', 'strike-through', 'separator',
51 | // 'superscript', 'subscript', 'remove-styles', 'emoji', 'separator', 'text-indent', 'text-align', 'separator',
52 | // 'headings', 'list-ul', 'list-ol', 'blockquote', 'code', 'separator',
53 | // 'link', 'separator', 'hr', 'separator',
54 | // 'clear', 'separator',
55 | // ]
56 |
57 | const controls = [
58 | "bold",
59 | "text-color",
60 | "font-size",
61 | "separator",
62 | "list-ul",
63 | "emoji",
64 | "separator",
65 | "clear",
66 | ];
67 |
68 | return (
69 |
78 | {/*
*/}
80 | {/*
*/}
81 |
94 |
95 | );
96 | });
97 |
98 | const SnippetsInMenu = memo(() => {
99 | const dispatch = useDispatch();
100 | const snippets = useSelector(state => state.snippets);
101 |
102 | const addSnippet = () => {
103 | //TODO:ID改成唯一性的uuid
104 | let new_id = (Math.random() * 1000000).toFixed(0);
105 | let new_snippets = snippets.concat({ id: new_id, content: "" });
106 | dispatch({
107 | type: "CHANGE_SNIPPETS",
108 | snippets: new_snippets,
109 | });
110 | };
111 |
112 | return (
113 |
114 |
115 |
116 | 便利贴
117 |
118 |
119 | );
120 | });
121 |
122 | export { SnippetsInMenu, Snippets };
123 |
--------------------------------------------------------------------------------
/src/components/StockMarket/StockMarket.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/components/StockMarket/StockMarket.css
--------------------------------------------------------------------------------
/src/components/StockMarket/StockMarket.js:
--------------------------------------------------------------------------------
1 | import { memo } from "react";
2 | import FuncCard from "../FuncCard/FuncCard";
3 |
4 | function StockMarket() {
5 | return (
6 |
14 | );
15 | }
16 |
17 | export default memo(StockMarket);
18 |
--------------------------------------------------------------------------------
/src/components/SwiperAera/SwiperAera.css:
--------------------------------------------------------------------------------
1 | .swiperaera {
2 | position: absolute;
3 | /* top: 45vh; */
4 | left: 50%;
5 | transform: translateX(-50%);
6 | width: 85vw;
7 | /* height: 22vw; */
8 | margin: 0 auto;
9 | /* z-index: 999; */
10 | border: 0px solid black;
11 | overflow: visible;
12 | border-radius: 20px;
13 | /* height: 50vh; */
14 | user-select: none;
15 | transition: 0.3s ease-in-out;
16 | }
17 | .fade_in {
18 | animation: fadein 0.5s ease-in-out;
19 | }
20 |
21 | @keyframes fadein {
22 | 0% {
23 | opacity: 0;
24 | }
25 | 100% {
26 | opacity: 1;
27 | }
28 | }
29 |
30 | .swiper-no-swiping .swiper-pagination-bullet {
31 | width: 50px;
32 | height: 25px;
33 | text-align: center;
34 | line-height: 25px;
35 | font-size: 12px;
36 | font-weight: 600;
37 | letter-spacing: 0.1rem;
38 | color: #000;
39 | opacity: 1;
40 | border-radius: 5px;
41 | background: rgba(0, 0, 0, 0.2);
42 | }
43 |
44 | .swiper-no-swiping .swiper-pagination-bullet-active {
45 | color: #fff;
46 | background: rgba(0, 0, 0, 0.5);
47 | }
48 |
--------------------------------------------------------------------------------
/src/components/SwiperAera/SwiperAera.js:
--------------------------------------------------------------------------------
1 | import "./SwiperAera.css";
2 | import { Swiper, SwiperSlide } from "swiper/react";
3 | import "swiper/css";
4 | import "swiper/css/pagination";
5 | import { useSelector } from "react-redux";
6 | import { Pagination, Mousewheel } from "swiper";
7 | import FunctionAera from "../FunctionAera/FunctionAera";
8 | import Apps from "../Apps/Apps";
9 | import { memo } from "react";
10 |
11 | const SwiperAera = () => {
12 | const clear = useSelector(state => state.clear);
13 | // const timePos = useSelector(state => state.timePos);
14 | let display = clear ? "none" : "block";
15 | let top = "25vh";
16 | let slideType = ["链接", "组件"];
17 | const pagination = {
18 | clickable: true,
19 | renderBullet: (index, className) => {
20 | return '' + slideType[index] + "";
21 | },
22 | };
23 |
24 | return (
25 |
29 | {/* 加swiper-no-swipping可以让swiper不能拖动滑动 */}
30 |
console.log("slide change")}
37 | // onSwiper={swiper => console.log(swiper)}
38 | pagination={pagination}
39 | //scrollbar={{ draggable: false }}
40 | mousewheel={true}
41 | modules={[Pagination, Mousewheel]}
42 | >
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | );
52 | };
53 |
54 | export default memo(SwiperAera); //memo防止由父组件引发的不必要重复渲染
55 |
--------------------------------------------------------------------------------
/src/components/Todo/AddItemInput/index.css:
--------------------------------------------------------------------------------
1 | #add-item-input {
2 | padding: 1em;
3 | background-color: aliceblue;
4 | display: flex;
5 | align-items: center;
6 | margin-bottom: 2%;
7 | border-radius: 10px;
8 | position: absolute;
9 | width: 97%;
10 | z-index: 3;
11 | }
12 |
13 | #add-item-input #plus-icon,
14 | #add-item-input input {
15 | display: block;
16 | width: 100%; /* vertical-align: top; */
17 | }
18 |
19 | #add-item-input #plus-icon {
20 | height: 1em;
21 | width: 1em;
22 | margin-right: 1em;
23 | }
24 |
25 | #add-item-input #plus-icon path {
26 | fill: gray;
27 | }
28 |
29 | #add-item-input input {
30 | border: 0px;
31 | color: gray;
32 | font-size: 1em;
33 | font-weight: 400;
34 | height: 1em;
35 | outline: 0px;
36 | padding: 0px;
37 | background-color: #00000000;
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/Todo/AddItemInput/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { PlusOutlined } from "@ant-design/icons";
3 | import "./index.css";
4 | import { nanoid } from "nanoid";
5 |
6 | function AddItemInput({ onSubmit }) {
7 | const [input, setInput] = useState("");
8 |
9 | const handleChange = e => {
10 | setInput(e.target.value);
11 | };
12 |
13 | const handleKeyDown = e => {
14 | if (e.key === "Enter") {
15 | onSubmit({
16 | id: nanoid(),
17 | isCompleted: false,
18 | text: input,
19 | date: new Date().toLocaleDateString(),
20 | });
21 | setInput("");
22 | }
23 | };
24 |
25 | return (
26 |
36 | );
37 | }
38 |
39 | export default AddItemInput;
40 |
--------------------------------------------------------------------------------
/src/components/Todo/EditItemInput.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from "react";
2 | import DatePicker from "react-datepicker";
3 | import "react-datepicker/dist/react-datepicker.css";
4 |
5 | function EditItemInput({ date, edit, onSubmit }) {
6 | const [input, setInput] = useState(edit ? edit.value : "");
7 | const [startDate, setStartDate] = useState(new Date(date));
8 | const textRef = useRef();
9 |
10 | useEffect(() => {
11 | textRef.current.focus();
12 | textRef.current.setSelectionRange(-1, -1);
13 | }, []);
14 |
15 | const editText = e => {
16 | setInput(e.target.value);
17 | };
18 |
19 | const changeDate = date => {
20 | setStartDate(date);
21 | onSubmit({
22 | id: edit.id,
23 | isCompleted: false,
24 | text: input,
25 | date: date.toLocaleDateString(),
26 | });
27 | };
28 |
29 | const handleKeyDown = e => {
30 | if (e.key === "Enter") {
31 | onSubmit({
32 | id: edit.id,
33 | isCompleted: false,
34 | text: input,
35 | date: startDate.toLocaleDateString(),
36 | });
37 | setInput("");
38 | }
39 | };
40 |
41 | return (
42 |
43 |
49 |
50 |
51 | );
52 | }
53 |
54 | export default EditItemInput;
55 |
--------------------------------------------------------------------------------
/src/components/Todo/TodoItems/index.css:
--------------------------------------------------------------------------------
1 | .item {
2 | display: flex;
3 | padding: 0;
4 | border-radius: 10px;
5 | -webkit-transition: all 0.5s, background-color 0s;
6 | transition: all 0.5s, background-color 0s;
7 | }
8 |
9 | .item:hover {
10 | background-color: rgba(126, 247, 152, 0.5);
11 | }
12 |
13 | .item:hover input {
14 | background-color: transparent;
15 | }
16 |
17 | .todo-icon {
18 | height: 1em;
19 | width: 1em;
20 | margin-right: 1em;
21 | margin-left: 0.5em;
22 | margin-top: 1.5em;
23 | cursor: pointer;
24 | }
25 |
26 | .todo-text {
27 | width: 90%;
28 | margin-right: 1em;
29 | margin-top: 0.5em;
30 | }
31 |
32 | .todo-text textarea {
33 | border: none;
34 | font-size: 1em;
35 | font-weight: 400;
36 | line-height: 1em;
37 | outline: none;
38 | padding: 0px;
39 | resize: none;
40 | width: 90%;
41 | background-color: transparent;
42 | }
43 |
44 | p.text {
45 | font-size: 1.3em;
46 | font-weight: 600;
47 | margin: auto;
48 | }
49 |
50 | .todo-text p.date {
51 | font-size: 0.6em;
52 | font-weight: 600;
53 | }
54 |
55 | .uncompleted {
56 | width: 1em;
57 | height: 1em;
58 | fill: currentColor;
59 | }
60 |
61 | .uncompleted:hover,
62 | .edit-icon:hover path {
63 | fill: rgb(68, 0, 255);
64 | }
65 |
66 | .completed:hover path {
67 | fill: ghostwhite;
68 | }
69 |
70 | .edit-icon,
71 | .delete-icon {
72 | opacity: 0;
73 | margin-right: 1em;
74 | margin-top: 0.5em;
75 | }
76 |
77 | .delete-icon:hover path {
78 | fill: red;
79 | }
80 |
81 | .item:hover > .edit-icon,
82 | .item:hover > .delete-icon {
83 | opacity: 1;
84 | }
85 |
86 | .complete p.text {
87 | text-decoration: line-through;
88 | opacity: 0.4;
89 | }
90 |
91 | .complete p.date {
92 | font-weight: 400;
93 | opacity: 0.4;
94 | }
95 |
96 | .complete > .edit-icon {
97 | display: none;
98 | }
99 |
--------------------------------------------------------------------------------
/src/components/Todo/TodoItems/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import EditItemInput from "../EditItemInput";
3 | import {
4 | createFromIconfontCN,
5 | EditOutlined,
6 | DeleteFilled,
7 | CheckCircleTwoTone,
8 | } from "@ant-design/icons";
9 | import "./index.css";
10 |
11 | function TodoItems({ todos, completeTodo, removeTodo, updateTodo }) {
12 | const defaultEditValue = { id: null, value: "" };
13 | const [edit, setEdit] = useState(defaultEditValue);
14 |
15 | const submitUpdate = value => {
16 | updateTodo(edit.id, value);
17 | setEdit(defaultEditValue);
18 | };
19 |
20 | const cancelEdit = e => {
21 | if (e.keyCode === 27) {
22 | setEdit(defaultEditValue);
23 | }
24 | };
25 |
26 | const IconFont = createFromIconfontCN({
27 | scriptUrl: "//at.alicdn.com/t/font_3180970_ek9le05bzhc.js",
28 | });
29 |
30 | return todos.length ? (
31 | todos.map((todo, index) => {
32 | return (
33 |
38 |
completeTodo(e, todo.id)}>
39 | {todo.isCompleted ? (
40 |
44 | ) : (
45 |
46 | )}
47 |
48 |
setEdit({ id: todo.id, value: todo.text })}
52 | >
53 | {todo.id === edit.id && !todo.isCompleted ? (
54 |
59 | ) : (
60 | <>
61 |
{todo.text}
62 |
{todo.date}
63 | >
64 | )}
65 |
66 |
67 | setEdit({ id: todo.id, value: todo.text })}
69 | />
70 |
71 |
72 | removeTodo(todo.id)} />
73 |
74 |
75 | );
76 | })
77 | ) : (
78 |
91 | 暂无内容
92 |
93 | );
94 | }
95 |
96 | export default TodoItems;
97 |
--------------------------------------------------------------------------------
/src/components/Todo/TodoModal.css:
--------------------------------------------------------------------------------
1 | .todo-modal span::-webkit-scrollbar {
2 | width: 0px;
3 | }
4 |
--------------------------------------------------------------------------------
/src/components/Todo/TodoModal.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import useLocalStorage from "../../hooks/useLocalStorage";
3 | import { getMeta } from "./Todo.js";
4 | import AddItemInput from "./AddItemInput";
5 | import TodoItems from "./TodoItems";
6 | import "./TodoModal.css";
7 |
8 | function TodoModal({ todos, setTodos, completeTodo }) {
9 | const [, setPersistedTodoList] = useLocalStorage("todoList", []);
10 | const addTodo = todo => {
11 | if (!todo.text || /^\s*$/.test(todo.text)) {
12 | return;
13 | }
14 | const newTodos = [...todos, todo];
15 | setTodos(newTodos);
16 | setPersistedTodoList(newTodos);
17 | };
18 |
19 | const removeTodo = id => {
20 | const aftTodos = [...todos].filter(todo => todo.id !== id);
21 | setTodos(aftTodos);
22 | setPersistedTodoList(aftTodos);
23 | };
24 |
25 | const updateTodo = (id, newValue) => {
26 | if (!newValue.text || /^\s*$/.test(newValue.text)) {
27 | return;
28 | }
29 | let updateTodos = todos.map(todo => {
30 | if (todo.id === id) {
31 | todo = newValue;
32 | }
33 | return todo;
34 | });
35 | setTodos(updateTodos);
36 | setPersistedTodoList(updateTodos);
37 | };
38 |
39 | const getItemsCountText = todos => {
40 | const meta = getMeta(todos);
41 | let itemCountText = "";
42 | if (meta.completed.length === 0) {
43 | itemCountText = "No completed items";
44 | } else {
45 | const pluralText = meta.completed.length === 1 ? "item" : "items";
46 | itemCountText = `${meta.completed.length} completed ${pluralText}`;
47 | }
48 | return itemCountText;
49 | };
50 |
51 | const itemCountText = getItemsCountText(todos);
52 |
53 | return (
54 |
61 |
62 |
73 |
82 |
88 |
89 | {/*
90 | */}
91 |
92 |
98 |
99 |
100 |
101 | );
102 | }
103 |
104 | export default TodoModal;
105 |
--------------------------------------------------------------------------------
/src/components/TomatoClock/TomatoClock.css:
--------------------------------------------------------------------------------
1 | .tomato-circle {
2 | height: 100px;
3 | width: 100px;
4 | position: relative;
5 | margin: 10px auto;
6 | border-radius: 50%;
7 | background-color: aqua;
8 | }
9 | .tomato-word {
10 | width: 86px;
11 | height: 86px;
12 | border-radius: 50%;
13 | line-height: 86px;
14 | text-align: center;
15 | color: aquamarine;
16 | font-size: 20px;
17 | font-weight: 600;
18 | background-color: #fff;
19 | position: absolute;
20 | top: 7px;
21 | left: 7px;
22 | }
23 | #rest-circle {
24 | margin-left: 2%;
25 | }
26 |
27 | .tomato_icon:hover {
28 | color: aqua;
29 | transition: 0.3s ease-in-out;
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/ToolKit/ToolKit.css:
--------------------------------------------------------------------------------
1 | .toolkit {
2 | border-radius: 10px;
3 | width: 96%;
4 | margin: 1.5% auto;
5 | height: 120px;
6 | }
7 | .toolkit-box {
8 | display: grid;
9 | height: 100%;
10 | grid-template-columns: repeat(6, calc(100% / 6));
11 | grid-template-rows: repeat(2, 50%);
12 | }
13 | .toolkit-box a {
14 | display: flex;
15 | flex-direction: column;
16 | align-items: center;
17 | justify-content: center;
18 | margin: 5px;
19 | }
20 | .toolkit-box img,
21 | .toolkit-box div {
22 | background: #fff5;
23 | border-radius: 10px;
24 | }
25 | .toolkit-box img:hover,
26 | .toolkit-box div:hover {
27 | background: #fffd;
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/ToolKit/ToolKit.js:
--------------------------------------------------------------------------------
1 | import "./ToolKit.css";
2 | import FuncCard from "../FuncCard/FuncCard";
3 | import { memo, useState } from "react";
4 | import { GlobalOutlined, HddOutlined } from "@ant-design/icons";
5 | import { Tooltip } from "antd";
6 |
7 | const wait = (
8 |
20 | 寻找图标中
21 |
22 | );
23 |
24 | // const colors = [
25 | // 'pink',
26 | // 'red',
27 | // 'yellow',
28 | // 'orange',
29 | // 'cyan',
30 | // 'green',
31 | // 'blue',
32 | // 'purple',
33 | // 'geekblue',
34 | // 'magenta',
35 | // 'volcano',
36 | // 'gold',
37 | // 'lime',
38 | // ];
39 |
40 | const frontend_toolkit_list = [
41 | {
42 | name: "CSS Shadow",
43 | href: "https://box-shadow.dev/",
44 | icon: "https://box-shadow.dev/favicon.svg",
45 | },
46 | {
47 | name: "Get Man",
48 | href: "https://getman.cn/",
49 | icon: "https://getman.cn/img/icon.png",
50 | },
51 | {
52 | name: "Cool Background",
53 | href: "http://coolbackgrounds.io/",
54 | icon: "http://coolbackgrounds.io/images/favicon-fe5a0ff5.png",
55 | },
56 | {
57 | name: "零代码工具箱",
58 | href: "https://lingdaima.com/",
59 | icon: ,
60 | },
61 | {
62 | name: "Can I Use",
63 | href: "https://caniuse.com/",
64 | icon: "https://caniuse.com/img/favicon-128.png",
65 | },
66 | { name: "随机占位图", href: "https://placem.at/", icon: },
67 | {
68 | name: "图标库",
69 | href: "https://thenounproject.com/",
70 | icon: "https://static.production.thenounproject.com/img/favicons/favicon-32x32.015f779a87e7.png",
71 | },
72 | ];
73 |
74 | function ToolkitBox(props) {
75 | const list = props.list;
76 |
77 | return (
78 |
109 | );
110 | }
111 |
112 | const ToolKit = () => {
113 | const [type, setType] = useState(0);
114 |
115 | const handleChangeType = value => {
116 | setType(value);
117 | };
118 |
119 | return (
120 |
129 |
130 |
131 |
132 |
133 |
{wait}
134 |
{wait}
135 |
136 |
137 | );
138 | };
139 |
140 | export default memo(ToolKit);
141 |
--------------------------------------------------------------------------------
/src/components/TopNav/TopNav.css:
--------------------------------------------------------------------------------
1 | /* 顶部导航 */
2 | .checkmode {
3 | visibility: hidden;
4 | }
5 | .checkmode input[type="checkbox"] {
6 | position: relative;
7 | width: 90px;
8 | height: 32px;
9 | left: 1vw;
10 | top: 2vh;
11 | appearance: none;
12 | /* appearence 设置div的显示形状 */
13 | background-color: rgba(255, 255, 255, 0.5);
14 | cursor: pointer;
15 | border-radius: 20px;
16 | transition: 0.5s;
17 | }
18 |
19 | .checkmode input[type="checkbox"]:checked {
20 | background-color: rgba(0, 0, 0, 0.5);
21 | }
22 | .checkmode input[type="checkbox"]::before {
23 | content: "Light";
24 | font-size: 12px;
25 | font-weight: 600;
26 | position: absolute;
27 | top: 0;
28 | left: 0;
29 | width: 60px;
30 | color: #000000cc;
31 | height: 32px;
32 | background: #ffffff;
33 | box-shadow: inset -2px -4px 4px rgba(0, 0, 0, 0.16);
34 | border-radius: 30px;
35 | text-align: center;
36 | line-height: 32px;
37 | transition: 0.5s;
38 | }
39 | .checkmode input[type="checkbox"]:checked:before {
40 | left: 30px;
41 | content: "Dark";
42 | background-color: #000000;
43 | color: #ffffffcc;
44 | box-shadow: inset 2px 4px 8px rgba(255, 255, 255, 0.4);
45 | }
46 |
47 | .avatar {
48 | background-color: #ffffff;
49 | height: 32px;
50 | width: 32px;
51 | border-radius: 16px;
52 | text-align: center;
53 | line-height: 32px;
54 | overflow: hidden;
55 | position: absolute;
56 | top: 2vh;
57 | left: 30px;
58 | cursor: pointer;
59 | }
60 |
61 | .setting {
62 | position: absolute;
63 | right: 30px;
64 | top: 2vh;
65 | font-weight: 600;
66 | color: #ffffff;
67 | font-size: 32px;
68 | line-height: 32px;
69 | cursor: pointer;
70 | }
71 |
72 | /* 设置面板 */
73 | .setting-collapse {
74 | background: rgba(0, 0, 0, 0);
75 | }
76 | .setting-collapse .setting-panel {
77 | font-size: 15px;
78 | font-weight: 500;
79 | margin-bottom: 10px;
80 | overflow: hidden;
81 | background: rgba(255, 255, 255, 0.5);
82 | box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.32),
83 | inset 0px 4px 4px rgba(255, 255, 255, 0.2);
84 | border: 0px;
85 | border-radius: 10px;
86 | }
87 | .panel-title {
88 | font-size: 18px;
89 | letter-spacing: 2px;
90 | font-weight: 600;
91 | }
92 |
93 | .setting-panel .ant-row {
94 | margin-bottom: 8px;
95 | margin-top: 24px;
96 | }
97 |
98 | /* .about-title {
99 | font-size: 18px;
100 | font-weight: 600;
101 | letter-spacing: 2px;
102 | user-select: none;
103 | } */
104 | .about-member {
105 | display: flex;
106 | justify-content: space-between;
107 | user-select: none;
108 | margin-top: 5px;
109 | }
110 | .about-member div {
111 | display: inline-block;
112 | font-size: 16px;
113 | font-weight: 700;
114 | color: #00000099;
115 | }
116 | .codeAd {
117 | font-size: 18px;
118 | font-weight: 600;
119 | margin-top: 5px;
120 | width: 100%;
121 | display: flex;
122 | justify-content: center;
123 | flex-direction: column;
124 | align-items: center;
125 | user-select: none;
126 | }
127 | .codeAd a {
128 | color: #000000;
129 | font-size: 30px;
130 | }
131 |
132 | .loginTitle {
133 | font-size: 18px;
134 | font-weight: 700;
135 | letter-spacing: 2px;
136 | margin-left: 23px;
137 | }
138 | .dot {
139 | position: absolute;
140 | top: 23px;
141 | width: 10px;
142 | height: 10px;
143 | border-radius: 50%;
144 | background: #0000ff;
145 | }
146 | .userlog {
147 | text-align: center;
148 | line-height: 60px;
149 | font-size: 30px;
150 | color: white;
151 | margin: 10px auto 0 auto;
152 | width: 60px;
153 | height: 60px;
154 | border-radius: 50%;
155 | background-color: #00000033;
156 | }
157 | .userlog + p {
158 | text-align: center;
159 | margin-top: 10px;
160 | letter-spacing: 2px;
161 | font-size: 16px;
162 | font-weight: 700;
163 | }
164 | .set_function > div {
165 | display: flex;
166 | justify-content: space-between;
167 | /* margin-top:5px; */
168 | height: 40px;
169 | align-items: center;
170 | }
171 |
172 | /* 滚动条样式 */
173 | .ant-drawer-body::-webkit-scrollbar {
174 | width: 0px;
175 | }
176 | .ant-drawer-body::-webkit-scrollbar-thumb {
177 | border-radius: 10px;
178 | box-shadow: inset 0 0 4px #00000033;
179 | background: rgba(0, 0, 0, 0.2);
180 | }
181 | .ant-drawer-body::-webkit-scrollbar-track {
182 | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
183 | border-radius: 10px;
184 | background: rgba(0, 0, 0, 0.1);
185 | }
186 |
--------------------------------------------------------------------------------
/src/components/TopNav/TopNav.js:
--------------------------------------------------------------------------------
1 | import "./TopNav.css";
2 | import "../../font/iconfont.css";
3 |
4 | import Account from "../Account/Account";
5 | import React, { useState, memo } from "react";
6 | import { Avatar, Modal } from "antd";
7 | import { UserOutlined } from "@ant-design/icons";
8 | // import { useSelector } from "react-redux";
9 | import Setting from "../Setting/Setting";
10 | // import SetFunctionArea from "../FunctionAera/SetFunctionAera/SetFunctionArea";
11 |
12 | // function CheckMode(){ //深浅色模式切换
13 | // return (
14 | //
15 | // )
16 | // }
17 |
18 | // function CheckMode() {
19 | // //深浅色模式切换
20 | // return (
21 | //
24 | // );
25 | // }
26 |
27 | function User() {
28 | const [isModalVisible, setIsModalVisible] = useState(false);
29 |
30 | const showModal = () => {
31 | setIsModalVisible(true);
32 | };
33 |
34 | const handleCancel = () => {
35 | setIsModalVisible(false);
36 | };
37 |
38 | return (
39 | <>
40 | }
44 | src='https://xsgames.co/randomusers/avatar.php?g=pixel&key=1'
45 | // 随机头像另一个api: https://api.multiavatar.com/Starcrasher.png
46 | />
47 |
52 |
53 | 登录
54 | >
55 | }
56 | visible={isModalVisible}
57 | width={"330px"}
58 | height={"50vh"}
59 | onCancel={handleCancel}
60 | >
61 | {/*
62 | 游客模式
*/}
63 |
64 |
65 | >
66 | );
67 | }
68 |
69 | const TopNav = () => {
70 | //顶部导航
71 |
72 | // const clear = useSelector(state => state.clear);
73 | // let opacity = clear ? 0 : 1;
74 | return (
75 |
76 | {/* */}
77 |
78 |
79 |
80 | );
81 | };
82 |
83 | export default memo(TopNav); //memo 防止子组件重复渲染
84 |
--------------------------------------------------------------------------------
/src/components/Weather/Weather.js:
--------------------------------------------------------------------------------
1 | import React, { memo } from "react";
2 | import FuncCard from "../FuncCard/FuncCard";
3 | import useScript from "../../hooks/useScript";
4 | import "./plugin.js";
5 | import "./style.css";
6 |
7 | const url1 =
8 | "https://widget.qweather.net/standard/static/js/he-standard-common.js?v=2.0";
9 | // const url2 = "https://widget-page.qweather.net/h5/index.html?md=0123456&bg=3&lc=auto&key=45b6b9fb03ef47f681c8c6f4c0e8f934&v=_1644894516681"
10 |
11 | const Weather = () => {
12 | // const [isModalVisible, setIsModalVisible] = useState(false);
13 | // const showModal = () => {
14 | // setIsModalVisible(true);
15 | // }
16 | // const handleOK = () => {
17 | // setIsModalVisible(false);
18 | // }
19 | // const handleCancel = () => {
20 | // setIsModalVisible(false);
21 | // }
22 | useScript(url1);
23 | return (
24 |
25 |
26 |
27 | {/*
28 | } size='small'/>
29 |
*/}
30 |
31 | {/*
38 |
39 |
42 |
43 | */}
44 |
45 | );
46 | };
47 | export default memo(Weather);
48 |
--------------------------------------------------------------------------------
/src/components/Weather/plugin.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line
2 | WIDGET = {
3 | CONFIG: {
4 | layout: "1",
5 | width: "325",
6 | height: "145",
7 | background: "5", //2 白色 3 浅色 4 深色 5 透明
8 | dataColor: "000000",
9 | language: "zh",
10 | borderRadius: "20",
11 | key: "5a6ac07be8ef4b53b7e0b4f1d0b3c1ad",
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/src/components/Weather/style.css:
--------------------------------------------------------------------------------
1 | @import "~antd/dist/antd.css";
2 |
3 | .Weather .ant-modal-body {
4 | padding: 0 !important;
5 | font-size: 0 !important;
6 | line-height: 1 !important;
7 | }
8 | .Weather .ant-modal-content {
9 | position: relative;
10 | background-color: #00000000 !important;
11 | border: 0;
12 | border-radius: 4px;
13 | background-clip: padding-box;
14 | box-shadow: 0 0 0 rgba(0, 0, 0, 0) !important;
15 | }
16 |
17 | .Card {
18 | /* position: absolute; */
19 | /* width: 18vw;
20 | height: 8.5vw; */
21 | width: 352px;
22 | height: 165px;
23 | /* left: 1136px;
24 | top: 20px; */
25 | /* left:392px;
26 | top:20px; */
27 | display: inline-block;
28 | background: #ffffff;
29 | border: 0px solid #ffffff;
30 | box-sizing: border-box;
31 | border-radius: 20px;
32 | transition: 0.1s ease-in;
33 | }
34 | .Card:active {
35 | transform: scale(0.95);
36 | }
37 |
38 | .pluginTitle {
39 | position: relative;
40 | left: 0;
41 | }
42 | .pluginFooter {
43 | position: relative;
44 | bottom: 0.2em;
45 | margin-right: 0em;
46 | }
47 | .content {
48 | position: inherit;
49 | overflow: hidden;
50 | width: 18vw;
51 | }
52 | /*- scrollbar -*/
53 | /* .content
54 | .-webkit-scrollbar {
55 | width: 5px;
56 | height: 5px;
57 | }
58 | .content
59 | .-webkit-scrollbar-thumb{
60 | background-color: #999;
61 | -webkit-border-radius: 5px;
62 | border-radius: 5px;
63 | }
64 | .content
65 | .-webkit-scrollbar-thumb:vertical:hover{
66 | background-color: #666;
67 | }
68 | .content
69 | .-webkit-scrollbar-thumb:vertical:active{
70 | background-color: #333;
71 | }
72 | .content
73 | .-webkit-scrollbar-button{
74 | display: none;
75 | }
76 | .content
77 | ::-webkit-scrollbar-track{
78 | background-color: #f1f1f1;
79 | } */
80 |
--------------------------------------------------------------------------------
/src/components/WoodenFish/WoodenFish.css:
--------------------------------------------------------------------------------
1 | .woodenfish:active img {
2 | animation: run 0.3s ease-in-out;
3 | }
4 | @keyframes run {
5 | 0% {
6 | transform: scale(1);
7 | }
8 | 50% {
9 | transform: scale(1.1);
10 | }
11 | 100% {
12 | transform: scale(1);
13 | }
14 | }
15 | .woodenfish_tag {
16 | position: absolute;
17 | top: 35%;
18 | margin-left: 50%;
19 | transform: translateX(-50%);
20 | font-weight: 800;
21 | font-family: "KaiTi";
22 | color: #fff;
23 | opacity: 0;
24 | }
25 |
26 | .woodenfish:active .woodenfish_tag {
27 | animation: yan 0.3s ease-out;
28 | }
29 |
30 | @keyframes yan {
31 | 0% {
32 | opacity: 1;
33 | }
34 | 100% {
35 | /* color: black; */
36 | transform: translate(-50%, -20px);
37 | opacity: 0;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/WoodenFish/WoodenFish.js:
--------------------------------------------------------------------------------
1 | import "./WoodenFish.css";
2 | import FuncCard from "../FuncCard/FuncCard";
3 | import { memo, useState } from "react";
4 | import woodenfish from "../../asset/woodenfish.png";
5 | import woodenfish_audio from "../../asset/woodenfish.mp3";
6 |
7 | function WoodenFish() {
8 | const [count, setCount] = useState(0);
9 | let audio = new Audio(woodenfish_audio);
10 |
11 | const addCount = e => {
12 | e.stopPropagation();
13 | // console.log(count);
14 | audio.play();
15 | setCount(count => count + 1);
16 | };
17 | return (
18 |
19 |
27 |
28 |

33 |
功德 + 1
34 |
43 | {"今日功德 " + count}
44 |
45 |
46 |
47 |
48 | );
49 | }
50 |
51 | export default memo(WoodenFish);
52 |
--------------------------------------------------------------------------------
/src/config/index.js:
--------------------------------------------------------------------------------
1 | const defaultSetting = {
2 | imgSite: "https://minio.wisdompanda.com/",
3 | site: "https://newtab.wisdompanda.com/api",
4 | // local test
5 | // site: "http://127.0.0.1:8000",
6 | // temp site
7 | // site: "http://101.43.98.53:8000",
8 | bingBg: "https://api.oneneko.com/v1/bing_today",
9 | randomBg1: "https://api.yimian.xyz/img?type=wallpaper",
10 | randomBg2: "https://api.likepoems.com/img/bing",
11 | };
12 |
13 | export default defaultSetting;
14 |
15 | //两个随机壁纸api
16 | // let random1 = "url(https://api.ixiaowai.cn/gqapi/gqapi.php)";
17 | // "url(https://api.btstu.cn/sjbz/api.php?lx=fengjing&format=images)";
18 | // 随机bing壁纸
19 | //TODO:unsplash API
20 | // let random2 = "url(https://source.unsplash.com/random)";
21 | // let random2 = "url(https://bing.img.run/rand_uhd.php)";
22 | // let random2 = "url(https://tu.ltyuanfang.cn/api/fengjing.php)";//暂时停止服务
23 | // let bingBackground = "url(https://bing.img.run/uhd.php)";
24 | //随机壁纸接口
25 | // let randomBackground = 'url(https://api.ixiaowai.cn/gqapi/gqapi.php)'
26 | // let randomBackground = "url(https://api.likepoems.com/img/bing)";
27 |
--------------------------------------------------------------------------------
/src/font/DS-Digital Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/font/DS-Digital Bold.ttf
--------------------------------------------------------------------------------
/src/font/UnidreamLED.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/font/UnidreamLED.eot
--------------------------------------------------------------------------------
/src/font/UnidreamLED.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/font/UnidreamLED.woff
--------------------------------------------------------------------------------
/src/font/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "iconfont"; /* Project id 3208106 */
3 | src: url("//at.alicdn.com/t/font_3208106_1ue2ah07vji.woff2?t=1645966374377")
4 | format("woff2"),
5 | url("//at.alicdn.com/t/font_3208106_1ue2ah07vji.woff?t=1645966374377")
6 | format("woff"),
7 | url("//at.alicdn.com/t/font_3208106_1ue2ah07vji.ttf?t=1645966374377")
8 | format("truetype");
9 | }
10 |
11 | .iconfont {
12 | font-family: "iconfont" !important;
13 | font-size: 35px;
14 | font-style: normal;
15 | -webkit-font-smoothing: antialiased;
16 | -moz-osx-font-smoothing: grayscale;
17 | }
18 |
19 | .icon-douyin1:before {
20 | content: "\e68d";
21 | }
22 |
23 | .icon-sousuo:before {
24 | content: "\e603";
25 | }
26 |
27 | .icon-douyin:before {
28 | content: "\e607";
29 | }
30 |
31 | .icon-downArrow:before {
32 | content: "\e60a";
33 | }
34 |
35 | .icon-bilibili-copy-copy:before {
36 | content: "\e600";
37 | }
38 |
39 | .icon-juejin-logo:before {
40 | content: "\e66b";
41 | }
42 |
43 | .icon-shezhi:before {
44 | content: "\e676";
45 | }
46 |
47 | .icon-biying:before {
48 | content: "\e66e";
49 | }
50 |
51 | .icon-weibo:before {
52 | content: "\e666";
53 | }
54 |
55 | .icon-google:before {
56 | content: "\ea0c";
57 | }
58 |
59 | .icon-baidu:before {
60 | content: "\e612";
61 | }
62 |
63 | .icon-zhihu:before {
64 | content: "\e7f8";
65 | }
66 |
67 | .icon-github:before {
68 | content: "\e673";
69 | }
70 |
--------------------------------------------------------------------------------
/src/font/iconfont.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "",
3 | "name": "",
4 | "font_family": "iconfont",
5 | "css_prefix_text": "icon-",
6 | "description": "",
7 | "glyphs": [
8 | {
9 | "icon_id": "1657346",
10 | "name": "搜狗",
11 | "font_class": "sougou",
12 | "unicode": "e647",
13 | "unicode_decimal": 58951
14 | },
15 | {
16 | "icon_id": "4247300",
17 | "name": "百度",
18 | "font_class": "baidu",
19 | "unicode": "e523",
20 | "unicode_decimal": 58659
21 | },
22 | {
23 | "icon_id": "7450641",
24 | "name": "搜索",
25 | "font_class": "sousuo",
26 | "unicode": "e665",
27 | "unicode_decimal": 58981
28 | },
29 | {
30 | "icon_id": "9512711",
31 | "name": "微博",
32 | "font_class": "weibo-fill",
33 | "unicode": "e645",
34 | "unicode_decimal": 58949
35 | },
36 | {
37 | "icon_id": "9758626",
38 | "name": "down arrow",
39 | "font_class": "downarrow",
40 | "unicode": "e610",
41 | "unicode_decimal": 58896
42 | },
43 | {
44 | "icon_id": "12662790",
45 | "name": "设置",
46 | "font_class": "shezhi",
47 | "unicode": "e676",
48 | "unicode_decimal": 58998
49 | },
50 | {
51 | "icon_id": "17137174",
52 | "name": "谷歌",
53 | "font_class": "guge",
54 | "unicode": "e62c",
55 | "unicode_decimal": 58924
56 | },
57 | {
58 | "icon_id": "17552875",
59 | "name": "必应",
60 | "font_class": "biying",
61 | "unicode": "e50c",
62 | "unicode_decimal": 58636
63 | },
64 | {
65 | "icon_id": "21102722",
66 | "name": "抖音",
67 | "font_class": "douyin",
68 | "unicode": "e68b",
69 | "unicode_decimal": 59019
70 | },
71 | {
72 | "icon_id": "22894714",
73 | "name": "github",
74 | "font_class": "github",
75 | "unicode": "e673",
76 | "unicode_decimal": 58995
77 | }
78 | ]
79 | }
80 |
--------------------------------------------------------------------------------
/src/font/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wisdompandamaster/NewTab/32294c506fc87eb0f0048f269d218e28b1659b8d/src/font/iconfont.ttf
--------------------------------------------------------------------------------
/src/hooks/useLocalStorage.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | // Hook
3 | export default function useLocalStorage(key, initialValue) {
4 | // State to store our value
5 | // Pass initial state function to useState so logic is only executed once
6 | const [storedValue, setStoredValue] = useState(() => {
7 | try {
8 | // Get from local storage by key
9 | const item = window.localStorage.getItem(key);
10 | // Parse stored json or if none return initialValue
11 | return item ? JSON.parse(item) : initialValue;
12 | } catch (error) {
13 | // If error also return initialValue
14 | console.log(error);
15 | return initialValue;
16 | }
17 | });
18 |
19 | // Return a wrapped version of useState's setter function that ...
20 | // ... persists the new value to localStorage.
21 | const setValue = value => {
22 | try {
23 | // Allow value to be a function so we have same API as useState
24 | const valueToStore =
25 | value instanceof Function ? value(storedValue) : value;
26 | // Save state
27 | setStoredValue(valueToStore);
28 | // Save to local storage
29 | window.localStorage.setItem(key, JSON.stringify(valueToStore));
30 | } catch (error) {
31 | // A more advanced implementation would handle the error case
32 | console.log(error);
33 | }
34 | };
35 |
36 | return [storedValue, setValue];
37 | }
38 |
--------------------------------------------------------------------------------
/src/hooks/useScript.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 |
3 | const useScript = (url1 /*, url2*/) => {
4 | useEffect(() => {
5 | const script1 = document.createElement("script");
6 | script1.src = url1;
7 | script1.async = false;
8 | document.body.appendChild(script1);
9 |
10 | // const script2 = document.createElement('script');
11 | // script2.src = url2;
12 | // script2.async = false;
13 | // document.body.appendChild(script2);
14 |
15 | return () => {
16 | // document.body.removeChild(script2);
17 | document.removeChild(script1);
18 | };
19 | }, [url1 /*, url2*/]);
20 | };
21 |
22 | export default useScript;
23 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
15 | /* 笔记的部分CSS */
16 | .note-card {
17 | /* position: absolute; */
18 | /* width: 18vw;
19 | height: 8.5vw;
20 | left: 392px;
21 | top: 205px; */
22 | width: 352px;
23 | height: 165px;
24 | background: #ffffff;
25 | border: 0px solid #e5e5e5;
26 | box-sizing: border-box;
27 | border-radius: 20px;
28 | transition: 0.1s ease-in;
29 | }
30 |
31 | .note-card:active {
32 | transform: scale(0.95);
33 | }
34 |
35 | .note-header {
36 | height: 20%;
37 | border-radius: 20px;
38 | }
39 | .note-icon {
40 | position: relative;
41 | width: 6px;
42 | height: 14px;
43 | left: 18px;
44 | top: 21px;
45 |
46 | background: linear-gradient(180deg, #6cb9ff 0%, #3355ff 100%);
47 | box-shadow: 0px 3px 6px rgba(55, 135, 255, 0.8);
48 | border-radius: 20px;
49 | }
50 | .note-title {
51 | position: relative;
52 | left: 36px;
53 | top: 2px;
54 | font-style: normal;
55 | font-weight: bold;
56 | font-size: 18px;
57 | line-height: 22px;
58 | letter-spacing: 0.2rem;
59 | color: rgba(0, 0, 0, 0.85);
60 | cursor: pointer;
61 | }
62 | .note-body {
63 | display: flex;
64 | flex-direction: column;
65 | font-family: PingFang SC;
66 | font-style: normal;
67 | font-weight: 400;
68 | font-size: 14px;
69 | line-height: 17px;
70 | /* identical to box height */
71 | color: #000000;
72 |
73 | margin: 5px 19px 5px 18px;
74 | }
75 | .note-content {
76 | height: 30px;
77 | line-height: 17px;
78 | padding: 6px;
79 | border-bottom: 1px solid rgba(0, 0, 0, 0.1);
80 | overflow: hidden;
81 | white-space: nowrap;
82 | text-overflow: ellipsis;
83 | }
84 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./App";
5 | import reportWebVitals from "./reportWebVitals";
6 | import { Provider } from "react-redux";
7 | import configureStore from "./store/index";
8 | // import { DndProvider } from 'react-dnd'; //react-dnd拖拽方案
9 | // import { HTML5Backend } from 'react-dnd-html5-backend';
10 |
11 | const store = configureStore();
12 |
13 | ReactDOM.render(
14 |
15 |
16 | ,
17 | document.getElementById("root")
18 | );
19 |
20 | // If you want to start measuring performance in your app, pass a function
21 | // to log results (for example: reportWebVitals(console.log))
22 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
23 | reportWebVitals();
24 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/service/getCookie.js:
--------------------------------------------------------------------------------
1 | export default function getCookie(name) {
2 | let arr;
3 | const reg = new RegExp(`(^| )${name}=([^;]*)(;|$)`);
4 | if ((arr = document.cookie.match(reg))) {
5 | return unescape(arr[2]);
6 | } else {
7 | return "";
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/setupProxy.js:
--------------------------------------------------------------------------------
1 | const { createProxyMiddleware } = require("http-proxy-middleware");
2 |
3 | module.exports = function (app) {
4 | app.use(
5 | createProxyMiddleware("/api", {
6 | //遇见/api前缀的就会触发这个转发
7 | target: "https://newtab.wisdompanda.com/api", //要转发的目标地址
8 | changeOrigin: true, //控制服务器中收到的请求头中host字段的值
9 | pathRewrite: { "^/api": "" }, //重写请求路径
10 | }),
11 | createProxyMiddleware("/pic", {
12 | target: "https://minio.wisdompanda.com",
13 | changeOrigin: true,
14 | pathRewrite: { "^/pic": "" },
15 | })
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import "@testing-library/jest-dom";
6 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import { createStore } from "redux";
2 | import reducer from "./reducer";
3 |
4 | const configureStore = () => createStore(reducer);
5 |
6 | export default configureStore;
7 |
--------------------------------------------------------------------------------