aboutsummaryrefslogtreecommitdiff
path: root/FrontEnd
diff options
context:
space:
mode:
Diffstat (limited to 'FrontEnd')
-rw-r--r--FrontEnd/.babelrc27
-rw-r--r--FrontEnd/.eslintignore2
-rw-r--r--FrontEnd/.eslintrc.js2
-rw-r--r--FrontEnd/index.html (renamed from FrontEnd/src/app/index.ejs)8
-rw-r--r--FrontEnd/package.json49
-rw-r--r--FrontEnd/postcss.config.js10
-rw-r--r--FrontEnd/src/App.tsx (renamed from FrontEnd/src/app/App.tsx)0
-rw-r--r--FrontEnd/src/app/index.sass120
-rw-r--r--FrontEnd/src/app/tsconfig.json13
-rw-r--r--FrontEnd/src/app/typings.d.ts24
-rw-r--r--FrontEnd/src/app/views/about/about.sass4
-rw-r--r--FrontEnd/src/app/views/admin/admin.sass22
-rw-r--r--FrontEnd/src/app/views/center/center.sass36
-rw-r--r--FrontEnd/src/app/views/common/FlatButton.tsx36
-rw-r--r--FrontEnd/src/app/views/common/common.sass191
-rw-r--r--FrontEnd/src/app/views/home/home.sass29
-rw-r--r--FrontEnd/src/app/views/login/login.sass2
-rw-r--r--FrontEnd/src/app/views/search/search.sass13
-rw-r--r--FrontEnd/src/app/views/settings/settings.sass14
-rw-r--r--FrontEnd/src/app/views/timeline-common/timeline-common.sass259
-rw-r--r--FrontEnd/src/app/views/timeline/timeline.sass0
-rw-r--r--FrontEnd/src/app/views/user/user.sass7
-rw-r--r--FrontEnd/src/common.ts (renamed from FrontEnd/src/app/common.ts)0
-rw-r--r--FrontEnd/src/http/bookmark.ts (renamed from FrontEnd/src/app/http/bookmark.ts)0
-rw-r--r--FrontEnd/src/http/common.ts (renamed from FrontEnd/src/app/http/common.ts)0
-rw-r--r--FrontEnd/src/http/highlight.ts (renamed from FrontEnd/src/app/http/highlight.ts)0
-rw-r--r--FrontEnd/src/http/search.ts (renamed from FrontEnd/src/app/http/search.ts)0
-rw-r--r--FrontEnd/src/http/timeline.ts (renamed from FrontEnd/src/app/http/timeline.ts)0
-rw-r--r--FrontEnd/src/http/token.ts (renamed from FrontEnd/src/app/http/token.ts)0
-rw-r--r--FrontEnd/src/http/user.ts (renamed from FrontEnd/src/app/http/user.ts)0
-rw-r--r--FrontEnd/src/i18n.ts (renamed from FrontEnd/src/app/i18n.ts)4
-rw-r--r--FrontEnd/src/index.css89
-rw-r--r--FrontEnd/src/index.tsx (renamed from FrontEnd/src/app/index.tsx)9
-rw-r--r--FrontEnd/src/locales/en/admin.json (renamed from FrontEnd/src/app/locales/en/admin.json)0
-rw-r--r--FrontEnd/src/locales/en/translation.json (renamed from FrontEnd/src/app/locales/en/translation.json)0
-rw-r--r--FrontEnd/src/locales/zh/admin.json (renamed from FrontEnd/src/app/locales/zh/admin.json)0
-rw-r--r--FrontEnd/src/locales/zh/translation.json (renamed from FrontEnd/src/app/locales/zh/translation.json)0
-rw-r--r--FrontEnd/src/palette.ts (renamed from FrontEnd/src/app/palette.ts)43
-rw-r--r--FrontEnd/src/service-worker.tsx (renamed from FrontEnd/src/app/service-worker.tsx)0
-rw-r--r--FrontEnd/src/services/TimelinePostBuilder.ts (renamed from FrontEnd/src/app/services/TimelinePostBuilder.ts)0
-rw-r--r--FrontEnd/src/services/alert.ts (renamed from FrontEnd/src/app/services/alert.ts)0
-rw-r--r--FrontEnd/src/services/timeline.ts (renamed from FrontEnd/src/app/services/timeline.ts)0
-rw-r--r--FrontEnd/src/services/user.ts (renamed from FrontEnd/src/app/services/user.ts)0
-rw-r--r--FrontEnd/src/sw.ts (renamed from FrontEnd/src/sw/sw.ts)4
-rw-r--r--FrontEnd/src/sw/tsconfig.json12
-rw-r--r--FrontEnd/src/utilities/mediaQuery.ts (renamed from FrontEnd/src/app/utilities/mediaQuery.ts)0
-rw-r--r--FrontEnd/src/utilities/url.ts (renamed from FrontEnd/src/app/utilities/url.ts)0
-rw-r--r--FrontEnd/src/utilities/useReverseScrollPositionRemember.ts (renamed from FrontEnd/src/app/utilities/useReverseScrollPositionRemember.ts)0
-rw-r--r--FrontEnd/src/utilities/useScrollToTop.ts (renamed from FrontEnd/src/app/utilities/useScrollToTop.ts)0
-rw-r--r--FrontEnd/src/views/about/author-avatar.png (renamed from FrontEnd/src/app/views/about/author-avatar.png)bin12038 -> 12038 bytes
-rw-r--r--FrontEnd/src/views/about/github.png (renamed from FrontEnd/src/app/views/about/github.png)bin4268 -> 4268 bytes
-rw-r--r--FrontEnd/src/views/about/index.css4
-rw-r--r--FrontEnd/src/views/about/index.tsx (renamed from FrontEnd/src/app/views/about/index.tsx)16
-rw-r--r--FrontEnd/src/views/admin/Admin.tsx (renamed from FrontEnd/src/app/views/admin/Admin.tsx)2
-rw-r--r--FrontEnd/src/views/admin/AdminNav.tsx (renamed from FrontEnd/src/app/views/admin/AdminNav.tsx)0
-rw-r--r--FrontEnd/src/views/admin/MoreAdmin.tsx (renamed from FrontEnd/src/app/views/admin/MoreAdmin.tsx)0
-rw-r--r--FrontEnd/src/views/admin/UserAdmin.tsx (renamed from FrontEnd/src/app/views/admin/UserAdmin.tsx)20
-rw-r--r--FrontEnd/src/views/admin/index.css19
-rw-r--r--FrontEnd/src/views/center/CenterBoards.tsx (renamed from FrontEnd/src/app/views/center/CenterBoards.tsx)0
-rw-r--r--FrontEnd/src/views/center/TimelineBoard.tsx (renamed from FrontEnd/src/app/views/center/TimelineBoard.tsx)27
-rw-r--r--FrontEnd/src/views/center/TimelineCreateDialog.tsx (renamed from FrontEnd/src/app/views/center/TimelineCreateDialog.tsx)0
-rw-r--r--FrontEnd/src/views/center/index.css78
-rw-r--r--FrontEnd/src/views/center/index.tsx (renamed from FrontEnd/src/app/views/center/index.tsx)2
-rw-r--r--FrontEnd/src/views/common/AppBar.tsx (renamed from FrontEnd/src/app/views/common/AppBar.tsx)2
-rw-r--r--FrontEnd/src/views/common/BlobImage.tsx (renamed from FrontEnd/src/app/views/common/BlobImage.tsx)0
-rw-r--r--FrontEnd/src/views/common/Card.css11
-rw-r--r--FrontEnd/src/views/common/Card.tsx22
-rw-r--r--FrontEnd/src/views/common/ConfirmDialog.tsx (renamed from FrontEnd/src/app/views/common/ConfirmDialog.tsx)0
-rw-r--r--FrontEnd/src/views/common/FullPage.tsx (renamed from FrontEnd/src/app/views/common/FullPage.tsx)0
-rw-r--r--FrontEnd/src/views/common/ImageCropper.tsx (renamed from FrontEnd/src/app/views/common/ImageCropper.tsx)0
-rw-r--r--FrontEnd/src/views/common/LoadFailReload.tsx (renamed from FrontEnd/src/app/views/common/LoadFailReload.tsx)0
-rw-r--r--FrontEnd/src/views/common/LoadingButton.tsx (renamed from FrontEnd/src/app/views/common/LoadingButton.tsx)0
-rw-r--r--FrontEnd/src/views/common/LoadingPage.tsx (renamed from FrontEnd/src/app/views/common/LoadingPage.tsx)0
-rw-r--r--FrontEnd/src/views/common/Menu.tsx (renamed from FrontEnd/src/app/views/common/Menu.tsx)0
-rw-r--r--FrontEnd/src/views/common/OperationDialog.tsx (renamed from FrontEnd/src/app/views/common/OperationDialog.tsx)0
-rw-r--r--FrontEnd/src/views/common/SearchInput.tsx (renamed from FrontEnd/src/app/views/common/SearchInput.tsx)0
-rw-r--r--FrontEnd/src/views/common/Skeleton.tsx (renamed from FrontEnd/src/app/views/common/Skeleton.tsx)0
-rw-r--r--FrontEnd/src/views/common/TabPages.tsx (renamed from FrontEnd/src/app/views/common/TabPages.tsx)0
-rw-r--r--FrontEnd/src/views/common/TimelineLogo.tsx (renamed from FrontEnd/src/app/views/common/TimelineLogo.tsx)0
-rw-r--r--FrontEnd/src/views/common/ToggleIconButton.tsx (renamed from FrontEnd/src/app/views/common/ToggleIconButton.tsx)0
-rw-r--r--FrontEnd/src/views/common/UserTimelineLogo.tsx (renamed from FrontEnd/src/app/views/common/UserTimelineLogo.tsx)0
-rw-r--r--FrontEnd/src/views/common/alert/AlertHost.tsx (renamed from FrontEnd/src/app/views/common/alert/AlertHost.tsx)0
-rw-r--r--FrontEnd/src/views/common/alert/alert.sass (renamed from FrontEnd/src/app/views/common/alert/alert.sass)0
-rw-r--r--FrontEnd/src/views/common/button/FlatButton.css48
-rw-r--r--FrontEnd/src/views/common/button/FlatButton.tsx41
-rw-r--r--FrontEnd/src/views/common/button/TextButton.css36
-rw-r--r--FrontEnd/src/views/common/button/TextButton.tsx41
-rw-r--r--FrontEnd/src/views/common/index.css273
-rw-r--r--FrontEnd/src/views/common/user/UserAvatar.tsx (renamed from FrontEnd/src/app/views/common/user/UserAvatar.tsx)0
-rw-r--r--FrontEnd/src/views/home/TimelineListView.tsx (renamed from FrontEnd/src/app/views/home/TimelineListView.tsx)2
-rw-r--r--FrontEnd/src/views/home/WebsiteIntroduction.tsx (renamed from FrontEnd/src/app/views/home/WebsiteIntroduction.tsx)0
-rw-r--r--FrontEnd/src/views/home/index.css73
-rw-r--r--FrontEnd/src/views/home/index.tsx (renamed from FrontEnd/src/app/views/home/index.tsx)2
-rw-r--r--FrontEnd/src/views/login/index.css3
-rw-r--r--FrontEnd/src/views/login/index.tsx (renamed from FrontEnd/src/app/views/login/index.tsx)2
-rw-r--r--FrontEnd/src/views/search/index.css15
-rw-r--r--FrontEnd/src/views/search/index.tsx (renamed from FrontEnd/src/app/views/search/index.tsx)6
-rw-r--r--FrontEnd/src/views/settings/ChangeAvatarDialog.tsx (renamed from FrontEnd/src/app/views/settings/ChangeAvatarDialog.tsx)0
-rw-r--r--FrontEnd/src/views/settings/ChangeNicknameDialog.tsx (renamed from FrontEnd/src/app/views/settings/ChangeNicknameDialog.tsx)0
-rw-r--r--FrontEnd/src/views/settings/ChangePasswordDialog.tsx (renamed from FrontEnd/src/app/views/settings/ChangePasswordDialog.tsx)0
-rw-r--r--FrontEnd/src/views/settings/index.css24
-rw-r--r--FrontEnd/src/views/settings/index.tsx (renamed from FrontEnd/src/app/views/settings/index.tsx)11
-rw-r--r--FrontEnd/src/views/timeline-common/CollapseButton.tsx (renamed from FrontEnd/src/app/views/timeline-common/CollapseButton.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/ConnectionStatusBadge.tsx (renamed from FrontEnd/src/app/views/timeline-common/ConnectionStatusBadge.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/MarkdownPostEdit.tsx (renamed from FrontEnd/src/app/views/timeline-common/MarkdownPostEdit.tsx)13
-rw-r--r--FrontEnd/src/views/timeline-common/PostPropertyChangeDialog.tsx (renamed from FrontEnd/src/app/views/timeline-common/PostPropertyChangeDialog.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/Timeline.tsx (renamed from FrontEnd/src/app/views/timeline-common/Timeline.tsx)2
-rw-r--r--FrontEnd/src/views/timeline-common/TimelineDateLabel.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelineDateLabel.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/TimelineLine.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelineLine.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/TimelineLoading.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelineLoading.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/TimelineMember.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelineMember.tsx)2
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelinePageCardTemplate.tsx)7
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePagedPostListView.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelinePagedPostListView.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostContentView.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelinePostContentView.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx)2
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostListView.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelinePostListView.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePostView.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelinePostView.tsx)28
-rw-r--r--FrontEnd/src/views/timeline-common/TimelinePropertyChangeDialog.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/TimelineTop.tsx (renamed from FrontEnd/src/app/views/timeline-common/TimelineTop.tsx)0
-rw-r--r--FrontEnd/src/views/timeline-common/index.css296
-rw-r--r--FrontEnd/src/views/timeline/TimelineCard.tsx (renamed from FrontEnd/src/app/views/timeline/TimelineCard.tsx)2
-rw-r--r--FrontEnd/src/views/timeline/TimelineDeleteDialog.tsx (renamed from FrontEnd/src/app/views/timeline/TimelineDeleteDialog.tsx)0
-rw-r--r--FrontEnd/src/views/timeline/index.tsx (renamed from FrontEnd/src/app/views/timeline/index.tsx)0
-rw-r--r--FrontEnd/src/views/user/UserCard.tsx (renamed from FrontEnd/src/app/views/user/UserCard.tsx)0
-rw-r--r--FrontEnd/src/views/user/index.css9
-rw-r--r--FrontEnd/src/views/user/index.tsx (renamed from FrontEnd/src/app/views/user/index.tsx)4
-rw-r--r--FrontEnd/tsconfig.json (renamed from FrontEnd/src/tsconfig.json)17
-rw-r--r--FrontEnd/vite.config.js33
-rw-r--r--FrontEnd/webpack.common.js73
-rw-r--r--FrontEnd/webpack.config.dev.js38
-rw-r--r--FrontEnd/webpack.config.prod.js53
133 files changed, 1256 insertions, 1132 deletions
diff --git a/FrontEnd/.babelrc b/FrontEnd/.babelrc
deleted file mode 100644
index 092f2f73..00000000
--- a/FrontEnd/.babelrc
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "presets": [
- "@babel/env",
- "@babel/preset-react"
- ],
- "plugins": [
- "@babel/plugin-syntax-dynamic-import",
- "@babel/plugin-proposal-class-properties",
- "@babel/plugin-proposal-optional-chaining",
- "@babel/plugin-proposal-nullish-coalescing-operator",
- [
- "@babel/plugin-proposal-decorators",
- {
- "decoratorsBeforeExport": true
- }
- ],
- [
- "babel-plugin-transform-builtin-extend",
- {
- "globals": [
- "Error",
- "Array"
- ]
- }
- ]
- ]
-} \ No newline at end of file
diff --git a/FrontEnd/.eslintignore b/FrontEnd/.eslintignore
index f29f7466..f4f28252 100644
--- a/FrontEnd/.eslintignore
+++ b/FrontEnd/.eslintignore
@@ -1,6 +1,6 @@
.yarn
node_modules
dist
-webpack.*.js
.eslintrc.js
postcss.config.js
+vite.config.js
diff --git a/FrontEnd/.eslintrc.js b/FrontEnd/.eslintrc.js
index 9bb22216..93b98978 100644
--- a/FrontEnd/.eslintrc.js
+++ b/FrontEnd/.eslintrc.js
@@ -18,7 +18,7 @@ module.exports = {
},
parser: "@typescript-eslint/parser",
parserOptions: {
- project: ["./src/app/tsconfig.json", "./src/sw/tsconfig.json"],
+ project: ["./tsconfig.json"],
ecmaFeatures: {
jsx: true,
},
diff --git a/FrontEnd/src/app/index.ejs b/FrontEnd/index.html
index c2ff4182..87e19743 100644
--- a/FrontEnd/src/app/index.ejs
+++ b/FrontEnd/index.html
@@ -14,16 +14,16 @@
<meta name="msapplication-TileColor" content="#2d89ef" />
<meta name="theme-color" content="#ffffff" />
- <title><%= htmlWebpackPlugin.options.title %></title>
+ <title>Timeline</title>
</head>
<body>
<noscript>
<strong>
- We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
- properly without JavaScript enabled. Please enable it to continue.
+ We're sorry but Timeline doesn't work properly without JavaScript
+ enabled. Please enable it to continue.
</strong>
</noscript>
<div id="app"></div>
- <!-- built files will be auto injected -->
+ <script type="module" src="/src/index.tsx"></script>
</body>
</html>
diff --git a/FrontEnd/package.json b/FrontEnd/package.json
index 58ac137a..e83180ae 100644
--- a/FrontEnd/package.json
+++ b/FrontEnd/package.json
@@ -30,34 +30,22 @@
"regenerator-runtime": "^0.13.7",
"remarkable": "^2.0.1",
"rxjs": "^7.1.0",
+ "xregexp": "^5.0.2",
"workbox-cacheable-response": "^6.1.5",
"workbox-expiration": "^6.1.2",
"workbox-precaching": "^6.1.0",
"workbox-routing": "^6.1.5",
"workbox-strategies": "^6.1.0",
- "workbox-window": "^6.1.1",
- "xregexp": "^5.0.2"
+ "workbox-window": "^6.1.1"
},
"scripts": {
- "start": "webpack serve --config ./webpack.config.dev.js",
- "build": "webpack --config ./webpack.config.prod.js",
+ "start": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview",
"lint": "eslint src/ --ext .js --ext .jsx --ext .ts --ext .tsx",
"lint:fix": "eslint src/ --ext .js --ext .jsx --ext .ts --ext .tsx --fix"
},
- "browserslist": {
- "production": [
- ">0.2%",
- "not dead",
- "not op_mini all"
- ],
- "development": [
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
- ]
- },
"devDependencies": {
- "@pmmmwh/react-refresh-webpack-plugin": "^0.5.0-rc.0",
"@types/color": "^3.0.1",
"@types/lodash": "^4.14.170",
"@types/node": "^15.12.2",
@@ -68,36 +56,17 @@
"@types/react-router": "^5.1.15",
"@types/react-router-dom": "^5.1.7",
"@types/remarkable": "^2.0.2",
- "@types/webpack-env": "^1.16.0",
"@typescript-eslint/eslint-plugin": "^4.27.0",
- "@typescript-eslint/parser": "^4.26.1",
- "clean-webpack-plugin": "^3.0.0",
- "copy-webpack-plugin": "^9.0.0",
- "css-loader": "^5.2.6",
+ "@typescript-eslint/parser": "^4.27.0",
+ "@vitejs/plugin-react-refresh": "^1.3.3",
"eslint": "^7.28.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
- "file-loader": "^6.2.0",
- "html-webpack-plugin": "5.3.1",
- "mini-css-extract-plugin": "^1.6.0",
- "postcss": "^8.3.3",
- "postcss-loader": "^6.1.0",
- "postcss-preset-env": "^6.7.0",
"prettier": "^2.3.1",
- "react-refresh": "^0.10.0",
- "react-refresh-typescript": "^2.0.1",
- "sass": "^1.34.1",
- "sass-loader": "^12.1.0",
- "style-loader": "^2.0.0",
- "ts-loader": "^9.2.3",
"typescript": "^4.3.2",
- "url-loader": "^4.1.1",
- "webpack": "^5.38.1",
- "webpack-chain": "^6.5.1",
- "webpack-cli": "^4.7.2",
- "webpack-dev-server": "^4.0.0-beta.3",
- "workbox-webpack-plugin": "^6.1.5"
+ "vite": "^2.3.7",
+ "vite-plugin-pwa": "^0.8.1"
}
}
diff --git a/FrontEnd/postcss.config.js b/FrontEnd/postcss.config.js
deleted file mode 100644
index 74ee8155..00000000
--- a/FrontEnd/postcss.config.js
+++ /dev/null
@@ -1,10 +0,0 @@
-module.exports = {
- plugins: [
- [
- "postcss-preset-env",
- {
- // Options
- },
- ],
- ],
-};
diff --git a/FrontEnd/src/app/App.tsx b/FrontEnd/src/App.tsx
index a4363ff5..a4363ff5 100644
--- a/FrontEnd/src/app/App.tsx
+++ b/FrontEnd/src/App.tsx
diff --git a/FrontEnd/src/app/index.sass b/FrontEnd/src/app/index.sass
deleted file mode 100644
index 4cee155f..00000000
--- a/FrontEnd/src/app/index.sass
+++ /dev/null
@@ -1,120 +0,0 @@
-@import 'bootstrap/scss/bootstrap'
-@import 'bootstrap-icons/font/bootstrap-icons.css'
-
-@import './views/common/common'
-@import './views/common/alert/alert'
-@import './views/center/center'
-@import './views/home/home'
-@import './views/about/about'
-@import './views/login/login'
-@import './views/settings/settings'
-@import './views/timeline-common/timeline-common'
-@import './views/timeline/timeline'
-@import './views/user/user'
-@import './views/search/search'
-
-@import './views/admin/admin'
-
-.tl-color-primary
- color: var(--tl-primary-color)
-
-.tl-color-danger
- color: var(--tl-danger-color)
-
-small
- line-height: 1.2
-
-.flex-fix-length
- flex-grow: 0
- flex-shrink: 0
-
-.position-lt
- left: 0
- top: 0
-
-.avatar
- width: 60px
- height: 60px
- &.large
- width: 100px
- height: 100px
- &.small
- width: 40px
- height: 40px
-
-.icon-button
- font-size: 1.4rem
- cursor: pointer
- &.large
- font-size: 1.6rem
-
-.flat-button
- cursor: pointer
- padding: 0.2em 0.5em
- border-radius: 0.2em
- &:hover:not(.disabled)
- background-color: $gray-200
- &.disabled
- cursor: default
- @each $color, $value in $theme-colors
- &.#{$color}
- color: $value
- &.disabled
- color: adjust-color($value, $lightness: +15%)
-
-.cursor-pointer
- cursor: pointer
-
-textarea
- resize: none
-
-.white-space-no-wrap
- white-space: nowrap
-
-.cru-card
- @extend .shadow
- @extend .rounded
- border: 1px solid
- border-color: $gray-200
- background: $gray-100
- transition: all 0.3s
- &:hover
- border-color: var(--tl-primary-color)
-
-.full-viewport-center-child
- position: fixed
- width: 100vw
- height: 100vh
- display: flex
- justify-content: center
- align-items: center
-
-.text-orange
- color: $orange
-
-.text-yellow
- color: $yellow
-
-.text-button
- background: transparent
- border: none
- @each $color, $value in $theme-colors
- &.#{$color}
- color: $value
- &:hover
- color: adjust-color($value, $lightness: +15%)
-
-.touch-action-none
- touch-action: none
-
-i
- line-height: 1
-
-.markdown-container
- white-space: initial
- img
- max-height: 200px
- max-width: 100%
-
-a
- text-decoration: none
diff --git a/FrontEnd/src/app/tsconfig.json b/FrontEnd/src/app/tsconfig.json
deleted file mode 100644
index 17ee69cb..00000000
--- a/FrontEnd/src/app/tsconfig.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": "../tsconfig.json",
- "compilerOptions": {
- "lib": [
- "dom",
- "dom.iterable",
- "esnext"
- ]
- },
- "include": [
- "."
- ]
-}
diff --git a/FrontEnd/src/app/typings.d.ts b/FrontEnd/src/app/typings.d.ts
deleted file mode 100644
index 34381682..00000000
--- a/FrontEnd/src/app/typings.d.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-declare module "*.png" {
- const content: string;
- export default content;
-}
-
-declare module "*.jpeg" {
- const content: string;
- export default content;
-}
-
-declare module "*.jpg" {
- const content: string;
- export default content;
-}
-
-declare module "*.gif" {
- const content: string;
- export default content;
-}
-
-declare module "*.svg" {
- const content: string;
- export default content;
-}
diff --git a/FrontEnd/src/app/views/about/about.sass b/FrontEnd/src/app/views/about/about.sass
deleted file mode 100644
index f4d00cae..00000000
--- a/FrontEnd/src/app/views/about/about.sass
+++ /dev/null
@@ -1,4 +0,0 @@
-.about-link-icon
- @extend .mx-2
- width: 1.2em
- height: 1.2em
diff --git a/FrontEnd/src/app/views/admin/admin.sass b/FrontEnd/src/app/views/admin/admin.sass
deleted file mode 100644
index 1ce010f8..00000000
--- a/FrontEnd/src/app/views/admin/admin.sass
+++ /dev/null
@@ -1,22 +0,0 @@
-.admin-user-item
- position: relative
-
- .edit-mask
- position: absolute
- top: 0
- left: 0
- bottom: 0
- right: 0
-
- background: #ffffffc5
- position: absolute
-
- display: flex
- justify-content: center
- align-items: center
-
- @include media-breakpoint-down(xs)
- flex-direction: column
-
- button
- margin: 0.5em 2em
diff --git a/FrontEnd/src/app/views/center/center.sass b/FrontEnd/src/app/views/center/center.sass
deleted file mode 100644
index c0dfb9c0..00000000
--- a/FrontEnd/src/app/views/center/center.sass
+++ /dev/null
@@ -1,36 +0,0 @@
-.timeline-board
- @extend .cru-card
- @extend .d-flex
- @extend .flex-column
- @extend .py-3
- min-height: 200px
- height: 100%
- position: relative
-
-.timeline-board-header
- @extend .px-3
- display: flex
- align-items: center
- justify-content: space-between
-
-.timeline-board-item
- font-size: 1.1em
- @extend .px-3
- height: 48px
- transition: background 0.3s
- display: flex
- align-items: center
- .icon
- height: 1.3em
- color: black
- @extend .me-2
- &:hover
- background: $gray-300
- .right
- display: flex
- align-items: center
- flex-shrink: 0
- .title
- white-space: nowrap
- overflow: hidden
- text-overflow: ellipsis
diff --git a/FrontEnd/src/app/views/common/FlatButton.tsx b/FrontEnd/src/app/views/common/FlatButton.tsx
deleted file mode 100644
index b1f7a051..00000000
--- a/FrontEnd/src/app/views/common/FlatButton.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from "react";
-import classnames from "classnames";
-
-import { BootstrapThemeColor } from "@/common";
-
-export interface FlatButtonProps {
- variant?: BootstrapThemeColor | string;
- disabled?: boolean;
- className?: string;
- style?: React.CSSProperties;
- onClick?: () => void;
-}
-
-const FlatButton: React.FC<FlatButtonProps> = (props) => {
- const { disabled, className, style } = props;
- const variant = props.variant ?? "primary";
-
- const onClick = disabled ? undefined : props.onClick;
-
- return (
- <div
- className={classnames(
- "flat-button",
- variant,
- disabled ? "disabled" : null,
- className
- )}
- style={style}
- onClick={onClick}
- >
- {props.children}
- </div>
- );
-};
-
-export default FlatButton;
diff --git a/FrontEnd/src/app/views/common/common.sass b/FrontEnd/src/app/views/common/common.sass
deleted file mode 100644
index cbf7292e..00000000
--- a/FrontEnd/src/app/views/common/common.sass
+++ /dev/null
@@ -1,191 +0,0 @@
-.image-cropper-container
- position: relative
- box-sizing: border-box
- user-select: none
-
-.image-cropper-container img
- position: absolute
- left: 0
- top: 0
- width: 100%
- height: 100%
-
-.image-cropper-mask-container
- position: absolute
- left: 0
- top: 0
- right: 0
- bottom: 0
- overflow: hidden
-
-.image-cropper-mask
- position: absolute
- box-shadow: 0 0 0 10000px rgba(255, 255, 255, 80%)
- touch-action: none
-
-.image-cropper-handler
- position: absolute
- width: 26px
- height: 26px
- border: black solid 2px
- border-radius: 50%
- background: white
- touch-action: none
-
-.app-bar
- display: flex
- align-items: center
- height: 56px
-
- position: fixed
- z-index: 1030
- top: 0
- left: 0
- right: 0
-
- background-color: var(--tl-primary-color)
-
- transition: background-color 1s
-
- a
- color: var(--tl-text-on-primary-inactive-color)
- text-decoration: none
- margin: 0 1em
-
- &:hover
- color: var(--tl-text-on-primary-color)
-
- &.active
- color: var(--tl-text-on-primary-color)
-
-.app-bar-brand
- display: flex
- align-items: center
-
-.app-bar-brand-icon
- height: 2em
-
-.app-bar-main-area
- display: flex
- flex-grow: 1
-
-.app-bar-link-area
- display: flex
- align-items: center
- flex-shrink: 0
-
-.app-bar-user-area
- display: flex
- align-items: center
- flex-shrink: 0
- margin-left: auto
-
-.small-screen
- .app-bar-main-area
- position: absolute
- top: 56px
- left: 0
- right: 0
-
- transform-origin: top
- transition: transform 0.6s, background-color 1s
-
- background-color: var(--tl-primary-color)
-
- flex-direction: column
-
- &.app-bar-collapse
- transform: scale(1,0)
-
- a
- text-align: left
- padding: 0.5em 0.5em
-
- .app-bar-link-area
- flex-direction: column
- align-items: stretch
-
- .app-bar-user-area
- flex-direction: column
- align-items: stretch
- margin-left: unset
-
- .app-bar-avatar
- align-self: flex-end
-
-.app-bar-toggler
- margin-left: auto
- font-size: 2em
- margin-right: 1em
- color: var(--tl-text-on-primary-color)
- cursor: pointer
- user-select: none
-
-.cru-skeleton
- padding: 0 1em
-
-.cru-skeleton-line
- height: 1em
- background-color: #e6e6e6
- margin: 0.7em 0
- border-radius: 0.2em
-
- &.last
- width: 50%
-
-.cru-full-page
- position: fixed
- z-index: 1031
- left: 0
- top: 0
- right: 0
- bottom: 0
- background-color: white
- padding-top: 56px
-
-.cru-full-page-top-bar
- height: 56px
-
- position: absolute
- top: 0
- left: 0
- right: 0
- z-index: 1
-
- background-color: var(--tl-primary-color)
-
- display: flex
- align-items: center
-
-.cru-full-page-content-container
- overflow: scroll
-
-.cru-menu
- min-width: 200px
-
-.cru-menu-item
- font-size: 1.2em
- padding: 0.5em 1.5em
- cursor: pointer
-
- @each $color, $value in $theme-colors
- &.color-#{$color}
- color: $value
-
- &:hover
- color: white
- background-color: $value
-
-.cru-menu-item-icon
- margin-right: 1em
-
-.cru-menu-divider
- border-top: 1px solid $gray-200
-
-.cru-tab-pages-action-area
- display: flex
- align-items: center
-
-.cru-search-input
- display: flex
- flex-wrap: wrap
diff --git a/FrontEnd/src/app/views/home/home.sass b/FrontEnd/src/app/views/home/home.sass
deleted file mode 100644
index b4cda586..00000000
--- a/FrontEnd/src/app/views/home/home.sass
+++ /dev/null
@@ -1,29 +0,0 @@
-.home-timeline-list-item
- display: flex
- align-items: center
-
-.home-timeline-list-item-timeline
- transition: background 0.8s
- animation: 0.8s home-timeline-list-item-timeline-enter
- &:hover
- background: $gray-200
-
-@keyframes home-timeline-list-item-timeline-enter
- from
- transform: translate(-100%,0)
- opacity: 0
-
-.home-timeline-list-item-line
- width: 80px
- flex-shrink: 0
-
-@keyframes home-timeline-list-loading-head-animation
- from
- transform: translate(0,-30px)
- opacity: 1
-
- to
- opacity: 0
-
-.home-timeline-list-loading-head
- animation: 1s infinite home-timeline-list-loading-head-animation
diff --git a/FrontEnd/src/app/views/login/login.sass b/FrontEnd/src/app/views/login/login.sass
deleted file mode 100644
index 0bf385f5..00000000
--- a/FrontEnd/src/app/views/login/login.sass
+++ /dev/null
@@ -1,2 +0,0 @@
-.login-container
- max-width: 600px
diff --git a/FrontEnd/src/app/views/search/search.sass b/FrontEnd/src/app/views/search/search.sass
deleted file mode 100644
index 83f297fe..00000000
--- a/FrontEnd/src/app/views/search/search.sass
+++ /dev/null
@@ -1,13 +0,0 @@
-.timeline-search-result-item
- @extend .rounded
- border: 1px solid
- border-color: $gray-200
- background: $gray-100
- transition: all 0.3s
- &:hover
- border-color: $primary
-
-.timeline-search-result-item-avatar
- width: 2em
- height: 2em
- border-radius: 50%
diff --git a/FrontEnd/src/app/views/settings/settings.sass b/FrontEnd/src/app/views/settings/settings.sass
deleted file mode 100644
index 8c6d24b8..00000000
--- a/FrontEnd/src/app/views/settings/settings.sass
+++ /dev/null
@@ -1,14 +0,0 @@
-.settings-item
- padding: 0.5em 1em
- transition: background 0.3s
- border-bottom: 1px solid $gray-200
-
- &.first
- border-top: 1px solid $gray-200
-
- &.clickable
- cursor: pointer
-
- &:hover
- background: $gray-300
-
diff --git a/FrontEnd/src/app/views/timeline-common/timeline-common.sass b/FrontEnd/src/app/views/timeline-common/timeline-common.sass
deleted file mode 100644
index 4400fead..00000000
--- a/FrontEnd/src/app/views/timeline-common/timeline-common.sass
+++ /dev/null
@@ -1,259 +0,0 @@
-@use 'sass:color'
-
-.timeline
- z-index: 0
- position: relative
- width: 100%
- overflow-wrap: break-word
- animation: 1s timeline-enter
-
-$timeline-line-width: 7px
-$timeline-line-node-radius: 18px
-$timeline-line-color: var(--tl-primary-color)
-$timeline-line-color-current: var(--tl-primary-enhance-color)
-
-@keyframes timeline-line-node-noncurrent
- to
- box-shadow: 0 0 20px 3px var(--tl-primary-lighter-color)
-
-@keyframes timeline-line-node-current
- to
- box-shadow: 0 0 20px 3px var(--tl-primary-enhance-lighter-color)
-
-@keyframes timeline-line-node-loading
- to
- box-shadow: 0 0 20px 3px var(--tl-primary-lighter-color)
-
-@keyframes timeline-line-node-loading-edge
- from
- transform: rotate(0turn)
- to
- transform: rotate(1turn)
-
-@keyframes timeline-enter
- from
- transform: translate(0, -100vh)
-
-@keyframes timeline-top-loading-enter
- from
- transform: translate(0, -100%)
-
-@keyframes timeline-post-enter
- from
- transform: translate(0, -100%)
- opacity: 0
-
- to
- opacity: 1
-
-.timeline-top-loading-enter
- animation: 1s timeline-top-loading-enter
-
-.timeline-line
- display: flex
- flex-direction: column
- align-items: center
- width: 30px
-
- position: absolute
- z-index: 1
- left: 2em
- top: 0
- bottom: 0
-
- transition: left 0.5s
-
- @include media-breakpoint-down(sm)
- left: 1em
-
- .segment
- width: $timeline-line-width
- background: $timeline-line-color
-
- &.start
- height: 1.8em
- flex: 0 0 auto
-
- &.end
- flex: 1 1 auto
-
- &.current-end
- height: 2em
- flex: 0 0 auto
- background: linear-gradient($timeline-line-color-current, white)
-
- .node-container
- flex: 0 0 auto
- position: relative
- width: $timeline-line-node-radius
- height: $timeline-line-node-radius
-
- .node
- width: $timeline-line-node-radius + 2
- height: $timeline-line-node-radius + 2
- position: absolute
- background: $timeline-line-color
- left: -1px
- top: -1px
- border-radius: 50%
- box-sizing: border-box
- z-index: 1
- animation: 1s infinite alternate
- animation-name: timeline-line-node-noncurrent
-
- .node-loading-edge
- color: $timeline-line-color
- width: $timeline-line-node-radius + 20
- height: $timeline-line-node-radius + 20
- position: absolute
- left: -10px
- top: -10px
- box-sizing: border-box
- z-index: 2
- animation: 1.5s linear infinite timeline-line-node-loading-edge
-
- &.current
- .segment
- &.start
- background: linear-gradient($timeline-line-color, $timeline-line-color-current)
- &.end
- background: $timeline-line-color-current
- .node
- background: $timeline-line-color-current
- animation-name: timeline-line-node-current
-
- &.loading
- .node
- background: $timeline-line-color
- animation-name: timeline-line-node-loading
-
-.timeline-item.current
- padding-bottom: 2.5em
-
-.timeline-top
- position: relative
- text-align: right
-
-.timeline-item
- position: relative
- padding: 0.5em
-
-.timeline-item-card
- @extend .cru-card
- position: relative
- padding: 0.3em 0.5em 1em 4em
- transition: background 0.5s, padding-left 0.5s
- animation: 0.6s forwards
- opacity: 0
-
- @include media-breakpoint-down(sm)
- padding-left: 3em
-
-.timeline-item-header
- display: flex
- align-items: center
- @extend .my-2
-
-.timeline-avatar
- border-radius: 50%
- width: 2em
- height: 2em
-
-.timeline-item-delete-button
- position: absolute
- right: 0
- bottom: 0
-
-.timeline-content
- white-space: pre-line
-
-.timeline-content-image
- max-width: 80%
- max-height: 200px
-
-.timeline-date-item
- position: relative
- padding: 0.3em 0 0.3em 4em
-
-.timeline-date-item-badge
- display: inline-block
- padding: 0.1em 0.4em
- border-radius: 0.4em
- background: #7c7c7c
- color: white
- font-size: 0.8em
-
-.timeline-post-edit-image
- max-width: 100px
- max-height: 100px
-
-.mask
- background: change-color($color: white, $alpha: 0.8)
- z-index: 100
-
-.timeline-sync-state-badge
- font-size: 0.8em
- padding: 3px 8px
- border-radius: 5px
- background: #e8fbff
-
-.timeline-sync-state-badge-pin
- display: inline-block
- width: 0.4em
- height: 0.4em
- border-radius: 50%
- vertical-align: middle
- margin-right: 0.6em
-
-.timeline-template-card
- position: fixed
- top: 56px
- right: 0
- margin: 0.5em
-
-.timeline-markdown-post-edit-page
- overflow: scroll
- max-height: 300px
-
-.timeline-markdown-post-edit-image-container
- position: relative
- text-align: center
- margin-bottom: 1em
-
-.timeline-markdown-post-edit-image
- max-width: 100%
- max-height: 200px
-
-.timeline-markdown-post-edit-image-delete-button
- position: absolute
- right: 10px
- top: 2px
-
-.connection-status-badge
- font-size: 0.8em
- border-radius: 5px
- padding: 0.1em 1em
- background-color: rgb(234 242 255)
-
- &::before
- width: 10px
- height: 10px
- border-radius: 50%
- display: inline-block
- content: ''
- margin-right: 0.6em
-
- &.success
- color: #006100
- &::before
- background-color: #006100
-
- &.warning
- color: #e4a700
- &::before
- background-color: #e4a700
-
- &.danger
- color: #fd1616
- &::before
- background-color: #fd1616
diff --git a/FrontEnd/src/app/views/timeline/timeline.sass b/FrontEnd/src/app/views/timeline/timeline.sass
deleted file mode 100644
index e69de29b..00000000
--- a/FrontEnd/src/app/views/timeline/timeline.sass
+++ /dev/null
diff --git a/FrontEnd/src/app/views/user/user.sass b/FrontEnd/src/app/views/user/user.sass
deleted file mode 100644
index 63a28e05..00000000
--- a/FrontEnd/src/app/views/user/user.sass
+++ /dev/null
@@ -1,7 +0,0 @@
-.change-avatar-cropper-row
- max-height: 400px
-
-.change-avatar-img
- min-width: 50%
- max-width: 100%
- max-height: 400px
diff --git a/FrontEnd/src/app/common.ts b/FrontEnd/src/common.ts
index 1a4f6dda..1a4f6dda 100644
--- a/FrontEnd/src/app/common.ts
+++ b/FrontEnd/src/common.ts
diff --git a/FrontEnd/src/app/http/bookmark.ts b/FrontEnd/src/http/bookmark.ts
index 3e5be229..3e5be229 100644
--- a/FrontEnd/src/app/http/bookmark.ts
+++ b/FrontEnd/src/http/bookmark.ts
diff --git a/FrontEnd/src/app/http/common.ts b/FrontEnd/src/http/common.ts
index e1672985..e1672985 100644
--- a/FrontEnd/src/app/http/common.ts
+++ b/FrontEnd/src/http/common.ts
diff --git a/FrontEnd/src/app/http/highlight.ts b/FrontEnd/src/http/highlight.ts
index fddf0729..fddf0729 100644
--- a/FrontEnd/src/app/http/highlight.ts
+++ b/FrontEnd/src/http/highlight.ts
diff --git a/FrontEnd/src/app/http/search.ts b/FrontEnd/src/http/search.ts
index 8ca48fe9..8ca48fe9 100644
--- a/FrontEnd/src/app/http/search.ts
+++ b/FrontEnd/src/http/search.ts
diff --git a/FrontEnd/src/app/http/timeline.ts b/FrontEnd/src/http/timeline.ts
index 9697c1a0..9697c1a0 100644
--- a/FrontEnd/src/app/http/timeline.ts
+++ b/FrontEnd/src/http/timeline.ts
diff --git a/FrontEnd/src/app/http/token.ts b/FrontEnd/src/http/token.ts
index f8b09d63..f8b09d63 100644
--- a/FrontEnd/src/app/http/token.ts
+++ b/FrontEnd/src/http/token.ts
diff --git a/FrontEnd/src/app/http/user.ts b/FrontEnd/src/http/user.ts
index dcf24cba..dcf24cba 100644
--- a/FrontEnd/src/app/http/user.ts
+++ b/FrontEnd/src/http/user.ts
diff --git a/FrontEnd/src/app/i18n.ts b/FrontEnd/src/i18n.ts
index 5b8e9d41..8caf51ec 100644
--- a/FrontEnd/src/app/i18n.ts
+++ b/FrontEnd/src/i18n.ts
@@ -71,8 +71,8 @@ export const i18nPromise = i18n
*/
});
-if (module.hot) {
- module.hot.accept(
+if (import.meta.hot) {
+ import.meta.hot.accept(
[
"./locales/en/translation.json",
"./locales/zh/translation.json",
diff --git a/FrontEnd/src/index.css b/FrontEnd/src/index.css
new file mode 100644
index 00000000..e102fbb4
--- /dev/null
+++ b/FrontEnd/src/index.css
@@ -0,0 +1,89 @@
+.tl-color-primary {
+ color: var(--tl-primary-color);
+}
+
+.tl-color-danger {
+ color: var(--tl-danger-color);
+}
+
+small {
+ line-height: 1.2;
+}
+
+.flex-fix-length {
+ flex-grow: 0;
+ flex-shrink: 0;
+}
+
+.avatar {
+ width: 60px;
+ height: 60px;
+}
+
+.avatar.large {
+ width: 100px;
+ height: 100px;
+}
+
+.avatar.small {
+ width: 40px;
+ height: 40px;
+}
+
+.icon-button {
+ font-size: 1.4rem;
+ cursor: pointer;
+}
+
+.icon-button.large {
+ font-size: 1.6rem;
+}
+
+.cursor-pointer {
+ cursor: pointer;
+}
+
+textarea {
+ resize: none;
+}
+
+.white-space-no-wrap {
+ white-space: nowrap;
+}
+
+.full-viewport-center-child {
+ position: fixed;
+ width: 100vw;
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.text-orange {
+ color: #fd7e14;
+}
+
+.text-yellow {
+ color: #ffc107;
+}
+
+.touch-action-none {
+ touch-action: none;
+}
+
+i {
+ line-height: 1;
+}
+
+.markdown-container {
+ white-space: initial;
+}
+.markdown-container img {
+ max-height: 200px;
+ max-width: 100%;
+}
+
+a {
+ text-decoration: none;
+}
diff --git a/FrontEnd/src/app/index.tsx b/FrontEnd/src/index.tsx
index fb0c8899..28034601 100644
--- a/FrontEnd/src/app/index.tsx
+++ b/FrontEnd/src/index.tsx
@@ -3,17 +3,20 @@ import "core-js/modules/es.promise";
import "core-js/modules/es.array.iterator";
import "pepjs";
+import "bootstrap/dist/css/bootstrap.css";
+import "bootstrap-icons/font/bootstrap-icons.css";
+
import React from "react";
import ReactDOM from "react-dom";
-import "./index.sass";
+import "./index.css";
import "./i18n";
+import "./palette";
+import "./service-worker";
import App from "./App";
-import "./palette";
-
import { userService } from "./services/user";
void userService.checkLoginState();
diff --git a/FrontEnd/src/app/locales/en/admin.json b/FrontEnd/src/locales/en/admin.json
index ddb3ffad..ddb3ffad 100644
--- a/FrontEnd/src/app/locales/en/admin.json
+++ b/FrontEnd/src/locales/en/admin.json
diff --git a/FrontEnd/src/app/locales/en/translation.json b/FrontEnd/src/locales/en/translation.json
index a2766b4e..a2766b4e 100644
--- a/FrontEnd/src/app/locales/en/translation.json
+++ b/FrontEnd/src/locales/en/translation.json
diff --git a/FrontEnd/src/app/locales/zh/admin.json b/FrontEnd/src/locales/zh/admin.json
index edd1cabd..edd1cabd 100644
--- a/FrontEnd/src/app/locales/zh/admin.json
+++ b/FrontEnd/src/locales/zh/admin.json
diff --git a/FrontEnd/src/app/locales/zh/translation.json b/FrontEnd/src/locales/zh/translation.json
index 5a5a6843..5a5a6843 100644
--- a/FrontEnd/src/app/locales/zh/translation.json
+++ b/FrontEnd/src/locales/zh/translation.json
diff --git a/FrontEnd/src/app/palette.ts b/FrontEnd/src/palette.ts
index c4f4f4f9..6385df66 100644
--- a/FrontEnd/src/app/palette.ts
+++ b/FrontEnd/src/palette.ts
@@ -19,16 +19,19 @@ export interface PaletteColor {
[key: string]: string;
}
-export interface Palette {
- primary: PaletteColor;
- primaryEnhance: PaletteColor;
- secondary: PaletteColor;
- textPrimary: PaletteColor;
- textOnPrimary: PaletteColor;
- danger: PaletteColor;
- success: PaletteColor;
- [key: string]: PaletteColor;
-}
+const paletteColorList = [
+ "primary",
+ "primary-enhance",
+ "secondary",
+ "text-primary",
+ "text-on-primary",
+ "danger",
+ "success",
+] as const;
+
+export type PaletteColorType = typeof paletteColorList[number];
+
+export type Palette = Record<PaletteColorType, PaletteColor>;
export function generatePaletteColor(color: string): PaletteColor {
const c = Color(color);
@@ -58,26 +61,24 @@ export function generatePalette(options: {
return {
primary: generatePaletteColor(p.toString()),
- primaryEnhance: generatePaletteColor(pe.toString()),
+ "primary-enhance": generatePaletteColor(pe.toString()),
secondary: generatePaletteColor(s.toString()),
- textPrimary: generatePaletteColor("#111111"),
- textOnPrimary: generatePaletteColor(p.lightness() > 60 ? "black" : "white"),
+ "text-primary": generatePaletteColor("#111111"),
+ "text-on-primary": generatePaletteColor(
+ p.lightness() > 60 ? "black" : "white"
+ ),
danger: generatePaletteColor("red"),
success: generatePaletteColor("green"),
};
}
export function generatePaletteCSS(palette: Palette): string {
- function toSnakeCase(s: string): string {
- return s.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
- }
-
const colors: [string, string][] = [];
- for (const paletteColorName in palette) {
- const paletteColor = palette[paletteColorName];
+ for (const colorType of paletteColorList) {
+ const paletteColor = palette[colorType];
for (const variant in paletteColor) {
- let key = `--tl-${toSnakeCase(paletteColorName)}`;
- if (variant !== "color") key += `-${toSnakeCase(variant)}`;
+ let key = `--tl-${colorType}`;
+ if (variant !== "color") key += `-${variant}`;
key += "-color";
colors.push([key, paletteColor[variant]]);
}
diff --git a/FrontEnd/src/app/service-worker.tsx b/FrontEnd/src/service-worker.tsx
index ea8dfc32..ea8dfc32 100644
--- a/FrontEnd/src/app/service-worker.tsx
+++ b/FrontEnd/src/service-worker.tsx
diff --git a/FrontEnd/src/app/services/TimelinePostBuilder.ts b/FrontEnd/src/services/TimelinePostBuilder.ts
index 40279eca..40279eca 100644
--- a/FrontEnd/src/app/services/TimelinePostBuilder.ts
+++ b/FrontEnd/src/services/TimelinePostBuilder.ts
diff --git a/FrontEnd/src/app/services/alert.ts b/FrontEnd/src/services/alert.ts
index 48d482ea..48d482ea 100644
--- a/FrontEnd/src/app/services/alert.ts
+++ b/FrontEnd/src/services/alert.ts
diff --git a/FrontEnd/src/app/services/timeline.ts b/FrontEnd/src/services/timeline.ts
index d8c0ae00..d8c0ae00 100644
--- a/FrontEnd/src/app/services/timeline.ts
+++ b/FrontEnd/src/services/timeline.ts
diff --git a/FrontEnd/src/app/services/user.ts b/FrontEnd/src/services/user.ts
index 9a8e5687..9a8e5687 100644
--- a/FrontEnd/src/app/services/user.ts
+++ b/FrontEnd/src/services/user.ts
diff --git a/FrontEnd/src/sw/sw.ts b/FrontEnd/src/sw.ts
index 724804dd..0130e345 100644
--- a/FrontEnd/src/sw/sw.ts
+++ b/FrontEnd/src/sw.ts
@@ -1,3 +1,7 @@
+/// <reference no-default-lib="true"/>
+/// <reference lib="esnext" />
+/// <reference lib="webworker" />
+
import { precacheAndRoute, matchPrecache } from "workbox-precaching";
import { registerRoute, setDefaultHandler } from "workbox-routing";
import {
diff --git a/FrontEnd/src/sw/tsconfig.json b/FrontEnd/src/sw/tsconfig.json
deleted file mode 100644
index 71fc0bcd..00000000
--- a/FrontEnd/src/sw/tsconfig.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "extends": "../tsconfig.json",
- "compilerOptions": {
- "lib": [
- "esnext",
- "webworker"
- ]
- },
- "include": [
- "."
- ]
-}
diff --git a/FrontEnd/src/app/utilities/mediaQuery.ts b/FrontEnd/src/utilities/mediaQuery.ts
index ad55c3c0..ad55c3c0 100644
--- a/FrontEnd/src/app/utilities/mediaQuery.ts
+++ b/FrontEnd/src/utilities/mediaQuery.ts
diff --git a/FrontEnd/src/app/utilities/url.ts b/FrontEnd/src/utilities/url.ts
index 4f2a6ecd..4f2a6ecd 100644
--- a/FrontEnd/src/app/utilities/url.ts
+++ b/FrontEnd/src/utilities/url.ts
diff --git a/FrontEnd/src/app/utilities/useReverseScrollPositionRemember.ts b/FrontEnd/src/utilities/useReverseScrollPositionRemember.ts
index a5812808..a5812808 100644
--- a/FrontEnd/src/app/utilities/useReverseScrollPositionRemember.ts
+++ b/FrontEnd/src/utilities/useReverseScrollPositionRemember.ts
diff --git a/FrontEnd/src/app/utilities/useScrollToTop.ts b/FrontEnd/src/utilities/useScrollToTop.ts
index 892e3545..892e3545 100644
--- a/FrontEnd/src/app/utilities/useScrollToTop.ts
+++ b/FrontEnd/src/utilities/useScrollToTop.ts
diff --git a/FrontEnd/src/app/views/about/author-avatar.png b/FrontEnd/src/views/about/author-avatar.png
index d890d8d0..d890d8d0 100644
--- a/FrontEnd/src/app/views/about/author-avatar.png
+++ b/FrontEnd/src/views/about/author-avatar.png
Binary files differ
diff --git a/FrontEnd/src/app/views/about/github.png b/FrontEnd/src/views/about/github.png
index ea6ff545..ea6ff545 100644
--- a/FrontEnd/src/app/views/about/github.png
+++ b/FrontEnd/src/views/about/github.png
Binary files differ
diff --git a/FrontEnd/src/views/about/index.css b/FrontEnd/src/views/about/index.css
new file mode 100644
index 00000000..2574f4b7
--- /dev/null
+++ b/FrontEnd/src/views/about/index.css
@@ -0,0 +1,4 @@
+.about-link-icon {
+ width: 1.2em;
+ height: 1.2em;
+}
diff --git a/FrontEnd/src/app/views/about/index.tsx b/FrontEnd/src/views/about/index.tsx
index a8a53a97..7b0e50b0 100644
--- a/FrontEnd/src/app/views/about/index.tsx
+++ b/FrontEnd/src/views/about/index.tsx
@@ -4,6 +4,10 @@ import { useTranslation, Trans } from "react-i18next";
import authorAvatarUrl from "./author-avatar.png";
import githubLogoUrl from "./github.png";
+import Card from "../common/Card";
+
+import "./index.css";
+
const frontendCredits: {
name: string;
url: string;
@@ -66,7 +70,7 @@ const AboutPage: React.FC = () => {
return (
<div className="px-2 mb-4">
- <div className="container mt-4 py-3 cru-card">
+ <Card className="container mt-4 py-3">
<h4 id="author-info">{t("about.author.title")}</h4>
<div>
<div className="d-flex">
@@ -100,8 +104,8 @@ const AboutPage: React.FC = () => {
</a>
</p>
</div>
- </div>
- <div className="container mt-4 py-3 cru-card">
+ </Card>
+ <Card className="container mt-4 py-3">
<h4>{t("about.site.title")}</h4>
<p>
<Trans i18nKey="about.site.content">
@@ -118,8 +122,8 @@ const AboutPage: React.FC = () => {
{t("about.site.repo")}
</a>
</p>
- </div>
- <div className="container mt-4 py-3 cru-card">
+ </Card>
+ <Card className="container mt-4 py-3">
<h4>{t("about.credits.title")}</h4>
<p>{t("about.credits.content")}</p>
<p>{t("about.credits.frontend")}</p>
@@ -148,7 +152,7 @@ const AboutPage: React.FC = () => {
})}
<li>...</li>
</ul>
- </div>
+ </Card>
</div>
);
};
diff --git a/FrontEnd/src/app/views/admin/Admin.tsx b/FrontEnd/src/views/admin/Admin.tsx
index 0b6d1f05..34e7e2f6 100644
--- a/FrontEnd/src/app/views/admin/Admin.tsx
+++ b/FrontEnd/src/views/admin/Admin.tsx
@@ -9,6 +9,8 @@ import AdminNav from "./AdminNav";
import UserAdmin from "./UserAdmin";
import MoreAdmin from "./MoreAdmin";
+import "./index.css";
+
interface AdminProps {
user: AuthUser;
}
diff --git a/FrontEnd/src/app/views/admin/AdminNav.tsx b/FrontEnd/src/views/admin/AdminNav.tsx
index 47e2138f..47e2138f 100644
--- a/FrontEnd/src/app/views/admin/AdminNav.tsx
+++ b/FrontEnd/src/views/admin/AdminNav.tsx
diff --git a/FrontEnd/src/app/views/admin/MoreAdmin.tsx b/FrontEnd/src/views/admin/MoreAdmin.tsx
index 042789a0..042789a0 100644
--- a/FrontEnd/src/app/views/admin/MoreAdmin.tsx
+++ b/FrontEnd/src/views/admin/MoreAdmin.tsx
diff --git a/FrontEnd/src/app/views/admin/UserAdmin.tsx b/FrontEnd/src/views/admin/UserAdmin.tsx
index 558d3aee..eb141520 100644
--- a/FrontEnd/src/app/views/admin/UserAdmin.tsx
+++ b/FrontEnd/src/views/admin/UserAdmin.tsx
@@ -14,6 +14,7 @@ import {
UserPermission,
} from "@/http/user";
import { Trans, useTranslation } from "react-i18next";
+import TextButton from "../common/button/TextButton";
interface DialogProps<TData = undefined, TReturn = undefined> {
open: boolean;
@@ -230,15 +231,16 @@ const UserItem: React.FC<UserItemProps> = ({ user, on }) => {
className={classnames("edit-mask", !editMaskVisible && "d-none")}
onClick={() => setEditMaskVisible(false)}
>
- <button className="text-button primary" onClick={on[kModify]}>
- {t("admin:user.modify")}
- </button>
- <button className="text-button primary" onClick={on[kModifyPermission]}>
- {t("admin:user.modifyPermissions")}
- </button>
- <button className="text-button danger" onClick={on[kDelete]}>
- {t("admin:user.delete")}
- </button>
+ <TextButton text="admin:user.modify" onClick={on[kModify]} />
+ <TextButton
+ text="admin:user.modifyPermissions"
+ onClick={on[kModifyPermission]}
+ />
+ <TextButton
+ text="admin:user.delete"
+ color="danger"
+ onClick={on[kDelete]}
+ />
</div>
</ListGroup.Item>
);
diff --git a/FrontEnd/src/views/admin/index.css b/FrontEnd/src/views/admin/index.css
new file mode 100644
index 00000000..00917600
--- /dev/null
+++ b/FrontEnd/src/views/admin/index.css
@@ -0,0 +1,19 @@
+.admin-user-item {
+ position: relative;
+}
+.admin-user-item .edit-mask {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ background: #ffffffc5;
+ position: absolute;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+}
+.admin-user-item .edit-mask button {
+ margin: 0.5em 2em;
+}
diff --git a/FrontEnd/src/app/views/center/CenterBoards.tsx b/FrontEnd/src/views/center/CenterBoards.tsx
index f5200415..f5200415 100644
--- a/FrontEnd/src/app/views/center/CenterBoards.tsx
+++ b/FrontEnd/src/views/center/CenterBoards.tsx
diff --git a/FrontEnd/src/app/views/center/TimelineBoard.tsx b/FrontEnd/src/views/center/TimelineBoard.tsx
index 35249f66..7b9981e5 100644
--- a/FrontEnd/src/app/views/center/TimelineBoard.tsx
+++ b/FrontEnd/src/views/center/TimelineBoard.tsx
@@ -1,7 +1,6 @@
import React from "react";
import classnames from "classnames";
import { Link } from "react-router-dom";
-import { useTranslation } from "react-i18next";
import { Spinner } from "react-bootstrap";
import { HttpTimelineInfo } from "@/http/timeline";
@@ -9,6 +8,8 @@ import { HttpTimelineInfo } from "@/http/timeline";
import TimelineLogo from "../common/TimelineLogo";
import UserTimelineLogo from "../common/UserTimelineLogo";
import LoadFailReload from "../common/LoadFailReload";
+import FlatButton from "../common/button/FlatButton";
+import Card from "../common/Card";
interface TimelineBoardItemProps {
timeline: HttpTimelineInfo;
@@ -34,7 +35,7 @@ const TimelineBoardItem: React.FC<TimelineBoardItemProps> = ({
actions,
}) => {
const { name, title } = timeline;
- const isPersonal = name.startsWith("@");
+ const isPersonal = name.startsWith("src");
const url = isPersonal
? `/users/${timeline.owner.username}`
: `/timelines/${name}`;
@@ -219,35 +220,29 @@ interface TimelineBoardUIProps {
const TimelineBoardUI: React.FC<TimelineBoardUIProps> = (props) => {
const { title, timelines, className, editHandler } = props;
- const { t } = useTranslation();
-
const editable = editHandler != null;
const [editing, setEditing] = React.useState<boolean>(false);
return (
- <div className={classnames("timeline-board", className)}>
+ <Card className={classnames("timeline-board", className)}>
<div className="timeline-board-header">
{title != null && <h3>{title}</h3>}
{editable &&
(editing ? (
- <div
- className="flat-button text-primary"
+ <FlatButton
+ text="done"
onClick={() => {
setEditing(false);
}}
- >
- {t("done")}
- </div>
+ />
) : (
- <div
- className="flat-button text-primary"
+ <FlatButton
+ text="edit"
onClick={() => {
setEditing(true);
}}
- >
- {t("edit")}
- </div>
+ />
))}
</div>
{(() => {
@@ -286,7 +281,7 @@ const TimelineBoardUI: React.FC<TimelineBoardUIProps> = (props) => {
);
}
})()}
- </div>
+ </Card>
);
};
diff --git a/FrontEnd/src/app/views/center/TimelineCreateDialog.tsx b/FrontEnd/src/views/center/TimelineCreateDialog.tsx
index b4e25ba1..b4e25ba1 100644
--- a/FrontEnd/src/app/views/center/TimelineCreateDialog.tsx
+++ b/FrontEnd/src/views/center/TimelineCreateDialog.tsx
diff --git a/FrontEnd/src/views/center/index.css b/FrontEnd/src/views/center/index.css
new file mode 100644
index 00000000..f5bbc63b
--- /dev/null
+++ b/FrontEnd/src/views/center/index.css
@@ -0,0 +1,78 @@
+.timeline-board {
+ min-height: 200px;
+ height: 100%;
+ position: relative;
+ padding: 1em 0;
+}
+
+.timeline-board-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 1em;
+}
+
+.timeline-board-item {
+ font-size: 1.1em;
+ height: 48px;
+ transition: background 0.3s;
+ display: flex;
+ align-items: center;
+ padding: 0 1em;
+}
+
+.timeline-board-item .icon {
+ height: 1.3em;
+ color: black;
+}
+
+.timeline-board-item:hover {
+ background: #dee2e6;
+}
+.timeline-board-item .right {
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+}
+.timeline-board-item .title {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.home-timeline-list-item {
+ display: flex;
+ align-items: center;
+}
+
+.home-timeline-list-item-timeline {
+ transition: background 0.8s;
+ animation: 0.8s home-timeline-list-item-timeline-enter;
+}
+.home-timeline-list-item-timeline:hover {
+ background: #e9ecef;
+}
+
+@keyframes home-timeline-list-item-timeline-enter {
+ from {
+ transform: translate(-100%, 0);
+ opacity: 0;
+ }
+}
+.home-timeline-list-item-line {
+ width: 80px;
+ flex-shrink: 0;
+}
+
+@keyframes home-timeline-list-loading-head-animation {
+ from {
+ transform: translate(0, -30px);
+ opacity: 1;
+ }
+ to {
+ opacity: 0;
+ }
+}
+.home-timeline-list-loading-head {
+ animation: 1s infinite home-timeline-list-loading-head-animation;
+}
diff --git a/FrontEnd/src/app/views/center/index.tsx b/FrontEnd/src/views/center/index.tsx
index 0a2abb2c..28d8b372 100644
--- a/FrontEnd/src/app/views/center/index.tsx
+++ b/FrontEnd/src/views/center/index.tsx
@@ -9,6 +9,8 @@ import SearchInput from "../common/SearchInput";
import CenterBoards from "./CenterBoards";
import TimelineCreateDialog from "./TimelineCreateDialog";
+import "./index.css";
+
const HomePage: React.FC = () => {
const history = useHistory();
diff --git a/FrontEnd/src/app/views/common/AppBar.tsx b/FrontEnd/src/views/common/AppBar.tsx
index 91dfbee9..ebc8bf0c 100644
--- a/FrontEnd/src/app/views/common/AppBar.tsx
+++ b/FrontEnd/src/views/common/AppBar.tsx
@@ -9,6 +9,8 @@ import { useUser } from "@/services/user";
import TimelineLogo from "./TimelineLogo";
import UserAvatar from "./user/UserAvatar";
+import "./index.css";
+
const AppBar: React.FC = (_) => {
const { t } = useTranslation();
diff --git a/FrontEnd/src/app/views/common/BlobImage.tsx b/FrontEnd/src/views/common/BlobImage.tsx
index 0dd25c52..0dd25c52 100644
--- a/FrontEnd/src/app/views/common/BlobImage.tsx
+++ b/FrontEnd/src/views/common/BlobImage.tsx
diff --git a/FrontEnd/src/views/common/Card.css b/FrontEnd/src/views/common/Card.css
new file mode 100644
index 00000000..17c3c779
--- /dev/null
+++ b/FrontEnd/src/views/common/Card.css
@@ -0,0 +1,11 @@
+.cru-card {
+ border: 1px solid;
+ border-color: #e9ecef;
+ border-radius: 8px;
+ background: #fefeff;
+ transition: all 0.3s;
+}
+
+.cru-card:hover {
+ border-color: var(--tl-primary-color);
+}
diff --git a/FrontEnd/src/views/common/Card.tsx b/FrontEnd/src/views/common/Card.tsx
new file mode 100644
index 00000000..da2a1b68
--- /dev/null
+++ b/FrontEnd/src/views/common/Card.tsx
@@ -0,0 +1,22 @@
+import classNames from "classnames";
+import React from "react";
+
+import "./Card.css";
+
+function _Card(
+ {
+ className,
+ children,
+ }: React.PropsWithChildren<React.HTMLAttributes<HTMLDivElement>>,
+ ref: React.ForwardedRef<HTMLDivElement>
+): React.ReactElement | null {
+ return (
+ <div ref={ref} className={classNames("cru-card", className)}>
+ {children}
+ </div>
+ );
+}
+
+const Card = React.forwardRef(_Card);
+
+export default Card;
diff --git a/FrontEnd/src/app/views/common/ConfirmDialog.tsx b/FrontEnd/src/views/common/ConfirmDialog.tsx
index 72940c51..72940c51 100644
--- a/FrontEnd/src/app/views/common/ConfirmDialog.tsx
+++ b/FrontEnd/src/views/common/ConfirmDialog.tsx
diff --git a/FrontEnd/src/app/views/common/FullPage.tsx b/FrontEnd/src/views/common/FullPage.tsx
index 1b59045a..1b59045a 100644
--- a/FrontEnd/src/app/views/common/FullPage.tsx
+++ b/FrontEnd/src/views/common/FullPage.tsx
diff --git a/FrontEnd/src/app/views/common/ImageCropper.tsx b/FrontEnd/src/views/common/ImageCropper.tsx
index 2ef5b7ed..2ef5b7ed 100644
--- a/FrontEnd/src/app/views/common/ImageCropper.tsx
+++ b/FrontEnd/src/views/common/ImageCropper.tsx
diff --git a/FrontEnd/src/app/views/common/LoadFailReload.tsx b/FrontEnd/src/views/common/LoadFailReload.tsx
index a80e7b76..a80e7b76 100644
--- a/FrontEnd/src/app/views/common/LoadFailReload.tsx
+++ b/FrontEnd/src/views/common/LoadFailReload.tsx
diff --git a/FrontEnd/src/app/views/common/LoadingButton.tsx b/FrontEnd/src/views/common/LoadingButton.tsx
index cd9f1adc..cd9f1adc 100644
--- a/FrontEnd/src/app/views/common/LoadingButton.tsx
+++ b/FrontEnd/src/views/common/LoadingButton.tsx
diff --git a/FrontEnd/src/app/views/common/LoadingPage.tsx b/FrontEnd/src/views/common/LoadingPage.tsx
index 590fafa0..590fafa0 100644
--- a/FrontEnd/src/app/views/common/LoadingPage.tsx
+++ b/FrontEnd/src/views/common/LoadingPage.tsx
diff --git a/FrontEnd/src/app/views/common/Menu.tsx b/FrontEnd/src/views/common/Menu.tsx
index ae73a331..ae73a331 100644
--- a/FrontEnd/src/app/views/common/Menu.tsx
+++ b/FrontEnd/src/views/common/Menu.tsx
diff --git a/FrontEnd/src/app/views/common/OperationDialog.tsx b/FrontEnd/src/views/common/OperationDialog.tsx
index ac4c51b9..ac4c51b9 100644
--- a/FrontEnd/src/app/views/common/OperationDialog.tsx
+++ b/FrontEnd/src/views/common/OperationDialog.tsx
diff --git a/FrontEnd/src/app/views/common/SearchInput.tsx b/FrontEnd/src/views/common/SearchInput.tsx
index ccb6dad6..ccb6dad6 100644
--- a/FrontEnd/src/app/views/common/SearchInput.tsx
+++ b/FrontEnd/src/views/common/SearchInput.tsx
diff --git a/FrontEnd/src/app/views/common/Skeleton.tsx b/FrontEnd/src/views/common/Skeleton.tsx
index 14886c71..14886c71 100644
--- a/FrontEnd/src/app/views/common/Skeleton.tsx
+++ b/FrontEnd/src/views/common/Skeleton.tsx
diff --git a/FrontEnd/src/app/views/common/TabPages.tsx b/FrontEnd/src/views/common/TabPages.tsx
index 2b1d91cb..2b1d91cb 100644
--- a/FrontEnd/src/app/views/common/TabPages.tsx
+++ b/FrontEnd/src/views/common/TabPages.tsx
diff --git a/FrontEnd/src/app/views/common/TimelineLogo.tsx b/FrontEnd/src/views/common/TimelineLogo.tsx
index 27d188fc..27d188fc 100644
--- a/FrontEnd/src/app/views/common/TimelineLogo.tsx
+++ b/FrontEnd/src/views/common/TimelineLogo.tsx
diff --git a/FrontEnd/src/app/views/common/ToggleIconButton.tsx b/FrontEnd/src/views/common/ToggleIconButton.tsx
index c4d2d132..c4d2d132 100644
--- a/FrontEnd/src/app/views/common/ToggleIconButton.tsx
+++ b/FrontEnd/src/views/common/ToggleIconButton.tsx
diff --git a/FrontEnd/src/app/views/common/UserTimelineLogo.tsx b/FrontEnd/src/views/common/UserTimelineLogo.tsx
index 19b9fee5..19b9fee5 100644
--- a/FrontEnd/src/app/views/common/UserTimelineLogo.tsx
+++ b/FrontEnd/src/views/common/UserTimelineLogo.tsx
diff --git a/FrontEnd/src/app/views/common/alert/AlertHost.tsx b/FrontEnd/src/views/common/alert/AlertHost.tsx
index 949be7ed..949be7ed 100644
--- a/FrontEnd/src/app/views/common/alert/AlertHost.tsx
+++ b/FrontEnd/src/views/common/alert/AlertHost.tsx
diff --git a/FrontEnd/src/app/views/common/alert/alert.sass b/FrontEnd/src/views/common/alert/alert.sass
index c3560b87..c3560b87 100644
--- a/FrontEnd/src/app/views/common/alert/alert.sass
+++ b/FrontEnd/src/views/common/alert/alert.sass
diff --git a/FrontEnd/src/views/common/button/FlatButton.css b/FrontEnd/src/views/common/button/FlatButton.css
new file mode 100644
index 00000000..522563b9
--- /dev/null
+++ b/FrontEnd/src/views/common/button/FlatButton.css
@@ -0,0 +1,48 @@
+.cru-flat-button {
+ cursor: pointer;
+ padding: 0.2em 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: transparent;
+ transition: all 0.6s;
+}
+
+.cru-flat-button:hover:not(.disabled) {
+ background-color: #e9ecef;
+}
+
+.cru-flat-button.disabled {
+ cursor: default;
+}
+
+.cru-flat-button.primary {
+ color: var(--tl-primary-color);
+}
+
+.cru-flat-button.primary.disabled {
+ color: var(--tl-primary-lighter-color);
+}
+
+.cru-flat-button.secondary {
+ color: var(--tl-secondary-color);
+}
+
+.cru-flat-button.secondary.disabled {
+ color: var(--tl-secondary-lighter-color);
+}
+
+.cru-flat-button.success {
+ color: var(--tl-success-color);
+}
+
+.cru-flat-button.success.disabled {
+ color: var(--tl-success-lighter-color);
+}
+
+.cru-flat-button.danger {
+ color: var(--tl-danger-color);
+}
+
+.cru-flat-button.danger.disabled {
+ color: var(--tl-danger-ligher-color);
+}
diff --git a/FrontEnd/src/views/common/button/FlatButton.tsx b/FrontEnd/src/views/common/button/FlatButton.tsx
new file mode 100644
index 00000000..6351971a
--- /dev/null
+++ b/FrontEnd/src/views/common/button/FlatButton.tsx
@@ -0,0 +1,41 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import classNames from "classnames";
+
+import { convertI18nText, I18nText } from "@/common";
+import { PaletteColorType } from "@/palette";
+
+import "./FlatButton.css";
+
+function _FlatButton(
+ {
+ text,
+ color,
+ onClick,
+ className,
+ style,
+ }: {
+ text: I18nText;
+ color?: PaletteColorType;
+ onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
+ className?: string;
+ style?: React.CSSProperties;
+ },
+ ref: React.ForwardedRef<HTMLButtonElement>
+): React.ReactElement | null {
+ const { t } = useTranslation();
+
+ return (
+ <button
+ ref={ref}
+ className={classNames("cru-flat-button", color ?? "primary", className)}
+ onClick={onClick}
+ style={style}
+ >
+ {convertI18nText(text, t)}
+ </button>
+ );
+}
+
+const FlatButton = React.forwardRef(_FlatButton);
+export default FlatButton;
diff --git a/FrontEnd/src/views/common/button/TextButton.css b/FrontEnd/src/views/common/button/TextButton.css
new file mode 100644
index 00000000..dc5abaaa
--- /dev/null
+++ b/FrontEnd/src/views/common/button/TextButton.css
@@ -0,0 +1,36 @@
+.cru-text-button {
+ background: transparent;
+ border: none;
+}
+
+.cru-text-button.primary {
+ color: var(--tl-primary-color);
+}
+
+.cru-text-button.primary:hover {
+ color: var(--tl-primary-lighter-color);
+}
+
+.cru-text-button.secondary {
+ color: var(--tl-secondary-color);
+}
+
+.cru-text-button.secondary:hover {
+ color: var(--tl-secondary-lighter-color);
+}
+
+.cru-text-button.success {
+ color: var(--tl-success-color);
+}
+
+.cru-text-button.success:hover {
+ color: var(--tl-success-lighter-color);
+}
+
+.cru-text-button.danger {
+ color: var(--tl-danger-color);
+}
+
+.cru-text-button.danger:hover {
+ color: var(--tl-danger-lighter-color);
+}
diff --git a/FrontEnd/src/views/common/button/TextButton.tsx b/FrontEnd/src/views/common/button/TextButton.tsx
new file mode 100644
index 00000000..1a2bac94
--- /dev/null
+++ b/FrontEnd/src/views/common/button/TextButton.tsx
@@ -0,0 +1,41 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import classNames from "classnames";
+
+import { convertI18nText, I18nText } from "@/common";
+import { PaletteColorType } from "@/palette";
+
+import "./TextButton.css";
+
+function _TextButton(
+ {
+ text,
+ color,
+ onClick,
+ className,
+ style,
+ }: {
+ text: I18nText;
+ color?: PaletteColorType;
+ onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
+ className?: string;
+ style?: React.CSSProperties;
+ },
+ ref: React.ForwardedRef<HTMLButtonElement>
+): React.ReactElement | null {
+ const { t } = useTranslation();
+
+ return (
+ <button
+ ref={ref}
+ className={classNames("cru-text-button", color ?? "primary", className)}
+ onClick={onClick}
+ style={style}
+ >
+ {convertI18nText(text, t)}
+ </button>
+ );
+}
+
+const TextButton = React.forwardRef(_TextButton);
+export default TextButton;
diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css
new file mode 100644
index 00000000..bfd82b58
--- /dev/null
+++ b/FrontEnd/src/views/common/index.css
@@ -0,0 +1,273 @@
+.image-cropper-container {
+ position: relative;
+ box-sizing: border-box;
+ user-select: none;
+}
+
+.image-cropper-container img {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.image-cropper-mask-container {
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+}
+
+.image-cropper-mask {
+ position: absolute;
+ box-shadow: 0 0 0 10000px rgba(255, 255, 255, 0.8);
+ touch-action: none;
+}
+
+.image-cropper-handler {
+ position: absolute;
+ width: 26px;
+ height: 26px;
+ border: black solid 2px;
+ border-radius: 50%;
+ background: white;
+ touch-action: none;
+}
+
+.app-bar {
+ display: flex;
+ align-items: center;
+ height: 56px;
+ position: fixed;
+ z-index: 1030;
+ top: 0;
+ left: 0;
+ right: 0;
+ background-color: var(--tl-primary-color);
+ transition: background-color 1s;
+}
+.app-bar a {
+ color: var(--tl-text-on-primary-inactive-color);
+ text-decoration: none;
+ margin: 0 1em;
+}
+.app-bar a:hover {
+ color: var(--tl-text-on-primary-color);
+}
+.app-bar a.active {
+ color: var(--tl-text-on-primary-color);
+}
+
+.app-bar-brand {
+ display: flex;
+ align-items: center;
+}
+
+.app-bar-brand-icon {
+ height: 2em;
+}
+
+.app-bar-main-area {
+ display: flex;
+ flex-grow: 1;
+}
+
+.app-bar-link-area {
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+}
+
+.app-bar-user-area {
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+ margin-left: auto;
+}
+
+.small-screen .app-bar-main-area {
+ position: absolute;
+ top: 56px;
+ left: 0;
+ right: 0;
+ transform-origin: top;
+ transition: transform 0.6s, background-color 1s;
+ background-color: var(--tl-primary-color);
+ flex-direction: column;
+}
+.small-screen .app-bar-main-area.app-bar-collapse {
+ transform: scale(1, 0);
+}
+.small-screen .app-bar-main-area a {
+ text-align: left;
+ padding: 0.5em 0.5em;
+}
+.small-screen .app-bar-link-area {
+ flex-direction: column;
+ align-items: stretch;
+}
+.small-screen .app-bar-user-area {
+ flex-direction: column;
+ align-items: stretch;
+ margin-left: unset;
+}
+.small-screen .app-bar-avatar {
+ align-self: flex-end;
+}
+
+.app-bar-toggler {
+ margin-left: auto;
+ font-size: 2em;
+ margin-right: 1em;
+ color: var(--tl-text-on-primary-color);
+ cursor: pointer;
+ user-select: none;
+}
+
+.cru-skeleton {
+ padding: 0 1em;
+}
+
+.cru-skeleton-line {
+ height: 1em;
+ background-color: #e6e6e6;
+ margin: 0.7em 0;
+ border-radius: 0.2em;
+}
+.cru-skeleton-line.last {
+ width: 50%;
+}
+
+.cru-full-page {
+ position: fixed;
+ z-index: 1031;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ background-color: white;
+ padding-top: 56px;
+}
+
+.cru-full-page-top-bar {
+ height: 56px;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 1;
+ background-color: var(--tl-primary-color);
+ display: flex;
+ align-items: center;
+}
+
+.cru-full-page-content-container {
+ overflow: scroll;
+}
+
+.cru-menu {
+ min-width: 200px;
+}
+
+.cru-menu-item {
+ font-size: 1.2em;
+ padding: 0.5em 1.5em;
+ cursor: pointer;
+}
+.cru-menu-item.color-primary {
+ color: #0d6efd;
+}
+.cru-menu-item.color-primary:hover {
+ color: white;
+ background-color: #0d6efd;
+}
+.cru-menu-item.color-secondary {
+ color: #6c757d;
+}
+.cru-menu-item.color-secondary:hover {
+ color: white;
+ background-color: #6c757d;
+}
+.cru-menu-item.color-success {
+ color: #198754;
+}
+.cru-menu-item.color-success:hover {
+ color: white;
+ background-color: #198754;
+}
+.cru-menu-item.color-info {
+ color: #0dcaf0;
+}
+.cru-menu-item.color-info:hover {
+ color: white;
+ background-color: #0dcaf0;
+}
+.cru-menu-item.color-warning {
+ color: #ffc107;
+}
+.cru-menu-item.color-warning:hover {
+ color: white;
+ background-color: #ffc107;
+}
+.cru-menu-item.color-danger {
+ color: #dc3545;
+}
+.cru-menu-item.color-danger:hover {
+ color: white;
+ background-color: #dc3545;
+}
+.cru-menu-item.color-light {
+ color: #f8f9fa;
+}
+.cru-menu-item.color-light:hover {
+ color: white;
+ background-color: #f8f9fa;
+}
+.cru-menu-item.color-dark {
+ color: #212529;
+}
+.cru-menu-item.color-dark:hover {
+ color: white;
+ background-color: #212529;
+}
+
+.cru-menu-item-icon {
+ margin-right: 1em;
+}
+
+.cru-menu-divider {
+ border-top: 1px solid #e9ecef;
+}
+
+.cru-tab-pages-action-area {
+ display: flex;
+ align-items: center;
+}
+
+.cru-search-input {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.alert-container {
+ position: fixed;
+ z-index: 1070;
+}
+
+@media (min-width: 576px) {
+ .alert-container {
+ bottom: 0;
+ right: 0;
+ }
+}
+@media (max-width: 575.98px) {
+ .alert-container {
+ bottom: 0;
+ right: 0;
+ left: 0;
+ text-align: center;
+ }
+}
diff --git a/FrontEnd/src/app/views/common/user/UserAvatar.tsx b/FrontEnd/src/views/common/user/UserAvatar.tsx
index 9e822528..9e822528 100644
--- a/FrontEnd/src/app/views/common/user/UserAvatar.tsx
+++ b/FrontEnd/src/views/common/user/UserAvatar.tsx
diff --git a/FrontEnd/src/app/views/home/TimelineListView.tsx b/FrontEnd/src/views/home/TimelineListView.tsx
index 95c3c367..2fb54820 100644
--- a/FrontEnd/src/app/views/home/TimelineListView.tsx
+++ b/FrontEnd/src/views/home/TimelineListView.tsx
@@ -13,7 +13,7 @@ interface TimelineListItemProps {
const TimelineListItem: React.FC<TimelineListItemProps> = ({ timeline }) => {
const url = React.useMemo(
() =>
- timeline.name.startsWith("@")
+ timeline.name.startsWith("src")
? `/users/${timeline.owner.username}`
: `/timelines/${timeline.name}`,
[timeline]
diff --git a/FrontEnd/src/app/views/home/WebsiteIntroduction.tsx b/FrontEnd/src/views/home/WebsiteIntroduction.tsx
index aea7b4b2..aea7b4b2 100644
--- a/FrontEnd/src/app/views/home/WebsiteIntroduction.tsx
+++ b/FrontEnd/src/views/home/WebsiteIntroduction.tsx
diff --git a/FrontEnd/src/views/home/index.css b/FrontEnd/src/views/home/index.css
new file mode 100644
index 00000000..516aba52
--- /dev/null
+++ b/FrontEnd/src/views/home/index.css
@@ -0,0 +1,73 @@
+.timeline-board {
+ min-height: 200px;
+ height: 100%;
+ position: relative;
+}
+
+.timeline-board-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.timeline-board-item {
+ font-size: 1.1em;
+ height: 48px;
+ transition: background 0.3s;
+ display: flex;
+ align-items: center;
+}
+.timeline-board-item .icon {
+ height: 1.3em;
+ color: black;
+}
+.timeline-board-item:hover {
+ background: #dee2e6;
+}
+.timeline-board-item .right {
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+}
+.timeline-board-item .title {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.home-timeline-list-item {
+ display: flex;
+ align-items: center;
+}
+
+.home-timeline-list-item-timeline {
+ transition: background 0.8s;
+ animation: 0.8s home-timeline-list-item-timeline-enter;
+}
+.home-timeline-list-item-timeline:hover {
+ background: #e9ecef;
+}
+
+@keyframes home-timeline-list-item-timeline-enter {
+ from {
+ transform: translate(-100%, 0);
+ opacity: 0;
+ }
+}
+.home-timeline-list-item-line {
+ width: 80px;
+ flex-shrink: 0;
+}
+
+@keyframes home-timeline-list-loading-head-animation {
+ from {
+ transform: translate(0, -30px);
+ opacity: 1;
+ }
+ to {
+ opacity: 0;
+ }
+}
+.home-timeline-list-loading-head {
+ animation: 1s infinite home-timeline-list-loading-head-animation;
+}
diff --git a/FrontEnd/src/app/views/home/index.tsx b/FrontEnd/src/views/home/index.tsx
index 0eca23ee..ddb72e76 100644
--- a/FrontEnd/src/app/views/home/index.tsx
+++ b/FrontEnd/src/views/home/index.tsx
@@ -8,6 +8,8 @@ import SearchInput from "../common/SearchInput";
import TimelineListView from "./TimelineListView";
import WebsiteIntroduction from "./WebsiteIntroduction";
+import "./index.css";
+
const highlightTimelineMessageMap = {
loading: "home.loadingHighlightTimelines",
done: "home.loadedHighlightTimelines",
diff --git a/FrontEnd/src/views/login/index.css b/FrontEnd/src/views/login/index.css
new file mode 100644
index 00000000..dca7054d
--- /dev/null
+++ b/FrontEnd/src/views/login/index.css
@@ -0,0 +1,3 @@
+.login-container {
+ max-width: 600px;
+}
diff --git a/FrontEnd/src/app/views/login/index.tsx b/FrontEnd/src/views/login/index.tsx
index 6adcef39..a39a9972 100644
--- a/FrontEnd/src/app/views/login/index.tsx
+++ b/FrontEnd/src/views/login/index.tsx
@@ -8,6 +8,8 @@ import { useUser, userService } from "@/services/user";
import AppBar from "../common/AppBar";
import LoadingButton from "../common/LoadingButton";
+import "./index.css";
+
const LoginPage: React.FC = (_) => {
const { t } = useTranslation();
const history = useHistory();
diff --git a/FrontEnd/src/views/search/index.css b/FrontEnd/src/views/search/index.css
new file mode 100644
index 00000000..6ff4d9fa
--- /dev/null
+++ b/FrontEnd/src/views/search/index.css
@@ -0,0 +1,15 @@
+.timeline-search-result-item {
+ border: 1px solid;
+ border-color: #e9ecef;
+ background: #f8f9fa;
+ transition: all 0.3s;
+}
+.timeline-search-result-item:hover {
+ border-color: #0d6efd;
+}
+
+.timeline-search-result-item-avatar {
+ width: 2em;
+ height: 2em;
+ border-radius: 50%;
+}
diff --git a/FrontEnd/src/app/views/search/index.tsx b/FrontEnd/src/views/search/index.tsx
index 966ca666..f5018c3e 100644
--- a/FrontEnd/src/app/views/search/index.tsx
+++ b/FrontEnd/src/views/search/index.tsx
@@ -11,10 +11,12 @@ import { HttpTimelineInfo } from "@/http/timeline";
import SearchInput from "../common/SearchInput";
import UserAvatar from "../common/user/UserAvatar";
+import "./index.css";
+
const TimelineSearchResultItemView: React.FC<{
timeline: HttpTimelineInfo;
}> = ({ timeline }) => {
- const link = timeline.name.startsWith("@")
+ const link = timeline.name.startsWith("src")
? `users/${timeline.owner.username}`
: `timelines/${timeline.name}`;
@@ -33,7 +35,7 @@ const TimelineSearchResultItemView: React.FC<{
/>
{timeline.owner.nickname}
<small className="ms-3 text-secondary">
- @{timeline.owner.username}
+ src{timeline.owner.username}
</small>
</div>
</div>
diff --git a/FrontEnd/src/app/views/settings/ChangeAvatarDialog.tsx b/FrontEnd/src/views/settings/ChangeAvatarDialog.tsx
index c4f6f492..c4f6f492 100644
--- a/FrontEnd/src/app/views/settings/ChangeAvatarDialog.tsx
+++ b/FrontEnd/src/views/settings/ChangeAvatarDialog.tsx
diff --git a/FrontEnd/src/app/views/settings/ChangeNicknameDialog.tsx b/FrontEnd/src/views/settings/ChangeNicknameDialog.tsx
index 4b44cdd6..4b44cdd6 100644
--- a/FrontEnd/src/app/views/settings/ChangeNicknameDialog.tsx
+++ b/FrontEnd/src/views/settings/ChangeNicknameDialog.tsx
diff --git a/FrontEnd/src/app/views/settings/ChangePasswordDialog.tsx b/FrontEnd/src/views/settings/ChangePasswordDialog.tsx
index 21eeeb09..21eeeb09 100644
--- a/FrontEnd/src/app/views/settings/ChangePasswordDialog.tsx
+++ b/FrontEnd/src/views/settings/ChangePasswordDialog.tsx
diff --git a/FrontEnd/src/views/settings/index.css b/FrontEnd/src/views/settings/index.css
new file mode 100644
index 00000000..566d501b
--- /dev/null
+++ b/FrontEnd/src/views/settings/index.css
@@ -0,0 +1,24 @@
+.change-avatar-cropper-row {
+ max-height: 400px;
+}
+
+.change-avatar-img {
+ min-width: 50%;
+ max-width: 100%;
+ max-height: 400px;
+}
+
+.settings-item {
+ padding: 0.5em 1em;
+ transition: background 0.3s;
+ border-bottom: 1px solid #e9ecef;
+}
+.settings-item.first {
+ border-top: 1px solid #e9ecef;
+}
+.settings-item.clickable {
+ cursor: pointer;
+}
+.settings-item:hover {
+ background: #dee2e6;
+}
diff --git a/FrontEnd/src/app/views/settings/index.tsx b/FrontEnd/src/views/settings/index.tsx
index 04a2777a..840bb7e8 100644
--- a/FrontEnd/src/app/views/settings/index.tsx
+++ b/FrontEnd/src/views/settings/index.tsx
@@ -8,6 +8,9 @@ import { useUser, userService } from "@/services/user";
import ChangePasswordDialog from "./ChangePasswordDialog";
import ChangeAvatarDialog from "./ChangeAvatarDialog";
import ChangeNicknameDialog from "./ChangeNicknameDialog";
+import Card from "../common/Card";
+
+import "./index.css";
const ConfirmLogoutDialog: React.FC<{
onClose: () => void;
@@ -50,7 +53,7 @@ const SettingsPage: React.FC = (_) => {
<>
<Container>
{user ? (
- <div className="cru-card my-3 py-3">
+ <Card className="my-3 py-3">
<h3 className="px-3 mb-3 text-primary">
{t("settings.subheaders.account")}
</h3>
@@ -80,9 +83,9 @@ const SettingsPage: React.FC = (_) => {
>
{t("settings.logout")}
</div>
- </div>
+ </Card>
) : null}
- <div className="cru-card my-3 py-3">
+ <Card className="my-3 py-3">
<h3 className="px-3 mb-3 text-primary">
{t("settings.subheaders.customization")}
</h3>
@@ -106,7 +109,7 @@ const SettingsPage: React.FC = (_) => {
</Form.Control>
</Col>
</Row>
- </div>
+ </Card>
</Container>
{(() => {
switch (dialog) {
diff --git a/FrontEnd/src/app/views/timeline-common/CollapseButton.tsx b/FrontEnd/src/views/timeline-common/CollapseButton.tsx
index 12a3b710..12a3b710 100644
--- a/FrontEnd/src/app/views/timeline-common/CollapseButton.tsx
+++ b/FrontEnd/src/views/timeline-common/CollapseButton.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/ConnectionStatusBadge.tsx b/FrontEnd/src/views/timeline-common/ConnectionStatusBadge.tsx
index df43d8d2..df43d8d2 100644
--- a/FrontEnd/src/app/views/timeline-common/ConnectionStatusBadge.tsx
+++ b/FrontEnd/src/views/timeline-common/ConnectionStatusBadge.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/MarkdownPostEdit.tsx b/FrontEnd/src/views/timeline-common/MarkdownPostEdit.tsx
index 685e17be..005da933 100644
--- a/FrontEnd/src/app/views/timeline-common/MarkdownPostEdit.tsx
+++ b/FrontEnd/src/views/timeline-common/MarkdownPostEdit.tsx
@@ -6,7 +6,7 @@ import { Prompt } from "react-router";
import { getHttpTimelineClient, HttpTimelinePostInfo } from "@/http/timeline";
-import FlatButton from "../common/FlatButton";
+import FlatButton from "../common/button/FlatButton";
import TabPages from "../common/TabPages";
import TimelinePostBuilder from "@/services/TimelinePostBuilder";
import ConfirmDialog from "../common/ConfirmDialog";
@@ -106,8 +106,9 @@ const MarkdownPostEdit: React.FC<MarkdownPostEditProps> = ({
) : (
<>
<FlatButton
+ text="operationDialog.cancel"
className="me-2"
- variant="danger"
+ color="danger"
onClick={() => {
if (canLeave) {
onClose();
@@ -115,12 +116,8 @@ const MarkdownPostEdit: React.FC<MarkdownPostEditProps> = ({
setShowLeaveConfirmDialog(true);
}
}}
- >
- {t("operationDialog.cancel")}
- </FlatButton>
- <FlatButton onClick={send} disabled={!canSend}>
- {t("timeline.send")}
- </FlatButton>
+ />
+ {canSend && <FlatButton text="timeline.send" onClick={send} />}
</>
)
}
diff --git a/FrontEnd/src/app/views/timeline-common/PostPropertyChangeDialog.tsx b/FrontEnd/src/views/timeline-common/PostPropertyChangeDialog.tsx
index 001e52d7..001e52d7 100644
--- a/FrontEnd/src/app/views/timeline-common/PostPropertyChangeDialog.tsx
+++ b/FrontEnd/src/views/timeline-common/PostPropertyChangeDialog.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/Timeline.tsx b/FrontEnd/src/views/timeline-common/Timeline.tsx
index 589382b0..21daa5e2 100644
--- a/FrontEnd/src/app/views/timeline-common/Timeline.tsx
+++ b/FrontEnd/src/views/timeline-common/Timeline.tsx
@@ -14,6 +14,8 @@ import TimelinePagedPostListView from "./TimelinePagedPostListView";
import TimelineTop from "./TimelineTop";
import TimelineLoading from "./TimelineLoading";
+import "./index.css";
+
export interface TimelineProps {
className?: string;
style?: React.CSSProperties;
diff --git a/FrontEnd/src/app/views/timeline-common/TimelineDateLabel.tsx b/FrontEnd/src/views/timeline-common/TimelineDateLabel.tsx
index 80968ee2..80968ee2 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelineDateLabel.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelineDateLabel.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/TimelineLine.tsx b/FrontEnd/src/views/timeline-common/TimelineLine.tsx
index 0a828b32..0a828b32 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelineLine.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelineLine.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/TimelineLoading.tsx b/FrontEnd/src/views/timeline-common/TimelineLoading.tsx
index fc42f4b4..fc42f4b4 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelineLoading.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelineLoading.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/TimelineMember.tsx b/FrontEnd/src/views/timeline-common/TimelineMember.tsx
index 299d6a53..1ef085a7 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelineMember.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelineMember.tsx
@@ -27,7 +27,7 @@ const TimelineMemberItem: React.FC<{
<Col>
<Row>{user.nickname}</Row>
<Row>
- <small>{"@" + user.username}</small>
+ <small>{"src" + user.username}</small>
</Row>
</Col>
{onAction ? (
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageCardTemplate.tsx b/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx
index 623d643f..851dfa55 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePageCardTemplate.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePageCardTemplate.tsx
@@ -19,6 +19,7 @@ import TimelinePropertyChangeDialog from "./TimelinePropertyChangeDialog";
import ConnectionStatusBadge from "./ConnectionStatusBadge";
import { MenuItems, PopupMenu } from "../common/Menu";
import FullPage from "../common/FullPage";
+import Card from "../common/Card";
export interface TimelineCardTemplateProps extends TimelinePageCardProps {
infoArea: React.ReactElement;
@@ -110,8 +111,8 @@ const TimelinePageCardTemplate: React.FC<TimelineCardTemplateProps> = ({
return (
<>
- <div
- className={classnames("cru-card p-2 clearfix", className)}
+ <Card
+ className={classnames("p-2 clearfix", className)}
style={{ zIndex: collapse ? 1029 : 1031 }}
>
<div className="float-end d-flex align-items-center">
@@ -129,7 +130,7 @@ const TimelinePageCardTemplate: React.FC<TimelineCardTemplateProps> = ({
) : (
<div style={{ display: collapse ? "none" : "block" }}>{content}</div>
)}
- </div>
+ </Card>
{(() => {
if (dialog === "member") {
return (
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx b/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx
index 658ce502..658ce502 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePageTemplate.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePageTemplate.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePagedPostListView.tsx b/FrontEnd/src/views/timeline-common/TimelinePagedPostListView.tsx
index 37f02a82..37f02a82 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePagedPostListView.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePagedPostListView.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePostContentView.tsx b/FrontEnd/src/views/timeline-common/TimelinePostContentView.tsx
index 607b72c9..607b72c9 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePostContentView.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePostContentView.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx b/FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx
index b2c7a470..b2c7a470 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePostDeleteConfirmDialog.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx
index 5f3f0345..1f9f02a5 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePostEdit.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePostEdit.tsx
@@ -138,7 +138,7 @@ const TimelinePostEdit: React.FC<TimelinePostEditProps> = (props) => {
(kind === "text" && text.length !== 0) ||
(kind === "image" && image != null);
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ // eslint-disable-next-line srctypescript-eslint/no-non-null-assertion
const containerRef = React.useRef<HTMLDivElement>(null!);
const notifyHeightChange = (): void => {
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePostListView.tsx b/FrontEnd/src/views/timeline-common/TimelinePostListView.tsx
index ba204b72..ba204b72 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePostListView.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePostListView.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePostView.tsx b/FrontEnd/src/views/timeline-common/TimelinePostView.tsx
index f7b81478..ea40f80a 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePostView.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePostView.tsx
@@ -1,13 +1,14 @@
import React from "react";
import classnames from "classnames";
import { Link } from "react-router-dom";
-import { useTranslation } from "react-i18next";
import { getHttpTimelineClient, HttpTimelinePostInfo } from "@/http/timeline";
import { pushAlert } from "@/services/alert";
import UserAvatar from "../common/user/UserAvatar";
+import Card from "../common/Card";
+import FlatButton from "../common/button/FlatButton";
import TimelineLine from "./TimelineLine";
import TimelinePostContentView from "./TimelinePostContentView";
import TimelinePostDeleteConfirmDialog from "./TimelinePostDeleteConfirmDialog";
@@ -27,8 +28,6 @@ const TimelinePostView: React.FC<TimelinePostViewProps> = (props) => {
const { post, className, style, cardStyle, onChanged, onDeleted } = props;
const current = props.current === true;
- const { t } = useTranslation();
-
const [operationMaskVisible, setOperationMaskVisible] =
React.useState<boolean>(false);
const [dialog, setDialog] = React.useState<
@@ -60,7 +59,7 @@ const TimelinePostView: React.FC<TimelinePostViewProps> = (props) => {
style={style}
>
<TimelineLine center="node" current={current} />
- <div ref={cardRef} className="timeline-item-card" style={cardStyle}>
+ <Card ref={cardRef} className="timeline-item-card" style={cardStyle}>
{post.editable ? (
<i
className="bi-chevron-down text-info icon-button float-end"
@@ -91,32 +90,29 @@ const TimelinePostView: React.FC<TimelinePostViewProps> = (props) => {
</div>
{operationMaskVisible ? (
<div
- className="position-absolute position-lt w-100 h-100 mask d-flex justify-content-around align-items-center"
+ className="timeline-post-item-options-mask d-flex justify-content-around align-items-center"
onClick={() => {
setOperationMaskVisible(false);
}}
>
- <span
- className="tl-color-primary"
+ <FlatButton
+ text="changeProperty"
onClick={(e) => {
setDialog("changeproperty");
e.stopPropagation();
}}
- >
- {t("changeProperty")}
- </span>
- <span
- className="tl-color-danger"
+ />
+ <FlatButton
+ text="delete"
+ color="danger"
onClick={(e) => {
setDialog("delete");
e.stopPropagation();
}}
- >
- {t("delete")}
- </span>
+ />
</div>
) : null}
- </div>
+ </Card>
{dialog === "delete" ? (
<TimelinePostDeleteConfirmDialog
onClose={() => {
diff --git a/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx b/FrontEnd/src/views/timeline-common/TimelinePropertyChangeDialog.tsx
index 70f72025..70f72025 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelinePropertyChangeDialog.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelinePropertyChangeDialog.tsx
diff --git a/FrontEnd/src/app/views/timeline-common/TimelineTop.tsx b/FrontEnd/src/views/timeline-common/TimelineTop.tsx
index dabbdf1e..dabbdf1e 100644
--- a/FrontEnd/src/app/views/timeline-common/TimelineTop.tsx
+++ b/FrontEnd/src/views/timeline-common/TimelineTop.tsx
diff --git a/FrontEnd/src/views/timeline-common/index.css b/FrontEnd/src/views/timeline-common/index.css
new file mode 100644
index 00000000..1cad2fb2
--- /dev/null
+++ b/FrontEnd/src/views/timeline-common/index.css
@@ -0,0 +1,296 @@
+.timeline {
+ z-index: 0;
+ position: relative;
+ width: 100%;
+ overflow-wrap: break-word;
+ animation: 1s timeline-enter;
+}
+
+@keyframes timeline-line-node-noncurrent {
+ to {
+ box-shadow: 0 0 20px 3px var(--tl-primary-lighter-color);
+ }
+}
+@keyframes timeline-line-node-current {
+ to {
+ box-shadow: 0 0 20px 3px var(--tl-primary-enhance-lighter-color);
+ }
+}
+@keyframes timeline-line-node-loading {
+ to {
+ box-shadow: 0 0 20px 3px var(--tl-primary-lighter-color);
+ }
+}
+@keyframes timeline-line-node-loading-edge {
+ from {
+ transform: rotate(0turn);
+ }
+ to {
+ transform: rotate(1turn);
+ }
+}
+@keyframes timeline-enter {
+ from {
+ transform: translate(0, -100vh);
+ }
+}
+@keyframes timeline-top-loading-enter {
+ from {
+ transform: translate(0, -100%);
+ }
+}
+@keyframes timeline-post-enter {
+ from {
+ transform: translate(0, -100%);
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+.timeline-top-loading-enter {
+ animation: 1s timeline-top-loading-enter;
+}
+
+.timeline-line {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 30px;
+ position: absolute;
+ z-index: 1;
+ left: 2em;
+ top: 0;
+ bottom: 0;
+ transition: left 0.5s;
+}
+@media (max-width: 575.98px) {
+ .timeline-line {
+ left: 1em;
+ }
+}
+.timeline-line .segment {
+ width: 7px;
+ background: var(--tl-primary-color);
+}
+.timeline-line .segment.start {
+ height: 1.8em;
+ flex: 0 0 auto;
+}
+.timeline-line .segment.end {
+ flex: 1 1 auto;
+}
+.timeline-line .segment.current-end {
+ height: 2em;
+ flex: 0 0 auto;
+ background: linear-gradient(var(--tl-primary-enhance-color), white);
+}
+.timeline-line .node-container {
+ flex: 0 0 auto;
+ position: relative;
+ width: 18px;
+ height: 18px;
+}
+.timeline-line .node {
+ width: 20px;
+ height: 20px;
+ position: absolute;
+ background: var(--tl-primary-color);
+ left: -1px;
+ top: -1px;
+ border-radius: 50%;
+ box-sizing: border-box;
+ z-index: 1;
+ animation: 1s infinite alternate;
+ animation-name: timeline-line-node-noncurrent;
+}
+.timeline-line .node-loading-edge {
+ color: var(--tl-primary-color);
+ width: 38px;
+ height: 38px;
+ position: absolute;
+ left: -10px;
+ top: -10px;
+ box-sizing: border-box;
+ z-index: 2;
+ animation: 1.5s linear infinite timeline-line-node-loading-edge;
+}
+.timeline-line.current .segment.start {
+ background: linear-gradient(
+ var(--tl-primary-color),
+ var(--tl-primary-enhance-color)
+ );
+}
+.timeline-line.current .segment.end {
+ background: var(--tl-primary-enhance-color);
+}
+.timeline-line.current .node {
+ background: var(--tl-primary-enhance-color);
+ animation-name: timeline-line-node-current;
+}
+.timeline-line.loading .node {
+ background: var(--tl-primary-color);
+ animation-name: timeline-line-node-loading;
+}
+
+.timeline-item.current {
+ padding-bottom: 2.5em;
+}
+
+.timeline-top {
+ position: relative;
+ text-align: right;
+}
+
+.timeline-item {
+ position: relative;
+ padding: 0.5em;
+}
+
+.timeline-item-card {
+ position: relative;
+ padding: 0.3em 0.5em 1em 4em;
+ transition: background 0.5s, padding-left 0.5s;
+ animation: 0.6s forwards;
+ opacity: 0;
+}
+
+@media (max-width: 575.98px) {
+ .timeline-item-card {
+ padding-left: 3em;
+ }
+}
+
+.timeline-item-header {
+ display: flex;
+ align-items: center;
+}
+
+.timeline-avatar {
+ border-radius: 50%;
+ width: 2em;
+ height: 2em;
+}
+
+.timeline-item-delete-button {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+}
+
+.timeline-content {
+ white-space: pre-line;
+}
+
+.timeline-content-image {
+ max-width: 80%;
+ max-height: 200px;
+}
+
+.timeline-date-item {
+ position: relative;
+ padding: 0.3em 0 0.3em 4em;
+}
+
+.timeline-date-item-badge {
+ display: inline-block;
+ padding: 0.1em 0.4em;
+ border-radius: 0.4em;
+ background: #7c7c7c;
+ color: white;
+ font-size: 0.8em;
+}
+
+.timeline-post-edit-image {
+ max-width: 100px;
+ max-height: 100px;
+}
+
+.timeline-post-item-options-mask {
+ background: rgba(255, 255, 255, 0.8);
+ z-index: 100;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+}
+
+.timeline-sync-state-badge {
+ font-size: 0.8em;
+ padding: 3px 8px;
+ border-radius: 5px;
+ background: #e8fbff;
+}
+
+.timeline-sync-state-badge-pin {
+ display: inline-block;
+ width: 0.4em;
+ height: 0.4em;
+ border-radius: 50%;
+ vertical-align: middle;
+ margin-right: 0.6em;
+}
+
+.timeline-template-card {
+ position: fixed;
+ z-index: 1031;
+ top: 56px;
+ right: 0;
+ margin: 0.5em;
+}
+
+.timeline-markdown-post-edit-page {
+ overflow: scroll;
+ max-height: 300px;
+}
+
+.timeline-markdown-post-edit-image-container {
+ position: relative;
+ text-align: center;
+ margin-bottom: 1em;
+}
+
+.timeline-markdown-post-edit-image {
+ max-width: 100%;
+ max-height: 200px;
+}
+
+.timeline-markdown-post-edit-image-delete-button {
+ position: absolute;
+ right: 10px;
+ top: 2px;
+}
+
+.connection-status-badge {
+ font-size: 0.8em;
+ border-radius: 5px;
+ padding: 0.1em 1em;
+ background-color: #eaf2ff;
+}
+.connection-status-badge::before {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ display: inline-block;
+ content: "";
+ margin-right: 0.6em;
+}
+.connection-status-badge.success {
+ color: #006100;
+}
+.connection-status-badge.success::before {
+ background-color: #006100;
+}
+.connection-status-badge.warning {
+ color: #e4a700;
+}
+.connection-status-badge.warning::before {
+ background-color: #e4a700;
+}
+.connection-status-badge.danger {
+ color: #fd1616;
+}
+.connection-status-badge.danger::before {
+ background-color: #fd1616;
+}
diff --git a/FrontEnd/src/app/views/timeline/TimelineCard.tsx b/FrontEnd/src/views/timeline/TimelineCard.tsx
index e031b565..86063843 100644
--- a/FrontEnd/src/app/views/timeline/TimelineCard.tsx
+++ b/FrontEnd/src/views/timeline/TimelineCard.tsx
@@ -29,7 +29,7 @@ const TimelineCard: React.FC<TimelinePageCardProps> = (props) => {
/>
{timeline.owner.nickname}
<small className="ms-3 text-secondary">
- @{timeline.owner.username}
+ src{timeline.owner.username}
</small>
</div>
</>
diff --git a/FrontEnd/src/app/views/timeline/TimelineDeleteDialog.tsx b/FrontEnd/src/views/timeline/TimelineDeleteDialog.tsx
index dbca62ca..dbca62ca 100644
--- a/FrontEnd/src/app/views/timeline/TimelineDeleteDialog.tsx
+++ b/FrontEnd/src/views/timeline/TimelineDeleteDialog.tsx
diff --git a/FrontEnd/src/app/views/timeline/index.tsx b/FrontEnd/src/views/timeline/index.tsx
index c5bfd7ab..c5bfd7ab 100644
--- a/FrontEnd/src/app/views/timeline/index.tsx
+++ b/FrontEnd/src/views/timeline/index.tsx
diff --git a/FrontEnd/src/app/views/user/UserCard.tsx b/FrontEnd/src/views/user/UserCard.tsx
index e7e4252e..e7e4252e 100644
--- a/FrontEnd/src/app/views/user/UserCard.tsx
+++ b/FrontEnd/src/views/user/UserCard.tsx
diff --git a/FrontEnd/src/views/user/index.css b/FrontEnd/src/views/user/index.css
new file mode 100644
index 00000000..35f01d38
--- /dev/null
+++ b/FrontEnd/src/views/user/index.css
@@ -0,0 +1,9 @@
+.change-avatar-cropper-row {
+ max-height: 400px;
+}
+
+.change-avatar-img {
+ min-width: 50%;
+ max-width: 100%;
+ max-height: 400px;
+}
diff --git a/FrontEnd/src/app/views/user/index.tsx b/FrontEnd/src/views/user/index.tsx
index 57454d0d..1f2fe9ed 100644
--- a/FrontEnd/src/app/views/user/index.tsx
+++ b/FrontEnd/src/views/user/index.tsx
@@ -4,6 +4,8 @@ import { useParams } from "react-router";
import TimelinePageTemplate from "../timeline-common/TimelinePageTemplate";
import UserCard from "./UserCard";
+import "./index.css";
+
const UserPage: React.FC = () => {
const { username } = useParams<{ username: string }>();
@@ -14,7 +16,7 @@ const UserPage: React.FC = () => {
return (
<>
<TimelinePageTemplate
- timelineName={`@${username}`}
+ timelineName={`src${username}`}
notFoundI18nKey="timeline.userNotExist"
reloadKey={reloadKey}
onReload={() => setReloadKey(reloadKey + 1)}
diff --git a/FrontEnd/src/tsconfig.json b/FrontEnd/tsconfig.json
index 21989043..6b691e0e 100644
--- a/FrontEnd/src/tsconfig.json
+++ b/FrontEnd/tsconfig.json
@@ -1,21 +1,22 @@
{
"compilerOptions": {
- "target": "ES6",
- "allowJs": true,
+ "target": "ESNext",
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
"skipLibCheck": true,
- "esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
- "module": "esnext",
- "moduleResolution": "node",
+ "module": "ESNext",
+ "moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react",
- "sourceMap": true,
+ "noEmit": true,
+ "types": ["vite/client"],
"baseUrl": "./",
"paths": {
- "@/*": ["app/*"]
+ "@/*": ["src/*"]
}
- }
+ },
+ "include": ["./src"]
}
diff --git a/FrontEnd/vite.config.js b/FrontEnd/vite.config.js
new file mode 100644
index 00000000..ee6f6931
--- /dev/null
+++ b/FrontEnd/vite.config.js
@@ -0,0 +1,33 @@
+/**
+ * @type {import('vite').UserConfig}
+ */
+
+import reactRefresh from "@vitejs/plugin-react-refresh";
+import { VitePWA } from "vite-plugin-pwa";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ plugins: [
+ reactRefresh(),
+ VitePWA({
+ strategies: "injectManifest",
+ srcDir: "src",
+ filename: "sw.ts",
+ base: "/",
+ manifest: false,
+ includeAssets: "**",
+ }),
+ ],
+ resolve: {
+ alias: [{ find: "@", replacement: "/src" }],
+ },
+ server: {
+ port: 13000,
+ proxy: {
+ "/api": {
+ target: "http://localhost:5000",
+ changeOrigin: true,
+ },
+ },
+ },
+});
diff --git a/FrontEnd/webpack.common.js b/FrontEnd/webpack.common.js
deleted file mode 100644
index 94cdf694..00000000
--- a/FrontEnd/webpack.common.js
+++ /dev/null
@@ -1,73 +0,0 @@
-const path = require("path");
-const HtmlWebpackPlugin = require("html-webpack-plugin");
-const Config = require("webpack-chain");
-
-const config = new Config();
-
-config.entry("index").add(path.resolve(__dirname, "src/app/index.tsx"));
-
-config.module
- .rule("jsts")
- .test(/\.[jt]sx?$/)
- .exclude.add(/node_modules/)
- .end()
- .use("ts")
- .loader("ts-loader")
- .end();
-
-config.module
- .rule("css")
- .test(/\.css$/)
- .use("css")
- .loader("css-loader")
- .end()
- .use("postcss")
- .loader("postcss-loader")
- .end();
-
-config.module
- .rule("sass")
- .test(/\.(scss|sass)$/)
- .use("css")
- .loader("css-loader")
- .end()
- .use("postcss")
- .loader("postcss-loader")
- .end()
- .use("sass")
- .loader("sass-loader")
- .end();
-
-config.module
- .rule("file")
- .test(/\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot)$/i)
- .use("url")
- .loader("url-loader")
- .options({
- limit: 8192,
- });
-
-config.resolve.extensions
- .add("*")
- .add(".js")
- .add(".jsx")
- .add(".ts")
- .add(".tsx")
- .end();
-
-config.resolve.alias.set("@", path.resolve(__dirname, "src/app"));
-
-config.output
- .path(path.resolve(__dirname, "dist/"))
- .filename("[name].[contenthash].js")
- .chunkFilename("[name].[contenthash].js")
- .publicPath("/");
-
-config.plugin("html").use(HtmlWebpackPlugin, [
- {
- template: "src/app/index.ejs",
- title: "Timeline",
- },
-]);
-
-module.exports = config;
diff --git a/FrontEnd/webpack.config.dev.js b/FrontEnd/webpack.config.dev.js
deleted file mode 100644
index 4c6031c7..00000000
--- a/FrontEnd/webpack.config.dev.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const path = require("path");
-const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
-const ReactRefreshTypeScript = require("react-refresh-typescript");
-
-const config = require("./webpack.common");
-
-config.mode("development");
-
-config.module
- .rule("jsts")
- .use("ts")
- .options({
- getCustomTransformers: () => ({
- before: [ReactRefreshTypeScript()],
- }),
- });
-
-config.module
- .rule("css")
- .use("style")
- .before("css")
- .loader("style-loader")
- .end();
-
-config.module
- .rule("sass")
- .use("style")
- .before("css")
- .loader("style-loader")
- .end();
-
-config.devtool("eval-cheap-module-source-map");
-
-config.devServer.port(3000).historyApiFallback(true).hot(true);
-
-config.plugin("react-refresh").use(new ReactRefreshWebpackPlugin());
-
-module.exports = config.toConfig();
diff --git a/FrontEnd/webpack.config.prod.js b/FrontEnd/webpack.config.prod.js
deleted file mode 100644
index 188cb940..00000000
--- a/FrontEnd/webpack.config.prod.js
+++ /dev/null
@@ -1,53 +0,0 @@
-const path = require("path");
-const { CleanWebpackPlugin } = require("clean-webpack-plugin");
-const CopyPlugin = require("copy-webpack-plugin");
-const WorkboxPlugin = require("workbox-webpack-plugin");
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
-
-const config = require("./webpack.common");
-
-config.mode("production");
-
-config
- .entry("index")
- .add(path.resolve(__dirname, "src/app/service-worker.tsx"));
-
-config.module
- .rule("css")
- .use("mini-css-extract")
- .before("css")
- .loader(MiniCssExtractPlugin.loader)
- .end();
-
-config.module
- .rule("sass")
- .use("mini-css-extract")
- .before("css")
- .loader(MiniCssExtractPlugin.loader)
- .end();
-
-config.devtool("source-map");
-
-config.plugin("mini-css-extract").use(MiniCssExtractPlugin);
-
-config.plugin("clean").use(CleanWebpackPlugin);
-
-config.plugin("copy").use(CopyPlugin, [
- {
- patterns: [
- {
- from: path.resolve(__dirname, "public/"),
- to: path.resolve(__dirname, "dist/"),
- },
- ],
- },
-]);
-
-config.plugin("workbox").use(WorkboxPlugin.InjectManifest, [
- {
- swSrc: path.resolve(__dirname, "src/sw/sw.ts"),
- maximumFileSizeToCacheInBytes: 15000000,
- },
-]);
-
-module.exports = config.toConfig();