From da7ffc93435bf07a8315698b5814e7bf3e3ec08b Mon Sep 17 00:00:00 2001 From: coward Date: Mon, 15 Jul 2024 16:47:53 +0800 Subject: [PATCH] =?UTF-8?q?:art:=E6=9B=B4=E6=8D=A2web=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web | 1 - web/.editorconfig | 9 + web/.env.development | 12 + web/.env.production | 10 + web/.eslint-global-variables.json | 63 ++++ web/.npmrc | 3 + web/LICENSE | 21 ++ web/README.md | 89 +++++ web/build/index.js | 39 +++ web/build/plugin-isme/icons.js | 25 ++ web/build/plugin-isme/index.js | 10 + web/build/plugin-isme/page-pathes.js | 25 ++ web/eslint.config.js | 34 ++ web/index.html | 94 ++++++ web/jsconfig.json | 14 + web/package.json | 60 ++++ web/public/favicon.png | Bin 0 -> 3859 bytes web/src/App.vue | 63 ++++ web/src/api/index.js | 24 ++ web/src/assets/icons/dynamic-icons.js | 10 + web/src/assets/icons/feather/activity.svg | 1 + web/src/assets/icons/feather/airplay.svg | 1 + web/src/assets/icons/feather/alert-circle.svg | 1 + .../assets/icons/feather/alert-octagon.svg | 1 + .../assets/icons/feather/alert-triangle.svg | 1 + web/src/assets/icons/feather/align-center.svg | 1 + .../assets/icons/feather/align-justify.svg | 1 + web/src/assets/icons/feather/align-left.svg | 1 + web/src/assets/icons/feather/align-right.svg | 1 + web/src/assets/icons/feather/anchor.svg | 1 + web/src/assets/icons/feather/aperture.svg | 1 + web/src/assets/icons/feather/archive.svg | 1 + .../icons/feather/arrow-down-circle.svg | 1 + .../assets/icons/feather/arrow-down-left.svg | 1 + .../assets/icons/feather/arrow-down-right.svg | 1 + web/src/assets/icons/feather/arrow-down.svg | 1 + .../icons/feather/arrow-left-circle.svg | 1 + web/src/assets/icons/feather/arrow-left.svg | 1 + .../icons/feather/arrow-right-circle.svg | 1 + web/src/assets/icons/feather/arrow-right.svg | 1 + .../assets/icons/feather/arrow-up-circle.svg | 1 + .../assets/icons/feather/arrow-up-left.svg | 1 + .../assets/icons/feather/arrow-up-right.svg | 1 + web/src/assets/icons/feather/arrow-up.svg | 1 + web/src/assets/icons/feather/at-sign.svg | 1 + web/src/assets/icons/feather/award.svg | 1 + web/src/assets/icons/feather/bar-chart-2.svg | 1 + web/src/assets/icons/feather/bar-chart.svg | 1 + .../assets/icons/feather/battery-charging.svg | 1 + web/src/assets/icons/feather/battery.svg | 1 + web/src/assets/icons/feather/bell-off.svg | 1 + web/src/assets/icons/feather/bell.svg | 1 + web/src/assets/icons/feather/bluetooth.svg | 1 + web/src/assets/icons/feather/bold.svg | 1 + web/src/assets/icons/feather/book-open.svg | 1 + web/src/assets/icons/feather/book.svg | 1 + web/src/assets/icons/feather/bookmark.svg | 1 + web/src/assets/icons/feather/box.svg | 1 + web/src/assets/icons/feather/briefcase.svg | 1 + web/src/assets/icons/feather/calendar.svg | 1 + web/src/assets/icons/feather/camera-off.svg | 1 + web/src/assets/icons/feather/camera.svg | 1 + web/src/assets/icons/feather/cast.svg | 1 + web/src/assets/icons/feather/check-circle.svg | 1 + web/src/assets/icons/feather/check-square.svg | 1 + web/src/assets/icons/feather/check.svg | 1 + web/src/assets/icons/feather/chevron-down.svg | 1 + web/src/assets/icons/feather/chevron-left.svg | 1 + .../assets/icons/feather/chevron-right.svg | 1 + web/src/assets/icons/feather/chevron-up.svg | 1 + .../assets/icons/feather/chevrons-down.svg | 1 + .../assets/icons/feather/chevrons-left.svg | 1 + .../assets/icons/feather/chevrons-right.svg | 1 + web/src/assets/icons/feather/chevrons-up.svg | 1 + web/src/assets/icons/feather/chrome.svg | 1 + web/src/assets/icons/feather/circle.svg | 1 + web/src/assets/icons/feather/clipboard.svg | 1 + web/src/assets/icons/feather/clock.svg | 1 + .../assets/icons/feather/cloud-drizzle.svg | 1 + .../assets/icons/feather/cloud-lightning.svg | 1 + web/src/assets/icons/feather/cloud-off.svg | 1 + web/src/assets/icons/feather/cloud-rain.svg | 1 + web/src/assets/icons/feather/cloud-snow.svg | 1 + web/src/assets/icons/feather/cloud.svg | 1 + web/src/assets/icons/feather/code.svg | 1 + web/src/assets/icons/feather/codepen.svg | 1 + web/src/assets/icons/feather/codesandbox.svg | 1 + web/src/assets/icons/feather/coffee.svg | 1 + web/src/assets/icons/feather/columns.svg | 1 + web/src/assets/icons/feather/command.svg | 1 + web/src/assets/icons/feather/compass.svg | 1 + web/src/assets/icons/feather/copy.svg | 1 + .../assets/icons/feather/corner-down-left.svg | 1 + .../icons/feather/corner-down-right.svg | 1 + .../assets/icons/feather/corner-left-down.svg | 1 + .../assets/icons/feather/corner-left-up.svg | 1 + .../icons/feather/corner-right-down.svg | 1 + .../assets/icons/feather/corner-right-up.svg | 1 + .../assets/icons/feather/corner-up-left.svg | 1 + .../assets/icons/feather/corner-up-right.svg | 1 + web/src/assets/icons/feather/cpu.svg | 1 + web/src/assets/icons/feather/credit-card.svg | 1 + web/src/assets/icons/feather/crop.svg | 1 + web/src/assets/icons/feather/crosshair.svg | 1 + web/src/assets/icons/feather/database.svg | 1 + web/src/assets/icons/feather/delete.svg | 1 + web/src/assets/icons/feather/disc.svg | 1 + web/src/assets/icons/feather/divide.svg | 1 + web/src/assets/icons/feather/dollar-sign.svg | 1 + .../assets/icons/feather/download-cloud.svg | 1 + web/src/assets/icons/feather/download.svg | 1 + web/src/assets/icons/feather/dribbble.svg | 1 + web/src/assets/icons/feather/droplet.svg | 1 + web/src/assets/icons/feather/edit-2.svg | 1 + web/src/assets/icons/feather/edit-3.svg | 1 + web/src/assets/icons/feather/edit.svg | 1 + .../assets/icons/feather/external-link.svg | 1 + web/src/assets/icons/feather/eye-off.svg | 1 + web/src/assets/icons/feather/eye.svg | 1 + web/src/assets/icons/feather/facebook.svg | 1 + web/src/assets/icons/feather/fast-forward.svg | 1 + web/src/assets/icons/feather/feather.svg | 1 + web/src/assets/icons/feather/figma.svg | 1 + web/src/assets/icons/feather/file-minus.svg | 1 + web/src/assets/icons/feather/file-plus.svg | 1 + web/src/assets/icons/feather/file-text.svg | 1 + web/src/assets/icons/feather/file.svg | 1 + web/src/assets/icons/feather/film.svg | 1 + web/src/assets/icons/feather/filter.svg | 1 + web/src/assets/icons/feather/flag.svg | 1 + web/src/assets/icons/feather/folder-minus.svg | 1 + web/src/assets/icons/feather/folder-plus.svg | 1 + web/src/assets/icons/feather/folder.svg | 1 + web/src/assets/icons/feather/framer.svg | 1 + web/src/assets/icons/feather/frown.svg | 1 + web/src/assets/icons/feather/gift.svg | 1 + web/src/assets/icons/feather/git-branch.svg | 1 + web/src/assets/icons/feather/git-commit.svg | 1 + web/src/assets/icons/feather/git-merge.svg | 1 + .../assets/icons/feather/git-pull-request.svg | 1 + web/src/assets/icons/feather/github.svg | 1 + web/src/assets/icons/feather/gitlab.svg | 1 + web/src/assets/icons/feather/globe.svg | 1 + web/src/assets/icons/feather/grid.svg | 1 + web/src/assets/icons/feather/hard-drive.svg | 1 + web/src/assets/icons/feather/hash.svg | 1 + web/src/assets/icons/feather/headphones.svg | 1 + web/src/assets/icons/feather/heart.svg | 1 + web/src/assets/icons/feather/help-circle.svg | 1 + web/src/assets/icons/feather/hexagon.svg | 1 + web/src/assets/icons/feather/home.svg | 1 + web/src/assets/icons/feather/image.svg | 1 + web/src/assets/icons/feather/inbox.svg | 1 + web/src/assets/icons/feather/info.svg | 1 + web/src/assets/icons/feather/instagram.svg | 1 + web/src/assets/icons/feather/italic.svg | 1 + web/src/assets/icons/feather/key.svg | 1 + web/src/assets/icons/feather/layers.svg | 1 + web/src/assets/icons/feather/layout.svg | 1 + web/src/assets/icons/feather/life-buoy.svg | 1 + web/src/assets/icons/feather/link-2.svg | 1 + web/src/assets/icons/feather/link.svg | 1 + web/src/assets/icons/feather/linkedin.svg | 1 + web/src/assets/icons/feather/list.svg | 1 + web/src/assets/icons/feather/loader.svg | 1 + web/src/assets/icons/feather/lock.svg | 1 + web/src/assets/icons/feather/log-in.svg | 1 + web/src/assets/icons/feather/log-out.svg | 1 + web/src/assets/icons/feather/mail.svg | 1 + web/src/assets/icons/feather/map-pin.svg | 1 + web/src/assets/icons/feather/map.svg | 1 + web/src/assets/icons/feather/maximize-2.svg | 1 + web/src/assets/icons/feather/maximize.svg | 1 + web/src/assets/icons/feather/meh.svg | 1 + web/src/assets/icons/feather/menu.svg | 1 + .../assets/icons/feather/message-circle.svg | 1 + .../assets/icons/feather/message-square.svg | 1 + web/src/assets/icons/feather/mic-off.svg | 1 + web/src/assets/icons/feather/mic.svg | 1 + web/src/assets/icons/feather/minimize-2.svg | 1 + web/src/assets/icons/feather/minimize.svg | 1 + web/src/assets/icons/feather/minus-circle.svg | 1 + web/src/assets/icons/feather/minus-square.svg | 1 + web/src/assets/icons/feather/minus.svg | 1 + web/src/assets/icons/feather/monitor.svg | 1 + web/src/assets/icons/feather/moon.svg | 1 + .../assets/icons/feather/more-horizontal.svg | 1 + .../assets/icons/feather/more-vertical.svg | 1 + .../assets/icons/feather/mouse-pointer.svg | 1 + web/src/assets/icons/feather/move.svg | 1 + web/src/assets/icons/feather/music.svg | 1 + web/src/assets/icons/feather/navigation-2.svg | 1 + web/src/assets/icons/feather/navigation.svg | 1 + web/src/assets/icons/feather/octagon.svg | 1 + web/src/assets/icons/feather/package.svg | 1 + web/src/assets/icons/feather/paperclip.svg | 1 + web/src/assets/icons/feather/pause-circle.svg | 1 + web/src/assets/icons/feather/pause.svg | 1 + web/src/assets/icons/feather/pen-tool.svg | 1 + web/src/assets/icons/feather/percent.svg | 1 + web/src/assets/icons/feather/phone-call.svg | 1 + .../assets/icons/feather/phone-forwarded.svg | 1 + .../assets/icons/feather/phone-incoming.svg | 1 + web/src/assets/icons/feather/phone-missed.svg | 1 + web/src/assets/icons/feather/phone-off.svg | 1 + .../assets/icons/feather/phone-outgoing.svg | 1 + web/src/assets/icons/feather/phone.svg | 1 + web/src/assets/icons/feather/pie-chart.svg | 1 + web/src/assets/icons/feather/play-circle.svg | 1 + web/src/assets/icons/feather/play.svg | 1 + web/src/assets/icons/feather/plus-circle.svg | 1 + web/src/assets/icons/feather/plus-square.svg | 1 + web/src/assets/icons/feather/plus.svg | 1 + web/src/assets/icons/feather/pocket.svg | 1 + web/src/assets/icons/feather/power.svg | 1 + web/src/assets/icons/feather/printer.svg | 1 + web/src/assets/icons/feather/radio.svg | 1 + web/src/assets/icons/feather/refresh-ccw.svg | 1 + web/src/assets/icons/feather/refresh-cw.svg | 1 + web/src/assets/icons/feather/repeat.svg | 1 + web/src/assets/icons/feather/rewind.svg | 1 + web/src/assets/icons/feather/rotate-ccw.svg | 1 + web/src/assets/icons/feather/rotate-cw.svg | 1 + web/src/assets/icons/feather/rss.svg | 1 + web/src/assets/icons/feather/save.svg | 1 + web/src/assets/icons/feather/scissors.svg | 1 + web/src/assets/icons/feather/search.svg | 1 + web/src/assets/icons/feather/send.svg | 1 + web/src/assets/icons/feather/server.svg | 1 + web/src/assets/icons/feather/settings.svg | 1 + web/src/assets/icons/feather/share-2.svg | 1 + web/src/assets/icons/feather/share.svg | 1 + web/src/assets/icons/feather/shield-off.svg | 1 + web/src/assets/icons/feather/shield.svg | 1 + web/src/assets/icons/feather/shopping-bag.svg | 1 + .../assets/icons/feather/shopping-cart.svg | 1 + web/src/assets/icons/feather/shuffle.svg | 1 + web/src/assets/icons/feather/sidebar.svg | 1 + web/src/assets/icons/feather/skip-back.svg | 1 + web/src/assets/icons/feather/skip-forward.svg | 1 + web/src/assets/icons/feather/slack.svg | 1 + web/src/assets/icons/feather/slash.svg | 1 + web/src/assets/icons/feather/sliders.svg | 1 + web/src/assets/icons/feather/smartphone.svg | 1 + web/src/assets/icons/feather/smile.svg | 1 + web/src/assets/icons/feather/speaker.svg | 1 + web/src/assets/icons/feather/square.svg | 1 + web/src/assets/icons/feather/star.svg | 1 + web/src/assets/icons/feather/stop-circle.svg | 1 + web/src/assets/icons/feather/sun.svg | 1 + web/src/assets/icons/feather/sunrise.svg | 1 + web/src/assets/icons/feather/sunset.svg | 1 + web/src/assets/icons/feather/table.svg | 1 + web/src/assets/icons/feather/tablet.svg | 1 + web/src/assets/icons/feather/tag.svg | 1 + web/src/assets/icons/feather/target.svg | 1 + web/src/assets/icons/feather/terminal.svg | 1 + web/src/assets/icons/feather/thermometer.svg | 1 + web/src/assets/icons/feather/thumbs-down.svg | 1 + web/src/assets/icons/feather/thumbs-up.svg | 1 + web/src/assets/icons/feather/toggle-left.svg | 1 + web/src/assets/icons/feather/toggle-right.svg | 1 + web/src/assets/icons/feather/tool.svg | 1 + web/src/assets/icons/feather/trash-2.svg | 1 + web/src/assets/icons/feather/trash.svg | 1 + web/src/assets/icons/feather/trello.svg | 1 + .../assets/icons/feather/trending-down.svg | 1 + web/src/assets/icons/feather/trending-up.svg | 1 + web/src/assets/icons/feather/triangle.svg | 1 + web/src/assets/icons/feather/truck.svg | 1 + web/src/assets/icons/feather/tv.svg | 1 + web/src/assets/icons/feather/twitch.svg | 1 + web/src/assets/icons/feather/twitter.svg | 1 + web/src/assets/icons/feather/type.svg | 1 + web/src/assets/icons/feather/umbrella.svg | 1 + web/src/assets/icons/feather/underline.svg | 1 + web/src/assets/icons/feather/unlock.svg | 1 + web/src/assets/icons/feather/upload-cloud.svg | 1 + web/src/assets/icons/feather/upload.svg | 1 + web/src/assets/icons/feather/user-check.svg | 1 + web/src/assets/icons/feather/user-minus.svg | 1 + web/src/assets/icons/feather/user-plus.svg | 1 + web/src/assets/icons/feather/user-x.svg | 1 + web/src/assets/icons/feather/user.svg | 1 + web/src/assets/icons/feather/users.svg | 1 + web/src/assets/icons/feather/video-off.svg | 1 + web/src/assets/icons/feather/video.svg | 1 + web/src/assets/icons/feather/voicemail.svg | 1 + web/src/assets/icons/feather/volume-1.svg | 1 + web/src/assets/icons/feather/volume-2.svg | 1 + web/src/assets/icons/feather/volume-x.svg | 1 + web/src/assets/icons/feather/volume.svg | 1 + web/src/assets/icons/feather/watch.svg | 1 + web/src/assets/icons/feather/wifi-off.svg | 1 + web/src/assets/icons/feather/wifi.svg | 1 + web/src/assets/icons/feather/wind.svg | 1 + web/src/assets/icons/feather/x-circle.svg | 1 + web/src/assets/icons/feather/x-octagon.svg | 1 + web/src/assets/icons/feather/x-square.svg | 1 + web/src/assets/icons/feather/x.svg | 1 + web/src/assets/icons/feather/youtube.svg | 1 + web/src/assets/icons/feather/zap-off.svg | 1 + web/src/assets/icons/feather/zap.svg | 1 + web/src/assets/icons/feather/zoom-in.svg | 1 + web/src/assets/icons/feather/zoom-out.svg | 1 + web/src/assets/icons/isme/apifox.svg | 16 + web/src/assets/icons/isme/awesome.svg | 1 + web/src/assets/icons/isme/dialog.svg | 1 + web/src/assets/icons/isme/docs.svg | 15 + web/src/assets/icons/isme/gitee.svg | 1 + web/src/assets/icons/isme/naiveui.svg | 37 +++ web/src/assets/images/404.webp | Bin 0 -> 14344 bytes web/src/assets/images/isme.png | Bin 0 -> 15442 bytes web/src/assets/images/login_banner.webp | Bin 0 -> 26198 bytes web/src/assets/images/login_bg.webp | Bin 0 -> 6944 bytes web/src/assets/images/logo.png | Bin 0 -> 8572 bytes web/src/components/common/AppCard.vue | 19 ++ web/src/components/common/AppPage.vue | 33 ++ web/src/components/common/CommonPage.vue | 76 +++++ web/src/components/common/LayoutSetting.vue | 102 ++++++ web/src/components/common/TheFooter.vue | 24 ++ web/src/components/common/TheLogo.vue | 12 + web/src/components/common/ThemeSetting.vue | 23 ++ web/src/components/common/ToggleTheme.vue | 44 +++ web/src/components/common/index.js | 6 + web/src/components/index.js | 2 + web/src/components/me/crud/QueryItem.vue | 35 ++ web/src/components/me/crud/index.vue | 204 ++++++++++++ web/src/components/me/index.js | 3 + web/src/components/me/modal/index.vue | 191 +++++++++++ web/src/components/me/modal/utils.js | 72 ++++ web/src/composables/index.js | 4 + web/src/composables/useAliveData.js | 30 ++ web/src/composables/useCrud.js | 127 +++++++ web/src/composables/useForm.js | 23 ++ web/src/composables/useModal.js | 20 ++ web/src/directives/index.js | 23 ++ web/src/layouts/components/BreadCrumb.vue | 86 +++++ web/src/layouts/components/Fullscreen.vue | 13 + web/src/layouts/components/MenuCollapse.vue | 22 ++ web/src/layouts/components/RoleSelect.vue | 90 +++++ web/src/layouts/components/SideLogo.vue | 27 ++ web/src/layouts/components/SideMenu.vue | 74 +++++ web/src/layouts/components/UserAvatar.vue | 85 +++++ web/src/layouts/components/index.js | 8 + .../layouts/components/tab/ContextMenu.vue | 125 +++++++ web/src/layouts/components/tab/index.vue | 99 ++++++ web/src/layouts/empty/index.vue | 11 + web/src/layouts/full/header/index.vue | 43 +++ web/src/layouts/full/index.vue | 42 +++ web/src/layouts/full/sidebar/index.vue | 16 + web/src/layouts/normal/header/index.vue | 45 +++ web/src/layouts/normal/index.vue | 38 +++ web/src/layouts/normal/sidebar/index.vue | 16 + web/src/layouts/simple/index.vue | 36 ++ web/src/layouts/simple/sidebar/index.vue | 23 ++ web/src/main.js | 31 ++ web/src/router/basic-routes.js | 40 +++ web/src/router/guards/index.js | 19 ++ web/src/router/guards/page-loading-guard.js | 23 ++ web/src/router/guards/page-title-guard.js | 21 ++ web/src/router/guards/permission-guard.js | 56 ++++ web/src/router/guards/tab-guard.js | 24 ++ web/src/router/index.js | 25 ++ web/src/settings.js | 77 +++++ web/src/store/helper.js | 30 ++ web/src/store/index.js | 18 + web/src/store/modules/app.js | 56 ++++ web/src/store/modules/auth.js | 59 ++++ web/src/store/modules/index.js | 6 + web/src/store/modules/permission.js | 82 +++++ web/src/store/modules/router.js | 26 ++ web/src/store/modules/tab.js | 94 ++++++ web/src/store/modules/user.js | 43 +++ web/src/styles/global.scss | 91 +++++ web/src/styles/reset.css | 49 +++ web/src/utils/common.js | 106 ++++++ web/src/utils/http/helpers.js | 67 ++++ web/src/utils/http/index.js | 30 ++ web/src/utils/http/interceptors.js | 70 ++++ web/src/utils/index.js | 14 + web/src/utils/is.js | 127 +++++++ web/src/utils/naiveTools.js | 121 +++++++ web/src/utils/storage/index.js | 30 ++ web/src/utils/storage/storage.js | 66 ++++ web/src/views/base/index.vue | 138 ++++++++ web/src/views/base/keep-alive.vue | 26 ++ web/src/views/base/test-modal.vue | 73 ++++ web/src/views/base/unocss-icon.vue | 44 +++ web/src/views/base/unocss.vue | 76 +++++ web/src/views/demo/upload/index.vue | 97 ++++++ web/src/views/error-page/403.vue | 44 +++ web/src/views/error-page/404.vue | 31 ++ web/src/views/home/index.vue | 289 ++++++++++++++++ web/src/views/iframe/index.vue | 9 + web/src/views/login/api.js | 15 + web/src/views/login/index.vue | 188 +++++++++++ web/src/views/pms/resource/api.js | 19 ++ .../pms/resource/components/MenuTree.vue | 123 +++++++ .../pms/resource/components/QuestionLabel.vue | 32 ++ .../pms/resource/components/ResAddOrEdit.vue | 241 ++++++++++++++ web/src/views/pms/resource/index.vue | 254 ++++++++++++++ web/src/views/pms/role/api.js | 21 ++ web/src/views/pms/role/index.vue | 220 +++++++++++++ web/src/views/pms/role/role-user.vue | 228 +++++++++++++ web/src/views/pms/user/api.js | 19 ++ web/src/views/pms/user/index.vue | 311 ++++++++++++++++++ web/src/views/profile/api.js | 14 + web/src/views/profile/index.vue | 167 ++++++++++ web/uno.config.js | 57 ++++ web/vite.config.js | 74 +++++ 411 files changed, 7244 insertions(+), 1 deletion(-) delete mode 160000 web create mode 100644 web/.editorconfig create mode 100644 web/.env.development create mode 100644 web/.env.production create mode 100644 web/.eslint-global-variables.json create mode 100644 web/.npmrc create mode 100644 web/LICENSE create mode 100644 web/README.md create mode 100644 web/build/index.js create mode 100644 web/build/plugin-isme/icons.js create mode 100644 web/build/plugin-isme/index.js create mode 100644 web/build/plugin-isme/page-pathes.js create mode 100644 web/eslint.config.js create mode 100644 web/index.html create mode 100644 web/jsconfig.json create mode 100644 web/package.json create mode 100644 web/public/favicon.png create mode 100644 web/src/App.vue create mode 100644 web/src/api/index.js create mode 100644 web/src/assets/icons/dynamic-icons.js create mode 100644 web/src/assets/icons/feather/activity.svg create mode 100644 web/src/assets/icons/feather/airplay.svg create mode 100644 web/src/assets/icons/feather/alert-circle.svg create mode 100644 web/src/assets/icons/feather/alert-octagon.svg create mode 100644 web/src/assets/icons/feather/alert-triangle.svg create mode 100644 web/src/assets/icons/feather/align-center.svg create mode 100644 web/src/assets/icons/feather/align-justify.svg create mode 100644 web/src/assets/icons/feather/align-left.svg create mode 100644 web/src/assets/icons/feather/align-right.svg create mode 100644 web/src/assets/icons/feather/anchor.svg create mode 100644 web/src/assets/icons/feather/aperture.svg create mode 100644 web/src/assets/icons/feather/archive.svg create mode 100644 web/src/assets/icons/feather/arrow-down-circle.svg create mode 100644 web/src/assets/icons/feather/arrow-down-left.svg create mode 100644 web/src/assets/icons/feather/arrow-down-right.svg create mode 100644 web/src/assets/icons/feather/arrow-down.svg create mode 100644 web/src/assets/icons/feather/arrow-left-circle.svg create mode 100644 web/src/assets/icons/feather/arrow-left.svg create mode 100644 web/src/assets/icons/feather/arrow-right-circle.svg create mode 100644 web/src/assets/icons/feather/arrow-right.svg create mode 100644 web/src/assets/icons/feather/arrow-up-circle.svg create mode 100644 web/src/assets/icons/feather/arrow-up-left.svg create mode 100644 web/src/assets/icons/feather/arrow-up-right.svg create mode 100644 web/src/assets/icons/feather/arrow-up.svg create mode 100644 web/src/assets/icons/feather/at-sign.svg create mode 100644 web/src/assets/icons/feather/award.svg create mode 100644 web/src/assets/icons/feather/bar-chart-2.svg create mode 100644 web/src/assets/icons/feather/bar-chart.svg create mode 100644 web/src/assets/icons/feather/battery-charging.svg create mode 100644 web/src/assets/icons/feather/battery.svg create mode 100644 web/src/assets/icons/feather/bell-off.svg create mode 100644 web/src/assets/icons/feather/bell.svg create mode 100644 web/src/assets/icons/feather/bluetooth.svg create mode 100644 web/src/assets/icons/feather/bold.svg create mode 100644 web/src/assets/icons/feather/book-open.svg create mode 100644 web/src/assets/icons/feather/book.svg create mode 100644 web/src/assets/icons/feather/bookmark.svg create mode 100644 web/src/assets/icons/feather/box.svg create mode 100644 web/src/assets/icons/feather/briefcase.svg create mode 100644 web/src/assets/icons/feather/calendar.svg create mode 100644 web/src/assets/icons/feather/camera-off.svg create mode 100644 web/src/assets/icons/feather/camera.svg create mode 100644 web/src/assets/icons/feather/cast.svg create mode 100644 web/src/assets/icons/feather/check-circle.svg create mode 100644 web/src/assets/icons/feather/check-square.svg create mode 100644 web/src/assets/icons/feather/check.svg create mode 100644 web/src/assets/icons/feather/chevron-down.svg create mode 100644 web/src/assets/icons/feather/chevron-left.svg create mode 100644 web/src/assets/icons/feather/chevron-right.svg create mode 100644 web/src/assets/icons/feather/chevron-up.svg create mode 100644 web/src/assets/icons/feather/chevrons-down.svg create mode 100644 web/src/assets/icons/feather/chevrons-left.svg create mode 100644 web/src/assets/icons/feather/chevrons-right.svg create mode 100644 web/src/assets/icons/feather/chevrons-up.svg create mode 100644 web/src/assets/icons/feather/chrome.svg create mode 100644 web/src/assets/icons/feather/circle.svg create mode 100644 web/src/assets/icons/feather/clipboard.svg create mode 100644 web/src/assets/icons/feather/clock.svg create mode 100644 web/src/assets/icons/feather/cloud-drizzle.svg create mode 100644 web/src/assets/icons/feather/cloud-lightning.svg create mode 100644 web/src/assets/icons/feather/cloud-off.svg create mode 100644 web/src/assets/icons/feather/cloud-rain.svg create mode 100644 web/src/assets/icons/feather/cloud-snow.svg create mode 100644 web/src/assets/icons/feather/cloud.svg create mode 100644 web/src/assets/icons/feather/code.svg create mode 100644 web/src/assets/icons/feather/codepen.svg create mode 100644 web/src/assets/icons/feather/codesandbox.svg create mode 100644 web/src/assets/icons/feather/coffee.svg create mode 100644 web/src/assets/icons/feather/columns.svg create mode 100644 web/src/assets/icons/feather/command.svg create mode 100644 web/src/assets/icons/feather/compass.svg create mode 100644 web/src/assets/icons/feather/copy.svg create mode 100644 web/src/assets/icons/feather/corner-down-left.svg create mode 100644 web/src/assets/icons/feather/corner-down-right.svg create mode 100644 web/src/assets/icons/feather/corner-left-down.svg create mode 100644 web/src/assets/icons/feather/corner-left-up.svg create mode 100644 web/src/assets/icons/feather/corner-right-down.svg create mode 100644 web/src/assets/icons/feather/corner-right-up.svg create mode 100644 web/src/assets/icons/feather/corner-up-left.svg create mode 100644 web/src/assets/icons/feather/corner-up-right.svg create mode 100644 web/src/assets/icons/feather/cpu.svg create mode 100644 web/src/assets/icons/feather/credit-card.svg create mode 100644 web/src/assets/icons/feather/crop.svg create mode 100644 web/src/assets/icons/feather/crosshair.svg create mode 100644 web/src/assets/icons/feather/database.svg create mode 100644 web/src/assets/icons/feather/delete.svg create mode 100644 web/src/assets/icons/feather/disc.svg create mode 100644 web/src/assets/icons/feather/divide.svg create mode 100644 web/src/assets/icons/feather/dollar-sign.svg create mode 100644 web/src/assets/icons/feather/download-cloud.svg create mode 100644 web/src/assets/icons/feather/download.svg create mode 100644 web/src/assets/icons/feather/dribbble.svg create mode 100644 web/src/assets/icons/feather/droplet.svg create mode 100644 web/src/assets/icons/feather/edit-2.svg create mode 100644 web/src/assets/icons/feather/edit-3.svg create mode 100644 web/src/assets/icons/feather/edit.svg create mode 100644 web/src/assets/icons/feather/external-link.svg create mode 100644 web/src/assets/icons/feather/eye-off.svg create mode 100644 web/src/assets/icons/feather/eye.svg create mode 100644 web/src/assets/icons/feather/facebook.svg create mode 100644 web/src/assets/icons/feather/fast-forward.svg create mode 100644 web/src/assets/icons/feather/feather.svg create mode 100644 web/src/assets/icons/feather/figma.svg create mode 100644 web/src/assets/icons/feather/file-minus.svg create mode 100644 web/src/assets/icons/feather/file-plus.svg create mode 100644 web/src/assets/icons/feather/file-text.svg create mode 100644 web/src/assets/icons/feather/file.svg create mode 100644 web/src/assets/icons/feather/film.svg create mode 100644 web/src/assets/icons/feather/filter.svg create mode 100644 web/src/assets/icons/feather/flag.svg create mode 100644 web/src/assets/icons/feather/folder-minus.svg create mode 100644 web/src/assets/icons/feather/folder-plus.svg create mode 100644 web/src/assets/icons/feather/folder.svg create mode 100644 web/src/assets/icons/feather/framer.svg create mode 100644 web/src/assets/icons/feather/frown.svg create mode 100644 web/src/assets/icons/feather/gift.svg create mode 100644 web/src/assets/icons/feather/git-branch.svg create mode 100644 web/src/assets/icons/feather/git-commit.svg create mode 100644 web/src/assets/icons/feather/git-merge.svg create mode 100644 web/src/assets/icons/feather/git-pull-request.svg create mode 100644 web/src/assets/icons/feather/github.svg create mode 100644 web/src/assets/icons/feather/gitlab.svg create mode 100644 web/src/assets/icons/feather/globe.svg create mode 100644 web/src/assets/icons/feather/grid.svg create mode 100644 web/src/assets/icons/feather/hard-drive.svg create mode 100644 web/src/assets/icons/feather/hash.svg create mode 100644 web/src/assets/icons/feather/headphones.svg create mode 100644 web/src/assets/icons/feather/heart.svg create mode 100644 web/src/assets/icons/feather/help-circle.svg create mode 100644 web/src/assets/icons/feather/hexagon.svg create mode 100644 web/src/assets/icons/feather/home.svg create mode 100644 web/src/assets/icons/feather/image.svg create mode 100644 web/src/assets/icons/feather/inbox.svg create mode 100644 web/src/assets/icons/feather/info.svg create mode 100644 web/src/assets/icons/feather/instagram.svg create mode 100644 web/src/assets/icons/feather/italic.svg create mode 100644 web/src/assets/icons/feather/key.svg create mode 100644 web/src/assets/icons/feather/layers.svg create mode 100644 web/src/assets/icons/feather/layout.svg create mode 100644 web/src/assets/icons/feather/life-buoy.svg create mode 100644 web/src/assets/icons/feather/link-2.svg create mode 100644 web/src/assets/icons/feather/link.svg create mode 100644 web/src/assets/icons/feather/linkedin.svg create mode 100644 web/src/assets/icons/feather/list.svg create mode 100644 web/src/assets/icons/feather/loader.svg create mode 100644 web/src/assets/icons/feather/lock.svg create mode 100644 web/src/assets/icons/feather/log-in.svg create mode 100644 web/src/assets/icons/feather/log-out.svg create mode 100644 web/src/assets/icons/feather/mail.svg create mode 100644 web/src/assets/icons/feather/map-pin.svg create mode 100644 web/src/assets/icons/feather/map.svg create mode 100644 web/src/assets/icons/feather/maximize-2.svg create mode 100644 web/src/assets/icons/feather/maximize.svg create mode 100644 web/src/assets/icons/feather/meh.svg create mode 100644 web/src/assets/icons/feather/menu.svg create mode 100644 web/src/assets/icons/feather/message-circle.svg create mode 100644 web/src/assets/icons/feather/message-square.svg create mode 100644 web/src/assets/icons/feather/mic-off.svg create mode 100644 web/src/assets/icons/feather/mic.svg create mode 100644 web/src/assets/icons/feather/minimize-2.svg create mode 100644 web/src/assets/icons/feather/minimize.svg create mode 100644 web/src/assets/icons/feather/minus-circle.svg create mode 100644 web/src/assets/icons/feather/minus-square.svg create mode 100644 web/src/assets/icons/feather/minus.svg create mode 100644 web/src/assets/icons/feather/monitor.svg create mode 100644 web/src/assets/icons/feather/moon.svg create mode 100644 web/src/assets/icons/feather/more-horizontal.svg create mode 100644 web/src/assets/icons/feather/more-vertical.svg create mode 100644 web/src/assets/icons/feather/mouse-pointer.svg create mode 100644 web/src/assets/icons/feather/move.svg create mode 100644 web/src/assets/icons/feather/music.svg create mode 100644 web/src/assets/icons/feather/navigation-2.svg create mode 100644 web/src/assets/icons/feather/navigation.svg create mode 100644 web/src/assets/icons/feather/octagon.svg create mode 100644 web/src/assets/icons/feather/package.svg create mode 100644 web/src/assets/icons/feather/paperclip.svg create mode 100644 web/src/assets/icons/feather/pause-circle.svg create mode 100644 web/src/assets/icons/feather/pause.svg create mode 100644 web/src/assets/icons/feather/pen-tool.svg create mode 100644 web/src/assets/icons/feather/percent.svg create mode 100644 web/src/assets/icons/feather/phone-call.svg create mode 100644 web/src/assets/icons/feather/phone-forwarded.svg create mode 100644 web/src/assets/icons/feather/phone-incoming.svg create mode 100644 web/src/assets/icons/feather/phone-missed.svg create mode 100644 web/src/assets/icons/feather/phone-off.svg create mode 100644 web/src/assets/icons/feather/phone-outgoing.svg create mode 100644 web/src/assets/icons/feather/phone.svg create mode 100644 web/src/assets/icons/feather/pie-chart.svg create mode 100644 web/src/assets/icons/feather/play-circle.svg create mode 100644 web/src/assets/icons/feather/play.svg create mode 100644 web/src/assets/icons/feather/plus-circle.svg create mode 100644 web/src/assets/icons/feather/plus-square.svg create mode 100644 web/src/assets/icons/feather/plus.svg create mode 100644 web/src/assets/icons/feather/pocket.svg create mode 100644 web/src/assets/icons/feather/power.svg create mode 100644 web/src/assets/icons/feather/printer.svg create mode 100644 web/src/assets/icons/feather/radio.svg create mode 100644 web/src/assets/icons/feather/refresh-ccw.svg create mode 100644 web/src/assets/icons/feather/refresh-cw.svg create mode 100644 web/src/assets/icons/feather/repeat.svg create mode 100644 web/src/assets/icons/feather/rewind.svg create mode 100644 web/src/assets/icons/feather/rotate-ccw.svg create mode 100644 web/src/assets/icons/feather/rotate-cw.svg create mode 100644 web/src/assets/icons/feather/rss.svg create mode 100644 web/src/assets/icons/feather/save.svg create mode 100644 web/src/assets/icons/feather/scissors.svg create mode 100644 web/src/assets/icons/feather/search.svg create mode 100644 web/src/assets/icons/feather/send.svg create mode 100644 web/src/assets/icons/feather/server.svg create mode 100644 web/src/assets/icons/feather/settings.svg create mode 100644 web/src/assets/icons/feather/share-2.svg create mode 100644 web/src/assets/icons/feather/share.svg create mode 100644 web/src/assets/icons/feather/shield-off.svg create mode 100644 web/src/assets/icons/feather/shield.svg create mode 100644 web/src/assets/icons/feather/shopping-bag.svg create mode 100644 web/src/assets/icons/feather/shopping-cart.svg create mode 100644 web/src/assets/icons/feather/shuffle.svg create mode 100644 web/src/assets/icons/feather/sidebar.svg create mode 100644 web/src/assets/icons/feather/skip-back.svg create mode 100644 web/src/assets/icons/feather/skip-forward.svg create mode 100644 web/src/assets/icons/feather/slack.svg create mode 100644 web/src/assets/icons/feather/slash.svg create mode 100644 web/src/assets/icons/feather/sliders.svg create mode 100644 web/src/assets/icons/feather/smartphone.svg create mode 100644 web/src/assets/icons/feather/smile.svg create mode 100644 web/src/assets/icons/feather/speaker.svg create mode 100644 web/src/assets/icons/feather/square.svg create mode 100644 web/src/assets/icons/feather/star.svg create mode 100644 web/src/assets/icons/feather/stop-circle.svg create mode 100644 web/src/assets/icons/feather/sun.svg create mode 100644 web/src/assets/icons/feather/sunrise.svg create mode 100644 web/src/assets/icons/feather/sunset.svg create mode 100644 web/src/assets/icons/feather/table.svg create mode 100644 web/src/assets/icons/feather/tablet.svg create mode 100644 web/src/assets/icons/feather/tag.svg create mode 100644 web/src/assets/icons/feather/target.svg create mode 100644 web/src/assets/icons/feather/terminal.svg create mode 100644 web/src/assets/icons/feather/thermometer.svg create mode 100644 web/src/assets/icons/feather/thumbs-down.svg create mode 100644 web/src/assets/icons/feather/thumbs-up.svg create mode 100644 web/src/assets/icons/feather/toggle-left.svg create mode 100644 web/src/assets/icons/feather/toggle-right.svg create mode 100644 web/src/assets/icons/feather/tool.svg create mode 100644 web/src/assets/icons/feather/trash-2.svg create mode 100644 web/src/assets/icons/feather/trash.svg create mode 100644 web/src/assets/icons/feather/trello.svg create mode 100644 web/src/assets/icons/feather/trending-down.svg create mode 100644 web/src/assets/icons/feather/trending-up.svg create mode 100644 web/src/assets/icons/feather/triangle.svg create mode 100644 web/src/assets/icons/feather/truck.svg create mode 100644 web/src/assets/icons/feather/tv.svg create mode 100644 web/src/assets/icons/feather/twitch.svg create mode 100644 web/src/assets/icons/feather/twitter.svg create mode 100644 web/src/assets/icons/feather/type.svg create mode 100644 web/src/assets/icons/feather/umbrella.svg create mode 100644 web/src/assets/icons/feather/underline.svg create mode 100644 web/src/assets/icons/feather/unlock.svg create mode 100644 web/src/assets/icons/feather/upload-cloud.svg create mode 100644 web/src/assets/icons/feather/upload.svg create mode 100644 web/src/assets/icons/feather/user-check.svg create mode 100644 web/src/assets/icons/feather/user-minus.svg create mode 100644 web/src/assets/icons/feather/user-plus.svg create mode 100644 web/src/assets/icons/feather/user-x.svg create mode 100644 web/src/assets/icons/feather/user.svg create mode 100644 web/src/assets/icons/feather/users.svg create mode 100644 web/src/assets/icons/feather/video-off.svg create mode 100644 web/src/assets/icons/feather/video.svg create mode 100644 web/src/assets/icons/feather/voicemail.svg create mode 100644 web/src/assets/icons/feather/volume-1.svg create mode 100644 web/src/assets/icons/feather/volume-2.svg create mode 100644 web/src/assets/icons/feather/volume-x.svg create mode 100644 web/src/assets/icons/feather/volume.svg create mode 100644 web/src/assets/icons/feather/watch.svg create mode 100644 web/src/assets/icons/feather/wifi-off.svg create mode 100644 web/src/assets/icons/feather/wifi.svg create mode 100644 web/src/assets/icons/feather/wind.svg create mode 100644 web/src/assets/icons/feather/x-circle.svg create mode 100644 web/src/assets/icons/feather/x-octagon.svg create mode 100644 web/src/assets/icons/feather/x-square.svg create mode 100644 web/src/assets/icons/feather/x.svg create mode 100644 web/src/assets/icons/feather/youtube.svg create mode 100644 web/src/assets/icons/feather/zap-off.svg create mode 100644 web/src/assets/icons/feather/zap.svg create mode 100644 web/src/assets/icons/feather/zoom-in.svg create mode 100644 web/src/assets/icons/feather/zoom-out.svg create mode 100644 web/src/assets/icons/isme/apifox.svg create mode 100644 web/src/assets/icons/isme/awesome.svg create mode 100644 web/src/assets/icons/isme/dialog.svg create mode 100644 web/src/assets/icons/isme/docs.svg create mode 100644 web/src/assets/icons/isme/gitee.svg create mode 100644 web/src/assets/icons/isme/naiveui.svg create mode 100644 web/src/assets/images/404.webp create mode 100644 web/src/assets/images/isme.png create mode 100644 web/src/assets/images/login_banner.webp create mode 100644 web/src/assets/images/login_bg.webp create mode 100644 web/src/assets/images/logo.png create mode 100644 web/src/components/common/AppCard.vue create mode 100644 web/src/components/common/AppPage.vue create mode 100644 web/src/components/common/CommonPage.vue create mode 100644 web/src/components/common/LayoutSetting.vue create mode 100644 web/src/components/common/TheFooter.vue create mode 100644 web/src/components/common/TheLogo.vue create mode 100644 web/src/components/common/ThemeSetting.vue create mode 100644 web/src/components/common/ToggleTheme.vue create mode 100644 web/src/components/common/index.js create mode 100644 web/src/components/index.js create mode 100644 web/src/components/me/crud/QueryItem.vue create mode 100644 web/src/components/me/crud/index.vue create mode 100644 web/src/components/me/index.js create mode 100644 web/src/components/me/modal/index.vue create mode 100644 web/src/components/me/modal/utils.js create mode 100644 web/src/composables/index.js create mode 100644 web/src/composables/useAliveData.js create mode 100644 web/src/composables/useCrud.js create mode 100644 web/src/composables/useForm.js create mode 100644 web/src/composables/useModal.js create mode 100644 web/src/directives/index.js create mode 100644 web/src/layouts/components/BreadCrumb.vue create mode 100644 web/src/layouts/components/Fullscreen.vue create mode 100644 web/src/layouts/components/MenuCollapse.vue create mode 100644 web/src/layouts/components/RoleSelect.vue create mode 100644 web/src/layouts/components/SideLogo.vue create mode 100644 web/src/layouts/components/SideMenu.vue create mode 100644 web/src/layouts/components/UserAvatar.vue create mode 100644 web/src/layouts/components/index.js create mode 100644 web/src/layouts/components/tab/ContextMenu.vue create mode 100644 web/src/layouts/components/tab/index.vue create mode 100644 web/src/layouts/empty/index.vue create mode 100644 web/src/layouts/full/header/index.vue create mode 100644 web/src/layouts/full/index.vue create mode 100644 web/src/layouts/full/sidebar/index.vue create mode 100644 web/src/layouts/normal/header/index.vue create mode 100644 web/src/layouts/normal/index.vue create mode 100644 web/src/layouts/normal/sidebar/index.vue create mode 100644 web/src/layouts/simple/index.vue create mode 100644 web/src/layouts/simple/sidebar/index.vue create mode 100644 web/src/main.js create mode 100644 web/src/router/basic-routes.js create mode 100644 web/src/router/guards/index.js create mode 100644 web/src/router/guards/page-loading-guard.js create mode 100644 web/src/router/guards/page-title-guard.js create mode 100644 web/src/router/guards/permission-guard.js create mode 100644 web/src/router/guards/tab-guard.js create mode 100644 web/src/router/index.js create mode 100644 web/src/settings.js create mode 100644 web/src/store/helper.js create mode 100644 web/src/store/index.js create mode 100644 web/src/store/modules/app.js create mode 100644 web/src/store/modules/auth.js create mode 100644 web/src/store/modules/index.js create mode 100644 web/src/store/modules/permission.js create mode 100644 web/src/store/modules/router.js create mode 100644 web/src/store/modules/tab.js create mode 100644 web/src/store/modules/user.js create mode 100644 web/src/styles/global.scss create mode 100644 web/src/styles/reset.css create mode 100644 web/src/utils/common.js create mode 100644 web/src/utils/http/helpers.js create mode 100644 web/src/utils/http/index.js create mode 100644 web/src/utils/http/interceptors.js create mode 100644 web/src/utils/index.js create mode 100644 web/src/utils/is.js create mode 100644 web/src/utils/naiveTools.js create mode 100644 web/src/utils/storage/index.js create mode 100644 web/src/utils/storage/storage.js create mode 100644 web/src/views/base/index.vue create mode 100644 web/src/views/base/keep-alive.vue create mode 100644 web/src/views/base/test-modal.vue create mode 100644 web/src/views/base/unocss-icon.vue create mode 100644 web/src/views/base/unocss.vue create mode 100644 web/src/views/demo/upload/index.vue create mode 100644 web/src/views/error-page/403.vue create mode 100644 web/src/views/error-page/404.vue create mode 100644 web/src/views/home/index.vue create mode 100644 web/src/views/iframe/index.vue create mode 100644 web/src/views/login/api.js create mode 100644 web/src/views/login/index.vue create mode 100644 web/src/views/pms/resource/api.js create mode 100644 web/src/views/pms/resource/components/MenuTree.vue create mode 100644 web/src/views/pms/resource/components/QuestionLabel.vue create mode 100644 web/src/views/pms/resource/components/ResAddOrEdit.vue create mode 100644 web/src/views/pms/resource/index.vue create mode 100644 web/src/views/pms/role/api.js create mode 100644 web/src/views/pms/role/index.vue create mode 100644 web/src/views/pms/role/role-user.vue create mode 100644 web/src/views/pms/user/api.js create mode 100644 web/src/views/pms/user/index.vue create mode 100644 web/src/views/profile/api.js create mode 100644 web/src/views/profile/index.vue create mode 100644 web/uno.config.js create mode 100644 web/vite.config.js diff --git a/web b/web deleted file mode 160000 index d0a99dc..0000000 --- a/web +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d0a99dcf123cefe5aed5b263ccde7acd4949da2a diff --git a/web/.editorconfig b/web/.editorconfig new file mode 100644 index 0000000..68cc827 --- /dev/null +++ b/web/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = unset +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/web/.env.development b/web/.env.development new file mode 100644 index 0000000..318c4cb --- /dev/null +++ b/web/.env.development @@ -0,0 +1,12 @@ +# 是否使用Hash路由 +VITE_USE_HASH = 'true' + +# 资源公共路径,需要以 /开头和结尾 +VITE_PUBLIC_PATH = '/' + +# Axios 基础路径 +# VITE_AXIOS_BASE_URL = '/api' # 用于代理 +VITE_AXIOS_BASE_URL = 'https://mock.apipark.cn/m1/3776410-0-default' # apifox云端mock + +# 代理配置-target +VITE_PROXY_TARGET = 'http://localhost:8085' diff --git a/web/.env.production b/web/.env.production new file mode 100644 index 0000000..1b309e4 --- /dev/null +++ b/web/.env.production @@ -0,0 +1,10 @@ +# 是否使用Hash路由 +VITE_USE_HASH = 'false' + +# 资源公共路径,需要以 /开头和结尾 +VITE_PUBLIC_PATH = '/' + +VITE_AXIOS_BASE_URL = '/api' # 用于代理 + +# 代理配置-target +VITE_PROXY_TARGET = 'http://localhost:8085' diff --git a/web/.eslint-global-variables.json b/web/.eslint-global-variables.json new file mode 100644 index 0000000..4f9c397 --- /dev/null +++ b/web/.eslint-global-variables.json @@ -0,0 +1,63 @@ +{ + "globals": { + "$loadingBar": true, + "$message": true, + "$dialog": true, + "$notification": true, + "$modal": true, + "defineOptions": true, + "EffectScope": true, + "computed": true, + "createApp": true, + "customRef": true, + "defineAsyncComponent": true, + "defineComponent": true, + "effectScope": true, + "getCurrentInstance": true, + "getCurrentScope": true, + "h": true, + "inject": true, + "isProxy": true, + "isReactive": true, + "isReadonly": true, + "isRef": true, + "markRaw": true, + "nextTick": true, + "onActivated": true, + "onBeforeMount": true, + "onBeforeUnmount": true, + "onBeforeUpdate": true, + "onDeactivated": true, + "onErrorCaptured": true, + "onMounted": true, + "onRenderTracked": true, + "onRenderTriggered": true, + "onScopeDispose": true, + "onServerPrefetch": true, + "onUnmounted": true, + "onUpdated": true, + "provide": true, + "reactive": true, + "readonly": true, + "ref": true, + "resolveComponent": true, + "shallowReactive": true, + "shallowReadonly": true, + "shallowRef": true, + "toRaw": true, + "toRef": true, + "toRefs": true, + "triggerRef": true, + "unref": true, + "useAttrs": true, + "useCssModule": true, + "useCssVars": true, + "useRoute": true, + "useRouter": true, + "useSlots": true, + "watch": true, + "watchEffect": true, + "watchPostEffect": true, + "watchSyncEffect": true + } +} diff --git a/web/.npmrc b/web/.npmrc new file mode 100644 index 0000000..5cee373 --- /dev/null +++ b/web/.npmrc @@ -0,0 +1,3 @@ +registry=https://registry.npmmirror.com +shamefully-hoist=true +strict-peer-dependencies=false diff --git a/web/LICENSE b/web/LICENSE new file mode 100644 index 0000000..888e80f --- /dev/null +++ b/web/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Ronnie Zhang(大脸怪) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/web/README.md b/web/README.md new file mode 100644 index 0000000..53c2ff5 --- /dev/null +++ b/web/README.md @@ -0,0 +1,89 @@ +

+ + Vue Naive Admin Logo + +

+

+ MIT License +

+ +## 简介 + +Vue Naive Admin 是一款极简风格的后台管理模板,包含前后端解决方案,前端使用 Vite + Vue3 + Pinia + Unocss,后端使用 Nestjs + TypeOrm + MySql,简单易用,赏心悦目,历经十几次重构和细节打磨,诚意满满!! + +## 设计理念 + +Vue Naive Admin 2022年2月开始开源,从 1.0 到现在的 2.0,一直秉持着`简单即正义`的理念,旨在帮助中小企业、在校大学生及个人开发者快速上手开发后台管理项目,为了降低使用者的学习成本,没有使用看似主流的 TypeScript(前端),这也使得 Vue Naive Admin 成为了市面上少有的 `使用 JavaScript 的 Vue3 后台管理模板`,而且还算优秀,得到了大量朋友的认可和喜爱。 + +## 特性 + +- 🆒 使用 **Vue3** 主流最新技术栈: `Vite + Vue3 + Pinia` +- 🍇 使用 **原子CSS**框架: `Unocss`,优雅、轻量、易用 +- 🍍 集成 `Pinia` 状态管理,支持状态持久化 +- 🤹 使用主流的 `iconify + unocss` 图标方案,支持自定义图标,支持动态渲染 +- 🎨 使用 Naive UI,`极致简洁的代码风格和清爽的页面设计`,审美在线,主题轻松定制 +- 👏 先进且易于理解的文件结构设计,多个模块之间**零耦合**,单个业务模块删除不影响其他模块 +- 🚀 `扁平化路由`设计,每一个组件都可以是一个页面,告别多级路由 `KeepAlive` 难实现问题 +- 🍒 `基于权限动态生成路由`,无需额外定义路由,`403和404页面可区分`,而不是无权限也跳404 +- 🔐 基于Redis集成 `无感刷新`,用户登录态可控,安全与体验缺一不可 +- ✨ 基于 Naive UI 封装 `message` 全局工具方法,支持批量提醒,支持跨页面单例模式 +- ⚡️ 基于 Naive UI 封装常用的业务组件,包含`Page` 组件、`CRUD` 表格组件及 `Modal`组件等,简单易用,减少大量重复性工作 + +## 极致的性能 + +![](https://docs.isme.top/Public/Uploads/2023-11-18/6558568b2b476.png) +![](https://docs.isme.top/Public/Uploads/2023-11-18/655853caa9ce8.png) + +## 2.0 和 1.0 区别 + +- 2.0 是基于 1.0 风格从 0 到 1 重新设计的,所以 2.0 看似跟 1.0 很像,但其实代码机构差别还挺大的。 +- 1.0 只提供前端,后端使用 Mock 模拟的,而 2.0 是全栈版,提供真实的后端接口。 +- 2.0 虽然版本高于 1.0,但复杂度却远低于 1.0,虽然 1.0 也很简单。 +- 2.0 的灵活度远高于 1.0,只要你愿意,你可以为每个页面单独定制一个 layout + +[体验1.0 | template.isme.top](https://template.isme.top) + +[体验2.0 | admin.isme.top](https://admin.isme.top) + +## Nestjs 后端 + +Vue Naive Admin 提供一套后端代码,技术栈使用 Nestjs + TypeOrm + MySql,内置 JWT、RABC及模板所需的一些基础接口。 + +- 源码-github: [isme-nest-serve | github](https://github.com/zclzone/isme-nest-serve) +- 源码-gitee: [isme-nest-serve | gitee](https://gitee.com/isme-admin/isme-nest-serve) + +## 文档 + +- 项目文档: [docs | vue-naive-admin](https://docs.isme.top/web/#/624306705/188522224) +- 接口文档: [apidoc | isme-nest-serve](https://apifox.com/apidoc/shared-ff4a4d32-c0d1-4caf-b0ee-6abc130f734a) + +> 注:有个比较常见的问题,就是如何添加菜单和修改菜单,由于项目是由后端控制菜单资源的,所以需要对接后端后在资源管理功能对菜单进行增删改,然后在角色管理功能给对应角色进行授权。具体如何对接后端,请参考 [项目文档](https://docs.isme.top/web/#/624306705/188522224)。当然,可能有些菜单你不想通过权限控制,那么你可以在 `/src/settings.js` 文件添加 basePermissions,只需对齐菜单资源的结构即可,结构可以参照 [接口文档](https://apifox.com/apidoc/shared-ff4a4d32-c0d1-4caf-b0ee-6abc130f734a/api-134536978)。 + +## 使用这个模板开始你的项目 + +[使用这个模板创建Github仓库](https://github.com/zclzone/vue-naive-admin/generate). + +或者使用 `degit` 克隆此仓库,这样将没有任何历史提交记录: + +```cmd +npx degit zclzone/vue-naive-admin +``` + +## 版权说明 + +本项目使用 `MIT协议`,默认授权给任何人,被授权人可免费地无限制的使用、复制、修改、合并、发布、发行、再许可、售卖本软件拷贝、并有权向被供应人授予同等的权利,但必须满足以下条件: + +- 复制、修改和发行本项目代码需包含原作者的版权及许可信息,包括但不限于文件头注释、协议等 + +简单来说,作者只想保留版权,没有任何其他限制。 + +## 其他已对接本项目的后端项目 + +- [isme-java-serve](https://github.com/DHBin/isme-java-serve): 一个轻量级的Java后端服务,基于SpringBoot、MybatisPlus、SaToken、MapStruct等实现,已对接 Vue Naive Admin 2.0。 +- [naive-admin-go](https://github.com/ituserxxx/naive-admin-go): 一个 Go 后端服务,基于 gin、gorm、mysql、jwt和session,已对接 Vue Naive Admin 2.0。 + +## 入群交流 + +添加微信,拉你进群 + +![](https://static.isme.top/image/coder_wx.jpg) diff --git a/web/build/index.js b/web/build/index.js new file mode 100644 index 0000000..985ced8 --- /dev/null +++ b/web/build/index.js @@ -0,0 +1,39 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:48:02 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import path from 'node:path' +import { globSync } from 'glob' +import dynamicIcons from '../src/assets/icons/dynamic-icons' + +/** + * @usage 生成icons, 用于 unocss safelist,以支持页面动态渲染自定义图标 + */ +export function getIcons() { + const feFiles = globSync('src/assets/icons/feather/*.svg', { nodir: true, strict: true }) + const meFiles = globSync('src/assets/icons/isme/*.svg', { nodir: true, strict: true }) + const feIcons = feFiles.map((filePath) => { + const fileName = path.basename(filePath) // 获取文件名,包括后缀 + const fileNameWithoutExt = path.parse(fileName).name // 获取去除后缀的文件名 + return `i-fe:${fileNameWithoutExt}` + }) + const meIcons = meFiles.map((filePath) => { + const fileName = path.basename(filePath) // 获取文件名,包括后缀 + const fileNameWithoutExt = path.parse(fileName).name // 获取去除后缀的文件名 + return `i-me:${fileNameWithoutExt}` + }) + + return [...dynamicIcons, ...feIcons, ...meIcons] +} + +/** + * @usage 生成.vue文件路径列表,用于添加菜单时可下拉选择对应的.vue文件路径,防止手动输入报错 + */ +export function getPagePathes() { + const files = globSync('src/views/**/*.vue') + return files.map(item => `/${path.normalize(item).replace(/\\/g, '/')}`) +} diff --git a/web/build/plugin-isme/icons.js b/web/build/plugin-isme/icons.js new file mode 100644 index 0000000..4da9779 --- /dev/null +++ b/web/build/plugin-isme/icons.js @@ -0,0 +1,25 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:48:11 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { getIcons } from '..' + +const PLUGIN_ICONS_ID = 'isme:icons' +export function pluginIcons() { + return { + name: 'isme:icons', + resolveId(id) { + if (id === PLUGIN_ICONS_ID) + return `\0${PLUGIN_ICONS_ID}` + }, + load(id) { + if (id === `\0${PLUGIN_ICONS_ID}`) { + return `export default ${JSON.stringify(getIcons())}` + } + }, + } +} diff --git a/web/build/plugin-isme/index.js b/web/build/plugin-isme/index.js new file mode 100644 index 0000000..326b960 --- /dev/null +++ b/web/build/plugin-isme/index.js @@ -0,0 +1,10 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:48:17 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +export { pluginPagePathes } from './page-pathes' +export { pluginIcons } from './icons' diff --git a/web/build/plugin-isme/page-pathes.js b/web/build/plugin-isme/page-pathes.js new file mode 100644 index 0000000..a29d8e2 --- /dev/null +++ b/web/build/plugin-isme/page-pathes.js @@ -0,0 +1,25 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:37:43 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { getPagePathes } from '..' + +const PLUGIN_PAGE_PATHES_ID = 'isme:page-pathes' +export function pluginPagePathes() { + return { + name: 'isme:page-pathes', + resolveId(id) { + if (id === PLUGIN_PAGE_PATHES_ID) + return `\0${PLUGIN_PAGE_PATHES_ID}` + }, + load(id) { + if (id === `\0${PLUGIN_PAGE_PATHES_ID}`) { + return `export default ${JSON.stringify(getPagePathes())}` + } + }, + } +} diff --git a/web/eslint.config.js b/web/eslint.config.js new file mode 100644 index 0000000..b15d4e5 --- /dev/null +++ b/web/eslint.config.js @@ -0,0 +1,34 @@ +import antfu from '@antfu/eslint-config' + +export default antfu({ + unocss: true, + formatters: true, + stylistic: true, + rules: { + 'n/prefer-global/process': 'off', + 'no-undef': 'error', + 'no-fallthrough': 'off', + 'vue/block-order': 'off', + '@typescript-eslint/no-this-alias': 'off', + 'prefer-promise-reject-errors': 'off', + }, + languageOptions: { + globals: { + h: 'readonly', + unref: 'readonly', + provide: 'readonly', + inject: 'readonly', + markRaw: 'readonly', + defineAsyncComponent: 'readonly', + nextTick: 'readonly', + useRoute: 'readonly', + useRouter: 'readonly', + Message: 'readonly', + $loadingBar: 'readonly', + $message: 'readonly', + $dialog: 'readonly', + $notification: 'readonly', + $modal: 'readonly', + }, + }, +}) diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..ce02b2d --- /dev/null +++ b/web/index.html @@ -0,0 +1,94 @@ + + + + + + + %VITE_TITLE% + + + +
+
+
+ + + + + +
+
+
+ + + diff --git a/web/jsconfig.json b/web/jsconfig.json new file mode 100644 index 0000000..270b986 --- /dev/null +++ b/web/jsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ESNext", + "baseUrl": "./", + "moduleResolution": "node", + "paths": { + "@/*": ["src/*"], + "~/*": ["./*"] + }, + "jsx": "preserve", + "allowJs": true + }, + "exclude": ["node_modules", "dist"] +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..fd9d2dc --- /dev/null +++ b/web/package.json @@ -0,0 +1,60 @@ +{ + "name": "vue-naive-admin", + "type": "module", + "version": "2.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "lint:fix": "eslint --fix", + "postinstall": "npx simple-git-hooks", + "up": "taze major -I" + }, + "dependencies": { + "@arco-design/color": "^0.4.0", + "@vueuse/core": "^10.11.0", + "axios": "^1.7.2", + "dayjs": "^1.11.11", + "echarts": "^5.5.1", + "lodash-es": "^4.17.21", + "naive-ui": "^2.38.2", + "pinia": "^2.1.7", + "pinia-plugin-persistedstate": "^3.2.1", + "vue": "^3.4.31", + "vue-echarts": "^6.7.3", + "vue-router": "^4.4.0", + "xlsx": "^0.18.5" + }, + "devDependencies": { + "@antfu/eslint-config": "^2.21.2", + "@iconify/json": "^2.2.223", + "@iconify/utils": "^2.1.25", + "@unocss/eslint-config": "^0.61.0", + "@unocss/eslint-plugin": "^0.61.0", + "@unocss/preset-rem-to-px": "^0.61.0", + "@vitejs/plugin-vue": "^5.0.5", + "eslint": "^9.6.0", + "eslint-plugin-format": "^0.1.2", + "esno": "^4.7.0", + "fs-extra": "^11.2.0", + "glob": "^10.4.2", + "lint-staged": "^15.2.7", + "rollup-plugin-visualizer": "^5.12.0", + "sass": "^1.77.6", + "simple-git-hooks": "^2.11.1", + "taze": "^0.13.9", + "unocss": "^0.61.0", + "unplugin-auto-import": "^0.17.6", + "unplugin-vue-components": "^0.27.2", + "vite": "^5.3.2", + "vite-plugin-router-warn": "^1.0.0", + "vite-plugin-vue-devtools": "^7.3.5" + }, + "simple-git-hooks": { + "pre-commit": "pnpm lint-staged" + }, + "lint-staged": { + "*": "eslint --fix" + } +} diff --git a/web/public/favicon.png b/web/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..929c58aa1707fb2320f9bab31262bfaab60a6a47 GIT binary patch literal 3859 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 F{|9)eUV#7r literal 0 HcmV?d00001 diff --git a/web/src/App.vue b/web/src/App.vue new file mode 100644 index 0000000..ccad917 --- /dev/null +++ b/web/src/App.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/web/src/api/index.js b/web/src/api/index.js new file mode 100644 index 0000000..23cbe93 --- /dev/null +++ b/web/src/api/index.js @@ -0,0 +1,24 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:50:38 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { request } from '@/utils' + +export default { + // 获取用户信息 + getUser: () => request.get('/user/detail'), + // 刷新token + refreshToken: () => request.get('/auth/refresh/token'), + // 登出 + logout: () => request.post('/auth/logout', {}, { needTip: false }), + // 切换当前角色 + switchCurrentRole: role => request.post(`/auth/current-role/switch/${role}`), + // 获取角色权限 + getRolePermissions: () => request.get('/role/permissions/tree'), + // 验证菜单路径 + validateMenuPath: path => request.get(`/permission/menu/validate?path=${path}`), +} diff --git a/web/src/assets/icons/dynamic-icons.js b/web/src/assets/icons/dynamic-icons.js new file mode 100644 index 0000000..5326f66 --- /dev/null +++ b/web/src/assets/icons/dynamic-icons.js @@ -0,0 +1,10 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:50:49 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +// 需要动态渲染的iconify图标,以i-开头 +export default ['i-simple-icons:juejin'] diff --git a/web/src/assets/icons/feather/activity.svg b/web/src/assets/icons/feather/activity.svg new file mode 100644 index 0000000..669a57a --- /dev/null +++ b/web/src/assets/icons/feather/activity.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/airplay.svg b/web/src/assets/icons/feather/airplay.svg new file mode 100644 index 0000000..7ce7302 --- /dev/null +++ b/web/src/assets/icons/feather/airplay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/alert-circle.svg b/web/src/assets/icons/feather/alert-circle.svg new file mode 100644 index 0000000..8d02b7d --- /dev/null +++ b/web/src/assets/icons/feather/alert-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/alert-octagon.svg b/web/src/assets/icons/feather/alert-octagon.svg new file mode 100644 index 0000000..de9b03f --- /dev/null +++ b/web/src/assets/icons/feather/alert-octagon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/alert-triangle.svg b/web/src/assets/icons/feather/alert-triangle.svg new file mode 100644 index 0000000..6dcb096 --- /dev/null +++ b/web/src/assets/icons/feather/alert-triangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/align-center.svg b/web/src/assets/icons/feather/align-center.svg new file mode 100644 index 0000000..5b8842e --- /dev/null +++ b/web/src/assets/icons/feather/align-center.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/align-justify.svg b/web/src/assets/icons/feather/align-justify.svg new file mode 100644 index 0000000..0539876 --- /dev/null +++ b/web/src/assets/icons/feather/align-justify.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/align-left.svg b/web/src/assets/icons/feather/align-left.svg new file mode 100644 index 0000000..9ac852a --- /dev/null +++ b/web/src/assets/icons/feather/align-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/align-right.svg b/web/src/assets/icons/feather/align-right.svg new file mode 100644 index 0000000..ef139ff --- /dev/null +++ b/web/src/assets/icons/feather/align-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/anchor.svg b/web/src/assets/icons/feather/anchor.svg new file mode 100644 index 0000000..e01627a --- /dev/null +++ b/web/src/assets/icons/feather/anchor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/aperture.svg b/web/src/assets/icons/feather/aperture.svg new file mode 100644 index 0000000..9936e86 --- /dev/null +++ b/web/src/assets/icons/feather/aperture.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/archive.svg b/web/src/assets/icons/feather/archive.svg new file mode 100644 index 0000000..428882c --- /dev/null +++ b/web/src/assets/icons/feather/archive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-down-circle.svg b/web/src/assets/icons/feather/arrow-down-circle.svg new file mode 100644 index 0000000..3238091 --- /dev/null +++ b/web/src/assets/icons/feather/arrow-down-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-down-left.svg b/web/src/assets/icons/feather/arrow-down-left.svg new file mode 100644 index 0000000..7248358 --- /dev/null +++ b/web/src/assets/icons/feather/arrow-down-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-down-right.svg b/web/src/assets/icons/feather/arrow-down-right.svg new file mode 100644 index 0000000..81d9822 --- /dev/null +++ b/web/src/assets/icons/feather/arrow-down-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-down.svg b/web/src/assets/icons/feather/arrow-down.svg new file mode 100644 index 0000000..4f84f62 --- /dev/null +++ b/web/src/assets/icons/feather/arrow-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-left-circle.svg b/web/src/assets/icons/feather/arrow-left-circle.svg new file mode 100644 index 0000000..3b19ff8 --- /dev/null +++ b/web/src/assets/icons/feather/arrow-left-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-left.svg b/web/src/assets/icons/feather/arrow-left.svg new file mode 100644 index 0000000..a5058fc --- /dev/null +++ b/web/src/assets/icons/feather/arrow-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-right-circle.svg b/web/src/assets/icons/feather/arrow-right-circle.svg new file mode 100644 index 0000000..ff01dd5 --- /dev/null +++ b/web/src/assets/icons/feather/arrow-right-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-right.svg b/web/src/assets/icons/feather/arrow-right.svg new file mode 100644 index 0000000..939b57c --- /dev/null +++ b/web/src/assets/icons/feather/arrow-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-up-circle.svg b/web/src/assets/icons/feather/arrow-up-circle.svg new file mode 100644 index 0000000..044a75d --- /dev/null +++ b/web/src/assets/icons/feather/arrow-up-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-up-left.svg b/web/src/assets/icons/feather/arrow-up-left.svg new file mode 100644 index 0000000..cea55e8 --- /dev/null +++ b/web/src/assets/icons/feather/arrow-up-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-up-right.svg b/web/src/assets/icons/feather/arrow-up-right.svg new file mode 100644 index 0000000..95678e0 --- /dev/null +++ b/web/src/assets/icons/feather/arrow-up-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/arrow-up.svg b/web/src/assets/icons/feather/arrow-up.svg new file mode 100644 index 0000000..16b13ab --- /dev/null +++ b/web/src/assets/icons/feather/arrow-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/at-sign.svg b/web/src/assets/icons/feather/at-sign.svg new file mode 100644 index 0000000..5a5e5d0 --- /dev/null +++ b/web/src/assets/icons/feather/at-sign.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/award.svg b/web/src/assets/icons/feather/award.svg new file mode 100644 index 0000000..be70d5a --- /dev/null +++ b/web/src/assets/icons/feather/award.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/bar-chart-2.svg b/web/src/assets/icons/feather/bar-chart-2.svg new file mode 100644 index 0000000..864167a --- /dev/null +++ b/web/src/assets/icons/feather/bar-chart-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/bar-chart.svg b/web/src/assets/icons/feather/bar-chart.svg new file mode 100644 index 0000000..074d7c1 --- /dev/null +++ b/web/src/assets/icons/feather/bar-chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/battery-charging.svg b/web/src/assets/icons/feather/battery-charging.svg new file mode 100644 index 0000000..644cb59 --- /dev/null +++ b/web/src/assets/icons/feather/battery-charging.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/battery.svg b/web/src/assets/icons/feather/battery.svg new file mode 100644 index 0000000..7fe8771 --- /dev/null +++ b/web/src/assets/icons/feather/battery.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/bell-off.svg b/web/src/assets/icons/feather/bell-off.svg new file mode 100644 index 0000000..4b07c84 --- /dev/null +++ b/web/src/assets/icons/feather/bell-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/bell.svg b/web/src/assets/icons/feather/bell.svg new file mode 100644 index 0000000..bba561c --- /dev/null +++ b/web/src/assets/icons/feather/bell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/bluetooth.svg b/web/src/assets/icons/feather/bluetooth.svg new file mode 100644 index 0000000..cebed7b --- /dev/null +++ b/web/src/assets/icons/feather/bluetooth.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/bold.svg b/web/src/assets/icons/feather/bold.svg new file mode 100644 index 0000000..d1a4efd --- /dev/null +++ b/web/src/assets/icons/feather/bold.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/book-open.svg b/web/src/assets/icons/feather/book-open.svg new file mode 100644 index 0000000..5e0ca0a --- /dev/null +++ b/web/src/assets/icons/feather/book-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/book.svg b/web/src/assets/icons/feather/book.svg new file mode 100644 index 0000000..12ffcbc --- /dev/null +++ b/web/src/assets/icons/feather/book.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/bookmark.svg b/web/src/assets/icons/feather/bookmark.svg new file mode 100644 index 0000000..2239cc5 --- /dev/null +++ b/web/src/assets/icons/feather/bookmark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/box.svg b/web/src/assets/icons/feather/box.svg new file mode 100644 index 0000000..d89be30 --- /dev/null +++ b/web/src/assets/icons/feather/box.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/briefcase.svg b/web/src/assets/icons/feather/briefcase.svg new file mode 100644 index 0000000..e3af050 --- /dev/null +++ b/web/src/assets/icons/feather/briefcase.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/calendar.svg b/web/src/assets/icons/feather/calendar.svg new file mode 100644 index 0000000..6c7fd87 --- /dev/null +++ b/web/src/assets/icons/feather/calendar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/camera-off.svg b/web/src/assets/icons/feather/camera-off.svg new file mode 100644 index 0000000..daa3e25 --- /dev/null +++ b/web/src/assets/icons/feather/camera-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/camera.svg b/web/src/assets/icons/feather/camera.svg new file mode 100644 index 0000000..0e7f060 --- /dev/null +++ b/web/src/assets/icons/feather/camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/cast.svg b/web/src/assets/icons/feather/cast.svg new file mode 100644 index 0000000..63c954d --- /dev/null +++ b/web/src/assets/icons/feather/cast.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/check-circle.svg b/web/src/assets/icons/feather/check-circle.svg new file mode 100644 index 0000000..f2f4fd1 --- /dev/null +++ b/web/src/assets/icons/feather/check-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/check-square.svg b/web/src/assets/icons/feather/check-square.svg new file mode 100644 index 0000000..72ab7a8 --- /dev/null +++ b/web/src/assets/icons/feather/check-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/check.svg b/web/src/assets/icons/feather/check.svg new file mode 100644 index 0000000..1c20989 --- /dev/null +++ b/web/src/assets/icons/feather/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/chevron-down.svg b/web/src/assets/icons/feather/chevron-down.svg new file mode 100644 index 0000000..278c6a3 --- /dev/null +++ b/web/src/assets/icons/feather/chevron-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/chevron-left.svg b/web/src/assets/icons/feather/chevron-left.svg new file mode 100644 index 0000000..747d46d --- /dev/null +++ b/web/src/assets/icons/feather/chevron-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/chevron-right.svg b/web/src/assets/icons/feather/chevron-right.svg new file mode 100644 index 0000000..258de41 --- /dev/null +++ b/web/src/assets/icons/feather/chevron-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/chevron-up.svg b/web/src/assets/icons/feather/chevron-up.svg new file mode 100644 index 0000000..4eb5ecc --- /dev/null +++ b/web/src/assets/icons/feather/chevron-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/chevrons-down.svg b/web/src/assets/icons/feather/chevrons-down.svg new file mode 100644 index 0000000..e67ef2f --- /dev/null +++ b/web/src/assets/icons/feather/chevrons-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/chevrons-left.svg b/web/src/assets/icons/feather/chevrons-left.svg new file mode 100644 index 0000000..c32e398 --- /dev/null +++ b/web/src/assets/icons/feather/chevrons-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/chevrons-right.svg b/web/src/assets/icons/feather/chevrons-right.svg new file mode 100644 index 0000000..f506814 --- /dev/null +++ b/web/src/assets/icons/feather/chevrons-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/chevrons-up.svg b/web/src/assets/icons/feather/chevrons-up.svg new file mode 100644 index 0000000..0eaf518 --- /dev/null +++ b/web/src/assets/icons/feather/chevrons-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/chrome.svg b/web/src/assets/icons/feather/chrome.svg new file mode 100644 index 0000000..9189815 --- /dev/null +++ b/web/src/assets/icons/feather/chrome.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/circle.svg b/web/src/assets/icons/feather/circle.svg new file mode 100644 index 0000000..b009088 --- /dev/null +++ b/web/src/assets/icons/feather/circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/clipboard.svg b/web/src/assets/icons/feather/clipboard.svg new file mode 100644 index 0000000..ccee454 --- /dev/null +++ b/web/src/assets/icons/feather/clipboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/clock.svg b/web/src/assets/icons/feather/clock.svg new file mode 100644 index 0000000..ea3f5e5 --- /dev/null +++ b/web/src/assets/icons/feather/clock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/cloud-drizzle.svg b/web/src/assets/icons/feather/cloud-drizzle.svg new file mode 100644 index 0000000..13af6bb --- /dev/null +++ b/web/src/assets/icons/feather/cloud-drizzle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/cloud-lightning.svg b/web/src/assets/icons/feather/cloud-lightning.svg new file mode 100644 index 0000000..32d154c --- /dev/null +++ b/web/src/assets/icons/feather/cloud-lightning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/cloud-off.svg b/web/src/assets/icons/feather/cloud-off.svg new file mode 100644 index 0000000..1e1e7d6 --- /dev/null +++ b/web/src/assets/icons/feather/cloud-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/cloud-rain.svg b/web/src/assets/icons/feather/cloud-rain.svg new file mode 100644 index 0000000..3e0b85b --- /dev/null +++ b/web/src/assets/icons/feather/cloud-rain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/cloud-snow.svg b/web/src/assets/icons/feather/cloud-snow.svg new file mode 100644 index 0000000..e4eb820 --- /dev/null +++ b/web/src/assets/icons/feather/cloud-snow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/cloud.svg b/web/src/assets/icons/feather/cloud.svg new file mode 100644 index 0000000..0ee0c63 --- /dev/null +++ b/web/src/assets/icons/feather/cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/code.svg b/web/src/assets/icons/feather/code.svg new file mode 100644 index 0000000..c4954b5 --- /dev/null +++ b/web/src/assets/icons/feather/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/codepen.svg b/web/src/assets/icons/feather/codepen.svg new file mode 100644 index 0000000..ab2a815 --- /dev/null +++ b/web/src/assets/icons/feather/codepen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/codesandbox.svg b/web/src/assets/icons/feather/codesandbox.svg new file mode 100644 index 0000000..49848f5 --- /dev/null +++ b/web/src/assets/icons/feather/codesandbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/coffee.svg b/web/src/assets/icons/feather/coffee.svg new file mode 100644 index 0000000..32905e5 --- /dev/null +++ b/web/src/assets/icons/feather/coffee.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/columns.svg b/web/src/assets/icons/feather/columns.svg new file mode 100644 index 0000000..d264b55 --- /dev/null +++ b/web/src/assets/icons/feather/columns.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/command.svg b/web/src/assets/icons/feather/command.svg new file mode 100644 index 0000000..93f554c --- /dev/null +++ b/web/src/assets/icons/feather/command.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/compass.svg b/web/src/assets/icons/feather/compass.svg new file mode 100644 index 0000000..3296260 --- /dev/null +++ b/web/src/assets/icons/feather/compass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/copy.svg b/web/src/assets/icons/feather/copy.svg new file mode 100644 index 0000000..4e0b09f --- /dev/null +++ b/web/src/assets/icons/feather/copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/corner-down-left.svg b/web/src/assets/icons/feather/corner-down-left.svg new file mode 100644 index 0000000..9fffb3e --- /dev/null +++ b/web/src/assets/icons/feather/corner-down-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/corner-down-right.svg b/web/src/assets/icons/feather/corner-down-right.svg new file mode 100644 index 0000000..b27d408 --- /dev/null +++ b/web/src/assets/icons/feather/corner-down-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/corner-left-down.svg b/web/src/assets/icons/feather/corner-left-down.svg new file mode 100644 index 0000000..24b8375 --- /dev/null +++ b/web/src/assets/icons/feather/corner-left-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/corner-left-up.svg b/web/src/assets/icons/feather/corner-left-up.svg new file mode 100644 index 0000000..e54527c --- /dev/null +++ b/web/src/assets/icons/feather/corner-left-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/corner-right-down.svg b/web/src/assets/icons/feather/corner-right-down.svg new file mode 100644 index 0000000..a49e6d6 --- /dev/null +++ b/web/src/assets/icons/feather/corner-right-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/corner-right-up.svg b/web/src/assets/icons/feather/corner-right-up.svg new file mode 100644 index 0000000..a5c5dce --- /dev/null +++ b/web/src/assets/icons/feather/corner-right-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/corner-up-left.svg b/web/src/assets/icons/feather/corner-up-left.svg new file mode 100644 index 0000000..0a1ffd6 --- /dev/null +++ b/web/src/assets/icons/feather/corner-up-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/corner-up-right.svg b/web/src/assets/icons/feather/corner-up-right.svg new file mode 100644 index 0000000..0b8f961 --- /dev/null +++ b/web/src/assets/icons/feather/corner-up-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/cpu.svg b/web/src/assets/icons/feather/cpu.svg new file mode 100644 index 0000000..2ed16ef --- /dev/null +++ b/web/src/assets/icons/feather/cpu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/credit-card.svg b/web/src/assets/icons/feather/credit-card.svg new file mode 100644 index 0000000..1b7fd02 --- /dev/null +++ b/web/src/assets/icons/feather/credit-card.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/crop.svg b/web/src/assets/icons/feather/crop.svg new file mode 100644 index 0000000..ffbfd04 --- /dev/null +++ b/web/src/assets/icons/feather/crop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/crosshair.svg b/web/src/assets/icons/feather/crosshair.svg new file mode 100644 index 0000000..ba39401 --- /dev/null +++ b/web/src/assets/icons/feather/crosshair.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/database.svg b/web/src/assets/icons/feather/database.svg new file mode 100644 index 0000000..c296fbc --- /dev/null +++ b/web/src/assets/icons/feather/database.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/delete.svg b/web/src/assets/icons/feather/delete.svg new file mode 100644 index 0000000..8c6074b --- /dev/null +++ b/web/src/assets/icons/feather/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/disc.svg b/web/src/assets/icons/feather/disc.svg new file mode 100644 index 0000000..2595b44 --- /dev/null +++ b/web/src/assets/icons/feather/disc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/divide.svg b/web/src/assets/icons/feather/divide.svg new file mode 100644 index 0000000..3cbff3a --- /dev/null +++ b/web/src/assets/icons/feather/divide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/dollar-sign.svg b/web/src/assets/icons/feather/dollar-sign.svg new file mode 100644 index 0000000..1a124d2 --- /dev/null +++ b/web/src/assets/icons/feather/dollar-sign.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/download-cloud.svg b/web/src/assets/icons/feather/download-cloud.svg new file mode 100644 index 0000000..f3126fc --- /dev/null +++ b/web/src/assets/icons/feather/download-cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/download.svg b/web/src/assets/icons/feather/download.svg new file mode 100644 index 0000000..76767a9 --- /dev/null +++ b/web/src/assets/icons/feather/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/dribbble.svg b/web/src/assets/icons/feather/dribbble.svg new file mode 100644 index 0000000..bb8577d --- /dev/null +++ b/web/src/assets/icons/feather/dribbble.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/droplet.svg b/web/src/assets/icons/feather/droplet.svg new file mode 100644 index 0000000..ca09301 --- /dev/null +++ b/web/src/assets/icons/feather/droplet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/edit-2.svg b/web/src/assets/icons/feather/edit-2.svg new file mode 100644 index 0000000..06830c9 --- /dev/null +++ b/web/src/assets/icons/feather/edit-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/edit-3.svg b/web/src/assets/icons/feather/edit-3.svg new file mode 100644 index 0000000..d728efc --- /dev/null +++ b/web/src/assets/icons/feather/edit-3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/edit.svg b/web/src/assets/icons/feather/edit.svg new file mode 100644 index 0000000..ec7b4ca --- /dev/null +++ b/web/src/assets/icons/feather/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/external-link.svg b/web/src/assets/icons/feather/external-link.svg new file mode 100644 index 0000000..6236df3 --- /dev/null +++ b/web/src/assets/icons/feather/external-link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/eye-off.svg b/web/src/assets/icons/feather/eye-off.svg new file mode 100644 index 0000000..77c54cb --- /dev/null +++ b/web/src/assets/icons/feather/eye-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/eye.svg b/web/src/assets/icons/feather/eye.svg new file mode 100644 index 0000000..9cde243 --- /dev/null +++ b/web/src/assets/icons/feather/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/facebook.svg b/web/src/assets/icons/feather/facebook.svg new file mode 100644 index 0000000..2570f56 --- /dev/null +++ b/web/src/assets/icons/feather/facebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/fast-forward.svg b/web/src/assets/icons/feather/fast-forward.svg new file mode 100644 index 0000000..fa39877 --- /dev/null +++ b/web/src/assets/icons/feather/fast-forward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/feather.svg b/web/src/assets/icons/feather/feather.svg new file mode 100644 index 0000000..ac3b868 --- /dev/null +++ b/web/src/assets/icons/feather/feather.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/figma.svg b/web/src/assets/icons/feather/figma.svg new file mode 100644 index 0000000..66fd217 --- /dev/null +++ b/web/src/assets/icons/feather/figma.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/file-minus.svg b/web/src/assets/icons/feather/file-minus.svg new file mode 100644 index 0000000..345756e --- /dev/null +++ b/web/src/assets/icons/feather/file-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/file-plus.svg b/web/src/assets/icons/feather/file-plus.svg new file mode 100644 index 0000000..eed1200 --- /dev/null +++ b/web/src/assets/icons/feather/file-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/file-text.svg b/web/src/assets/icons/feather/file-text.svg new file mode 100644 index 0000000..4197ddd --- /dev/null +++ b/web/src/assets/icons/feather/file-text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/file.svg b/web/src/assets/icons/feather/file.svg new file mode 100644 index 0000000..378519a --- /dev/null +++ b/web/src/assets/icons/feather/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/film.svg b/web/src/assets/icons/feather/film.svg new file mode 100644 index 0000000..ac46360 --- /dev/null +++ b/web/src/assets/icons/feather/film.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/filter.svg b/web/src/assets/icons/feather/filter.svg new file mode 100644 index 0000000..38a47e0 --- /dev/null +++ b/web/src/assets/icons/feather/filter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/flag.svg b/web/src/assets/icons/feather/flag.svg new file mode 100644 index 0000000..037737c --- /dev/null +++ b/web/src/assets/icons/feather/flag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/folder-minus.svg b/web/src/assets/icons/feather/folder-minus.svg new file mode 100644 index 0000000..d5b7af6 --- /dev/null +++ b/web/src/assets/icons/feather/folder-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/folder-plus.svg b/web/src/assets/icons/feather/folder-plus.svg new file mode 100644 index 0000000..898f2fc --- /dev/null +++ b/web/src/assets/icons/feather/folder-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/folder.svg b/web/src/assets/icons/feather/folder.svg new file mode 100644 index 0000000..134458b --- /dev/null +++ b/web/src/assets/icons/feather/folder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/framer.svg b/web/src/assets/icons/feather/framer.svg new file mode 100644 index 0000000..3e66347 --- /dev/null +++ b/web/src/assets/icons/feather/framer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/frown.svg b/web/src/assets/icons/feather/frown.svg new file mode 100644 index 0000000..f312254 --- /dev/null +++ b/web/src/assets/icons/feather/frown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/gift.svg b/web/src/assets/icons/feather/gift.svg new file mode 100644 index 0000000..d2c14bd --- /dev/null +++ b/web/src/assets/icons/feather/gift.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/git-branch.svg b/web/src/assets/icons/feather/git-branch.svg new file mode 100644 index 0000000..4400372 --- /dev/null +++ b/web/src/assets/icons/feather/git-branch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/git-commit.svg b/web/src/assets/icons/feather/git-commit.svg new file mode 100644 index 0000000..e959d72 --- /dev/null +++ b/web/src/assets/icons/feather/git-commit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/git-merge.svg b/web/src/assets/icons/feather/git-merge.svg new file mode 100644 index 0000000..c65fffd --- /dev/null +++ b/web/src/assets/icons/feather/git-merge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/git-pull-request.svg b/web/src/assets/icons/feather/git-pull-request.svg new file mode 100644 index 0000000..fc80bdf --- /dev/null +++ b/web/src/assets/icons/feather/git-pull-request.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/github.svg b/web/src/assets/icons/feather/github.svg new file mode 100644 index 0000000..ff0af48 --- /dev/null +++ b/web/src/assets/icons/feather/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/gitlab.svg b/web/src/assets/icons/feather/gitlab.svg new file mode 100644 index 0000000..85d54a1 --- /dev/null +++ b/web/src/assets/icons/feather/gitlab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/globe.svg b/web/src/assets/icons/feather/globe.svg new file mode 100644 index 0000000..0a0586d --- /dev/null +++ b/web/src/assets/icons/feather/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/grid.svg b/web/src/assets/icons/feather/grid.svg new file mode 100644 index 0000000..8ef2e9d --- /dev/null +++ b/web/src/assets/icons/feather/grid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/hard-drive.svg b/web/src/assets/icons/feather/hard-drive.svg new file mode 100644 index 0000000..8e90fa1 --- /dev/null +++ b/web/src/assets/icons/feather/hard-drive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/hash.svg b/web/src/assets/icons/feather/hash.svg new file mode 100644 index 0000000..c9c8d41 --- /dev/null +++ b/web/src/assets/icons/feather/hash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/headphones.svg b/web/src/assets/icons/feather/headphones.svg new file mode 100644 index 0000000..fd8915b --- /dev/null +++ b/web/src/assets/icons/feather/headphones.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/heart.svg b/web/src/assets/icons/feather/heart.svg new file mode 100644 index 0000000..a083b7e --- /dev/null +++ b/web/src/assets/icons/feather/heart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/help-circle.svg b/web/src/assets/icons/feather/help-circle.svg new file mode 100644 index 0000000..51fddd8 --- /dev/null +++ b/web/src/assets/icons/feather/help-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/hexagon.svg b/web/src/assets/icons/feather/hexagon.svg new file mode 100644 index 0000000..eae7f25 --- /dev/null +++ b/web/src/assets/icons/feather/hexagon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/home.svg b/web/src/assets/icons/feather/home.svg new file mode 100644 index 0000000..7bb31b2 --- /dev/null +++ b/web/src/assets/icons/feather/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/image.svg b/web/src/assets/icons/feather/image.svg new file mode 100644 index 0000000..a7d84b9 --- /dev/null +++ b/web/src/assets/icons/feather/image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/inbox.svg b/web/src/assets/icons/feather/inbox.svg new file mode 100644 index 0000000..03a13b4 --- /dev/null +++ b/web/src/assets/icons/feather/inbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/info.svg b/web/src/assets/icons/feather/info.svg new file mode 100644 index 0000000..a09fa5f --- /dev/null +++ b/web/src/assets/icons/feather/info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/instagram.svg b/web/src/assets/icons/feather/instagram.svg new file mode 100644 index 0000000..9fdb8e3 --- /dev/null +++ b/web/src/assets/icons/feather/instagram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/italic.svg b/web/src/assets/icons/feather/italic.svg new file mode 100644 index 0000000..a123d37 --- /dev/null +++ b/web/src/assets/icons/feather/italic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/key.svg b/web/src/assets/icons/feather/key.svg new file mode 100644 index 0000000..e778e74 --- /dev/null +++ b/web/src/assets/icons/feather/key.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/layers.svg b/web/src/assets/icons/feather/layers.svg new file mode 100644 index 0000000..ea788c2 --- /dev/null +++ b/web/src/assets/icons/feather/layers.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/layout.svg b/web/src/assets/icons/feather/layout.svg new file mode 100644 index 0000000..28743d9 --- /dev/null +++ b/web/src/assets/icons/feather/layout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/life-buoy.svg b/web/src/assets/icons/feather/life-buoy.svg new file mode 100644 index 0000000..54c2bd7 --- /dev/null +++ b/web/src/assets/icons/feather/life-buoy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/link-2.svg b/web/src/assets/icons/feather/link-2.svg new file mode 100644 index 0000000..8cc7f6d --- /dev/null +++ b/web/src/assets/icons/feather/link-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/link.svg b/web/src/assets/icons/feather/link.svg new file mode 100644 index 0000000..c89dd41 --- /dev/null +++ b/web/src/assets/icons/feather/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/linkedin.svg b/web/src/assets/icons/feather/linkedin.svg new file mode 100644 index 0000000..3953109 --- /dev/null +++ b/web/src/assets/icons/feather/linkedin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/list.svg b/web/src/assets/icons/feather/list.svg new file mode 100644 index 0000000..5ce38ea --- /dev/null +++ b/web/src/assets/icons/feather/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/loader.svg b/web/src/assets/icons/feather/loader.svg new file mode 100644 index 0000000..e1a70c1 --- /dev/null +++ b/web/src/assets/icons/feather/loader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/lock.svg b/web/src/assets/icons/feather/lock.svg new file mode 100644 index 0000000..de09d9d --- /dev/null +++ b/web/src/assets/icons/feather/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/log-in.svg b/web/src/assets/icons/feather/log-in.svg new file mode 100644 index 0000000..ba0da59 --- /dev/null +++ b/web/src/assets/icons/feather/log-in.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/log-out.svg b/web/src/assets/icons/feather/log-out.svg new file mode 100644 index 0000000..c9002c9 --- /dev/null +++ b/web/src/assets/icons/feather/log-out.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/mail.svg b/web/src/assets/icons/feather/mail.svg new file mode 100644 index 0000000..2af169e --- /dev/null +++ b/web/src/assets/icons/feather/mail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/map-pin.svg b/web/src/assets/icons/feather/map-pin.svg new file mode 100644 index 0000000..d5548e9 --- /dev/null +++ b/web/src/assets/icons/feather/map-pin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/map.svg b/web/src/assets/icons/feather/map.svg new file mode 100644 index 0000000..ecebd7b --- /dev/null +++ b/web/src/assets/icons/feather/map.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/maximize-2.svg b/web/src/assets/icons/feather/maximize-2.svg new file mode 100644 index 0000000..e41fc0b --- /dev/null +++ b/web/src/assets/icons/feather/maximize-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/maximize.svg b/web/src/assets/icons/feather/maximize.svg new file mode 100644 index 0000000..fc30518 --- /dev/null +++ b/web/src/assets/icons/feather/maximize.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/meh.svg b/web/src/assets/icons/feather/meh.svg new file mode 100644 index 0000000..6f57fff --- /dev/null +++ b/web/src/assets/icons/feather/meh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/menu.svg b/web/src/assets/icons/feather/menu.svg new file mode 100644 index 0000000..e8a84a9 --- /dev/null +++ b/web/src/assets/icons/feather/menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/message-circle.svg b/web/src/assets/icons/feather/message-circle.svg new file mode 100644 index 0000000..4b21b32 --- /dev/null +++ b/web/src/assets/icons/feather/message-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/message-square.svg b/web/src/assets/icons/feather/message-square.svg new file mode 100644 index 0000000..6a2e4e5 --- /dev/null +++ b/web/src/assets/icons/feather/message-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/mic-off.svg b/web/src/assets/icons/feather/mic-off.svg new file mode 100644 index 0000000..0786219 --- /dev/null +++ b/web/src/assets/icons/feather/mic-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/mic.svg b/web/src/assets/icons/feather/mic.svg new file mode 100644 index 0000000..dc5f780 --- /dev/null +++ b/web/src/assets/icons/feather/mic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/minimize-2.svg b/web/src/assets/icons/feather/minimize-2.svg new file mode 100644 index 0000000..a720fa6 --- /dev/null +++ b/web/src/assets/icons/feather/minimize-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/minimize.svg b/web/src/assets/icons/feather/minimize.svg new file mode 100644 index 0000000..46d6119 --- /dev/null +++ b/web/src/assets/icons/feather/minimize.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/minus-circle.svg b/web/src/assets/icons/feather/minus-circle.svg new file mode 100644 index 0000000..80c0de1 --- /dev/null +++ b/web/src/assets/icons/feather/minus-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/minus-square.svg b/web/src/assets/icons/feather/minus-square.svg new file mode 100644 index 0000000..4862832 --- /dev/null +++ b/web/src/assets/icons/feather/minus-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/minus.svg b/web/src/assets/icons/feather/minus.svg new file mode 100644 index 0000000..93cc734 --- /dev/null +++ b/web/src/assets/icons/feather/minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/monitor.svg b/web/src/assets/icons/feather/monitor.svg new file mode 100644 index 0000000..6c3556d --- /dev/null +++ b/web/src/assets/icons/feather/monitor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/moon.svg b/web/src/assets/icons/feather/moon.svg new file mode 100644 index 0000000..dbf7c6c --- /dev/null +++ b/web/src/assets/icons/feather/moon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/more-horizontal.svg b/web/src/assets/icons/feather/more-horizontal.svg new file mode 100644 index 0000000..dc6a855 --- /dev/null +++ b/web/src/assets/icons/feather/more-horizontal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/more-vertical.svg b/web/src/assets/icons/feather/more-vertical.svg new file mode 100644 index 0000000..cba6958 --- /dev/null +++ b/web/src/assets/icons/feather/more-vertical.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/mouse-pointer.svg b/web/src/assets/icons/feather/mouse-pointer.svg new file mode 100644 index 0000000..f5af559 --- /dev/null +++ b/web/src/assets/icons/feather/mouse-pointer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/move.svg b/web/src/assets/icons/feather/move.svg new file mode 100644 index 0000000..4e251b5 --- /dev/null +++ b/web/src/assets/icons/feather/move.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/music.svg b/web/src/assets/icons/feather/music.svg new file mode 100644 index 0000000..7bee2f7 --- /dev/null +++ b/web/src/assets/icons/feather/music.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/navigation-2.svg b/web/src/assets/icons/feather/navigation-2.svg new file mode 100644 index 0000000..ae31db9 --- /dev/null +++ b/web/src/assets/icons/feather/navigation-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/navigation.svg b/web/src/assets/icons/feather/navigation.svg new file mode 100644 index 0000000..f600a41 --- /dev/null +++ b/web/src/assets/icons/feather/navigation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/octagon.svg b/web/src/assets/icons/feather/octagon.svg new file mode 100644 index 0000000..124c548 --- /dev/null +++ b/web/src/assets/icons/feather/octagon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/package.svg b/web/src/assets/icons/feather/package.svg new file mode 100644 index 0000000..f1e09ee --- /dev/null +++ b/web/src/assets/icons/feather/package.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/paperclip.svg b/web/src/assets/icons/feather/paperclip.svg new file mode 100644 index 0000000..b1f69b7 --- /dev/null +++ b/web/src/assets/icons/feather/paperclip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/pause-circle.svg b/web/src/assets/icons/feather/pause-circle.svg new file mode 100644 index 0000000..f6b1a8d --- /dev/null +++ b/web/src/assets/icons/feather/pause-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/pause.svg b/web/src/assets/icons/feather/pause.svg new file mode 100644 index 0000000..4e78038 --- /dev/null +++ b/web/src/assets/icons/feather/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/pen-tool.svg b/web/src/assets/icons/feather/pen-tool.svg new file mode 100644 index 0000000..0d26fa1 --- /dev/null +++ b/web/src/assets/icons/feather/pen-tool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/percent.svg b/web/src/assets/icons/feather/percent.svg new file mode 100644 index 0000000..2cb9719 --- /dev/null +++ b/web/src/assets/icons/feather/percent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/phone-call.svg b/web/src/assets/icons/feather/phone-call.svg new file mode 100644 index 0000000..8b86660 --- /dev/null +++ b/web/src/assets/icons/feather/phone-call.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/phone-forwarded.svg b/web/src/assets/icons/feather/phone-forwarded.svg new file mode 100644 index 0000000..aa21bef --- /dev/null +++ b/web/src/assets/icons/feather/phone-forwarded.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/phone-incoming.svg b/web/src/assets/icons/feather/phone-incoming.svg new file mode 100644 index 0000000..b2d523a --- /dev/null +++ b/web/src/assets/icons/feather/phone-incoming.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/phone-missed.svg b/web/src/assets/icons/feather/phone-missed.svg new file mode 100644 index 0000000..4950f09 --- /dev/null +++ b/web/src/assets/icons/feather/phone-missed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/phone-off.svg b/web/src/assets/icons/feather/phone-off.svg new file mode 100644 index 0000000..4d00fb3 --- /dev/null +++ b/web/src/assets/icons/feather/phone-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/phone-outgoing.svg b/web/src/assets/icons/feather/phone-outgoing.svg new file mode 100644 index 0000000..fea27a3 --- /dev/null +++ b/web/src/assets/icons/feather/phone-outgoing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/phone.svg b/web/src/assets/icons/feather/phone.svg new file mode 100644 index 0000000..2a35154 --- /dev/null +++ b/web/src/assets/icons/feather/phone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/pie-chart.svg b/web/src/assets/icons/feather/pie-chart.svg new file mode 100644 index 0000000..b5bbe67 --- /dev/null +++ b/web/src/assets/icons/feather/pie-chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/play-circle.svg b/web/src/assets/icons/feather/play-circle.svg new file mode 100644 index 0000000..8766dc7 --- /dev/null +++ b/web/src/assets/icons/feather/play-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/play.svg b/web/src/assets/icons/feather/play.svg new file mode 100644 index 0000000..fd76e30 --- /dev/null +++ b/web/src/assets/icons/feather/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/plus-circle.svg b/web/src/assets/icons/feather/plus-circle.svg new file mode 100644 index 0000000..4291ff0 --- /dev/null +++ b/web/src/assets/icons/feather/plus-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/plus-square.svg b/web/src/assets/icons/feather/plus-square.svg new file mode 100644 index 0000000..c380e24 --- /dev/null +++ b/web/src/assets/icons/feather/plus-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/plus.svg b/web/src/assets/icons/feather/plus.svg new file mode 100644 index 0000000..703c5b7 --- /dev/null +++ b/web/src/assets/icons/feather/plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/pocket.svg b/web/src/assets/icons/feather/pocket.svg new file mode 100644 index 0000000..a3b2561 --- /dev/null +++ b/web/src/assets/icons/feather/pocket.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/power.svg b/web/src/assets/icons/feather/power.svg new file mode 100644 index 0000000..598308f --- /dev/null +++ b/web/src/assets/icons/feather/power.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/printer.svg b/web/src/assets/icons/feather/printer.svg new file mode 100644 index 0000000..8a9a7ac --- /dev/null +++ b/web/src/assets/icons/feather/printer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/radio.svg b/web/src/assets/icons/feather/radio.svg new file mode 100644 index 0000000..5abfcd1 --- /dev/null +++ b/web/src/assets/icons/feather/radio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/refresh-ccw.svg b/web/src/assets/icons/feather/refresh-ccw.svg new file mode 100644 index 0000000..10cff0e --- /dev/null +++ b/web/src/assets/icons/feather/refresh-ccw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/refresh-cw.svg b/web/src/assets/icons/feather/refresh-cw.svg new file mode 100644 index 0000000..06c358d --- /dev/null +++ b/web/src/assets/icons/feather/refresh-cw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/repeat.svg b/web/src/assets/icons/feather/repeat.svg new file mode 100644 index 0000000..c7657b0 --- /dev/null +++ b/web/src/assets/icons/feather/repeat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/rewind.svg b/web/src/assets/icons/feather/rewind.svg new file mode 100644 index 0000000..7b0fa3d --- /dev/null +++ b/web/src/assets/icons/feather/rewind.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/rotate-ccw.svg b/web/src/assets/icons/feather/rotate-ccw.svg new file mode 100644 index 0000000..ade5dc4 --- /dev/null +++ b/web/src/assets/icons/feather/rotate-ccw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/rotate-cw.svg b/web/src/assets/icons/feather/rotate-cw.svg new file mode 100644 index 0000000..83dca35 --- /dev/null +++ b/web/src/assets/icons/feather/rotate-cw.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/rss.svg b/web/src/assets/icons/feather/rss.svg new file mode 100644 index 0000000..c9a1368 --- /dev/null +++ b/web/src/assets/icons/feather/rss.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/save.svg b/web/src/assets/icons/feather/save.svg new file mode 100644 index 0000000..46c7299 --- /dev/null +++ b/web/src/assets/icons/feather/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/scissors.svg b/web/src/assets/icons/feather/scissors.svg new file mode 100644 index 0000000..fd0647f --- /dev/null +++ b/web/src/assets/icons/feather/scissors.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/search.svg b/web/src/assets/icons/feather/search.svg new file mode 100644 index 0000000..8710306 --- /dev/null +++ b/web/src/assets/icons/feather/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/send.svg b/web/src/assets/icons/feather/send.svg new file mode 100644 index 0000000..42ef2a2 --- /dev/null +++ b/web/src/assets/icons/feather/send.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/server.svg b/web/src/assets/icons/feather/server.svg new file mode 100644 index 0000000..54ce094 --- /dev/null +++ b/web/src/assets/icons/feather/server.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/settings.svg b/web/src/assets/icons/feather/settings.svg new file mode 100644 index 0000000..19c2726 --- /dev/null +++ b/web/src/assets/icons/feather/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/share-2.svg b/web/src/assets/icons/feather/share-2.svg new file mode 100644 index 0000000..09b1c7b --- /dev/null +++ b/web/src/assets/icons/feather/share-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/share.svg b/web/src/assets/icons/feather/share.svg new file mode 100644 index 0000000..df38c14 --- /dev/null +++ b/web/src/assets/icons/feather/share.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/shield-off.svg b/web/src/assets/icons/feather/shield-off.svg new file mode 100644 index 0000000..18692dd --- /dev/null +++ b/web/src/assets/icons/feather/shield-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/shield.svg b/web/src/assets/icons/feather/shield.svg new file mode 100644 index 0000000..c7c4841 --- /dev/null +++ b/web/src/assets/icons/feather/shield.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/shopping-bag.svg b/web/src/assets/icons/feather/shopping-bag.svg new file mode 100644 index 0000000..eaa39e8 --- /dev/null +++ b/web/src/assets/icons/feather/shopping-bag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/shopping-cart.svg b/web/src/assets/icons/feather/shopping-cart.svg new file mode 100644 index 0000000..17a40bf --- /dev/null +++ b/web/src/assets/icons/feather/shopping-cart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/shuffle.svg b/web/src/assets/icons/feather/shuffle.svg new file mode 100644 index 0000000..8cfb5db --- /dev/null +++ b/web/src/assets/icons/feather/shuffle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/sidebar.svg b/web/src/assets/icons/feather/sidebar.svg new file mode 100644 index 0000000..8ba817e --- /dev/null +++ b/web/src/assets/icons/feather/sidebar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/skip-back.svg b/web/src/assets/icons/feather/skip-back.svg new file mode 100644 index 0000000..88d024e --- /dev/null +++ b/web/src/assets/icons/feather/skip-back.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/skip-forward.svg b/web/src/assets/icons/feather/skip-forward.svg new file mode 100644 index 0000000..f3fdac3 --- /dev/null +++ b/web/src/assets/icons/feather/skip-forward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/slack.svg b/web/src/assets/icons/feather/slack.svg new file mode 100644 index 0000000..5d97346 --- /dev/null +++ b/web/src/assets/icons/feather/slack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/slash.svg b/web/src/assets/icons/feather/slash.svg new file mode 100644 index 0000000..f4131b8 --- /dev/null +++ b/web/src/assets/icons/feather/slash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/sliders.svg b/web/src/assets/icons/feather/sliders.svg new file mode 100644 index 0000000..19c9385 --- /dev/null +++ b/web/src/assets/icons/feather/sliders.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/smartphone.svg b/web/src/assets/icons/feather/smartphone.svg new file mode 100644 index 0000000..0171a95 --- /dev/null +++ b/web/src/assets/icons/feather/smartphone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/smile.svg b/web/src/assets/icons/feather/smile.svg new file mode 100644 index 0000000..24dc8a2 --- /dev/null +++ b/web/src/assets/icons/feather/smile.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/speaker.svg b/web/src/assets/icons/feather/speaker.svg new file mode 100644 index 0000000..75d5ff9 --- /dev/null +++ b/web/src/assets/icons/feather/speaker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/square.svg b/web/src/assets/icons/feather/square.svg new file mode 100644 index 0000000..6eabc77 --- /dev/null +++ b/web/src/assets/icons/feather/square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/star.svg b/web/src/assets/icons/feather/star.svg new file mode 100644 index 0000000..bcdc31a --- /dev/null +++ b/web/src/assets/icons/feather/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/stop-circle.svg b/web/src/assets/icons/feather/stop-circle.svg new file mode 100644 index 0000000..c10d9d4 --- /dev/null +++ b/web/src/assets/icons/feather/stop-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/sun.svg b/web/src/assets/icons/feather/sun.svg new file mode 100644 index 0000000..7f51b94 --- /dev/null +++ b/web/src/assets/icons/feather/sun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/sunrise.svg b/web/src/assets/icons/feather/sunrise.svg new file mode 100644 index 0000000..eff4b1e --- /dev/null +++ b/web/src/assets/icons/feather/sunrise.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/sunset.svg b/web/src/assets/icons/feather/sunset.svg new file mode 100644 index 0000000..a5a2221 --- /dev/null +++ b/web/src/assets/icons/feather/sunset.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/table.svg b/web/src/assets/icons/feather/table.svg new file mode 100644 index 0000000..679bd57 --- /dev/null +++ b/web/src/assets/icons/feather/table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/tablet.svg b/web/src/assets/icons/feather/tablet.svg new file mode 100644 index 0000000..9c80b40 --- /dev/null +++ b/web/src/assets/icons/feather/tablet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/tag.svg b/web/src/assets/icons/feather/tag.svg new file mode 100644 index 0000000..7219b15 --- /dev/null +++ b/web/src/assets/icons/feather/tag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/target.svg b/web/src/assets/icons/feather/target.svg new file mode 100644 index 0000000..be84b17 --- /dev/null +++ b/web/src/assets/icons/feather/target.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/terminal.svg b/web/src/assets/icons/feather/terminal.svg new file mode 100644 index 0000000..af459c0 --- /dev/null +++ b/web/src/assets/icons/feather/terminal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/thermometer.svg b/web/src/assets/icons/feather/thermometer.svg new file mode 100644 index 0000000..33142cc --- /dev/null +++ b/web/src/assets/icons/feather/thermometer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/thumbs-down.svg b/web/src/assets/icons/feather/thumbs-down.svg new file mode 100644 index 0000000..3e7bcd6 --- /dev/null +++ b/web/src/assets/icons/feather/thumbs-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/thumbs-up.svg b/web/src/assets/icons/feather/thumbs-up.svg new file mode 100644 index 0000000..226c44d --- /dev/null +++ b/web/src/assets/icons/feather/thumbs-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/toggle-left.svg b/web/src/assets/icons/feather/toggle-left.svg new file mode 100644 index 0000000..240be29 --- /dev/null +++ b/web/src/assets/icons/feather/toggle-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/toggle-right.svg b/web/src/assets/icons/feather/toggle-right.svg new file mode 100644 index 0000000..fc6e81c --- /dev/null +++ b/web/src/assets/icons/feather/toggle-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/tool.svg b/web/src/assets/icons/feather/tool.svg new file mode 100644 index 0000000..f3cbf3d --- /dev/null +++ b/web/src/assets/icons/feather/tool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/trash-2.svg b/web/src/assets/icons/feather/trash-2.svg new file mode 100644 index 0000000..f24d55b --- /dev/null +++ b/web/src/assets/icons/feather/trash-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/trash.svg b/web/src/assets/icons/feather/trash.svg new file mode 100644 index 0000000..55650bd --- /dev/null +++ b/web/src/assets/icons/feather/trash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/trello.svg b/web/src/assets/icons/feather/trello.svg new file mode 100644 index 0000000..b2f599b --- /dev/null +++ b/web/src/assets/icons/feather/trello.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/trending-down.svg b/web/src/assets/icons/feather/trending-down.svg new file mode 100644 index 0000000..a9d4cfa --- /dev/null +++ b/web/src/assets/icons/feather/trending-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/trending-up.svg b/web/src/assets/icons/feather/trending-up.svg new file mode 100644 index 0000000..52026a4 --- /dev/null +++ b/web/src/assets/icons/feather/trending-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/triangle.svg b/web/src/assets/icons/feather/triangle.svg new file mode 100644 index 0000000..274b652 --- /dev/null +++ b/web/src/assets/icons/feather/triangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/truck.svg b/web/src/assets/icons/feather/truck.svg new file mode 100644 index 0000000..3389837 --- /dev/null +++ b/web/src/assets/icons/feather/truck.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/tv.svg b/web/src/assets/icons/feather/tv.svg new file mode 100644 index 0000000..955bbff --- /dev/null +++ b/web/src/assets/icons/feather/tv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/twitch.svg b/web/src/assets/icons/feather/twitch.svg new file mode 100644 index 0000000..1706249 --- /dev/null +++ b/web/src/assets/icons/feather/twitch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/twitter.svg b/web/src/assets/icons/feather/twitter.svg new file mode 100644 index 0000000..f8886ec --- /dev/null +++ b/web/src/assets/icons/feather/twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/type.svg b/web/src/assets/icons/feather/type.svg new file mode 100644 index 0000000..c6b2de3 --- /dev/null +++ b/web/src/assets/icons/feather/type.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/umbrella.svg b/web/src/assets/icons/feather/umbrella.svg new file mode 100644 index 0000000..dc77c0c --- /dev/null +++ b/web/src/assets/icons/feather/umbrella.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/underline.svg b/web/src/assets/icons/feather/underline.svg new file mode 100644 index 0000000..044945d --- /dev/null +++ b/web/src/assets/icons/feather/underline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/unlock.svg b/web/src/assets/icons/feather/unlock.svg new file mode 100644 index 0000000..01dc359 --- /dev/null +++ b/web/src/assets/icons/feather/unlock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/upload-cloud.svg b/web/src/assets/icons/feather/upload-cloud.svg new file mode 100644 index 0000000..a1db297 --- /dev/null +++ b/web/src/assets/icons/feather/upload-cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/upload.svg b/web/src/assets/icons/feather/upload.svg new file mode 100644 index 0000000..91eaff7 --- /dev/null +++ b/web/src/assets/icons/feather/upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/user-check.svg b/web/src/assets/icons/feather/user-check.svg new file mode 100644 index 0000000..42f91b2 --- /dev/null +++ b/web/src/assets/icons/feather/user-check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/user-minus.svg b/web/src/assets/icons/feather/user-minus.svg new file mode 100644 index 0000000..44b75f5 --- /dev/null +++ b/web/src/assets/icons/feather/user-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/user-plus.svg b/web/src/assets/icons/feather/user-plus.svg new file mode 100644 index 0000000..21460f6 --- /dev/null +++ b/web/src/assets/icons/feather/user-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/user-x.svg b/web/src/assets/icons/feather/user-x.svg new file mode 100644 index 0000000..0c41a48 --- /dev/null +++ b/web/src/assets/icons/feather/user-x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/user.svg b/web/src/assets/icons/feather/user.svg new file mode 100644 index 0000000..7bb5f29 --- /dev/null +++ b/web/src/assets/icons/feather/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/users.svg b/web/src/assets/icons/feather/users.svg new file mode 100644 index 0000000..aacf6b0 --- /dev/null +++ b/web/src/assets/icons/feather/users.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/video-off.svg b/web/src/assets/icons/feather/video-off.svg new file mode 100644 index 0000000..08ec697 --- /dev/null +++ b/web/src/assets/icons/feather/video-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/video.svg b/web/src/assets/icons/feather/video.svg new file mode 100644 index 0000000..8ff156a --- /dev/null +++ b/web/src/assets/icons/feather/video.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/voicemail.svg b/web/src/assets/icons/feather/voicemail.svg new file mode 100644 index 0000000..5d78a8e --- /dev/null +++ b/web/src/assets/icons/feather/voicemail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/volume-1.svg b/web/src/assets/icons/feather/volume-1.svg new file mode 100644 index 0000000..150e875 --- /dev/null +++ b/web/src/assets/icons/feather/volume-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/volume-2.svg b/web/src/assets/icons/feather/volume-2.svg new file mode 100644 index 0000000..03d521c --- /dev/null +++ b/web/src/assets/icons/feather/volume-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/volume-x.svg b/web/src/assets/icons/feather/volume-x.svg new file mode 100644 index 0000000..be44240 --- /dev/null +++ b/web/src/assets/icons/feather/volume-x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/volume.svg b/web/src/assets/icons/feather/volume.svg new file mode 100644 index 0000000..53bfe15 --- /dev/null +++ b/web/src/assets/icons/feather/volume.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/watch.svg b/web/src/assets/icons/feather/watch.svg new file mode 100644 index 0000000..a1099da --- /dev/null +++ b/web/src/assets/icons/feather/watch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/wifi-off.svg b/web/src/assets/icons/feather/wifi-off.svg new file mode 100644 index 0000000..35eae43 --- /dev/null +++ b/web/src/assets/icons/feather/wifi-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/wifi.svg b/web/src/assets/icons/feather/wifi.svg new file mode 100644 index 0000000..748c285 --- /dev/null +++ b/web/src/assets/icons/feather/wifi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/wind.svg b/web/src/assets/icons/feather/wind.svg new file mode 100644 index 0000000..82b3646 --- /dev/null +++ b/web/src/assets/icons/feather/wind.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/x-circle.svg b/web/src/assets/icons/feather/x-circle.svg new file mode 100644 index 0000000..94aad5e --- /dev/null +++ b/web/src/assets/icons/feather/x-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/x-octagon.svg b/web/src/assets/icons/feather/x-octagon.svg new file mode 100644 index 0000000..8543198 --- /dev/null +++ b/web/src/assets/icons/feather/x-octagon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/x-square.svg b/web/src/assets/icons/feather/x-square.svg new file mode 100644 index 0000000..7677c38 --- /dev/null +++ b/web/src/assets/icons/feather/x-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/x.svg b/web/src/assets/icons/feather/x.svg new file mode 100644 index 0000000..7d5875c --- /dev/null +++ b/web/src/assets/icons/feather/x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/youtube.svg b/web/src/assets/icons/feather/youtube.svg new file mode 100644 index 0000000..c482438 --- /dev/null +++ b/web/src/assets/icons/feather/youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/zap-off.svg b/web/src/assets/icons/feather/zap-off.svg new file mode 100644 index 0000000..c636f8b --- /dev/null +++ b/web/src/assets/icons/feather/zap-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/zap.svg b/web/src/assets/icons/feather/zap.svg new file mode 100644 index 0000000..8fdafa9 --- /dev/null +++ b/web/src/assets/icons/feather/zap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/zoom-in.svg b/web/src/assets/icons/feather/zoom-in.svg new file mode 100644 index 0000000..da4572d --- /dev/null +++ b/web/src/assets/icons/feather/zoom-in.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/feather/zoom-out.svg b/web/src/assets/icons/feather/zoom-out.svg new file mode 100644 index 0000000..fd678d7 --- /dev/null +++ b/web/src/assets/icons/feather/zoom-out.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/assets/icons/isme/apifox.svg b/web/src/assets/icons/isme/apifox.svg new file mode 100644 index 0000000..009cdf5 --- /dev/null +++ b/web/src/assets/icons/isme/apifox.svg @@ -0,0 +1,16 @@ + + + diff --git a/web/src/assets/icons/isme/awesome.svg b/web/src/assets/icons/isme/awesome.svg new file mode 100644 index 0000000..cfaab8b --- /dev/null +++ b/web/src/assets/icons/isme/awesome.svg @@ -0,0 +1 @@ + diff --git a/web/src/assets/icons/isme/dialog.svg b/web/src/assets/icons/isme/dialog.svg new file mode 100644 index 0000000..809330d --- /dev/null +++ b/web/src/assets/icons/isme/dialog.svg @@ -0,0 +1 @@ + diff --git a/web/src/assets/icons/isme/docs.svg b/web/src/assets/icons/isme/docs.svg new file mode 100644 index 0000000..907ac11 --- /dev/null +++ b/web/src/assets/icons/isme/docs.svg @@ -0,0 +1,15 @@ + + + diff --git a/web/src/assets/icons/isme/gitee.svg b/web/src/assets/icons/isme/gitee.svg new file mode 100644 index 0000000..5896c65 --- /dev/null +++ b/web/src/assets/icons/isme/gitee.svg @@ -0,0 +1 @@ + diff --git a/web/src/assets/icons/isme/naiveui.svg b/web/src/assets/icons/isme/naiveui.svg new file mode 100644 index 0000000..c236f7f --- /dev/null +++ b/web/src/assets/icons/isme/naiveui.svg @@ -0,0 +1,37 @@ + + + + + + + diff --git a/web/src/assets/images/404.webp b/web/src/assets/images/404.webp new file mode 100644 index 0000000000000000000000000000000000000000..3482bf96530efee4fbb405eea59b32a875c0e575 GIT binary patch literal 14344 zcmaL7b8se6*X|v2V%rnjwvCBx+qP}nPA0Z(+sRC9C-;5kd5_*x_0{*Q-d+2T?yl~= zu65Pky_br#gail|2#AKbh?2SzmnIwt2nh1O_6Yi)Ls(8pO5z6y2xwzCu)w-vk;sFi zqx;Vw>;kFVPP4q|@{x9ky!7%>qP$c4Xt0eF{AgK~5thd*u`nk5s6XQb|LYF7g*o8y zLSh6$X#fZcg#IGB3;6%(6vmP8qarfU+OK7Q2e%v4vsxYA`OoEs4PQ{JVj^DJ%xKEK zZS6%;yro(Wc@Msxp4Ge|;OVC_>8l$4VOajfvzeX|_G4XWqkGA=jN51#?e{8_`zxFF zeH#H2%`fp9kZl9()Q5f&W|3N=Yf%GL6=&$ZJq@|iU4Je^2{?!FSMj6JfrNQ^seFXS zuaK!F3*m_Yv(J3fy3z}mGi*h-K=L3Z4AqhB;I{2kg)PQv7h&jKsC z?|B_X(8wIp1O*Nx2haq|^$>4hJ#dQzWyX$XFmP+5`fgMS3^d7;6QhKAo2U9zhynTf zh;n*^GS;`TP<4sqDe2Mr3u*KUv7K17Z(`&aV2ByAfJDmpd@hR=DzLOjG`J|Mn)`(q zGb-{|T3|&B@{rTtRg`}FwBQAIYoDKsYUQ&Vak7_&#<-upov0&30In3Uy zOoFWA-(El#{i)6!GKT?fR({IxoT3xK_l+i4 zhes5i(d;5fiK*l%OhBNTwr*+)13Zt9t_o~B3A;#rxG1C7EY%+4KY=b9 z6J=$TvgGJtR4K1Qe#+-D>aZOXj99JcUA07n;D6CBvNunanGt>S?kfVL4=+S2Tv^6n zF+Xd-(%<9$Z6Wtd*_&c$?pioH#h#+&$zRz59lJ*m2h+o^Kr|2q%jgxoY!VkqUhgUt zEaY~0y`=7Y4cj8+T4bsHBH0Je^;yg9e#l{9uEQ7r3mGWu4l22)oGJplu#PYkHhktX z`*jcb)yI(*ow@@Z=eMfV=(w>z+NXegSD<`>;tQeO{i{~y^*gZO>f=9hslY8-*dF%^ z)rRVCYpTEs-9@X#%wvacB6SOEi0M+`vw&Q^{tKOyK_lLBgO5pdYewW>B`d}@JJmbX z_aF7hFw1!;8RX_S5(-m~YY&t^^~L_vPO5R&%M98dBpc?FZ!~!9)8T*0k*7|#QA}o9 zHS(g?Y72a&8x?*!lWEfPX>4yJMx!I3Hmr*ZGpM5rz5A7RR0ueD{u?ZU--s?Ppzsjx z&|4Sy)|q zY8IiKjI{?4sPXlVW3pD*Wnu82n_4<^!=bl4V89$Kto@(?oHn@%_ zq5xk*vj&2esqHB_%7Ym+nfpF-Swbno~GU(X02yZX9dx?tc zGD8o3*1p5=_4z>uq|BmDe_#y%H~T7K*Hw#?471F5;J%1mrM+2`Jbdn&4z>9uPGd*7 z;(P7L_R69aL8@_G{o!b&ufPH=JhUC0vo?4dmA~kAApHKj<0x43#`1vGAl&`1yyf?e zdODzaX(Ij1(OcaN<`aIazp*Qroef+=P=rzQVe>+8V^^NTq^P*E4nfD;8a@QXo!E>BkMk}$PJL@vSKMVsn4 zAaHGqilrI^jwe&|5!PN8wTD1<&}U547}_C~X(|RjvRI{o?7b*W(L-`kCD1$$?hrm~ zX$9srzpV!p1a|VD^d^ANQY@Zxb!>}bj>9tP!4Zvx^zxg!C4mUa7LK6bwMWo7U=&7N zmPIQ-1o%vR7=aG$-2CnzICK)&K|dhyfY$>18E_w0rU8cT{#$n#09s&BcS4T_L5_9n z57pDRElUEb-=T4bdG`rasU#l&>eWDL3Utz<^fC^}w|{`>1~j3D!8wkVIqMqo8tPbp zzI3W_&77%cXd7~+ccK6IW17)r!Ufg2;xxRtTjtM-KdV<=a#(q$(lTp%;#7ml7z@?; zLdp4K%;mKhIia)T);P7vAi1jJ%v{XO0y`S*Mqc}jIo65tp zhz-&WKOI~-V(J1iA|3Mg`}qt+I%$d6I$#6)pjC|OaR9pfAWANhW&|gA+nL0=XB9>_ z5kdKt73v_-muh{%^ktiZq}V#9$Psw>4c9dg>@%FEb@pG(EXXxI*^J&_j;M%~;jWY)(_Ejg5 zQ*#F$P)lUijZwP*Qi?0@D}))ZqiFL`57M8%koR} z{|)L{9j6Iga`Kw~m=^6Gg_&J%M9qtM;#7IO!b#8X8BnvXjNCB?0OxC?`?WOcrcCChpbZdw9* z-xg`UmU;}jAX|_D0Fe?Qwr7ZzvqUuo6BBouIz={-V@+$4;!=>fE_P#{M3N`bzWmZJ zhnEm>N(5Kio5o=V@u&PZRX$@ICrRA3Yb@oQpS*Vt{TYg24|aY;OZySNy(X%N_Kqzy zHMoA3 zPEp$+ATHj{N^EO?tVE}x8x7k0Dx*|&Qq%<%Ej_PDF{T=YjANrzvOfZq)t$deP=hRr zD8#tHdah$=B>C6baBUE3(TO(YH2lc?JbkU9TJ?ho6Yt zmUn_c?v;pdHV=<7QvMheN=`7@Ql7w{MTB5(2srFh@E&>;&R|wZqI*$Vq5TUXr*Tn zf36{Ek(OM`M}7|jQfE6GCSfG>GA3gVy(W+`^N15DNKBD08%)`|&(^s{)Naz!o&Q|o_0xiM7zh1x#mzjO5?tG?uiMs2EWBlu z;gxGQ?}v3l%uOO68zs)_SBXLQK(V!{t_`Eh)@_lgsm`s_(yA0oYgGvv0c$-I&JJoy zUQ;y#&fe>KjK_g2%fK~Kj9a?{6w6Q+v;eZDw-(D7#*x_O6D-c@n2tEtW>~DtD=WYo z7f%d|=ikWo&oqdHcWp)fcHb>nP5t4%wKlE4)p*U?F4CkF~mezAUo06@Dy|AKyieu1HQJQf&YmGx9?1~daUJ@&L2_5tuOil6&e z{WGf;AN?==3xYd>rv56x>Kl`$ugx!yC&j1z-GFi6B9H+1j~%3UgTKAWfI?ux4djOb zK=pI{UGTkNryuxz`;>5o_F?hr@MW<3y%8`P@CQh6WAd5shV<5d*gp>het-hXzCQsP zts38o#z=QW&jIhB!9Z5PH_%`m9$4`~^cq01zY?$kyay@*)`7rT!^lSP}xJ&t7xAr&vt(-t}H3SaD3kRQVUq`22xgZuB`fH8D|U-Z>hRVEt26CeeO`&{y?;gY(S%|AB=l3FW_m`~iXJ zECFw{gV5kGn>I4Ba`L$mniMmuU`^hGc&(l3W+t9DqALuC;%GvB`}@s)XH8=@{QHOD)@1r0f1`V@j-7>xO6f> zQy+IIq^9eaUHz?dk+q>KITY{?4sxKj8`x|td@n5xd)$(s^0Ggh5lOzd9VhH8bz>T` z`kuLIKe_=h4yl{<+&?`{uuEa#qL@%wpQvldzmeBuy|d;?G_T9jr0@NuP){;aZy9x3 zN><|asX2+EtB4O%L99>1|FqXcZ9}hWv|s=MCrM(c^!pkT(c+0k5C4U{%p;qZ6?a*L{P2iS3AHl54^Il+7iz07mJ~Le(`jJqM1113spfutIt!W ze+h$mr^O*IyKVG zFZUYi2Up`MH`t~dIXg3o_?760i6Smypwx$lP55|&qcu#JAt znlzu!@fxF#H4#ftr&OC3puECw=9hkSWO?_AfFl!ud3M;JT9=dv=dDPvVySy>hmABT z2WFVoXV(!et@IV&;c);swLV#Nt9k#Ymi#Z~tG^;2rxH7Q5+@@pr_d+(DKoZ^Y2* z6%N+b|78^>8O{>*1s6Cty*$^SuRl5PgvbN_E1PpNSSVw-MB|`b>IVd?@vm}1J^v;C zztnFZe-ar~o7-8^yE87r`DY6M+d>Gf`UZi5wo|zO{G;k5GYIaUQ+bnPVPhDD~oe~U_=^|81zvzb}p4Ptkd7{HFic+BYfBZXI#ggme7i73((Y( z1PCTSy%1cd%Kg4)9QhmCXs!DCsxQHkdXC!3<4cm0N{(TC+Aj-osuG*{VvY6gGNF})X74e?_u?T-i$r{paPNZQ~0{CWI(n9xVi`2a0mLl750`FTK9$9kt< zC%9*PwTfBgDSzq=1Yj-!rF{>V1 zJD27}SL?k#Zo*C1P^LpNow$10gqJR zOZ&K6YXL-*3-Y|&`!m$eE~b$mL@{Vu`*f`WswC{5i!pw)-lKmU+y$_Oc;rWe+}G%Y zuR*4sJGe}y3ju^5JSfXC#uG`TkJvWKO<8MwDyI_N0xQt!ul3!6%S%ZK!wL_Gvk-qwJgTjh3Rw2&8o?^A zGr?xkX6xh!N2S(5Hm7Z#WID9BAhkSJ>_%D5g5!&Ndxcrw%W2RC?k)0EuDi-13qpvb z{D2eVz6@7<#Ae?0`Gex`4G=4_o+v|W%Bgvp`~r@fnXQ0By58i>Rl3P1N+zpj!9$MR7NDw-!2=< zEMd;NzA^ePl4U}s=Bey6 z(aArrqu(@pCRo7ysmS1xQ-@3piG1F7_2BOIJ`_8Cn?uS3;DZ+z)^ir1;ov&mhOJ3b zPA9Z@QZd|_P)YZ5Kr3@np|U~vS&#HIuha=i*f|!2h2I{L_u;Q#L|=TU>(NFtxkM;M z3qQz!Af($SAU`$MAJ-$=l4oKwYLs00pp~LONsPlXIgvR?i=$u;L zp8xx<<0c58jlhpsOs|85BX{h4HB7wM%R9(Fv!ek(jbX<7Nf1EC;1uewxKtMAz9nK~ zzImq`|EPO_B<+Nhz~W&_BM5DIN2p=9!Jlbo#@zbFUS#Sa$t&1~JxKk&&?$3Q{21CeZz7^rVhXdIe*=x{5<(!ce7|n?~2I z!6Wd%cs}zHD(bVMyYz&xNa!Y+%PT|0VW^VhJ_v1^$@x*GC)@MIL((cctyU=_h%{=kMqd>$E{LyNK+_}=Eiw~g1Q!KwoTrfxHx51%{LG2}v2eyY?VNh*ZVllDQ97>k_Da?xL@eK~j&KLA%X zO(!J(ebw~yAuAASn|o;T9K2m}H2_Q!8i zZixCA^vZ*=1U?Rf*A~wUpCJn*WDY2F%cYh>V75<$i5nV1wFyQ%_F{y6Ao7K{eJ&|? z3oXDz`w7yyPd^^Np!;m3k4LcWeRcm^cwaun0XQmQtFBQE-SnB9al9y1DwoyrxOhJS=W7JEvb?A2g(}e=#VAOvmx1+ z9ZZ^>4!0;os;|Is!7wjVo>tUn*Js0SfM5_0PUoG1#5+r*im=ZN=EqXJN8}YE%0zD_ zv2q+zb!ZO{itHEJ^{&ywWkh!JgYM_hZMm1WxOvTnP{4jGMPsNND){i&;Q<>A^PZ#QJ&a3?-4O2&3)3nWQ9Usi;~%H&h`p^qcX!ImTcu&E zSR_S2L0J-^!KKvntJLsJnP6^qH@csdzu~VBW%(>;rj^YA=->FX(9|;o3%?9VgmmmV{+4%^y*7PrHHT#_0#u?EVW6D8ORQ+2PYO> zg2}T^@;O@5WZu0>Pea|Cu4$C?w+u(+73sVPUFSr)337H97(>E&03aKclfdBIeN_DR39vu~t%!K*LT%>A}fsFNxu z84);S)zcis!|?k#H^rlsuNO94n2=f?qEU)F8U$dhN~-0 z_6s8di5XUZtGFi6_<}X2MpTs`$kW5;GbbU9%yKgjjGju0;|vuD|Cd*%w=9P==8MBm)FeKb$%^M6SJ($+&e_XZ@@-06~W_V;c#LP(oP&oK~PaO&*OIZU8)h}fRZ@XgPdoh{mw)# z_Tv)^`U@4!j*wD*>hXyW%Gu-z25tXe$hRq zI*4V9i&sx^#89goGuZ3?{z_vK4EmGw6nBj>guEtx)$Es+2TTv1&|h}2&{PAIk1%#` zuEZldhxU5>2xz>u;`$eFi`}{%sb@|thW8lkhGsEc0%i<~aPReeYYhAH{rCWlu+nmr z_?7m2ubfuhg_v>;#gP5HmxiD8t=rI!UCG=$K&qHyrtTiXj7&Yx5yF-{@sy|fwlNrZ z@c}x9YmU3iDka`j-vK|At83fnH?w*Xu}pa`h)*YF3+b0vD!gQz0^2`ra=$zYiHDfH zHxe+@O1^MLx3ylo)k7AOI&*h(hK6Zj@HqXSdmoyMuU{Z?Axg(8U&lyN15dS5K!Lje z0DVz{0c*46;;^XRyE7(43! zj-z#7{DuQ{rSmSqs>!=fxghP%!tuh(C>CxD#irq8Jd1qJFZJk^cONe?v@0*W1FC08 z^+T;ehic+#sjga>K~%XrGXG|OWr`0~-C1-%Vx1e^el*}v_L5{K9>S@w&zHqhm$@oS z=4!~r!z6+G>`8nSVO?lfu~qgKBtsjrPQ#KK)wJBBEw=86tULtb(e1*{6bf;bLhdXz z615TWdS%Pu9LWi`kV5g4+-;#Qqa?G)xY5h#xTDvRRu2XF`KP5od+d-1ESL-b=1Ds( zlxkv?;De!UOGGC*H7~D9ZbO@YK0&XCaS3KF>w$^5#xtKs3^!Z`MjZ&QdbG9+(uRa$ zS4Wa%Jg%vUkveZ4V&_}~Va6>#ox~0Xf9yxenNZ`ElWS)M*!pYHMcP2E+>j_|*SGh% z;-;aMJ?p62Z_9p@R$t-+7NoJ&on3V?>R_rE6`vJ8^n#vl5f( zroW3@6P6U=cU7e3z7=ki;4(#EdIMRaz($>1@+zBDW^?n&@^9cgQdVdZq?f9a>JhxE zC<*nmZ!V|8)E}YbA8}Pr!0v?^6!4?y4RLxq%y*%9Ze_mg^FUjLfYVym#j8U1G&!!x zj8}@9OKU~9_}s|y^e-_Czo25nstqr>!D$4RPKq7I7GBIY*n_e*r6H%2*#_7ss7cJ7 z)zPcua?y#8p6uPw_bxB(OXG*psY9nq^Gix!`!o|R;RNTgg8TD_+o&D9&0l2B_BUBlp2F4VbTOh{^X25RM?eaj2A8jv!hhT7H zx7p7$riw=-*$~;F)7@2vF3XVe2?yz@{${9~e~Z z&u6mLdXsyEioJt^nixIR$hKT{d{S{cz1o>v-vb!}K3M~WYzg26h$qk75SO4a?VNST z#bQ+gwVQN-v3jd8s}BKa{E(`jI|1({v6Qn4sl7O;#Z1YcvOFZm&EzmUwV>L#W>a!` zQfvwtCEa9VDFYgn6bEvj8-=nK?LR)<5uPfK25z}nlQ0DpBX^Gqf$0#qIkh?RI`BL6 zuVV3C9iRmcz$wL_Lravp0YM}BRi)~B`VQWx92X)owj5A~kt}?2-a7;Q(^BF}iCPjI zSrr1!eF0Olzft-#@Q&iG!fNd1;^nZapK8X`PJ!BvS+((uQk%mRQn+$6vx*Z>@f#ssXLoFfEO+T4Crl zoIzt(PD(cvK5h7Zj*XHKx>#{bLV6FXxW@eXdD3rKLj{2QL~>+Bu;I3*a?Sca#t5y~ zwdjI}T5p)yWBYp}g0FtyTj+&_`={61<>FedOD5t5*ggLLYLe)FLIGh4S~9QJrFG`|XZaiHKtrDasVrY)+n2 zynv(9LaMcnu!r)7;5&oRhelu798+fMo(B22c~CxHKyu(Sbk>b*-rq{;eDR(K>E&s} zLt48SXcJod30S(?=_7SBoNQ`5hm5IGB*~H&OPs_>y^!A@T6HN-gOQKtKW@pEO&;Uu zmWGIyri!;$nvp>oVQ<33uHAj|3^)iqQj%~( znk(8dG6_9seM2+Dn$pl>v?ob2REb>+@YONG(zOiF;P|LV{IEoMnTeozMO0&D93$DQ5Z{ag*^=LYsTpo0-U@>cE z(|ZfW2W20u8W}w%SFO4QO{a7seb~Pla%WC9Hix0(ePYe|WwG21O6w8rX6_E@mm_ru ze?I%r&6h6)W_1@#Kk@#A>&T(`fBG9~XQ(SG19)Z)SBH?|AkG;nYg*%&YyDL!NKk@w zyjo9#x(eiWVh#2KPEN9ZqY4attO>~B=Dnt}N0N%I!R)u*&U4`Sk&e;fOt!nQAksJy z^MKN0>)$MD8(|0}J8}pj!Nc*@VLWd_do)EDCWMzsr2Vbwzj&Du^7cq~BmaGBO~_8z zaF|C{6BVO6JNHl#1kX_cA37r>S;_?tTi@swI)k)8Y%}dV-0p2!LB;(kY^5O(IiL{) zF?*^rDbk6$Jk7Q0sBFI(j?WC!cy&@d;&;3KmNmLGWQ$QyB7(VZ(UBj_pN~TdY?tl5 z&#oRv%`%&{G*WNcr&aG?jesQok=-^r*wR?R{uC2S+hQI>)N~BFbX&xwINhffKEDQ$ zG-jz|1TIb;%tqoA9~w~KKsd$UI{35-@~PZF=R$y&cT4wslvfFoC$+|P4{P!7X9{tr zk9C7-_fqpdT@>0&6JIoNN%DnTB}Y32t@t4|*NAop{|llq43qA_>94k)tsn=K860*Y z=$$$&TCQ0>&^v1mn3$;;+}1 z@u3Jpu^BL?+st~mPrU~^56Do(SV*l5vzBcb68O|Wro-+(q%lZEraopuYtN033)xx$ zMu|_+%*4F7xfsm7+>b>}nB-ChXsS3FK2f*x5jg$I1Nm61{G7kicJh-Pc6wy*yhbEc z#BG9`O{OrF?B{0h1V^b)rFiC`Ai3lu+p^F#TN_MR-*$2aXAMGrwO^s?et~x61E0Z> zWNHL{+gHlUBLO4nFdQ1p9RlW zHyxeUYb2UuNictW(2t&YAk~kWLra`W8Hl_6RfNpd85b)%-s6`N|3n@1i-ZxpD}8+_ zfChI$J)Tz=*XTWheUe{mG9C(uYn&Z{O;WXSQ8`q9;}(@f}NG?DDiJwMzBB;cpHxfBhfG~J#$zMRE>?8jp6%y1OK`K7aaXwKo z%L$p&7aVl8w|NMuHDA#Y!|PYPo}`EiC)lE$;~0=V#yfVDeaP6%NGSlyIk^~?0-ToN zigM@ln!INm>cy{tDL6RPBwCQ_FTgAJ+Ge#5nC+!D&%NHXmivxUSq%2yohF$|exr5D z0QOZ}Y$5o37xTq%wVPd&C}HA-t}vpr?A+zQA$7j~cR%+J>CpIj?4lJw+s{Q{8Y-G>O)Ht#_pxEFLRL_|)z6{dN0~qb zHb|D5xCy~m#vp8Q^z$Fnek(ugfdqH6F!n z(CbQb`9>JHDgyoH2~sL8e!#%~PzEm&oUSNY!)$*gl{GGWn(hdxU@mt!07gcfh!r=A zXerFeS!41@IJ-VVit;R*U_otl!3|M+R<;_3e2<)!dsji2{1+!!6c~kX@@X&0VCVTumu*zUU9L=F`2|tE5tGo{6Vw=Un zajw*Idl38!0<&JvACoguNX8NAc^>w|d>-rXhF+kR5W$;NRtQg3_J+y`;q$wm#$vy^ zONyBC;ic^vN$n#4H7g3DT`(Q7d`}Ym>*`aXF7YponuF4>2D0GCY_aX#!|1S9HQ{Nr zSi8tc{0*vX)>TM;Qp!bjw(L)jmb*WMWr(pxd1W0&tEG zeN4nzN_G)M!KsK(BWk@#DgAK+@ozCKHp#H2loO6=2$91w zxRw3$>wKZ%6%z}RGyh;C8W6&H+a=IO(R6GP>mWrz)Chz)X!}(U#OM(H@*F#-J{LPRW9MN{=|zr*klzPAU5k%WkQ|kP>bv?{3QmfDQzSVr-s-6cq6#<<^_^489ah;WSs^KvzZl$pOu zxvN1Z6`${CoN2*y{nbV$oKp>Ne zF#k<^+6_rua)3{-lzknd5zx#G!}#i-ZwQXTtSdAMWe}1a8f{DQw+;&WGi04!gv}RO zRdD)QdPO1B>l=pz&vF5!?1w|36{DA6!E1G%nZ-`Ji4eCWWor0m5m~A6Mmk7$HwD%b z8KQn0-I%-iapG*bLjdCx6-FpL3TQ>-U^`7UV45L|?CF-${-VRPX0n3k%DCqaxqR&` z&H3)5llE}=3KicI!u^3k%2Z*1x?`EJ4=(rL4&4BVz%wEHR?ZpQ7@rohpkcSIU{W8^ zEp!xq_vo|GN_t~nf)Fobt_frr<6NTs2r zy8UU$-8@FxQB3}&HzuoWU?4&KXDocRIp&8r$-;y_hz+jh7#L&koQcFpl47`Zl3 z8jDb*dIj0+@P>3DBi3cFobm3y;f*34RSH!Oh$kL{0!;y;of7s6mQks#Q4;D2NW239 zp+Hf;GZG1WpS|~!g3h6QEO{s%AZ?ily^GGu0RZBOI9?4zhJy3{K_%MHqC+J4U zO!HgO_mJFU6p-i-+e4np(+tBR+njkQK+5$!?o;cMsd7SaNIXUpy$M}kL9MhArvdgY z&#=UTd)t%U41p!kEzx;&8{l*1py~wu5V?z@MvEj~;X9EwNhsdePLIqA@AHtZJL(uG zOZdKI$}D9iV#JkoB%LAe^rU%boce8^mv=kW-AmB)lO#cFvL__~0}Z!9(u~Myx2Qu+ zO21eNsz+q!`-se8x{Y7J7~~YI z^YHgmzYYm&c&+K8P74uXR<*$~NsdT~Hp>?Xh`$WNl}r|l>_sGKF9!BO(4xHsh9vs$ z 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 literal 0 HcmV?d00001 diff --git a/web/src/assets/images/login_banner.webp b/web/src/assets/images/login_banner.webp new file mode 100644 index 0000000000000000000000000000000000000000..2bc7cad978b05a8eb407ee2e2e78f7a8c8f07836 GIT binary patch literal 26198 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 P{02Y92SmId2<`s?>zme* literal 0 HcmV?d00001 diff --git a/web/src/assets/images/logo.png b/web/src/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..187ff0bc8b5d29c1a573702ca1b64dda2293cdcd GIT binary patch literal 8572 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 + + + + diff --git a/web/src/components/common/AppPage.vue b/web/src/components/common/AppPage.vue new file mode 100644 index 0000000..31881b8 --- /dev/null +++ b/web/src/components/common/AppPage.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/web/src/components/common/CommonPage.vue b/web/src/components/common/CommonPage.vue new file mode 100644 index 0000000..1e3c423 --- /dev/null +++ b/web/src/components/common/CommonPage.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/web/src/components/common/LayoutSetting.vue b/web/src/components/common/LayoutSetting.vue new file mode 100644 index 0000000..137493b --- /dev/null +++ b/web/src/components/common/LayoutSetting.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/web/src/components/common/TheFooter.vue b/web/src/components/common/TheFooter.vue new file mode 100644 index 0000000..e2cf27e --- /dev/null +++ b/web/src/components/common/TheFooter.vue @@ -0,0 +1,24 @@ + + + diff --git a/web/src/components/common/TheLogo.vue b/web/src/components/common/TheLogo.vue new file mode 100644 index 0000000..e5a8420 --- /dev/null +++ b/web/src/components/common/TheLogo.vue @@ -0,0 +1,12 @@ + + diff --git a/web/src/components/common/ThemeSetting.vue b/web/src/components/common/ThemeSetting.vue new file mode 100644 index 0000000..55c5cd1 --- /dev/null +++ b/web/src/components/common/ThemeSetting.vue @@ -0,0 +1,23 @@ + + + diff --git a/web/src/components/common/ToggleTheme.vue b/web/src/components/common/ToggleTheme.vue new file mode 100644 index 0000000..ca97e19 --- /dev/null +++ b/web/src/components/common/ToggleTheme.vue @@ -0,0 +1,44 @@ + + + diff --git a/web/src/components/common/index.js b/web/src/components/common/index.js new file mode 100644 index 0000000..14e66b2 --- /dev/null +++ b/web/src/components/common/index.js @@ -0,0 +1,6 @@ +export { default as AppCard } from './AppCard.vue' +export { default as TheFooter } from './TheFooter.vue' +export { default as AppPage } from './AppPage.vue' +export { default as CommonPage } from './CommonPage.vue' +export { default as LayoutSetting } from './LayoutSetting.vue' +export { default as ToggleTheme } from './ToggleTheme.vue' diff --git a/web/src/components/index.js b/web/src/components/index.js new file mode 100644 index 0000000..8621d75 --- /dev/null +++ b/web/src/components/index.js @@ -0,0 +1,2 @@ +export * from './common' +export * from './me' diff --git a/web/src/components/me/crud/QueryItem.vue b/web/src/components/me/crud/QueryItem.vue new file mode 100644 index 0000000..01ba98f --- /dev/null +++ b/web/src/components/me/crud/QueryItem.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/web/src/components/me/crud/index.vue b/web/src/components/me/crud/index.vue new file mode 100644 index 0000000..ae2e60a --- /dev/null +++ b/web/src/components/me/crud/index.vue @@ -0,0 +1,204 @@ + + + + + diff --git a/web/src/components/me/index.js b/web/src/components/me/index.js new file mode 100644 index 0000000..795b613 --- /dev/null +++ b/web/src/components/me/index.js @@ -0,0 +1,3 @@ +export { default as MeModal } from './modal/index.vue' +export { default as MeCrud } from './crud/index.vue' +export { default as MeQueryItem } from './crud/QueryItem.vue' diff --git a/web/src/components/me/modal/index.vue b/web/src/components/me/modal/index.vue new file mode 100644 index 0000000..40b2585 --- /dev/null +++ b/web/src/components/me/modal/index.vue @@ -0,0 +1,191 @@ + + + + + diff --git a/web/src/components/me/modal/utils.js b/web/src/components/me/modal/utils.js new file mode 100644 index 0000000..dcba865 --- /dev/null +++ b/web/src/components/me/modal/utils.js @@ -0,0 +1,72 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2024/01/13 17:41:26 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +// 获取元素的CSS样式 +function getCss(element, key) { + return element.currentStyle + ? element.currentStyle[key] + : window.getComputedStyle(element, null)[key] +} + +// 初始化拖拽 +export function initDrag(bar, box) { + if (!bar || !box) + return + const params = { + left: 0, + top: 0, + currentX: 0, + currentY: 0, + flag: false, + } + + if (getCss(box, 'left') !== 'auto') { + params.left = getCss(box, 'left') + } + if (getCss(box, 'top') !== 'auto') { + params.top = getCss(box, 'top') + } + + // 设置触发拖动元素的鼠标样式为移动图标 + bar.style.cursor = 'move' + // 鼠标按下事件处理函数 + bar.onmousedown = function (e) { + params.flag = true // 设置拖拽标志为true + e.preventDefault() // 阻止默认事件 + params.currentX = e.clientX // 鼠标当前位置的X坐标 + params.currentY = e.clientY // 鼠标当前位置的Y坐标 + } + document.onmouseup = function () { + params.flag = false // 设置拖拽标志为false + if (getCss(box, 'left') !== 'auto') { + params.left = getCss(box, 'left') + } + if (getCss(box, 'top') !== 'auto') { + params.top = getCss(box, 'top') + } + } + document.onmousemove = function (e) { + if (e.target !== bar && !params.flag) + return + + e.preventDefault() // 阻止默认事件 + // 如果拖拽标志为true + if (params.flag) { + const nowX = e.clientX // 鼠标当前位置的X坐标 + const nowY = e.clientY // 鼠标当前位置的Y坐标 + const disX = nowX - params.currentX // 鼠标移动的X距离 + const disY = nowY - params.currentY // 鼠标移动的Y距离 + + const left = Number.parseInt(params.left) + disX // 盒子元素的新left值 + const top = Number.parseInt(params.top) + disY // 盒子元素的新top值 + + box.style.left = `${left}px` + box.style.top = `${top}px` + } + } +} diff --git a/web/src/composables/index.js b/web/src/composables/index.js new file mode 100644 index 0000000..2e9b5a1 --- /dev/null +++ b/web/src/composables/index.js @@ -0,0 +1,4 @@ +export * from './useCrud' +export * from './useForm' +export * from './useModal' +export * from './useAliveData' diff --git a/web/src/composables/useAliveData.js b/web/src/composables/useAliveData.js new file mode 100644 index 0000000..bcc2f06 --- /dev/null +++ b/web/src/composables/useAliveData.js @@ -0,0 +1,30 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:22:28 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +const lastDataMap = new Map() +export function useAliveData(initData = {}, key) { + key = key ?? useRoute().name + const lastData = lastDataMap.get(key) + const aliveData = ref(lastData || { ...initData }) + + watch( + aliveData, + (v) => { + lastDataMap.set(key, v) + }, + { deep: true }, + ) + + return { + aliveData, + reset() { + aliveData.value = { ...initData } + lastDataMap.delete(key) + }, + } +} diff --git a/web/src/composables/useCrud.js b/web/src/composables/useCrud.js new file mode 100644 index 0000000..d3c4425 --- /dev/null +++ b/web/src/composables/useCrud.js @@ -0,0 +1,127 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/12 09:03:00 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { useForm, useModal } from '.' + +const ACTIONS = { + view: '查看', + edit: '编辑', + add: '新增', +} + +export function useCrud({ name, initForm = {}, doCreate, doDelete, doUpdate, refresh }) { + const modalAction = ref('') + const [modalRef, okLoading] = useModal() + const [modalFormRef, modalForm, validation] = useForm(initForm) + + /** 新增 */ + function handleAdd(row = {}, title) { + handleOpen({ action: 'add', title, row: { ...initForm, ...row } }) + } + + /** 修改 */ + function handleEdit(row, title) { + handleOpen({ action: 'edit', title, row }) + } + + /** 查看 */ + function handleView(row, title) { + handleOpen({ action: 'view', title, row }) + } + + /** 打开modal */ + function handleOpen(options = {}) { + const { action, row, title, onOk } = options + modalAction.value = action + modalForm.value = { ...row } + modalRef.value?.open({ + ...options, + async onOk() { + if (typeof onOk === 'function') { + return await onOk() + } + else { + return await handleSave() + } + }, + title: title ?? (ACTIONS[modalAction.value] || '') + name, + }) + } + + /** 保存 */ + async function handleSave(action) { + if (!action && !['edit', 'add'].includes(modalAction.value)) { + return false + } + await validation() + const actions = { + add: { + api: () => doCreate(modalForm.value), + cb: () => $message.success('新增成功'), + }, + edit: { + api: () => doUpdate(modalForm.value), + cb: () => $message.success('保存成功'), + }, + } + + action = action || actions[modalAction.value] + + try { + okLoading.value = true + const data = await action.api() + action.cb() + okLoading.value = false + data && refresh(data) + } + catch (error) { + okLoading.value = false + return false + } + } + + /** 删除 */ + function handleDelete(id, confirmOptions) { + if (!id && id !== 0) + return + const d = $dialog.warning({ + content: '确定删除?', + title: '提示', + positiveText: '确定', + negativeText: '取消', + async onPositiveClick() { + try { + d.loading = true + const data = await doDelete(id) + $message.success('删除成功') + d.loading = false + refresh(data, true) + } + catch (error) { + d.loading = false + } + }, + ...confirmOptions, + }) + } + + return { + modalRef, + modalFormRef, + modalAction, + modalForm, + okLoading, + validation, + handleAdd, + handleDelete, + handleEdit, + handleView, + handleOpen, + handleSave, + } +} diff --git a/web/src/composables/useForm.js b/web/src/composables/useForm.js new file mode 100644 index 0000000..69f9d50 --- /dev/null +++ b/web/src/composables/useForm.js @@ -0,0 +1,23 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:22:43 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +export function useForm(initFormData = {}) { + const formRef = ref(null) + const formModel = ref({ ...initFormData }) + const rules = { + required: { + required: true, + message: '此为必填项', + trigger: ['blur', 'change'], + }, + } + const validation = () => { + return formRef.value?.validate() + } + return [formRef, formModel, validation, rules] +} diff --git a/web/src/composables/useModal.js b/web/src/composables/useModal.js new file mode 100644 index 0000000..dc08216 --- /dev/null +++ b/web/src/composables/useModal.js @@ -0,0 +1,20 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:22:49 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +export function useModal() { + const modalRef = ref(null) + const okLoading = computed({ + get() { + return modalRef.value?.okLoading + }, + set(v) { + modalRef.value.okLoading = v + }, + }) + return [modalRef, okLoading] +} diff --git a/web/src/directives/index.js b/web/src/directives/index.js new file mode 100644 index 0000000..f27a036 --- /dev/null +++ b/web/src/directives/index.js @@ -0,0 +1,23 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:23:01 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { router } from '@/router' + +const permission = { + mounted(el, binding) { + const currentRoute = unref(router.currentRoute) + const btns = currentRoute.meta?.btns?.map(item => item.code) || [] + if (!btns.includes(binding.value)) { + el.remove() + } + }, +} + +export function setupDirectives(app) { + app.directive('permission', permission) +} diff --git a/web/src/layouts/components/BreadCrumb.vue b/web/src/layouts/components/BreadCrumb.vue new file mode 100644 index 0000000..dadc9ad --- /dev/null +++ b/web/src/layouts/components/BreadCrumb.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/web/src/layouts/components/Fullscreen.vue b/web/src/layouts/components/Fullscreen.vue new file mode 100644 index 0000000..7ccc3d4 --- /dev/null +++ b/web/src/layouts/components/Fullscreen.vue @@ -0,0 +1,13 @@ + + + diff --git a/web/src/layouts/components/MenuCollapse.vue b/web/src/layouts/components/MenuCollapse.vue new file mode 100644 index 0000000..1ec6d30 --- /dev/null +++ b/web/src/layouts/components/MenuCollapse.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/web/src/layouts/components/RoleSelect.vue b/web/src/layouts/components/RoleSelect.vue new file mode 100644 index 0000000..b839df4 --- /dev/null +++ b/web/src/layouts/components/RoleSelect.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/web/src/layouts/components/SideLogo.vue b/web/src/layouts/components/SideLogo.vue new file mode 100644 index 0000000..a9cfba0 --- /dev/null +++ b/web/src/layouts/components/SideLogo.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/web/src/layouts/components/SideMenu.vue b/web/src/layouts/components/SideMenu.vue new file mode 100644 index 0000000..a369658 --- /dev/null +++ b/web/src/layouts/components/SideMenu.vue @@ -0,0 +1,74 @@ + + + + + + + diff --git a/web/src/layouts/components/UserAvatar.vue b/web/src/layouts/components/UserAvatar.vue new file mode 100644 index 0000000..84bf105 --- /dev/null +++ b/web/src/layouts/components/UserAvatar.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/web/src/layouts/components/index.js b/web/src/layouts/components/index.js new file mode 100644 index 0000000..a9d0280 --- /dev/null +++ b/web/src/layouts/components/index.js @@ -0,0 +1,8 @@ +export { default as RoleSelect } from './RoleSelect.vue' +export { default as UserAvatar } from './UserAvatar.vue' +export { default as MenuCollapse } from './MenuCollapse.vue' +export { default as BreadCrumb } from './BreadCrumb.vue' +export { default as AppTab } from './tab/index.vue' +export { default as SideLogo } from './SideLogo.vue' +export { default as SideMenu } from './SideMenu.vue' +export { default as Fullscreen } from './Fullscreen.vue' diff --git a/web/src/layouts/components/tab/ContextMenu.vue b/web/src/layouts/components/tab/ContextMenu.vue new file mode 100644 index 0000000..ceaaae9 --- /dev/null +++ b/web/src/layouts/components/tab/ContextMenu.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/web/src/layouts/components/tab/index.vue b/web/src/layouts/components/tab/index.vue new file mode 100644 index 0000000..0936732 --- /dev/null +++ b/web/src/layouts/components/tab/index.vue @@ -0,0 +1,99 @@ + + + + + + + diff --git a/web/src/layouts/empty/index.vue b/web/src/layouts/empty/index.vue new file mode 100644 index 0000000..31d7e98 --- /dev/null +++ b/web/src/layouts/empty/index.vue @@ -0,0 +1,11 @@ + + + diff --git a/web/src/layouts/full/header/index.vue b/web/src/layouts/full/header/index.vue new file mode 100644 index 0000000..45850d7 --- /dev/null +++ b/web/src/layouts/full/header/index.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/web/src/layouts/full/index.vue b/web/src/layouts/full/index.vue new file mode 100644 index 0000000..24d8d86 --- /dev/null +++ b/web/src/layouts/full/index.vue @@ -0,0 +1,42 @@ + + + + + + + diff --git a/web/src/layouts/full/sidebar/index.vue b/web/src/layouts/full/sidebar/index.vue new file mode 100644 index 0000000..030938e --- /dev/null +++ b/web/src/layouts/full/sidebar/index.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/web/src/layouts/normal/header/index.vue b/web/src/layouts/normal/header/index.vue new file mode 100644 index 0000000..9590e8f --- /dev/null +++ b/web/src/layouts/normal/header/index.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/web/src/layouts/normal/index.vue b/web/src/layouts/normal/index.vue new file mode 100644 index 0000000..12fb6de --- /dev/null +++ b/web/src/layouts/normal/index.vue @@ -0,0 +1,38 @@ + + + + + + + diff --git a/web/src/layouts/normal/sidebar/index.vue b/web/src/layouts/normal/sidebar/index.vue new file mode 100644 index 0000000..f6b71fb --- /dev/null +++ b/web/src/layouts/normal/sidebar/index.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/web/src/layouts/simple/index.vue b/web/src/layouts/simple/index.vue new file mode 100644 index 0000000..ef192dd --- /dev/null +++ b/web/src/layouts/simple/index.vue @@ -0,0 +1,36 @@ + + + + + + + diff --git a/web/src/layouts/simple/sidebar/index.vue b/web/src/layouts/simple/sidebar/index.vue new file mode 100644 index 0000000..27a7e6f --- /dev/null +++ b/web/src/layouts/simple/sidebar/index.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/web/src/main.js b/web/src/main.js new file mode 100644 index 0000000..ce2e92f --- /dev/null +++ b/web/src/main.js @@ -0,0 +1,31 @@ +/********************************** + * @Description: 入口文件 + * @FilePath: main.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:41:32 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import '@/styles/reset.css' +import '@/styles/global.scss' +import 'uno.css' + +import { createApp } from 'vue' +import App from './App.vue' +import { setupRouter } from './router' +import { setupStore } from './store' +import { setupNaiveDiscreteApi } from './utils' +import { setupDirectives } from './directives' + +async function bootstrap() { + const app = createApp(App) + setupStore(app) + setupDirectives(app) + await setupRouter(app) + app.mount('#app') + setupNaiveDiscreteApi() +} + +bootstrap() diff --git a/web/src/router/basic-routes.js b/web/src/router/basic-routes.js new file mode 100644 index 0000000..e8321ab --- /dev/null +++ b/web/src/router/basic-routes.js @@ -0,0 +1,40 @@ +export const basicRoutes = [ + { + name: 'Login', + path: '/login', + component: () => import('@/views/login/index.vue'), + meta: { + title: '登录页', + layout: 'empty', + }, + }, + + { + name: 'Home', + path: '/', + component: () => import('@/views/home/index.vue'), + meta: { + title: '首页', + }, + }, + + { + name: '404', + path: '/404', + component: () => import('@/views/error-page/404.vue'), + meta: { + title: '页面飞走了', + layout: 'empty', + }, + }, + + { + name: '403', + path: '/403', + component: () => import('@/views/error-page/403.vue'), + meta: { + title: '没有权限', + layout: 'empty', + }, + }, +] diff --git a/web/src/router/guards/index.js b/web/src/router/guards/index.js new file mode 100644 index 0000000..35f274b --- /dev/null +++ b/web/src/router/guards/index.js @@ -0,0 +1,19 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:24:46 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { createPageLoadingGuard } from './page-loading-guard' +import { createPageTitleGuard } from './page-title-guard' +import { createPermissionGuard } from './permission-guard' +import { createTabGuard } from './tab-guard' + +export function setupRouterGuards(router) { + createPageLoadingGuard(router) + createPermissionGuard(router) + createPageTitleGuard(router) + createTabGuard(router) +} diff --git a/web/src/router/guards/page-loading-guard.js b/web/src/router/guards/page-loading-guard.js new file mode 100644 index 0000000..ba145fa --- /dev/null +++ b/web/src/router/guards/page-loading-guard.js @@ -0,0 +1,23 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:24:53 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +export function createPageLoadingGuard(router) { + router.beforeEach(() => { + $loadingBar.start() + }) + + router.afterEach(() => { + setTimeout(() => { + $loadingBar.finish() + }, 200) + }) + + router.onError(() => { + $loadingBar.error() + }) +} diff --git a/web/src/router/guards/page-title-guard.js b/web/src/router/guards/page-title-guard.js new file mode 100644 index 0000000..96042f6 --- /dev/null +++ b/web/src/router/guards/page-title-guard.js @@ -0,0 +1,21 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:25:00 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +const baseTitle = import.meta.env.VITE_TITLE + +export function createPageTitleGuard(router) { + router.afterEach((to) => { + const pageTitle = to.meta?.title + if (pageTitle) { + document.title = `${pageTitle} | ${baseTitle}` + } + else { + document.title = baseTitle + } + }) +} diff --git a/web/src/router/guards/permission-guard.js b/web/src/router/guards/permission-guard.js new file mode 100644 index 0000000..b317a08 --- /dev/null +++ b/web/src/router/guards/permission-guard.js @@ -0,0 +1,56 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:25:07 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { useAuthStore, usePermissionStore, useUserStore } from '@/store' +import api from '@/api' +import { getPermissions, getUserInfo } from '@/store/helper' + +const WHITE_LIST = ['/login', '/404'] +export function createPermissionGuard(router) { + router.beforeEach(async (to) => { + const authStore = useAuthStore() + const token = authStore.accessToken + + /** 没有token */ + if (!token) { + if (WHITE_LIST.includes(to.path)) + return true + return { path: 'login', query: { ...to.query, redirect: to.path } } + } + + // 有token的情况 + if (to.path === '/login') + return { path: '/' } + if (WHITE_LIST.includes(to.path)) + return true + + const userStore = useUserStore() + const permissionStore = usePermissionStore() + if (!userStore.userInfo) { + const [user, permissions] = await Promise.all([getUserInfo(), getPermissions()]) + userStore.setUser(user) + permissionStore.setPermissions(permissions) + const routeComponents = import.meta.glob('@/views/**/*.vue') + permissionStore.accessRoutes.forEach((route) => { + route.component = routeComponents[route.component] || undefined + !router.hasRoute(route.name) && router.addRoute(route) + }) + return { ...to, replace: true } + } + + const routes = router.getRoutes() + if (routes.find(route => route.name === to.name)) + return true + + // 判断是无权限还是404 + const { data: hasMenu } = await api.validateMenuPath(to.path) + return hasMenu + ? { name: '403', query: { path: to.fullPath }, state: { from: 'permission-guard' } } + : { name: '404', query: { path: to.fullPath } } + }) +} diff --git a/web/src/router/guards/tab-guard.js b/web/src/router/guards/tab-guard.js new file mode 100644 index 0000000..e74b652 --- /dev/null +++ b/web/src/router/guards/tab-guard.js @@ -0,0 +1,24 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:25:17 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { useTabStore } from '@/store' + +export const EXCLUDE_TAB = ['/404', '/403', '/login'] + +export function createTabGuard(router) { + router.afterEach((to) => { + if (EXCLUDE_TAB.includes(to.path)) + return + const tabStore = useTabStore() + const { name, fullPath: path } = to + const title = to.meta?.title + const icon = to.meta?.icon + const keepAlive = to.meta?.keepAlive + tabStore.addTab({ name, path, title, icon, keepAlive }) + }) +} diff --git a/web/src/router/index.js b/web/src/router/index.js new file mode 100644 index 0000000..994157b --- /dev/null +++ b/web/src/router/index.js @@ -0,0 +1,25 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:25:23 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router' +import { setupRouterGuards } from './guards' +import { basicRoutes } from './basic-routes' + +export const router = createRouter({ + history: + import.meta.env.VITE_USE_HASH === 'true' + ? createWebHashHistory(import.meta.env.VITE_PUBLIC_PATH || '/') + : createWebHistory(import.meta.env.VITE_PUBLIC_PATH || '/'), + routes: basicRoutes, + scrollBehavior: () => ({ left: 0, top: 0 }), +}) + +export async function setupRouter(app) { + app.use(router) + setupRouterGuards(router) +} diff --git a/web/src/settings.js b/web/src/settings.js new file mode 100644 index 0000000..b337449 --- /dev/null +++ b/web/src/settings.js @@ -0,0 +1,77 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/13 20:54:36 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +export const defaultLayout = 'normal' + +export const defaultPrimaryColor = '#316C72' + +// 控制 LayoutSetting 组件是否可见 +export const layoutSettingVisible = true + +export const naiveThemeOverrides = { + common: { + primaryColor: '#316C72FF', + primaryColorHover: '#316C72E3', + primaryColorPressed: '#2B4C59FF', + primaryColorSuppl: '#316C72E3', + }, +} + +export const basePermissions = [ + { + code: 'ExternalLink', + name: '外链(可内嵌打开)', + type: 'MENU', + icon: 'i-fe:external-link', + order: 98, + enable: true, + show: true, + children: [ + { + code: 'ShowDocs', + name: '项目文档', + type: 'MENU', + path: 'https://docs.isme.top/web/#/624306705/188522224', + icon: 'i-me:docs', + order: 1, + enable: true, + show: true, + }, + { + code: 'ApiFoxDocs', + name: '接口文档', + type: 'MENU', + path: 'https://apifox.com/apidoc/shared-ff4a4d32-c0d1-4caf-b0ee-6abc130f734a', + icon: 'i-me:apifox', + order: 2, + enable: true, + show: true, + }, + { + code: 'NaiveUI', + name: 'Naive UI', + type: 'MENU', + path: 'https://www.naiveui.com/zh-CN/os-theme', + icon: 'i-me:naiveui', + order: 3, + enable: true, + show: true, + }, + { + code: 'MyBlog', + name: '博客-掘金', + type: 'MENU', + path: 'https://juejin.cn/user/1961184475483255/posts', + icon: 'i-simple-icons:juejin', + order: 4, + enable: true, + show: true, + }, + ], + }, +] diff --git a/web/src/store/helper.js b/web/src/store/helper.js new file mode 100644 index 0000000..dd8fd26 --- /dev/null +++ b/web/src/store/helper.js @@ -0,0 +1,30 @@ +import { basePermissions } from '@/settings' +import api from '@/api' + +export async function getUserInfo() { + const res = await api.getUser() + const { id, username, profile, roles, currentRole } = res.data || {} + return { + id, + username, + avatar: profile?.avatar, + nickName: profile?.nickName, + gender: profile?.gender, + address: profile?.address, + email: profile?.email, + roles, + currentRole, + } +} + +export async function getPermissions() { + let asyncPermissions = [] + try { + const res = await api.getRolePermissions() + asyncPermissions = res?.data || [] + } + catch (error) { + console.error(error) + } + return basePermissions.concat(asyncPermissions) +} diff --git a/web/src/store/index.js b/web/src/store/index.js new file mode 100644 index 0000000..a193337 --- /dev/null +++ b/web/src/store/index.js @@ -0,0 +1,18 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:26:15 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { createPinia } from 'pinia' +import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' + +export function setupStore(app) { + const pinia = createPinia() + pinia.use(piniaPluginPersistedstate) + app.use(pinia) +} + +export * from './modules' diff --git a/web/src/store/modules/app.js b/web/src/store/modules/app.js new file mode 100644 index 0000000..d16aca3 --- /dev/null +++ b/web/src/store/modules/app.js @@ -0,0 +1,56 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:25:31 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { defineStore } from 'pinia' +import { useDark } from '@vueuse/core' +import { generate, getRgbStr } from '@arco-design/color' +import { defaultLayout, defaultPrimaryColor, naiveThemeOverrides } from '@/settings' + +export const useAppStore = defineStore('app', { + state: () => ({ + collapsed: false, + isDark: useDark(), + layout: defaultLayout, + primaryColor: defaultPrimaryColor, + naiveThemeOverrides, + }), + actions: { + switchCollapsed() { + this.collapsed = !this.collapsed + }, + setCollapsed(b) { + this.collapsed = b + }, + toggleDark() { + this.isDark = !this.isDark + }, + setLayout(v) { + this.layout = v + }, + setPrimaryColor(color) { + this.primaryColor = color + }, + setThemeColor(color = this.primaryColor, isDark = this.isDark) { + const colors = generate(color, { + list: true, + dark: isDark, + }) + document.body.style.setProperty('--primary-color', getRgbStr(colors[5])) + this.naiveThemeOverrides.common = Object.assign(this.naiveThemeOverrides.common || {}, { + primaryColor: colors[5], + primaryColorHover: colors[4], + primaryColorSuppl: colors[4], + primaryColorPressed: colors[6], + }) + }, + }, + persist: { + paths: ['collapsed', 'layout', 'primaryColor', 'naiveThemeOverrides'], + storage: sessionStorage, + }, +}) diff --git a/web/src/store/modules/auth.js b/web/src/store/modules/auth.js new file mode 100644 index 0000000..aea8f0e --- /dev/null +++ b/web/src/store/modules/auth.js @@ -0,0 +1,59 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:25:39 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { defineStore } from 'pinia' +import { usePermissionStore, useRouterStore, useTabStore, useUserStore } from '@/store' + +export const useAuthStore = defineStore('auth', { + state: () => ({ + accessToken: undefined, + }), + actions: { + setToken({ accessToken }) { + this.accessToken = accessToken + }, + resetToken() { + this.$reset() + }, + toLogin() { + const { router, route } = useRouterStore() + router.replace({ + path: '/login', + query: route.query, + }) + }, + async switchCurrentRole(data) { + this.resetLoginState() + await nextTick() + this.setToken(data) + }, + resetLoginState() { + const { resetUser } = useUserStore() + const { resetRouter } = useRouterStore() + const { resetPermission, accessRoutes } = usePermissionStore() + const { resetTabs } = useTabStore() + // 重置路由 + resetRouter(accessRoutes) + // 重置用户 + resetUser() + // 重置权限 + resetPermission() + // 重置Tabs + resetTabs() + // 重置token + this.resetToken() + }, + async logout() { + this.resetLoginState() + this.toLogin() + }, + }, + persist: { + key: 'vue-naivue-admin_auth', + }, +}) diff --git a/web/src/store/modules/index.js b/web/src/store/modules/index.js new file mode 100644 index 0000000..9672b79 --- /dev/null +++ b/web/src/store/modules/index.js @@ -0,0 +1,6 @@ +export * from './app' +export * from './auth' +export * from './permission' +export * from './tab' +export * from './user' +export * from './router' diff --git a/web/src/store/modules/permission.js b/web/src/store/modules/permission.js new file mode 100644 index 0000000..b61a039 --- /dev/null +++ b/web/src/store/modules/permission.js @@ -0,0 +1,82 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:25:47 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { hyphenate } from '@vueuse/core' +import { defineStore } from 'pinia' +import { isExternal } from '@/utils' + +export const usePermissionStore = defineStore('permission', { + state: () => ({ + accessRoutes: [], + permissions: [], + menus: [], + }), + actions: { + setPermissions(permissions) { + this.permissions = permissions + this.menus = this.permissions + .filter(item => item.type === 'MENU') + .map(item => this.getMenuItem(item)) + .filter(item => !!item) + .sort((a, b) => a.order - b.order) + }, + getMenuItem(item, parent) { + const route = this.generateRoute(item, item.show ? null : parent?.key) + if (item.enable && route.path && !route.path.startsWith('http')) + this.accessRoutes.push(route) + if (!item.show) + return null + const menuItem = { + label: route.meta.title, + key: route.name, + path: route.path, + originPath: route.meta.originPath, + icon: () => h('i', { class: `${route.meta.icon} text-16` }), + order: item.order ?? 0, + } + const children = item.children?.filter(item => item.type === 'MENU') || [] + if (children.length) { + menuItem.children = children + .map(child => this.getMenuItem(child, menuItem)) + .filter(item => !!item) + .sort((a, b) => a.order - b.order) + if (!menuItem.children.length) + delete menuItem.children + } + return menuItem + }, + generateRoute(item, parentKey) { + let originPath + if (isExternal(item.path)) { + originPath = item.path + item.component = '/src/views/iframe/index.vue' + item.path = `/iframe/${hyphenate(item.code)}` + } + return { + name: item.code, + path: item.path, + redirect: item.redirect, + component: item.component, + meta: { + originPath, + icon: `${item.icon}?mask`, + title: item.name, + layout: item.layout, + keepAlive: !!item.keepAlive, + parentKey, + btns: item.children + ?.filter(item => item.type === 'BUTTON') + .map(item => ({ code: item.code, name: item.name })), + }, + } + }, + resetPermission() { + this.$reset() + }, + }, +}) diff --git a/web/src/store/modules/router.js b/web/src/store/modules/router.js new file mode 100644 index 0000000..51a5b59 --- /dev/null +++ b/web/src/store/modules/router.js @@ -0,0 +1,26 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2024/01/06 17:18:40 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { defineStore } from 'pinia' + +export const useRouterStore = defineStore('router', () => { + const router = useRouter() + const route = useRoute() + + function resetRouter(accessRoutes) { + accessRoutes.forEach((item) => { + router.hasRoute(item.name) && router.removeRoute(item.name) + }) + } + + return { + router, + route, + resetRouter, + } +}) diff --git a/web/src/store/modules/tab.js b/web/src/store/modules/tab.js new file mode 100644 index 0000000..12c5e46 --- /dev/null +++ b/web/src/store/modules/tab.js @@ -0,0 +1,94 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:25:52 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { defineStore } from 'pinia' +import { useRouterStore } from './router' + +export const useTabStore = defineStore('tab', { + state: () => ({ + tabs: [], + activeTab: '', + reloading: false, + }), + getters: { + activeIndex() { + return this.tabs.findIndex(item => item.path === this.activeTab) + }, + }, + actions: { + async setActiveTab(path) { + await nextTick() // tab栏dom更新完再设置激活,让tab栏定位到新增的tab上生效 + this.activeTab = path + }, + setTabs(tabs) { + this.tabs = tabs + }, + addTab(tab = {}) { + const findIndex = this.tabs.findIndex(item => item.path === tab.path) + if (findIndex !== -1) { + this.tabs.splice(findIndex, 1, tab) + } + else { + this.setTabs([...this.tabs, tab]) + } + this.setActiveTab(tab.path) + }, + async reloadTab(path, keepAlive) { + const findItem = this.tabs.find(item => item.path === path) + if (!findItem) + return + // 更新key可让keepAlive失效 + if (keepAlive) + findItem.keepAlive = false + $loadingBar.start() + this.reloading = true + await nextTick() + this.reloading = false + findItem.keepAlive = !!keepAlive + setTimeout(() => { + document.documentElement.scrollTo({ left: 0, top: 0 }) + $loadingBar.finish() + }, 100) + }, + async removeTab(path) { + this.setTabs(this.tabs.filter(tab => tab.path !== path)) + if (path === this.activeTab) { + useRouterStore().router?.push(this.tabs[this.tabs.length - 1].path) + } + }, + removeOther(curPath = this.activeTab) { + this.setTabs(this.tabs.filter(tab => tab.path === curPath)) + if (curPath !== this.activeTab) { + useRouterStore().router?.push(this.tabs[this.tabs.length - 1].path) + } + }, + removeLeft(curPath) { + const curIndex = this.tabs.findIndex(item => item.path === curPath) + const filterTabs = this.tabs.filter((item, index) => index >= curIndex) + this.setTabs(filterTabs) + if (!filterTabs.find(item => item.path === this.activeTab)) { + useRouterStore().router?.push(filterTabs[filterTabs.length - 1].path) + } + }, + removeRight(curPath) { + const curIndex = this.tabs.findIndex(item => item.path === curPath) + const filterTabs = this.tabs.filter((item, index) => index <= curIndex) + this.setTabs(filterTabs) + if (!filterTabs.find(item => item.path === this.activeTab.value)) { + useRouterStore().router?.push(filterTabs[filterTabs.length - 1].path) + } + }, + resetTabs() { + this.$reset() + }, + }, + persist: { + paths: ['tabs'], + storage: sessionStorage, + }, +}) diff --git a/web/src/store/modules/user.js b/web/src/store/modules/user.js new file mode 100644 index 0000000..c434737 --- /dev/null +++ b/web/src/store/modules/user.js @@ -0,0 +1,43 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:25:59 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { defineStore } from 'pinia' + +export const useUserStore = defineStore('user', { + state: () => ({ + userInfo: null, + }), + getters: { + userId() { + return this.userInfo?.id + }, + username() { + return this.userInfo?.username + }, + nickName() { + return this.userInfo?.nickName + }, + avatar() { + return this.userInfo?.avatar + }, + currentRole() { + return this.userInfo?.currentRole || {} + }, + roles() { + return this.userInfo?.roles || [] + }, + }, + actions: { + setUser(user) { + this.userInfo = user + }, + resetUser() { + this.$reset() + }, + }, +}) diff --git a/web/src/styles/global.scss b/web/src/styles/global.scss new file mode 100644 index 0000000..857043c --- /dev/null +++ b/web/src/styles/global.scss @@ -0,0 +1,91 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:26:28 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +html, +body { + width: 100%; + height: 100%; + overflow: hidden; +} + +#app { + width: 100%; + height: 100%; +} + +/* transition fade-slide */ +.fade-slide-leave-active, +.fade-slide-enter-active { + transition: all 0.3s; +} + +.fade-slide-enter-from { + opacity: 0; + transform: translateX(-30px); +} + +.fade-slide-leave-to { + opacity: 0; + transform: translateX(30px); +} + +/* 自定义滚动条样式 */ +.cus-scroll { + overflow: auto; + &::-webkit-scrollbar { + width: 8px; + height: 8px; + } +} +.cus-scroll-x { + overflow-x: auto; + &::-webkit-scrollbar { + width: 0; + height: 8px; + } +} +.cus-scroll-y { + overflow-y: auto; + &::-webkit-scrollbar { + width: 8px; + height: 0; + } +} +.cus-scroll, +.cus-scroll-x, +.cus-scroll-y { + &::-webkit-scrollbar-thumb { + background-color: transparent; + border-radius: 4px; + } + &:hover { + &::-webkit-scrollbar-thumb { + background: #bfbfbf; + } + &::-webkit-scrollbar-thumb:hover { + background: rgb(var(--primary-color)); + } + } +} + +/* 切换主题的动画效果 */ +::view-transition-old(root), +::view-transition-new(root) { + animation: none; + mix-blend-mode: normal; +} + +::view-transition-old(root), +.dark::view-transition-new(root) { + z-index: 1; +} + +::view-transition-new(root), +.dark::view-transition-old(root) { + z-index: 9999; +} diff --git a/web/src/styles/reset.css b/web/src/styles/reset.css new file mode 100644 index 0000000..71447a2 --- /dev/null +++ b/web/src/styles/reset.css @@ -0,0 +1,49 @@ +/********************************** + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/05 21:26:38 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +html { + box-sizing: border-box; +} + +*, +::before, +::after { + margin: 0; + padding: 0; + box-sizing: inherit; +} + +a { + text-decoration: none; + color: inherit; +} + +a:hover, +a:link, +a:visited, +a:active { + text-decoration: none; +} + +ol, +ul { + list-style: none; +} + +input, +textarea { + outline: none; + border: none; + resize: none; +} + +img, +video { + max-width: 100%; + height: auto; +} diff --git a/web/src/utils/common.js b/web/src/utils/common.js new file mode 100644 index 0000000..eccf9e9 --- /dev/null +++ b/web/src/utils/common.js @@ -0,0 +1,106 @@ +/********************************** + * @FilePath: common.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:45:46 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import dayjs from 'dayjs' + +/** + * @param {(object | string | number)} time + * @param {string} format + * @returns {string | null} 格式化后的时间字符串 + * + */ +export function formatDateTime(time = undefined, format = 'YYYY-MM-DD HH:mm:ss') { + return dayjs(time).format(format) +} + +export function formatDate(date = undefined, format = 'YYYY-MM-DD') { + return formatDateTime(date, format) +} + +/** + * @param {Function} fn + * @param {number} wait + * @returns {Function} 节流函数 + * + */ +export function throttle(fn, wait) { + let context, args + let previous = 0 + + return function (...argArr) { + const now = +new Date() + context = this + args = argArr + if (now - previous > wait) { + fn.apply(context, args) + previous = now + } + } +} + +/** + * @param {Function} method + * @param {number} wait + * @param {boolean} immediate + * @return {*} 防抖函数 + */ +export function debounce(method, wait, immediate) { + let timeout + return function (...args) { + const context = this + if (timeout) { + clearTimeout(timeout) + } + // 立即执行需要两个条件,一是immediate为true,二是timeout未被赋值或被置为null + if (immediate) { + /** + * 如果定时器不存在,则立即执行,并设置一个定时器,wait毫秒后将定时器置为null + * 这样确保立即执行后wait毫秒内不会被再次触发 + */ + const callNow = !timeout + timeout = setTimeout(() => { + timeout = null + }, wait) + if (callNow) { + method.apply(context, args) + } + } + else { + // 如果immediate为false,则函数wait毫秒后执行 + timeout = setTimeout(() => { + /** + * args是一个类数组对象,所以使用fn.apply + * 也可写作method.call(context, ...args) + */ + method.apply(context, args) + }, wait) + } + } +} + +/** + * @param {number} time 毫秒数 + * @returns 睡一会儿,让子弹暂停一下 + */ +export function sleep(time) { + return new Promise(resolve => setTimeout(resolve, time)) +} + +/** + * @param {HTMLElement} el + * @param {Function} cb + * @return {ResizeObserver} + */ +export function useResize(el, cb) { + const observer = new ResizeObserver((entries) => { + cb(entries[0].contentRect) + }) + observer.observe(el) + return observer +} diff --git a/web/src/utils/http/helpers.js b/web/src/utils/http/helpers.js new file mode 100644 index 0000000..b7de8bb --- /dev/null +++ b/web/src/utils/http/helpers.js @@ -0,0 +1,67 @@ +/********************************** + * @FilePath: helpers.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:46:22 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { useAuthStore } from '@/store' + +let isConfirming = false +export function resolveResError(code, message, needTip = true) { + switch (code) { + case 401: + if (isConfirming || !needTip) + return + isConfirming = true + $dialog.confirm({ + title: '提示', + type: 'info', + content: '登录已过期,是否重新登录?', + confirm() { + useAuthStore().logout() + window.$message?.success('已退出登录') + isConfirming = false + }, + cancel() { + isConfirming = false + }, + }) + return false + case 11007: + case 11008: + if (isConfirming || !needTip) + return + isConfirming = true + $dialog.confirm({ + title: '提示', + type: 'info', + content: `${message},是否重新登录?`, + confirm() { + useAuthStore().logout() + window.$message?.success('已退出登录') + isConfirming = false + }, + cancel() { + isConfirming = false + }, + }) + return false + case 403: + message = '请求被拒绝' + break + case 404: + message = '请求资源或接口不存在' + break + case 500: + message = '服务器发生异常' + break + default: + message = message ?? `【${code}】: 未知异常!` + break + } + needTip && window.$message?.error(message) + return message +} diff --git a/web/src/utils/http/index.js b/web/src/utils/http/index.js new file mode 100644 index 0000000..b0d5ca0 --- /dev/null +++ b/web/src/utils/http/index.js @@ -0,0 +1,30 @@ +/********************************** + * @FilePath: index.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:46:28 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import axios from 'axios' +import { setupInterceptors } from './interceptors' + +export function createAxios(options = {}) { + const defaultOptions = { + baseURL: import.meta.env.VITE_AXIOS_BASE_URL, + timeout: 12000, + } + const service = axios.create({ + ...defaultOptions, + ...options, + }) + setupInterceptors(service) + return service +} + +export const request = createAxios() + +export const mockRequest = createAxios({ + baseURL: '/mock-api', +}) diff --git a/web/src/utils/http/interceptors.js b/web/src/utils/http/interceptors.js new file mode 100644 index 0000000..d048d3d --- /dev/null +++ b/web/src/utils/http/interceptors.js @@ -0,0 +1,70 @@ +/********************************** + * @FilePath: interceptors.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:46:40 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { resolveResError } from './helpers' +import { useAuthStore } from '@/store' + +export function setupInterceptors(axiosInstance) { + function reqResolve(config) { + // 处理不需要token的请求 + if (config.needToken === false) { + return config + } + + const { accessToken } = useAuthStore() + if (accessToken) { + // token: Bearer + xxx + config.headers.Authorization = `Bearer ${accessToken}` + } + + return config + } + + function reqReject(error) { + return Promise.reject(error) + } + + const SUCCESS_CODES = [0, 200] + function resResolve(response) { + const { data, status, config, statusText, headers } = response + if (headers['content-type']?.includes('json')) { + if (SUCCESS_CODES.includes(data?.code)) { + return Promise.resolve(data) + } + const code = data?.code ?? status + + const needTip = config?.needTip !== false + + // 根据code处理对应的操作,并返回处理后的message + const message = resolveResError(code, data?.message ?? statusText, needTip) + + return Promise.reject({ code, message, error: data ?? response }) + } + return Promise.resolve(data ?? response) + } + + async function resReject(error) { + if (!error || !error.response) { + const code = error?.code + /** 根据code处理对应的操作,并返回处理后的message */ + const message = resolveResError(code, error.message) + return Promise.reject({ code, message, error }) + } + + const { data, status, config } = error.response + const code = data?.code ?? status + + const needTip = config?.needTip !== false + const message = resolveResError(code, data?.message ?? error.message, needTip) + return Promise.reject({ code, message, error: error.response?.data || error.response }) + } + + axiosInstance.interceptors.request.use(reqResolve, reqReject) + axiosInstance.interceptors.response.use(resResolve, resReject) +} diff --git a/web/src/utils/index.js b/web/src/utils/index.js new file mode 100644 index 0000000..a18642a --- /dev/null +++ b/web/src/utils/index.js @@ -0,0 +1,14 @@ +/********************************** + * @FilePath: index.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:45:53 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +export * from './common' +export * from './http' +export * from './is' +export * from './naiveTools' +export * from './storage' diff --git a/web/src/utils/is.js b/web/src/utils/is.js new file mode 100644 index 0000000..6b9a814 --- /dev/null +++ b/web/src/utils/is.js @@ -0,0 +1,127 @@ +/********************************** + * @FilePath: is.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:45:32 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +const toString = Object.prototype.toString + +export function is(val, type) { + return toString.call(val) === `[object ${type}]` +} + +export function isDef(val) { + return typeof val !== 'undefined' +} + +export function isUndef(val) { + return typeof val === 'undefined' +} + +export function isNull(val) { + return val === null +} + +export function isWhitespace(val) { + return val === '' +} + +export function isObject(val) { + return !isNull(val) && is(val, 'Object') +} + +export function isArray(val) { + return val && Array.isArray(val) +} + +export function isString(val) { + return is(val, 'String') +} + +export function isNumber(val) { + return is(val, 'Number') +} + +export function isBoolean(val) { + return is(val, 'Boolean') +} + +export function isDate(val) { + return is(val, 'Date') +} + +export function isRegExp(val) { + return is(val, 'RegExp') +} + +export function isFunction(val) { + return typeof val === 'function' +} + +export function isPromise(val) { + return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch) +} + +export function isElement(val) { + return isObject(val) && !!val.tagName +} + +export function isWindow(val) { + return typeof window !== 'undefined' && isDef(window) && is(val, 'Window') +} + +export function isNullOrUndef(val) { + return isNull(val) || isUndef(val) +} + +export function isNullOrWhitespace(val) { + return isNullOrUndef(val) || isWhitespace(val) +} + +/** 空数组 | 空字符串 | 空对象 | 空Map | 空Set */ +export function isEmpty(val) { + if (isArray(val) || isString(val)) { + return val.length === 0 + } + + if (val instanceof Map || val instanceof Set) { + return val.size === 0 + } + + if (isObject(val)) { + return Object.keys(val).length === 0 + } + + return false +} + +/** + * 类似mysql的IFNULL函数 + * + * @param {number | boolean | string} val + * @param {number | boolean | string} def + * @returns 第一个参数为null | undefined | '' 则返回第二个参数作为备用值,否则返回第一个参数 + */ +export function ifNull(val, def = '') { + return isNullOrWhitespace(val) ? def : val +} + +export function isUrl(path) { + const reg = /^https?:\/\/[-\w+&@#/%?=~|!:,.;]+[-\w+&@#/%=~|]$/ + return reg.test(path) +} + +/** + * @param {string} path + * @returns {boolean} 是否是外部链接 + */ +export function isExternal(path) { + return /^https?:|mailto:|tel:/.test(path) +} + +export const isServer = typeof window === 'undefined' + +export const isClient = !isServer diff --git a/web/src/utils/naiveTools.js b/web/src/utils/naiveTools.js new file mode 100644 index 0000000..20efe5e --- /dev/null +++ b/web/src/utils/naiveTools.js @@ -0,0 +1,121 @@ +/********************************** + * @FilePath: naiveTools.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:45:20 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import * as NaiveUI from 'naive-ui' +import { isNullOrUndef } from '@/utils' +import { useAppStore } from '@/store' + +export function setupMessage(NMessage) { + class Message { + static instance + constructor() { + // 单例模式 + if (Message.instance) + return Message.instance + Message.instance = this + this.message = {} + this.removeTimer = {} + } + + removeMessage(key, duration = 5000) { + this.removeTimer[key] && clearTimeout(this.removeTimer[key]) + this.removeTimer[key] = setTimeout(() => { + this.message[key]?.destroy() + }, duration) + } + + destroy(key, duration = 200) { + setTimeout(() => { + this.message[key]?.destroy() + }, duration) + } + + showMessage(type, content, option = {}) { + if (Array.isArray(content)) { + return content.forEach(msg => NMessage[type](msg, option)) + } + + if (!option.key) { + return NMessage[type](content, option) + } + + const currentMessage = this.message[option.key] + if (currentMessage) { + currentMessage.type = type + currentMessage.content = content + } + else { + this.message[option.key] = NMessage[type](content, { + ...option, + duration: 0, + onAfterLeave: () => { + delete this.message[option.key] + }, + }) + } + this.removeMessage(option.key, option.duration) + } + + loading(content, option) { + this.showMessage('loading', content, option) + } + + success(content, option) { + this.showMessage('success', content, option) + } + + error(content, option) { + this.showMessage('error', content, option) + } + + info(content, option) { + this.showMessage('info', content, option) + } + + warning(content, option) { + this.showMessage('warning', content, option) + } + } + + return new Message() +} + +export function setupDialog(NDialog) { + NDialog.confirm = function (option = {}) { + const showIcon = !isNullOrUndef(option.title) + return NDialog[option.type || 'warning']({ + showIcon, + positiveText: '确定', + negativeText: '取消', + onPositiveClick: option.confirm, + onNegativeClick: option.cancel, + onMaskClick: option.cancel, + ...option, + }) + } + + return NDialog +} + +export function setupNaiveDiscreteApi() { + const appStore = useAppStore() + const configProviderProps = computed(() => ({ + theme: appStore.isDark ? NaiveUI.darkTheme : undefined, + themeOverrides: useAppStore().naiveThemeOverrides, + })) + const { message, dialog, notification, loadingBar } = NaiveUI.createDiscreteApi( + ['message', 'dialog', 'notification', 'loadingBar'], + { configProviderProps }, + ) + + window.$loadingBar = loadingBar + window.$notification = notification + window.$message = setupMessage(message) + window.$dialog = setupDialog(dialog) +} diff --git a/web/src/utils/storage/index.js b/web/src/utils/storage/index.js new file mode 100644 index 0000000..f173867 --- /dev/null +++ b/web/src/utils/storage/index.js @@ -0,0 +1,30 @@ +/********************************** + * @FilePath: index.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:46:07 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { createStorage } from './storage' + +const prefixKey = 'vue-naive-admin_' + +export const createLocalStorage = function (option = {}) { + return createStorage({ + prefixKey: option.prefixKey || '', + storage: localStorage, + }) +} + +export const createSessionStorage = function (option = {}) { + return createStorage({ + prefixKey: option.prefixKey || '', + storage: sessionStorage, + }) +} + +export const lStorage = createLocalStorage({ prefixKey }) + +export const sStorage = createSessionStorage({ prefixKey }) diff --git a/web/src/utils/storage/storage.js b/web/src/utils/storage/storage.js new file mode 100644 index 0000000..6741e07 --- /dev/null +++ b/web/src/utils/storage/storage.js @@ -0,0 +1,66 @@ +/********************************** + * @FilePath: storage.js + * @Author: Ronnie Zhang + * @LastEditor: Ronnie Zhang + * @LastEditTime: 2023/12/04 22:46:13 + * @Email: zclzone@outlook.com + * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top + **********************************/ + +import { isNullOrUndef } from '@/utils' + +class Storage { + constructor(option) { + this.storage = option.storage + this.prefixKey = option.prefixKey + } + + getKey(key) { + return `${this.prefixKey}${key}`.toLowerCase() + } + + set(key, value, expire) { + const stringData = JSON.stringify({ + value, + time: Date.now(), + expire: !isNullOrUndef(expire) ? new Date().getTime() + expire * 1000 : null, + }) + this.storage.setItem(this.getKey(key), stringData) + } + + get(key) { + const { value } = this.getItem(key, {}) + return value + } + + getItem(key, def = null) { + const val = this.storage.getItem(this.getKey(key)) + if (!val) + return def + try { + const data = JSON.parse(val) + const { value, time, expire } = data + if (isNullOrUndef(expire) || expire > new Date().getTime()) { + return { value, time } + } + this.remove(key) + return def + } + catch (error) { + this.remove(key) + return def + } + } + + remove(key) { + this.storage.removeItem(this.getKey(key)) + } + + clear() { + this.storage.clear() + } +} + +export function createStorage({ prefixKey = '', storage = sessionStorage }) { + return new Storage({ prefixKey, storage }) +} diff --git a/web/src/views/base/index.vue b/web/src/views/base/index.vue new file mode 100644 index 0000000..d768f38 --- /dev/null +++ b/web/src/views/base/index.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/web/src/views/base/keep-alive.vue b/web/src/views/base/keep-alive.vue new file mode 100644 index 0000000..b268b7b --- /dev/null +++ b/web/src/views/base/keep-alive.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/web/src/views/base/test-modal.vue b/web/src/views/base/test-modal.vue new file mode 100644 index 0000000..2013550 --- /dev/null +++ b/web/src/views/base/test-modal.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/web/src/views/base/unocss-icon.vue b/web/src/views/base/unocss-icon.vue new file mode 100644 index 0000000..8960d8d --- /dev/null +++ b/web/src/views/base/unocss-icon.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/web/src/views/base/unocss.vue b/web/src/views/base/unocss.vue new file mode 100644 index 0000000..980d2f3 --- /dev/null +++ b/web/src/views/base/unocss.vue @@ -0,0 +1,76 @@ + + + diff --git a/web/src/views/demo/upload/index.vue b/web/src/views/demo/upload/index.vue new file mode 100644 index 0000000..9145dd7 --- /dev/null +++ b/web/src/views/demo/upload/index.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/web/src/views/error-page/403.vue b/web/src/views/error-page/403.vue new file mode 100644 index 0000000..880c3de --- /dev/null +++ b/web/src/views/error-page/403.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/web/src/views/error-page/404.vue b/web/src/views/error-page/404.vue new file mode 100644 index 0000000..322aeeb --- /dev/null +++ b/web/src/views/error-page/404.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/web/src/views/home/index.vue b/web/src/views/home/index.vue new file mode 100644 index 0000000..3b5211d --- /dev/null +++ b/web/src/views/home/index.vue @@ -0,0 +1,289 @@ + + + + + diff --git a/web/src/views/iframe/index.vue b/web/src/views/iframe/index.vue new file mode 100644 index 0000000..8768865 --- /dev/null +++ b/web/src/views/iframe/index.vue @@ -0,0 +1,9 @@ +