重构console-ui

This commit is contained in:
userA
2023-04-20 01:41:52 +08:00
parent d528b284ef
commit f2b55c725d
363 changed files with 36817 additions and 5773 deletions

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -14,3 +14,8 @@
- 🚧工作中(勿动)
......
```
## [V 1.0.0] - 2023.4.20
### console-ui
- 🧹重构: 重构console-ui使用vue3.0,vite,typescript进行重构

View File

@@ -0,0 +1,4 @@
> 1%
last 2 versions
not dead
not ie 11

5
console-ui/.editorconfig Normal file
View File

@@ -0,0 +1,5 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

10
console-ui/.env.dev Normal file
View File

@@ -0,0 +1,10 @@
# Firebase 🔥
VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_PROJECT_ID=
VITE_FIREBASE_STORAGE_BUCKET=
VITE_FIREBASE_MESSAGING_SENDER_ID=
VITE_FIREBASE_APP_ID=
VITE_FIREBASE_MEASUREMENT_ID=

1
console-ui/.env.pro Normal file
View File

@@ -0,0 +1 @@
VITE_API_BASE_URL=https://api.example.com

3
console-ui/.env.template Normal file
View File

@@ -0,0 +1,3 @@
VITE_OPENAI_API_KEY = XXXXXXXXXXXX
VITE_UNSPLASH_ACCESS_KEY = XXXXXXXXXXXX
VITE_GITHUB_CLIENT_ID = XXXXXXXXXXXX

2
console-ui/.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@@ -1,9 +1,11 @@
.DS_Store
node_modules
/dist
/.vite_cache
# local env files
.env
.env.local
.env.*.local
@@ -21,3 +23,7 @@ pnpm-debug.log*
*.njsproj
*.sln
*.sw?
# Local Netlify folder
.netlify
.env

21
console-ui/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 jk.yang
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.

120
console-ui/README.jp.md Normal file
View File

@@ -0,0 +1,120 @@
<br><br>
<p align='center' >
<img src='/src/assets/logo_light.svg' alt='Vuetify3' width='300'/>
</p>
<br><br>
<p align="center">
<a href="https://vuejs.org/">
<img src="https://img.shields.io/badge/vue-v3.2.47-brightgreen.svg" alt="vue">
</a>
<a href="https://vuetifyjs.com/">
<img src="https://img.shields.io/badge/vuetify-v3.1.13-blue.svg" alt="element-ui">
</a>
<a href="https://vitejs.dev/">
<img src="https://img.shields.io/badge/vite-v4.2.1-blueviolet.svg" alt="element-ui">
</a>
<a href="https://github.com/yangjiakai/lux-admin-vuetify3/blob/main/LICENSE">
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
</a>
</p>
<h4 align='center'>
<a href="https://lux.vuetify3.com/">ライブ・デモ</a>
</h4>
<br>
<p align='center'>
<a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.md">English</a> | <a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.zh-CN.md">简体中文</a>| <b >日本語</b>
</p>
## 序文
> 目標は、最も優れた Vuetify 3 の Admin オープンソーステンプレートを作成することです。
Vuetify の洗練されたテーマを基盤に、明確で効率的なプロジェクト構造を構築し、最新の技術フレームワークを統合しています。このプロジェクトは、さまざまな一般的な技術要件や機能に対応することを目指し、AI アシスタントを組み込むことで、よりインテリジェントな体験を提供します。さらに、すべてのページが複数のデバイスで適応的に表示されるようにし、シームレスなクロスプラットフォーム互換性を実現しています。
## 特徴
- 📖 [Vue 3.2](https://github.com/vuejs/core)
- 📖 [Vite 4.x](https://github.com/vitejs/vite)
- 📖 UI Framework [Vuetify 3](https://next.vuetifyjs.com/en/)
- 📖 TypeScript
- 📦 Component Auto Importing
- 🍍 [Pinia](https://pinia.vuejs.org/)
- 📔 `<script setup>`
- 📚 Use icons from any icon sets in [Iconify](https://icon-sets.iconify.design/)
- ☁️ Deploy on Netlify, zero-config
- 🔑 Firebase auth
- 📈 Echarts, ApexChart
- 🧭 Openai, Chatgpt
- 🌍 vue-i18n
- 📚 virtual-scroller , vuedraggable , perfect-scrollbar
- 📝 Rich Text Editor
- 📇 Responsive multi-platform adaptive
## Contact Me
- Email <a href="mailto:yjkbako@gmail.com">yjkbako@gmail.com</a>
- Twitter https://twitter.com/baibaixiang
- Wechat <img src='/src/assets/wechat-qrcode.png' alt='DashBoard' width='300' />
## プレビュー
<img src='/src/assets/previews/DashBoard.png' alt='DashBoard' />
<img src='/src/assets/previews/TaskBoard.png' alt='ChatGPT' />
<img src='/src/assets/previews/DataTable.png' alt='DataTable' />
<img src='/src/assets/previews/Todo.png' alt='ChatGPT' />
<img src='/src/assets/previews/ChatGPT.png' alt='ChatGPT' />
<img src='/src/assets/previews/Card.png' alt='Card' />
<img src='/src/assets/previews/Color.png' alt='Color' />
<img src='/src/assets/previews/Gradient.png' alt='Gradient' />
<img src='/src/assets/previews/Login.png' alt='ChatGPT' />
<img src='/src/assets/previews/Unsplash.png' alt='ChatGPT' />
<img src='/src/assets/previews/Unsplash2.png' alt='ChatGPT' />
<br>
## プリパック
### UI Frameworks
- [Vuetify3](https://next.vuetifyjs.com/en/) - Vuetify は、美しく手作りされた Vue コンポーネントで構成された、デザインスキル不要の UI フレームワークです。
### Icons
- [Iconify](https://iconify.design) - 任意のアイコンセットを使用 [🔍Icônes](https://icones.netlify.app/)
- [Pure CSS Icons via UnoCSS](https://github.com/antfu/unocss/tree/main/packages/preset-icons)
### プラグイン
- [Vue Router4](https://router.vuejs.org/)
- [VueUse](https://github.com/antfu/vueuse) - 便利なコンポジション API 集
- [VuedDaggable](https://github.com/SortableJS/Vue.Draggable) - 配列モデルと同期したドラッグ&ドロップによる配置操作が可能
- [Vue-Masonry-Wall](https://github.com/DerYeger/yeger/tree/main/packages/vue-masonry-wall) -Vue 3 のレスポンシブな Masonry レイアウト SSR をサポートしています
- [Vue-Virtual-Scroller](https://github.com/Akryum/vue-virtual-scroller) - 超高速の任意のデータ量のスクロール
## 今すぐ試す!
```
git clone https://github.com/yangjiakai/lux-admin-vuetify3.git
cd lux-admin-vuetify3
npm install
npm run dev
```
### Set ApiKey
Find the `.env.template` file in the root directory, remove the `.template` suffix, and replace` VITE_OPENAI_API_KEY`, `VITE_UNSPLASH_ACCESS_KEY`, and `VITE_GITHUB_CLIENT_ID` with your own keys.
> openai apikey https://platform.openai.com/account/api-keys
> unsplash apikey https://unsplash.com/oauth/applications
> github apikey https://github.com/settings/tokens

View File

@@ -1,19 +1,119 @@
# console-ui
<br><br>
<p align='center' >
<img src='/src/assets/logo_light.svg' alt='Vuetify3' width='300'/>
</p>
<br><br>
<p align="center">
<a href="https://vuejs.org/">
<img src="https://img.shields.io/badge/vue-v3.2.47-brightgreen.svg" alt="vue">
</a>
<a href="https://vuetifyjs.com/">
<img src="https://img.shields.io/badge/vuetify-v3.1.13-blue.svg" alt="element-ui">
</a>
<a href="https://vitejs.dev/">
<img src="https://img.shields.io/badge/vite-v4.2.1-blueviolet.svg" alt="element-ui">
</a>
<a href="https://github.com/yangjiakai/lux-admin-vuetify3/blob/main/LICENSE">
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
</a>
</p>
<h4 align='center'>
<a href="https://lux.vuetify3.com/">Live Demo</a>
</h4>
<br>
<p align='center'>
<b>English</b> | <a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.zh-CN.md">简体中文</a>| <a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.jp.md">日本語</a>
</p>
## Introduction
> Goal: Creating the best Vuetify 3 Admin open-source template.
Built upon the elegant themes of Vuetify, we have established a clear and efficient project structure, integrating the latest technology frameworks. This project aims to address a wide range of common technical requirements and features, while incorporating an AI assistant for a more intelligent experience. Additionally, we ensure that all pages are adaptive across multiple devices, achieving a seamless cross-platform compatibility.
## Features
- 📖 [Vue 3.2](https://github.com/vuejs/core)
- 📖 [Vite 4.x](https://github.com/vitejs/vite)
- 📖 UI Framework [Vuetify 3](https://next.vuetifyjs.com/en/)
- 📖 TypeScript
- 📦 Component Auto Importing
- 🍍 [Pinia](https://pinia.vuejs.org/)
- 📔 `<script setup>`
- 📚 Use icons from any icon sets in [Iconify](https://icon-sets.iconify.design/)
- ☁️ Deploy on Netlify, zero-config
- 🔑 Firebase auth
- 📈 Echarts, ApexChart
- 🧭 Openai, Chatgpt
- 🌍 vue-i18n
- 📚 virtual-scroller , vuedraggable , perfect-scrollbar
- 📝 Rich Text Editor
- 📇 Responsive multi-platform adaptive
## Contact Me
- Email <a href="mailto:yjkbako@gmail.com">yjkbako@gmail.com</a>
- Twitter https://twitter.com/baibaixiang
- Wechat <img src='/src/assets/wechat-qrcode.png' alt='DashBoard' width='300' />
## Preview
<img src='/src/assets/previews/DashBoard.png' alt='DashBoard' />
<img src='/src/assets/previews/TaskBoard.png' alt='ChatGPT' />
<img src='/src/assets/previews/DataTable.png' alt='DataTable' />
<img src='/src/assets/previews/Todo.png' alt='ChatGPT' />
<img src='/src/assets/previews/ChatGPT.png' alt='ChatGPT' />
<img src='/src/assets/previews/Card.png' alt='Card' />
<img src='/src/assets/previews/Color.png' alt='Color' />
<img src='/src/assets/previews/Gradient.png' alt='Gradient' />
<img src='/src/assets/previews/Login.png' alt='ChatGPT' />
<img src='/src/assets/previews/Unsplash.png' alt='ChatGPT' />
<img src='/src/assets/previews/Unsplash2.png' alt='ChatGPT' />
<br>
## Pre-packed
### UI Frameworks
- [Vuetify3](https://next.vuetifyjs.com/en/) - Vuetify is a no design skills required UI Framework with beautifully handcrafted Vue Components.
### Icons
- [Iconify](https://iconify.design) - use icons from any icon sets [🔍Icônes](https://icones.netlify.app/)
- [Pure CSS Icons via UnoCSS](https://github.com/antfu/unocss/tree/main/packages/preset-icons)
### Plugins
- [Vue Router4](https://router.vuejs.org/)
- [VueUse](https://github.com/antfu/vueuse) - collection of useful composition APIs
- [VuedDaggable](https://github.com/SortableJS/Vue.Draggable) - allowing drag-and-drop and synchronization with view model array.
- [Vue-Masonry-Wall](https://github.com/DerYeger/yeger/tree/main/packages/vue-masonry-wall) - Responsive masonry layout with SSR support and zero dependencies for Vue 3.
- [Vue-Virtual-Scroller](https://github.com/Akryum/vue-virtual-scroller) - Blazing fast scrolling of any amount of data
## Try it now!
## Project setup
```
yarn install
git clone https://github.com/yangjiakai/lux-admin-vuetify3.git
cd lux-admin-vuetify3
npm install
npm run dev
```
### Compiles and hot-reloads for development
```
yarn serve
```
### Set ApiKey
### Compiles and minifies for production
```
yarn build
```
Find the `.env.template` file in the root directory, remove the `.template` suffix, and replace` VITE_OPENAI_API_KEY`, `VITE_UNSPLASH_ACCESS_KEY`, and `VITE_GITHUB_CLIENT_ID` with your own keys.
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
> openai apikey https://platform.openai.com/account/api-keys
> unsplash apikey https://unsplash.com/oauth/applications
> github apikey https://github.com/settings/tokens

158
console-ui/README.zh-CN.md Normal file
View File

@@ -0,0 +1,158 @@
<br><br>
<p align='center' >
<img src='/src/assets/logo_light.svg' alt='Vuetify3' width='300'/>
</p>
<br><br>
<p align="center">
<a href="https://vuejs.org/">
<img src="https://img.shields.io/badge/vue-v3.2.47-brightgreen.svg" alt="vue">
</a>
<a href="https://vuetifyjs.com/">
<img src="https://img.shields.io/badge/vuetify-v3.1.13-blue.svg" alt="element-ui">
</a>
<a href="https://vitejs.dev/">
<img src="https://img.shields.io/badge/vite-v4.2.1-blueviolet.svg" alt="element-ui">
</a>
<a href="https://github.com/yangjiakai/lux-admin-vuetify3/blob/main/LICENSE">
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
</a>
</p>
<h4 align='center'>
<a href="https://lux.vuetify3.com/">在线 Demo</a>
</h4>
<br>
<p align='center'>
<a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.md">English</a> | <b>简体中文</b>| <a href="https://github.com/yangjiakai/jk-vuetify3-lux-admin/blob/main/README.jp.md">日本語</a>
</p>
## 序文
> 目标创造最优秀的 vuetify3 的 Admin 开源模板
在 Vuetify 精美的主题基础上,我们构建了一个清晰且高效的项目逻辑架构,整合了最新的技术框架。本项目旨在实现各种常见的技术需求和功能,同时融合了 AI 助手,以提供更智能化的体验。此外,我们确保所有页面在多种设备上均能自适应展示,实现优雅的跨平台兼容性。
## 特性
- 📖 [Vue 3.2](https://github.com/vuejs/core)
- 📖 [Vite 4.x](https://github.com/vitejs/vite)
- 📖 UI Framework [Vuetify 3](https://next.vuetifyjs.com/en/)
- 📖 TypeScript
- 📦 组件自动导入
- 🍍 通过 [Pinia](https://pinia.vuejs.org/)进行状态管理
- 📔 使用新的 `<script setup>` 语法
- 📚 使用任意的图标集 [Iconify](https://icon-sets.iconify.design/)
- ☁️ 零配置部署在 Netlify
- 🔑 Firebase 授权
- 📈 Echarts, ApexChart
- 🧭 Openai, Chatgpt 支持
- 🌍 vue-i18n 多语言支持
- 📚 virtual-scroller , vuedraggable , perfect-scrollbar
- 📝 富文本编辑器
- 📇 响应式多平台自适应
## 联络我
- 邮箱 <a href="mailto:yjkbako@gmail.com">yjkbako@gmail.com</a>
- 推特 https://twitter.com/baibaixiang
- 微信 <img src='/src/assets/wechat-qrcode.png' alt='DashBoard' width='300' />
## 预览
<img src='/src/assets/previews/DashBoard.png' alt='DashBoard' />
<img src='/src/assets/previews/TaskBoard.png' alt='ChatGPT' />
<img src='/src/assets/previews/DataTable.png' alt='DataTable' />
<img src='/src/assets/previews/Todo.png' alt='ChatGPT' />
<img src='/src/assets/previews/ChatGPT.png' alt='ChatGPT' />
<img src='/src/assets/previews/Card.png' alt='Card' />
<img src='/src/assets/previews/Color.png' alt='Color' />
<img src='/src/assets/previews/Gradient.png' alt='Gradient' />
<img src='/src/assets/previews/Login.png' alt='ChatGPT' />
<img src='/src/assets/previews/Unsplash.png' alt='ChatGPT' />
<img src='/src/assets/previews/Unsplash2.png' alt='ChatGPT' />
<br>
## Pre-packed
### UI 框架
- [Vuetify3](https://next.vuetifyjs.com/en/) - Vuetify 是一个不要求设计能力的 Vue 界面组件框架,自带了许多自行设计实现的 Vue 组件。
### Icons
- [Iconify](https://iconify.design) - 使用任意的图标集 [🔍Icônes](https://icones.netlify.app/)
- [Pure CSS Icons via UnoCSS](https://github.com/antfu/unocss/tree/main/packages/preset-icons)
## 目标功能
- [x] 明暗主题切换 -- 完成
- [x] 主题色切换 -- 完成
- [x] 中日英三语言切换-- 完成
- [x] 整合 ChatGpt-- 完成
## 目标页面
### 认证相关
- [x] 登录 -- 完成
- [x] 注册 -- 完成
- [x] 验证邮件 -- 完成
- [ ] 密码重置 -- 施工中
### 公共页面
- [x] 404 -- 完成
- [x] 500 -- 施工中
- [x] 系统维护 -- 施工中
- [x] 常见问题 -- 施工中
### UI 相关
- [x] 瀑布流布局 -- 完成
- [x] 大数据虚拟列表 -- 完成
- [ ] 骨架屏 -- 施工中
### 功能页面
- [x] 任务版(拖拽功能) -- 完成
- [x] 任务列表() -- 施工中
### 站点仿写
- [ ] ......
### 插件
- [Vue Router4](https://router.vuejs.org/)
- [VueUse](https://github.com/antfu/vueuse) - 非常有用的组合式 API 合集
- [VuedDaggable](https://github.com/SortableJS/Vue.Draggable) - 允许进行与数组模型同步的拖拽放置操作
- [Vue-Masonry-Wall](https://github.com/DerYeger/yeger/tree/main/packages/vue-masonry-wall) - 是一种 Vue3 响应式,支持 SSR,且零依的的瀑布流布局方案
- [Vue-Virtual-Scroller](https://github.com/Akryum/vue-virtual-scroller) - 大数据快速虚拟滚动插件
## 现在可以试试!
```
git clone https://github.com/yangjiakai/lux-admin-vuetify3.git
cd lux-admin-vuetify3
npm install
npm run dev
```
### 配置 ApiKey
找到根目录下的`.env.template`文件,去掉`.template`后缀
`VITE_OPENAI_API_KEY`,`VITE_UNSPLASH_ACCESS_KEY`,`VITE_GITHUB_CLIENT_ID`分别替换成你自己的 Key
> openai apikey https://platform.openai.com/account/api-keys
> unsplash apikey https://unsplash.com/oauth/applications
> github apikey https://github.com/settings/tokens

73
console-ui/auto-imports.d.ts vendored Normal file
View File

@@ -0,0 +1,73 @@
// Generated by 'unplugin-auto-import'
export {};
declare global {
const EffectScope: typeof import("vue")["EffectScope"];
const acceptHMRUpdate: typeof import("pinia")["acceptHMRUpdate"];
const computed: typeof import("vue")["computed"];
const createApp: typeof import("vue")["createApp"];
const createPinia: typeof import("pinia")["createPinia"];
const customRef: typeof import("vue")["customRef"];
const defineAsyncComponent: typeof import("vue")["defineAsyncComponent"];
const defineComponent: typeof import("vue")["defineComponent"];
const defineStore: typeof import("pinia")["defineStore"];
const effectScope: typeof import("vue")["effectScope"];
const getActivePinia: typeof import("pinia")["getActivePinia"];
const getCurrentInstance: typeof import("vue")["getCurrentInstance"];
const getCurrentScope: typeof import("vue")["getCurrentScope"];
const h: typeof import("vue")["h"];
const inject: typeof import("vue")["inject"];
const isProxy: typeof import("vue")["isProxy"];
const isReactive: typeof import("vue")["isReactive"];
const isReadonly: typeof import("vue")["isReadonly"];
const isRef: typeof import("vue")["isRef"];
const mapActions: typeof import("pinia")["mapActions"];
const mapGetters: typeof import("pinia")["mapGetters"];
const mapState: typeof import("pinia")["mapState"];
const mapStores: typeof import("pinia")["mapStores"];
const mapWritableState: typeof import("pinia")["mapWritableState"];
const markRaw: typeof import("vue")["markRaw"];
const nextTick: typeof import("vue")["nextTick"];
const onActivated: typeof import("vue")["onActivated"];
const onBeforeMount: typeof import("vue")["onBeforeMount"];
const onBeforeRouteLeave: typeof import("vue-router")["onBeforeRouteLeave"];
const onBeforeRouteUpdate: typeof import("vue-router")["onBeforeRouteUpdate"];
const onBeforeUnmount: typeof import("vue")["onBeforeUnmount"];
const onBeforeUpdate: typeof import("vue")["onBeforeUpdate"];
const onDeactivated: typeof import("vue")["onDeactivated"];
const onErrorCaptured: typeof import("vue")["onErrorCaptured"];
const onMounted: typeof import("vue")["onMounted"];
const onRenderTracked: typeof import("vue")["onRenderTracked"];
const onRenderTriggered: typeof import("vue")["onRenderTriggered"];
const onScopeDispose: typeof import("vue")["onScopeDispose"];
const onServerPrefetch: typeof import("vue")["onServerPrefetch"];
const onUnmounted: typeof import("vue")["onUnmounted"];
const onUpdated: typeof import("vue")["onUpdated"];
const provide: typeof import("vue")["provide"];
const reactive: typeof import("vue")["reactive"];
const readonly: typeof import("vue")["readonly"];
const ref: typeof import("vue")["ref"];
const resolveComponent: typeof import("vue")["resolveComponent"];
const resolveDirective: typeof import("vue")["resolveDirective"];
const setActivePinia: typeof import("pinia")["setActivePinia"];
const setMapStoreSuffix: typeof import("pinia")["setMapStoreSuffix"];
const shallowReactive: typeof import("vue")["shallowReactive"];
const shallowReadonly: typeof import("vue")["shallowReadonly"];
const shallowRef: typeof import("vue")["shallowRef"];
const storeToRefs: typeof import("pinia")["storeToRefs"];
const toRaw: typeof import("vue")["toRaw"];
const toRef: typeof import("vue")["toRef"];
const toRefs: typeof import("vue")["toRefs"];
const triggerRef: typeof import("vue")["triggerRef"];
const unref: typeof import("vue")["unref"];
const useAttrs: typeof import("vue")["useAttrs"];
const useCssModule: typeof import("vue")["useCssModule"];
const useCssVars: typeof import("vue")["useCssVars"];
const useLink: typeof import("vue-router")["useLink"];
const useRoute: typeof import("vue-router")["useRoute"];
const useRouter: typeof import("vue-router")["useRouter"];
const useSlots: typeof import("vue")["useSlots"];
const watch: typeof import("vue")["watch"];
const watchEffect: typeof import("vue")["watchEffect"];
const watchPostEffect: typeof import("vue")["watchPostEffect"];
const watchSyncEffect: typeof import("vue")["watchSyncEffect"];
}

View File

@@ -1,5 +0,0 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

19
console-ui/index.html Normal file
View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.tailwindcss.com"></script>
<title>Vuetify-Lux</title>
<link
href="https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -1,19 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

4615
console-ui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,66 @@
{
"name": "console-ui",
"version": "0.1.0",
"private": true,
"name": "vuetify3-design",
"version": "0.0.0",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
"dev": "vite --mode dev",
"build": "vite build --mode pro",
"preview": "vite preview",
"test": "vitest",
"test:ui": "vitest --ui",
"coverage": "vitest run --coverage"
},
"dependencies": {
"core-js": "^3.8.3",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vuex": "^3.6.2"
"@mdi/font": "7.2.96",
"@tiptap/pm": "^2.0.2",
"@tiptap/starter-kit": "^2.0.2",
"@tiptap/vue-3": "^2.0.2",
"@vueup/vue-quill": "^1.1.1",
"@vueuse/core": "^9.13.0",
"@vueuse/integrations": "^9.13.0",
"@yeger/vue-masonry-wall": "^3.4.4",
"apexcharts": "^3.37.3",
"axios": "^1.3.5",
"echarts": "^5.4.2",
"firebase": "^9.19.1",
"flag-icons": "^6.6.6",
"focus-trap": "^7.4.0",
"happy-dom": "^9.6.1",
"md-editor-v3": "^2.11.2",
"moment": "^2.29.4",
"openai": "^3.2.1",
"pinia": "^2.0.34",
"pinia-plugin-persist": "^1.0.0",
"roboto-fontface": "*",
"unsplash-js": "^7.0.15",
"vue": "^3.2.47",
"vue-echarts": "^6.5.4",
"vue-i18n": "^9.2.2",
"vue-masonry": "^0.16.0",
"vue-router": "^4.1.6",
"vue-virtual-scroller": "^2.0.0-beta.8",
"vue-waterfall-plugin-next": "^2.2.0",
"vue3-apexcharts": "^1.4.1",
"vue3-lottie": "^2.5.0",
"vue3-perfect-scrollbar": "^1.6.1",
"vuedraggable": "^4.1.0",
"vuetify": "^3.1.13",
"webfontloader": "^1.6.28"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"vue-template-compiler": "^2.6.14"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
"@faker-js/faker": "^7.6.0",
"@fortawesome/fontawesome-free": "^6.4.0",
"@iconify/vue": "^4.1.1",
"@types/node": "^18.15.11",
"@vitejs/plugin-vue": "^4.1.0",
"@vitest/ui": "^0.30.1",
"@vue/test-utils": "^2.0.0-rc.18",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.21",
"sass": "^1.61.0",
"tailwindcss": "^3.3.1",
"unplugin-auto-import": "^0.15.2",
"vite": "^4.2.1",
"vite-plugin-vuetify": "^1.0.2",
"vitest": "^0.30.1"
}
}

View File

@@ -0,0 +1 @@
/* /index.html 200

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@@ -1,32 +1,48 @@
<template>
<div id="app">
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<router-view/>
</div>
<v-app id="app" :theme="customizeTheme.darkTheme ? 'dark' : 'light'">
<component :is="currentLayout" v-if="isRouterLoaded">
<router-view> </router-view>
</component>
<CustomizationMenu />
<BackToTop />
<Snackbar />
</v-app>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
<script setup lang="ts">
import UILayout from "@/layouts/UILayout.vue";
import LandingLayout from "@/layouts/LandingLayout.vue";
import DefaultLayout from "@/layouts/DefaultLayout.vue";
import AuthLayout from "@/layouts/AuthLayout.vue";
import CustomizationMenu from "@/components/CustomizationMenu.vue";
import { useCustomizeThemeStore } from "@/stores/customizeTheme";
import BackToTop from "@/components/common/BackToTop.vue";
import Snackbar from "@/components/common/Snackbar.vue";
nav {
padding: 30px;
}
const customizeTheme = useCustomizeThemeStore();
const route = useRoute();
nav a {
font-weight: bold;
color: #2c3e50;
}
const isRouterLoaded = computed(() => {
if (route.name !== null) return true;
return false;
});
nav a.router-link-exact-active {
color: #42b983;
}
</style>
const layouts = {
default: DefaultLayout,
ui: UILayout,
landing: LandingLayout,
auth: AuthLayout,
};
type LayoutName = "default" | "ui" | "landing" | "auth" | "error";
const currentLayout = computed(() => {
const layoutName = route.meta.layout as LayoutName;
if (!layoutName) {
return DefaultLayout;
}
return layouts[layoutName];
});
</script>
<style scoped></style>

View File

@@ -0,0 +1,59 @@
import axios from "axios";
import { useSnackbarStore } from "@/stores/snackbarStore";
const gptInstance = axios.create({
baseURL: "https://api.openai.com",
timeout: 100000,
});
gptInstance.interceptors.response.use(
(response) => {
return response;
},
(error) => {
const snackbarStore = useSnackbarStore();
if (error.response) {
const status = error.response.status;
const data = error.response.data;
snackbarStore.showErrorMessage(data.error);
} else {
snackbarStore.showErrorMessage("Network Error");
}
return Promise.reject(error);
}
);
// Get all models.
export const getModelsApi = (apiKey: string) => {
return gptInstance.get("/v1/models", {
headers: {
Authorization: "Bearer " + apiKey,
},
});
};
// Get account balance information.
export const getBalanceApi = (apiKey: string) => {
return gptInstance.get("/dashboard/billing/credit_grants", {
headers: {
Authorization: "Bearer " + apiKey,
},
});
};
// speech-to-text
export const createTranscriptionApi = (formData: any, apiKey: string) => {
return gptInstance.post("/v1/audio/transcriptions", formData, {
headers: {
Authorization: "Bearer " + apiKey,
},
});
};
// completions(Stream UnUsed)
export const createCompletionApi = (data: any, apiKey: string) => {
return gptInstance.post("/v1/chat/completions", data, {
headers: {
Authorization: "Bearer " + apiKey,
},
});
};

View File

@@ -0,0 +1,39 @@
import axios from "axios";
import { useSnackbarStore } from "@/stores/snackbarStore";
const snackbarStore = useSnackbarStore();
// change the access key to your own
const ACCESS_KEY = import.meta.env.VITE_GITHUB_CLIENT_ID;
const instance = axios.create({
baseURL: "https://api.github.com",
timeout: 20000,
headers: { Authorization: "Bearer" + " " + ACCESS_KEY },
});
instance.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (error.response) {
const status = error.response.status;
const data = error.response.data;
snackbarStore.showErrorMessage(data.message);
} else {
snackbarStore.showErrorMessage("Network Error");
}
return Promise.reject(error);
}
);
// https://api.github.com/users/yangjiakai/events/public
// Get public events for a user
export const getPublicEventsApi = (username: string) => {
return instance.get("/users/" + username + "/events/public");
};
// Get public events for a network of repositories
export const getPublicEventsForNetworkApi = (username: string) => {
return instance.get("/networks/" + username + "/events");
};

View File

@@ -0,0 +1,33 @@
import axios from "axios";
export const textToSpeech = async () => {
const googleInstance = axios.create({
baseURL: "https://us-central1-texttospeech.googleapis.com",
timeout: 100000,
});
const res = await googleInstance.post(
"/v1/chat/completions/text:synthesize",
{
audioConfig: {
audioEncoding: "LINEAR16",
effectsProfileId: ["small-bluetooth-speaker-class-device"],
pitch: 0,
speakingRate: 1,
},
input: {
text: "Google Cloud Text-to-Speech enables developers to synthesize natural-sounding speech with 100+ voices, available in multiple languages and variants. It applies DeepMinds groundbreaking research in WaveNet and Googles powerful neural networks to deliver the highest fidelity possible. As an easy-to-use API, you can create lifelike interactions with your users, across many applications and devices.",
},
voice: {
languageCode: "en-US",
name: "en-US-Neural2-J",
},
},
{
headers: {
"Content-Type": "application/json",
"x-goog-api-key": "AIzaSyBSXdkeyAvIZX5n_bj4KsqSjJf1W-_TfCntvk",
},
}
);
};

View File

@@ -0,0 +1,160 @@
import axios from "axios";
import { useSnackbarStore } from "@/stores/snackbarStore";
const snackbarStore = useSnackbarStore();
// change the access key to your own
const ACCESS_KEY = import.meta.env.VITE_UNSPLASH_ACCESS_KEY;
const instance = axios.create({
baseURL: "https://api.unsplash.com",
timeout: 20000,
headers: { Authorization: "Client-ID" + " " + ACCESS_KEY },
});
instance.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (error.response) {
const status = error.response.status;
const data = error.response.data;
snackbarStore.showErrorMessage(data.errors[0]);
} else {
snackbarStore.showErrorMessage("Network Error");
}
return Promise.reject(error);
}
);
interface Query {
page?: number;
per_page?: number;
}
// List photos 图片一览
export const getPhotosApi = (query?: Query) => {
return instance.get("/photos/", { params: query });
};
// Get a photo 获取图片信息
export const getPhotoApi = (id: string) => {
return instance.get("/photos/" + id);
};
// Get a random photo 获取一张随机图片
export const getRandomPhotoApi = () => {
return instance.get("/photos/random");
};
// Get a photos statistics 获取照片的统计数据
export const getPhotoStatisticsApi = (id: string) => {
return instance.get("/photos/" + id + "/statistics");
};
// Get a photos related 获取照片的相关照片
export const getPhotoRelatedApi = (id: string) => {
return instance.get("/photos/" + id + "/related");
};
// Track a photo download
// Update a photo
// Like a photo
// Unlike a photo
// Topic
// List topics
export const getTopicsApi = (query?: Query) => {
return instance.get("/topics", { params: query });
};
// Get a topic
export const getTopicApi = (id_or_slug: string | string[]) => {
return instance.get("/topics/" + id_or_slug);
};
// Get a topics photos
export const getTopicPhotosApi = (
id_or_slug: string | string[],
query?: Query
) => {
return instance.get("/topics/" + id_or_slug + "/photos", { params: query });
};
// Get a user
export const getUserApi = (username: string | string[]) => {
return instance.get("/users/" + username);
};
// Get a users portfolio
export const getUserPortfolioApi = (username: string | string[]) => {
return instance.get("/users/" + username + "/portfolio");
};
// List a users photos
export const getUserPhotosApi = (
username: string | string[],
query?: Query
) => {
return instance.get("/users/" + username + "/photos", { params: query });
};
// List a users liked photos
export const getUserLikesApi = (username: string | string[], query?: Query) => {
return instance.get("/users/" + username + "/likes", { params: query });
};
// List a users collections
export const getUserCollectionsApi = (
username: string | string[],
query?: Query
) => {
return instance.get("/users/" + username + "/collections", { params: query });
};
// Get a users statistics
export const getUserStatisticsApi = (username: string | string[]) => {
return instance.get("/users/" + username + "/statistics");
};
// Collections 图集
// List collections 图集一览
export const getCollectionsApi = (query?: Query) => {
return instance.get("/collections", { params: query });
};
// Get a collection 获取图集信息
export const getCollectionApi = (id: string | string[]) => {
return instance.get("/collections/" + id);
};
// Get a collections photos 获取该图集下所有图片
export const getCollectionPhotosApi = (
id: string | string[],
query?: Query
) => {
return instance.get("/collections/" + id + "/photos", { params: query });
};
// List a collections related collections 获取该图集相关联图集
export const getCollectionRelatedApi = (id: string | string[]) => {
return instance.get("/collections/" + id + "/related");
};
// Create a new collection 新增图集
// Update an existing collection 更新现存图集
// Delete a collection 删除某个图集
// Add a photo to a collection 添加图片到图集
// Remove a photo from a collection 从图集删除图片
// Search
// Search All
export const searchAllApi = (query?: Query) => {
return instance.get("/search", { params: query });
};
// Search photos
export const searchPhotosApi = (query?: Query) => {
return instance.get("/search/photos", { params: query });
};
// Search collections
export const searchCollectionsApi = (query?: Query) => {
return instance.get("/search/collections", { params: query });
};
// Search users
export const searchUsersApi = (query?: Query) => {
return instance.get("/search/users", { params: query });
};

View File

@@ -0,0 +1,24 @@
import type { User } from "firebase/auth";
import { db, auth } from "@/firebase";
import { doc, setDoc, getDoc, getDocs, collection } from "firebase/firestore";
export const addUserToUsersCollection = async (user: User) => {
const profile = {
id: user.uid,
name: user.displayName,
avatar: user.photoURL,
created: false,
};
try {
await setDoc(doc(db, "users", user.uid), {
name: user.displayName,
avatar: user.photoURL,
});
profile.created = true;
} catch (error) {
console.error("Error adding document: ", error);
}
return profile;
};

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<rect x="0" y="0" width="100" height="100" fill="purple"/>
<circle cx="50" cy="50" r="30" fill="white"/>
<circle cx="40" cy="40" r="4" fill="black"/>
<circle cx="60" cy="40" r="4" fill="black"/>
<path d="M 40 60 Q 50 70, 60 60" stroke="black" stroke-width="2" fill="none"/>
<polygon points="90,90 80,70 70,90" fill="black"/>
<rect x="78" y="65" width="2" height="25" fill="black" transform="rotate(-45, 79, 65)"/>
<circle cx="79" cy="65" r="3" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: rgb(255, 255, 255); display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<g transform="translate(80,50)">
<g transform="rotate(0)">
<circle cx="0" cy="0" r="6" fill="#72c9ff" fill-opacity="1">
<animateTransform attributeName="transform" type="scale" begin="-0.875s" values="1.5 1.5;1 1" keyTimes="0;1" dur="1s" repeatCount="indefinite"></animateTransform>
<animate attributeName="fill-opacity" keyTimes="0;1" dur="1s" repeatCount="indefinite" values="1;0" begin="-0.875s"></animate>
</circle>
</g>
</g><g transform="translate(71.21320343559643,71.21320343559643)">
<g transform="rotate(45)">
<circle cx="0" cy="0" r="6" fill="#72c9ff" fill-opacity="0.875">
<animateTransform attributeName="transform" type="scale" begin="-0.75s" values="1.5 1.5;1 1" keyTimes="0;1" dur="1s" repeatCount="indefinite"></animateTransform>
<animate attributeName="fill-opacity" keyTimes="0;1" dur="1s" repeatCount="indefinite" values="1;0" begin="-0.75s"></animate>
</circle>
</g>
</g><g transform="translate(50,80)">
<g transform="rotate(90)">
<circle cx="0" cy="0" r="6" fill="#72c9ff" fill-opacity="0.75">
<animateTransform attributeName="transform" type="scale" begin="-0.625s" values="1.5 1.5;1 1" keyTimes="0;1" dur="1s" repeatCount="indefinite"></animateTransform>
<animate attributeName="fill-opacity" keyTimes="0;1" dur="1s" repeatCount="indefinite" values="1;0" begin="-0.625s"></animate>
</circle>
</g>
</g><g transform="translate(28.786796564403577,71.21320343559643)">
<g transform="rotate(135)">
<circle cx="0" cy="0" r="6" fill="#72c9ff" fill-opacity="0.625">
<animateTransform attributeName="transform" type="scale" begin="-0.5s" values="1.5 1.5;1 1" keyTimes="0;1" dur="1s" repeatCount="indefinite"></animateTransform>
<animate attributeName="fill-opacity" keyTimes="0;1" dur="1s" repeatCount="indefinite" values="1;0" begin="-0.5s"></animate>
</circle>
</g>
</g><g transform="translate(20,50.00000000000001)">
<g transform="rotate(180)">
<circle cx="0" cy="0" r="6" fill="#72c9ff" fill-opacity="0.5">
<animateTransform attributeName="transform" type="scale" begin="-0.375s" values="1.5 1.5;1 1" keyTimes="0;1" dur="1s" repeatCount="indefinite"></animateTransform>
<animate attributeName="fill-opacity" keyTimes="0;1" dur="1s" repeatCount="indefinite" values="1;0" begin="-0.375s"></animate>
</circle>
</g>
</g><g transform="translate(28.78679656440357,28.786796564403577)">
<g transform="rotate(225)">
<circle cx="0" cy="0" r="6" fill="#72c9ff" fill-opacity="0.375">
<animateTransform attributeName="transform" type="scale" begin="-0.25s" values="1.5 1.5;1 1" keyTimes="0;1" dur="1s" repeatCount="indefinite"></animateTransform>
<animate attributeName="fill-opacity" keyTimes="0;1" dur="1s" repeatCount="indefinite" values="1;0" begin="-0.25s"></animate>
</circle>
</g>
</g><g transform="translate(49.99999999999999,20)">
<g transform="rotate(270)">
<circle cx="0" cy="0" r="6" fill="#72c9ff" fill-opacity="0.25">
<animateTransform attributeName="transform" type="scale" begin="-0.125s" values="1.5 1.5;1 1" keyTimes="0;1" dur="1s" repeatCount="indefinite"></animateTransform>
<animate attributeName="fill-opacity" keyTimes="0;1" dur="1s" repeatCount="indefinite" values="1;0" begin="-0.125s"></animate>
</circle>
</g>
</g><g transform="translate(71.21320343559643,28.78679656440357)">
<g transform="rotate(315)">
<circle cx="0" cy="0" r="6" fill="#72c9ff" fill-opacity="0.125">
<animateTransform attributeName="transform" type="scale" begin="0s" values="1.5 1.5;1 1" keyTimes="0;1" dur="1s" repeatCount="indefinite"></animateTransform>
<animate attributeName="fill-opacity" keyTimes="0;1" dur="1s" repeatCount="indefinite" values="1;0" begin="0s"></animate>
</circle>
</g>
</g>
<!-- [ldio] generated by https://loading.io/ --></svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,6 @@
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M261.126 140.65L164.624 307.732L256.001 466L377.028 256.5L498.001 47H315.192L261.126 140.65Z" fill="#1697F6"/>
<path d="M135.027 256.5L141.365 267.518L231.64 111.178L268.731 47H256H14L135.027 256.5Z" fill="#AEDDFF"/>
<path d="M315.191 47C360.935 197.446 256 466 256 466L164.624 307.732L315.191 47Z" fill="#1867C0"/>
<path d="M268.731 47C76.0026 47 141.366 267.518 141.366 267.518L268.731 47Z" fill="#7BC6FF"/>
</svg>

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,65 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100%" viewBox="0 0 292 350" enable-background="new 0 0 292 350" xml:space="preserve">
<path fill="#FEFFFF" opacity="1.000000" stroke="none"
d="
M1.000000,128.000000
C1.000000,85.349754 1.000000,43.199505 1.000000,1.024629
C98.279007,1.024629 195.558014,1.024629 292.918518,1.024629
C292.918518,117.566864 292.918518,234.133804 292.918518,350.850372
C195.666840,350.850372 98.333450,350.850372 1.000000,350.850372
C1.000000,276.775421 1.000000,202.637711 1.000000,128.000000
M60.945122,103.841530
C42.713490,103.841530 24.481857,103.841530 5.292197,103.841530
C52.947048,186.459473 100.087868,268.186249 147.480728,350.349976
C195.001831,268.033112 242.189346,186.294067 289.779907,103.856873
C270.104889,103.856873 251.620804,103.856873 233.073532,103.150719
C233.940903,101.371254 234.704636,99.532021 235.691330,97.821396
C248.489014,75.634048 261.324280,53.468391 274.136688,31.289537
C279.085297,22.723295 284.000122,14.137545 289.584625,4.422431
C286.640228,5.343472 284.933716,5.822242 283.264526,6.407475
C238.979431,21.934256 194.704971,37.491520 150.390533,52.934074
C148.682556,53.529266 146.411621,53.569023 144.713531,52.976955
C105.802299,39.409748 66.936913,25.711136 28.055904,12.057143
C20.953766,9.563058 13.820872,7.156544 5.668715,4.354370
C6.763332,6.406374 7.201184,7.288102 7.692324,8.139076
C24.146460,36.648350 40.631691,65.139748 57.028324,93.682045
C58.893276,96.928444 60.264931,100.458237 60.945122,103.841530
z"/>
<path fill="#2064EA" opacity="1.000000" stroke="none"
d="
M233.136719,103.856873
C251.620804,103.856873 270.104889,103.856873 289.779907,103.856873
C242.189346,186.294067 195.001831,268.033112 147.480728,350.349976
C100.087868,268.186249 52.947048,186.459473 5.292197,103.841530
C24.481857,103.841530 42.713490,103.841530 61.662327,103.928421
C62.558861,104.006554 62.738190,103.997810 63.065762,104.306396
C91.225380,153.133133 119.236748,201.642517 147.536011,250.650467
C175.919067,201.411285 203.997498,152.700562 232.346878,104.002457
C232.790787,103.962349 232.963760,103.909615 233.136719,103.856873
z"/>
<path fill="#7486FB" opacity="1.000000" stroke="none"
d="
M233.105133,103.503799
C232.963760,103.909615 232.790787,103.962349 231.872528,103.984970
C175.057327,103.966263 118.987419,103.977661 62.917519,103.989059
C62.738190,103.997810 62.558861,104.006554 62.122425,103.935959
C60.264931,100.458237 58.893276,96.928444 57.028324,93.682045
C40.631691,65.139748 24.146460,36.648350 7.692324,8.139076
C7.201184,7.288102 6.763332,6.406374 5.668715,4.354370
C13.820872,7.156544 20.953766,9.563058 28.055904,12.057143
C66.936913,25.711136 105.802299,39.409748 144.713531,52.976955
C146.411621,53.569023 148.682556,53.529266 150.390533,52.934074
C194.704971,37.491520 238.979431,21.934256 283.264526,6.407475
C284.933716,5.822242 286.640228,5.343472 289.584625,4.422431
C284.000122,14.137545 279.085297,22.723295 274.136688,31.289537
C261.324280,53.468391 248.489014,75.634048 235.691330,97.821396
C234.704636,99.532021 233.940903,101.371254 233.105133,103.503799
z"/>
<path fill="#FEFEFF" opacity="1.000000" stroke="none"
d="
M63.065762,104.306396
C118.987419,103.977661 175.057327,103.966263 231.601578,103.972351
C203.997498,152.700562 175.919067,201.411285 147.536011,250.650467
C119.236748,201.642517 91.225380,153.133133 63.065762,104.306396
z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,24 @@
<svg y="558.665" x="988" viewBox="0 0 356 52" height="52" width="356" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
<g id="Layer_1">
<title>Layer 1</title>
<metadata id="svg_28">image/svg+xml</metadata>
<g id="svg_3" transform="translate(0 0)">
<image id="svg_18" x="-333.96937" y="-358.11919" height="0" width="0"/>
<g id="svg_17" transform="translate(0 0)" font-style="normal" font-weight="600" font-size="32px" font-family="Karma" text-anchor="middle"/>
<g id="svg_5" transform="translate(0 0)" font-style="normal" font-weight="400" font-size="72px" font-family="Megrim" text-anchor="middle">
<path id="svg_16" d="m32.76,53.35921l-16.38,38.6568l-16.38,-38.6568l2.09664,0l14.28336,33.61176l14.28336,-33.61176l2.09664,0z" stroke-width="0" stroke-miterlimit="2" fill="#ec9126" stroke="#ec9126" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_15" d="m41.41887,53.35921l0,19.0008q0,9.76248 3.07944,13.7592q3.14496,3.9312 8.58312,3.9312q5.43816,0 8.5176,-3.9312q3.14496,-3.99672 3.14496,-13.7592l0,-19.0008l1.9656,0l0,19.0008q0,19.656 -13.62816,19.656q-13.62816,0 -13.62816,-19.656l0,-19.0008l1.9656,0z" stroke-width="0" stroke-miterlimit="2" fill="#e58b25" stroke="#e58b25" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_14" d="m103.92086,87.49513q-3.6036,4.52088 -11.7936,4.52088q-8.19,0 -11.72808,-4.65192q-3.53808,-4.65192 -3.53808,-15.00408q0,-10.35216 3.53808,-15.00408q3.53808,-4.65192 11.72808,-4.65192q9.5004,0 12.90744,6.2244l-16.0524,13.4316l-3.07944,0l16.57656,-13.82472q-2.88288,-3.86568 -10.35216,-3.86568q-3.276,0 -5.50368,0.72072q-2.22768,0.6552 -4.12776,2.55528q-1.83456,1.83456 -2.75184,5.43816q-0.91728,3.53808 -0.91728,8.97624q0,5.43816 0.91728,9.04176q0.91728,3.53808 2.75184,5.43816q1.90008,1.83456 4.12776,2.55528q2.22768,0.6552 5.50368,0.6552q7.46928,0 10.35216,-3.86568l1.44144,1.3104z" stroke-width="0" stroke-miterlimit="2" fill="#dd8524" stroke="#dd8524" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_13" d="m139.02831,53.35921l0,1.9656l-13.7592,0l0,36.036l-1.96561,0l0,-36.036l-13.7592,0l0,-1.9656l29.48401,0z" stroke-width="0" stroke-miterlimit="2" fill="#d67f23" stroke="#d67f23" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_12" d="m146.57848,53.35921l1.9656,0l0,38.0016l-1.9656,0l0,-38.0016z" stroke-width="0" stroke-miterlimit="2" fill="#ce7922" stroke="#ce7922" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_11" d="m160.38372,91.36081l0,-19.0008q0,-10.35216 3.53808,-15.00408q3.60361,-4.65192 11.72809,-4.65192q9.5004,0 12.90744,6.2244l-13.69369,11.466l13.95577,0l0,1.9656l-19.39393,0l16.57657,-13.82472q-2.88288,-3.86568 -10.35216,-3.86568q-3.27601,0 -5.50368,0.72072q-2.22769,0.6552 -4.12777,2.55528q-1.83456,1.83456 -2.75184,5.43816q-0.91728,3.53808 -0.91728,8.97624l0,19.0008l-1.9656,0z" stroke-width="0" stroke-miterlimit="2" fill="#c77321" stroke="#c77321" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_10" d="m200.95496,53.35921l25.35624,0l-15.39721,36.3636l0,14.742l-1.9656,0l0,-14.742l-15.39719,-36.3636l2.09664,0l14.28336,33.61176l13.4316,-31.64616l-22.40784,0l0,-1.9656z" stroke-width="0" stroke-miterlimit="2" fill="#c06c20" stroke="#c06c20" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_9" d="m230.71435,97.25761l0,-1.9656l26.208,0l0,1.9656l-26.208,0z" stroke-width="0" stroke-miterlimit="2" fill="#b8661f" stroke="#b8661f" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_8" d="m288.36888,89.39521l0,1.9656l-21.88368,0l0,-38.0016l1.96559,0l0,36.036l19.91809,0z" stroke-width="0" stroke-miterlimit="2" fill="#b1601e" stroke="#b1601e" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_7" d="m297.22841,53.35921l0,19.0008q0,9.76248 3.07944,13.7592q3.14496,3.9312 8.58312,3.9312q5.43816,0 8.51761,-3.9312q3.14496,-3.99672 3.14496,-13.7592l0,-19.0008l1.96559,0l0,19.0008q0,19.656 -13.62816,19.656q-13.62816,0 -13.62816,-19.656l0,-19.0008l1.9656,0z" stroke-width="0" stroke-miterlimit="2" fill="#a95a1d" stroke="#a95a1d" transform="translate(0 -357) translate(0 304.296)"/>
<path id="svg_6" d="m344.26767,70.85305l11.79361,20.50776l-2.2932,0l-10.67976,-18.47664l-10.67977,18.47664l-2.2932,0l11.7936,-20.50776l-10.09007,-17.49384l2.2932,0l8.97624,15.52824l8.97623,-15.52824l2.2932,0l-10.09008,17.49384z" stroke-width="0" stroke-miterlimit="2" fill="#a2541c" stroke="#a2541c" transform="translate(0 -357) translate(0 304.296)"/>
</g>
<image id="svg_4" x="-333.96937" y="-358.11919" height="0" width="0"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -0,0 +1,32 @@
<svg y="552.665" x="1007.5" version="1.1" width="317" height="64" viewBox="0 0 317 64" id="svg78192" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata id="metadata78198">image/svg+xml</metadata>
<linearGradient id="3d_gradient2-logo-682f3222-452d-46d2-bf30-c93cee4278d2" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad">
<stop offset="0%" stop-color="#ffffff" id="stop78173"/>
<stop offset="100%" stop-color="#000000" id="stop78175"/>
</linearGradient>
<linearGradient id="3d_gradient3-logo-682f3222-452d-46d2-bf30-c93cee4278d2" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad" gradientTransform="rotate(-30)">
<stop offset="0%" stop-color="#ffffff" id="stop78178"/>
<stop offset="50%" stop-color="#cccccc" id="stop78180"/>
<stop offset="100%" stop-color="#000000" id="stop78182"/>
</linearGradient>
<g id="logo-group">
<g id="logo-center">
<image width="0" height="0" y="-351.98328" x="-353.51215" id="icon_container"/>
<g text-anchor="middle" font-family="Orienta" font-size="32px" font-weight="400" font-style="normal" transform="translate(0 0)" id="slogan"/>
<g text-anchor="middle" font-family="'Brandmark Didone 1'" font-size="72px" font-weight="normal" font-style="normal" transform="translate(0 0)" id="title">
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#3a456c" fill="#3a456c" stroke-miterlimit="2" stroke-width="0" d="m385.6421,97.05592l-11.07,32.454l-9.342,-27.378c-1.08,-3.186 -3.83399,-5.076 -7.12799,-5.076l-4.59,0l0,0.27c2.53799,0 3.99599,1.89 4.91399,4.32l11.34,33.588l3.94201,0l13.01399,-38.178l-1.08,0z" id="path78201"/>
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#465075" fill="#465075" stroke-miterlimit="2" stroke-width="0" d="m421.85332,97.05592l0,23.598c0,7.344 -6.534,13.284 -12.69,13.284c-6.156,0 -9.666,-5.94 -9.666,-13.284l0,-23.598l-10.692,0l0,0.27c2.7,0 4.86,2.16 4.86,4.806l0,18.522c0,8.046 6.534,14.58 14.634,14.58c8.1,0 14.634,-6.534 14.634,-14.58l0,-23.598l-1.08,0z" id="path78203"/>
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#525c7e" fill="#525c7e" stroke-miterlimit="2" stroke-width="0" d="m438.63129,98.13592l16.308,0l0,-1.08l-27,0l0,0.27c2.7,0 4.86001,2.16 4.86001,4.806l0,32.67l22.13999,0l0,-1.08l-16.308,0l0,-21.276l15.012,0l0,-1.08l-15.012,0l0,-13.23z" id="path78205"/>
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#5d6786" fill="#5d6786" stroke-miterlimit="2" stroke-width="0" d="m486.45842,98.13592l0,-1.08l-29.376,0l0,1.08l11.77199,0l0,36.666l5.832,0l0,-36.666l11.77201,0z" id="path78207"/>
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#69728f" fill="#69728f" stroke-miterlimit="2" stroke-width="0" d="m498.85395,97.05592l-10.692,0l0,0.27c2.7,0 4.86,2.16 4.86,4.806l0,32.67l5.832,0l0,-37.746z" id="path78209"/>
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#757e98" fill="#757e98" stroke-miterlimit="2" stroke-width="0" d="m515.09614,98.13592l16.308,0l0,-1.08l-27,0l0,0.27c2.7,0 4.86,2.16 4.86,4.806l0,32.67l5.832,0l0,-22.302l14.256,0l0,-1.08l-14.256,0l0,-13.284z" id="path78211"/>
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#8189a1" fill="#8189a1" stroke-miterlimit="2" stroke-width="0" d="m602.68245,82.52992c-0.054,-0.972 -0.162,-1.944 -0.432,-2.862c-0.54,-1.89 -1.62,-3.618 -2.97,-5.022c-1.404,-1.404 -3.186,-2.43 -5.076,-2.97c-3.726,-1.026 -7.668,-0.324 -10.854,1.458c-1.566,0.918 -2.97,2.052 -4.158,3.402c-0.594,0.648 -1.134,1.404 -1.566,2.106c-0.486,0.756 -0.972,1.458 -1.404,2.214c-1.944,2.808 -3.78,5.724 -5.616,8.64l-2.754,4.32c-0.648,1.134 -1.35,2.16 -1.998,3.294l-11.826,18.522l-10.908,-18.576l-10.26,0l0,0.27c2.7,0 4.752,2.16 6.318,4.86l-0.054,0l9.504,16.146l0,1.08l5.832,0l0,-2.808l0.054,-0.054l12.42,-19.494c0.594,-0.864 1.188,-1.782 1.782,-2.7l2.808,-4.32c1.89,-2.862 3.726,-5.724 5.508,-8.64l1.404,-2.214c0.432,-0.702 0.972,-1.35 1.566,-1.89c1.134,-1.188 2.538,-2.106 4.05,-2.7c0.756,-0.324 1.512,-0.54 2.322,-0.648c0.81,-0.162 1.566,-0.216 2.376,-0.216c0.756,0 1.566,0.108 2.322,0.216c0.756,0.162 1.512,0.378 2.16,0.648c2.808,1.08 4.968,3.294 6.048,6.048c0.54,1.35 0.81,2.862 0.648,4.428c0,0.756 -0.162,1.512 -0.432,2.214c-0.216,0.702 -0.594,1.404 -1.026,1.998c-0.486,0.648 -1.08,1.188 -1.674,1.674c-0.648,0.432 -1.404,0.81 -2.16,1.08c-1.512,0.486 -3.24,0.432 -4.752,-0.108c-1.458,-0.54 -2.754,-1.62 -3.51,-3.024c-0.81,-1.35 -1.026,-3.024 -0.648,-4.59l-1.08,-0.216c-0.432,1.782 -0.162,3.726 0.756,5.346c0.864,1.62 2.376,2.916 4.158,3.51c1.728,0.594 3.618,0.594 5.4,0.162c0.864,-0.216 1.728,-0.54 2.538,-0.972c0.81,-0.486 1.566,-1.026 2.214,-1.728c0.702,-0.648 1.242,-1.458 1.728,-2.268c0.216,-0.432 0.432,-0.864 0.594,-1.35c0.162,-0.432 0.27,-0.918 0.378,-1.35c0.216,-0.972 0.324,-1.944 0.27,-2.916zm-51.948,38.016l-2.106,0l0,14.256l5.832,0l0,-10.476c0,-2.106 -1.674,-3.78 -3.726,-3.78z" id="path78213"/>
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#8c94a9" fill="#8c94a9" stroke-miterlimit="2" stroke-width="0" d="m598.00805,133.72192l-18.576,0l0,-36.666l-10.692,0l0,0.27c2.7,0 4.86,2.16 4.86,4.806l0,32.67l24.408,0l0,-1.08z" id="path78215"/>
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#98a0b2" fill="#98a0b2" stroke-miterlimit="2" stroke-width="0" d="m627.41197,97.05592l0,23.598c0,7.344 -6.534,13.284 -12.69001,13.284c-6.156,0 -9.66599,-5.94 -9.66599,-13.284l0,-23.598l-10.692,0l0,0.27c2.69999,0 4.85999,2.16 4.85999,4.806l0,18.522c0,8.046 6.534,14.58 14.63401,14.58c8.09999,0 14.63399,-6.534 14.63399,-14.58l0,-23.598l-1.07999,0z" id="path78217"/>
<path transform="translate(-353.512 -351.983) translate(0 280.783)" stroke="#a4abbb" fill="#a4abbb" stroke-miterlimit="2" stroke-width="0" d="m664.49391,130.58992l-11.772,-18.414l11.88,-15.12l-1.08,0l-11.34,14.364l-7.074,-11.124c-1.35,-2.052 -3.51,-3.24 -5.94,-3.24l-6.102,0l0,0.27c2.7,0 4.914,2.16 6.588,4.806l8.91,13.878l-14.796,18.792l1.134,0l14.148,-17.982l9.45,14.742c1.35,2.052 3.51,3.24 5.94,3.24l6.048,0l0,-0.27c-2.376,0 -4.374,-1.674 -5.994,-3.942z" id="path78219"/>
</g>
<image width="0" height="0" y="-351.98328" x="-353.51215" id="icon"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1,33 @@
<svg y="588.165" x="922" version="1.1" width="488" height="49" viewBox="0 0 488 49" id="svg164351" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata id="metadata164357">image/svg+xml</metadata>
<linearGradient id="3d_gradient2-logo-b69ed5b7-9e72-4003-be77-c6c49a364658" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad">
<stop offset="0%" stop-color="#ffffff" id="stop164332"/>
<stop offset="100%" stop-color="#000000" id="stop164334"/>
</linearGradient>
<linearGradient id="3d_gradient3-logo-b69ed5b7-9e72-4003-be77-c6c49a364658" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad" gradientTransform="rotate(-30)">
<stop offset="0%" stop-color="#ffffff" id="stop164337"/>
<stop offset="50%" stop-color="#cccccc" id="stop164339"/>
<stop offset="100%" stop-color="#000000" id="stop164341"/>
</linearGradient>
<g id="logo-group">
<g id="logo-center">
<image width="0" height="0" y="-359.3645" x="-267.7655" id="icon_container"/>
<g text-anchor="middle" font-family="'Nunito Sans'" font-size="32px" font-weight="300" font-style="oblique" transform="translate(0 0)" id="slogan"/>
<g text-anchor="middle" font-family="'Meedori Sans'" font-size="72px" font-weight="700" font-style="normal" transform="translate(0 0)" id="title">
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#5e636e" fill="#5e636e" stroke-miterlimit="2" stroke-width="0" d="m307.79824,54.932l9.10727,0l-24.57,49.14l-24.57,-49.14l9.95904,0l14.61096,30.99096l15.46273,-30.99096z" id="path164360"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#656a74" fill="#656a74" stroke-miterlimit="2" stroke-width="0" d="m362.42759,54.932l0,30.92544q0,0.6552 -0.13104,2.2932q-0.06552,1.57248 -0.58968,3.6036q-0.52416,2.03112 -1.70351,4.2588q-1.11385,2.16216 -3.27601,3.99672q-2.09663,1.76904 -5.37264,2.9484q-3.21048,1.11384 -7.99344,1.11384q-4.52088,0 -7.66583,-1.11384q-3.14496,-1.17936 -5.17609,-2.9484q-2.03111,-1.83456 -3.14495,-3.99672q-1.04833,-2.22768 -1.57248,-4.2588q-0.45865,-2.03112 -0.58969,-3.6036q-0.06552,-1.638 -0.06552,-2.2932l0,-30.92544l8.19,0l0,30.92544q0,0.72072 0.13104,2.48976q0.19656,1.76904 1.11384,3.66912q0.91729,1.83456 2.9484,3.276q2.09665,1.44144 5.83128,1.44144q4.06224,0 6.2244,-1.44144q2.22769,-1.44144 3.21048,-3.276q1.04832,-1.90008 1.17936,-3.66912q0.19656,-1.76904 0.19656,-2.48976l0,-30.92544l8.25552,0z" id="path164362"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#6c707b" fill="#6c707b" stroke-miterlimit="2" stroke-width="0" d="m408.65397,63.122l-24.63552,0l0,12.25224l20.96641,0l0,8.19l-20.96641,0l0,12.31776l24.63552,0l0,8.19l-32.82552,0l0,-49.14l32.82552,0l0,8.19z" id="path164364"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#727781" fill="#727781" stroke-miterlimit="2" stroke-width="0" d="m458.21678,63.122l-16.38,0l0,40.95l-8.19,0l0,-40.95l-16.38,0l0,-8.19l40.95,0l0,8.19z" id="path164366"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#797d88" fill="#797d88" stroke-miterlimit="2" stroke-width="0" d="m468.09393,54.932l8.12448,0l0,49.14l-8.12448,0l0,-49.14z" id="path164368"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#80848e" fill="#80848e" stroke-miterlimit="2" stroke-width="0" d="m498.0386,84.0884l0,19.9836l-8.19,0l0,-49.14l32.76,0l0,8.19l-24.57,0l0,12.71088l21.88368,0l0,8.25552l-21.88368,0z" id="path164370"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#878b94" fill="#878b94" stroke-miterlimit="2" stroke-width="0" d="m557.82253,81.33656l0,22.73544l-8.19,0l0,-22.73544l-20.04912,-26.40456l10.02457,0l14.61096,18.21456l13.62815,-18.21456l10.94185,0l-20.96641,26.40456z" id="path164372"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#8e919b" fill="#8e919b" stroke-miterlimit="2" stroke-width="0" d="m609.90891,76.68464l0,8.25552l-23.19407,0l0,-8.25552l23.19407,0z" id="path164374"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#9498a1" fill="#9498a1" stroke-miterlimit="2" stroke-width="0" d="m651.95222,95.882l0,8.19l-32.82552,0l0,-49.20552l8.12448,0l0.06552,41.01552l24.63552,0z" id="path164376"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#9b9ea8" fill="#9b9ea8" stroke-miterlimit="2" stroke-width="0" d="m698.34551,54.932l0,30.92544q0,0.6552 -0.13104,2.2932q-0.06552,1.57248 -0.58968,3.6036q-0.52416,2.03112 -1.70352,4.2588q-1.11384,2.16216 -3.276,3.99672q-2.09664,1.76904 -5.37264,2.9484q-3.21048,1.11384 -7.99344,1.11384q-4.52088,0 -7.66584,-1.11384q-3.14496,-1.17936 -5.17608,-2.9484q-2.03112,-1.83456 -3.14496,-3.99672q-1.04832,-2.22768 -1.57248,-4.2588q-0.45864,-2.03112 -0.58968,-3.6036q-0.06552,-1.638 -0.06552,-2.2932l0,-30.92544l8.19,0l0,30.92544q0,0.72072 0.13104,2.48976q0.19656,1.76904 1.11384,3.66912q0.91728,1.83456 2.9484,3.276q2.09664,1.44144 5.83128,1.44144q4.06224,0 6.2244,-1.44144q2.22768,-1.44144 3.21048,-3.276q1.04832,-1.90008 1.17936,-3.66912q0.19656,-1.76904 0.19656,-2.48976l0,-30.92544l8.25552,0z" id="path164378"/>
<path transform="translate(-267.766 -359.365) translate(0 304.498)" stroke="#a2a5ae" fill="#a2a5ae" stroke-miterlimit="2" stroke-width="0" d="m707.02898,104.13752l19.06632,-24.50448l-19.06632,-24.70104l10.87632,0l13.62816,18.21456l13.7592,-18.21456l10.94184,0l-18.21456,24.70104l18.21456,24.50448l-10.94184,0l-13.7592,-18.14904l-13.62816,18.14904l-10.87632,0z" id="path164380"/>
</g>
<image width="0" height="0" y="-359.3645" x="-267.7655" id="icon"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -0,0 +1,33 @@
<svg y="563.665" x="996.5" version="1.1" width="335" height="38" viewBox="0 0 335 38" id="svg194368" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata id="metadata194374">image/svg+xml</metadata>
<linearGradient id="3d_gradient2-logo-682f3222-452d-46d2-bf30-c93cee4278d2" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad">
<stop offset="0%" stop-color="#ffffff" id="stop194349"/>
<stop offset="100%" stop-color="#000000" id="stop194351"/>
</linearGradient>
<linearGradient id="3d_gradient3-logo-682f3222-452d-46d2-bf30-c93cee4278d2" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad" gradientTransform="rotate(-30)">
<stop offset="0%" stop-color="#ffffff" id="stop194354"/>
<stop offset="50%" stop-color="#cccccc" id="stop194356"/>
<stop offset="100%" stop-color="#000000" id="stop194358"/>
</linearGradient>
<g id="logo-group">
<g id="logo-center">
<image width="0" height="0" y="-364.91104" x="-344.33633" id="icon_container"/>
<g text-anchor="middle" font-family="Orienta" font-size="32px" font-weight="400" font-style="normal" transform="translate(0 0)" id="slogan"/>
<g text-anchor="middle" font-family="'Brandmark Didone 1'" font-size="72px" font-weight="normal" font-style="normal" transform="translate(0 0)" id="title">
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#3a456c" fill="#3a456c" stroke-miterlimit="2" stroke-width="0" d="m32.13001,-302.32904l-11.07,32.454l-9.342,-27.378c-1.08,-3.186 -3.834,-5.076 -7.128,-5.076l-4.59,0l0,0.27c2.538,0 3.996,1.89 4.914,4.32l11.34,33.588l3.942,0l13.014,-38.178l-1.08,0z" id="path194377"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#454f74" fill="#454f74" stroke-miterlimit="2" stroke-width="0" d="m68.34123,-302.32904l0,23.598c0,7.344 -6.534,13.284 -12.69001,13.284c-6.156,0 -9.66599,-5.94 -9.66599,-13.284l0,-23.598l-10.69201,0l0,0.27c2.70001,0 4.86001,2.16 4.86001,4.806l0,18.522c0,8.046 6.53399,14.58 14.634,14.58c8.1,0 14.634,-6.534 14.634,-14.58l0,-23.598l-1.08,0z" id="path194379"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#4f597c" fill="#4f597c" stroke-miterlimit="2" stroke-width="0" d="m85.11918,-301.24904l16.308,0l0,-1.08l-27,0l0,0.27c2.7,0 4.86,2.16 4.86,4.806l0,32.67l22.14,0l0,-1.08l-16.308,0l0,-21.276l15.012,0l0,-1.08l-15.012,0l0,-13.23z" id="path194381"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#5a6484" fill="#5a6484" stroke-miterlimit="2" stroke-width="0" d="m132.94632,-301.24904l0,-1.08l-29.376,0l0,1.08l11.772,0l0,36.666l5.832,0l0,-36.666l11.772,0z" id="path194383"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#646e8c" fill="#646e8c" stroke-miterlimit="2" stroke-width="0" d="m145.34183,-302.32904l-10.692,0l0,0.27c2.7,0 4.86001,2.16 4.86001,4.806l0,32.67l5.83199,0l0,-37.746z" id="path194385"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#6f7894" fill="#6f7894" stroke-miterlimit="2" stroke-width="0" d="m161.58402,-301.24904l16.308,0l0,-1.08l-27,0l0,0.27c2.7,0 4.86001,2.16 4.86001,4.806l0,32.67l5.83199,0l0,-22.302l14.256,0l0,-1.08l-14.256,0l0,-13.284z" id="path194387"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#7a829b" fill="#7a829b" stroke-miterlimit="2" stroke-width="0" d="m200.94833,-282.78104l12.47401,-19.548l-1.13401,0l-11.826,18.576l-8.856,-15.066c-1.296,-2.268 -3.564,-3.51 -6.156,-3.51l-6.15599,0l0,0.27c2.7,0 4.752,2.16 6.31799,4.806l9.45001,16.146l0,16.524l5.88599,0l0,-18.198z" id="path194389"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#848ca3" fill="#848ca3" stroke-miterlimit="2" stroke-width="0" d="m212.79459,-280.40504l18.57599,0l0,-1.89l-18.57599,0l0,1.89z" id="path194391"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#8f97ab" fill="#8f97ab" stroke-miterlimit="2" stroke-width="0" d="m262.8475,-265.66304l-18.576,0l0,-36.666l-10.69201,0l0,0.27c2.7,0 4.86,2.16 4.86,4.806l0,32.67l24.40801,0l0,-1.08z" id="path194393"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#99a1b3" fill="#99a1b3" stroke-miterlimit="2" stroke-width="0" d="m292.25141,-302.32904l0,23.598c0,7.344 -6.534,13.284 -12.69,13.284c-6.156,0 -9.666,-5.94 -9.666,-13.284l0,-23.598l-10.692,0l0,0.27c2.7,0 4.86,2.16 4.86,4.806l0,18.522c0,8.046 6.534,14.58 14.634,14.58c8.1,0 14.634,-6.534 14.634,-14.58l0,-23.598l-1.08,0z" id="path194395"/>
<path transform="translate(1.13687e-13 0) translate(0 302.329)" stroke="#a4abbb" fill="#a4abbb" stroke-miterlimit="2" stroke-width="0" d="m329.33336,-268.79504l-11.77201,-18.414l11.88001,-15.12l-1.08001,0l-11.34,14.364l-7.074,-11.124c-1.34999,-2.052 -3.50999,-3.24 -5.94,-3.24l-6.10199,0l0,0.27c2.69999,0 4.91399,2.16 6.588,4.806l8.91,13.878l-14.79601,18.792l1.13401,0l14.148,-17.982l9.44999,14.742c1.35001,2.052 3.51001,3.24 5.94001,3.24l6.04799,0l0,-0.27c-2.376,0 -4.374,-1.674 -5.99399,-3.942z" id="path194397"/>
</g>
<image width="0" height="0" y="-364.91104" x="-344.33633" id="icon"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -0,0 +1,33 @@
<svg y="551.165" x="960" version="1.1" width="412" height="67" viewBox="0 0 412 67" id="svg687764" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata id="metadata687770">image/svg+xml</metadata>
<linearGradient id="3d_gradient2-logo-be9fcf93-76f3-4195-b816-3f382377cd48" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad">
<stop offset="0%" stop-color="#ffffff" id="stop687745"/>
<stop offset="100%" stop-color="#000000" id="stop687747"/>
</linearGradient>
<linearGradient id="3d_gradient3-logo-be9fcf93-76f3-4195-b816-3f382377cd48" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad" gradientTransform="rotate(-30)">
<stop offset="0%" stop-color="#ffffff" id="stop687750"/>
<stop offset="50%" stop-color="#cccccc" id="stop687752"/>
<stop offset="100%" stop-color="#000000" id="stop687754"/>
</linearGradient>
<g id="logo-group">
<g transform="translate(0 0)" id="logo-center">
<image width="0" height="0" y="-350.55203" x="-306.10635" id="icon_container"/>
<g text-anchor="middle" font-family="Raleway" font-size="32px" font-weight="600" font-style="normal" transform="translate(0 0)" id="slogan"/>
<g text-anchor="middle" font-family="'Comfortaa Bold Alt1'" font-size="72px" font-weight="700" font-style="normal" transform="translate(0 0)" id="title">
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#ffffff" fill="#ffffff" stroke-miterlimit="2" stroke-width="0" d="m340.17676,71.96504c-0.3276,-0.45864 -0.78624,-0.85176 -1.3104,-1.11384c-0.45864,-0.19656 -0.9828,-0.3276 -1.50696,-0.3276c-0.58968,0 -1.11384,0.19656 -1.638,0.45864c-0.52416,0.26208 -0.85176,0.6552 -1.11384,1.17936l-11.26944,24.57l-11.40048,-24.57c-0.26208,-0.52416 -0.6552,-0.91728 -1.11384,-1.17936c-0.52416,-0.26208 -0.9828,-0.45864 -1.50696,-0.45864c-0.52416,0 -0.9828,0.13104 -1.37592,0.3276c-1.24488,0.6552 -1.83456,1.50696 -1.83456,2.68632c0,0.45864 0.06552,0.85176 0.26208,1.17936l13.89024,29.28744c0.39312,0.78624 0.78624,1.37592 1.3104,1.70352c0.45864,0.3276 1.04832,0.45864 1.83456,0.45864c1.3104,0 2.35872,-0.72072 3.01392,-2.16216l13.89024,-29.28744c0.19656,-0.39312 0.3276,-0.85176 0.3276,-1.24488c0,-0.52416 -0.19656,-1.04832 -0.45864,-1.50696z" id="path687773"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#fcfcfc" fill="#fcfcfc" stroke-miterlimit="2" stroke-width="0" d="m386.5027,102.89048l0,-29.22192c0,-0.9828 -0.3276,-1.76904 -0.91728,-2.42424c-0.6552,-0.58968 -1.44144,-0.91728 -2.42424,-0.91728c-0.9828,0 -1.76904,0.3276 -2.42424,0.91728c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.42424l0,18.47664c0,1.638 -0.45864,3.01392 -1.3104,4.2588c-0.85176,1.3104 -2.03112,2.2932 -3.53808,3.01392c-1.50696,0.78624 -3.21048,1.11384 -4.97952,1.11384c-3.21048,0 -5.70024,-0.85176 -7.60032,-2.68632c-1.90008,-1.83456 -2.81736,-4.52088 -2.81736,-8.05896l0,-16.11792c0,-0.91728 -0.3276,-1.70352 -0.9828,-2.35872c-0.6552,-0.6552 -1.44144,-0.9828 -2.35872,-0.9828c-0.9828,0 -1.76904,0.3276 -2.42424,0.9828c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872l0,16.11792c0,3.6036 0.6552,6.61752 2.03112,9.10728c1.3104,2.48976 3.21048,4.45536 5.63472,5.70024c2.2932,1.3104 4.78296,1.9656 7.5348,2.03112c0.13104,0 5.17608,0 15.33168,0c0.85176,0 1.57248,-0.3276 2.16216,-0.91728c0.58968,-0.58968 0.91728,-1.3104 0.91728,-2.22768l0,-0.58968z" id="path687775"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#f8f8f8" fill="#f8f8f8" stroke-miterlimit="2" stroke-width="0" d="m435.96133,89.852c0.52416,-0.52416 0.85176,-1.24488 0.85176,-2.09664c0,-3.40704 -0.6552,-6.48648 -1.9656,-9.1728c-1.3104,-2.6208 -3.21048,-4.71744 -5.63472,-6.2244c-2.48976,-1.44144 -5.37264,-2.22768 -8.71416,-2.22768c-3.40704,0 -6.48648,0.78624 -9.1728,2.35872c-2.68632,1.57248 -4.78296,3.73464 -6.28992,6.48648c-1.50696,2.75184 -2.22768,5.8968 -2.22768,9.36936c0,3.53808 0.78624,6.61752 2.35872,9.36936c1.57248,2.75184 3.80016,4.914 6.68304,6.48648c2.81736,1.57248 6.02784,2.2932 9.63144,2.2932c1.9656,0 4.06224,-0.3276 6.28992,-1.11384c2.22768,-0.72072 4.06224,-1.70352 5.5692,-2.88288c0.6552,-0.52416 1.04832,-1.17936 1.04832,-1.9656c0,-0.78624 -0.39312,-1.57248 -1.17936,-2.22768c-0.52416,-0.39312 -1.17936,-0.6552 -1.9656,-0.6552c-0.85176,0 -1.57248,0.26208 -2.16216,0.72072c-0.91728,0.72072 -2.09664,1.3104 -3.53808,1.76904c-1.44144,0.52416 -2.75184,0.72072 -4.06224,0.72072c-3.34152,0 -6.15888,-0.91728 -8.45208,-2.81736c-2.2932,-1.83456 -3.66912,-4.32432 -4.12776,-7.40376l24.8976,0c0.85176,0 1.57248,-0.26208 2.16216,-0.78624zm-23.2596,-11.466c1.9656,-1.70352 4.5864,-2.6208 7.79688,-2.6208c2.88288,0 5.17608,0.91728 7.01064,2.6208c1.76904,1.76904 2.88288,4.12776 3.276,7.01064l-21.81816,0c0.52416,-2.88288 1.76904,-5.2416 3.73464,-7.01064z" id="path687777"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#f5f5f5" fill="#f5f5f5" stroke-miterlimit="2" stroke-width="0" d="m453.21376,71.70296l0,5.63472l0,16.18344c0,2.42424 0.45864,4.5864 1.50696,6.48648c0.9828,1.9656 2.35872,3.47256 4.12776,4.5864c1.76904,1.11384 3.73464,1.638 5.8968,1.638l1.17936,0c1.11384,0 2.03112,-0.26208 2.75184,-0.91728c0.72072,-0.58968 1.11384,-1.37592 1.11384,-2.35872c0,-0.91728 -0.3276,-1.70352 -0.85176,-2.35872c-0.52416,-0.58968 -1.17936,-0.91728 -1.9656,-0.91728l-2.22768,0c-1.44144,0 -2.6208,-0.58968 -3.53808,-1.76904c-0.9828,-1.17936 -1.44144,-2.6208 -1.44144,-4.38984l0,-16.18344l5.5692,0c0.91728,0 1.638,-0.26208 2.22768,-0.78624c0.52416,-0.52416 0.85176,-1.17936 0.85176,-1.9656c0,-0.85176 -0.3276,-1.57248 -0.85176,-2.09664c-0.58968,-0.52416 -1.3104,-0.78624 -2.22768,-0.78624l-5.5692,0l0,-9.43488c0,-0.91728 -0.3276,-1.70352 -0.91728,-2.35872c-0.6552,-0.58968 -1.44144,-0.91728 -2.35872,-0.91728c-0.9828,0 -1.76904,0.3276 -2.35872,0.91728c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872l0,9.43488z" id="path687779"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#f2f2f2" fill="#f2f2f2" stroke-miterlimit="2" stroke-width="0" d="m485.88287,71.30984c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.42424l0,29.1564c0,0.9828 0.26208,1.76904 0.91728,2.42424c0.6552,0.6552 1.44144,0.91728 2.42424,0.91728c0.9828,0 1.76904,-0.26208 2.42424,-0.91728c0.58968,-0.6552 0.91728,-1.44144 0.91728,-2.42424l0,-29.1564c0,-0.9828 -0.3276,-1.76904 -0.91728,-2.42424c-0.6552,-0.58968 -1.44144,-0.91728 -2.42424,-0.91728c-0.9828,0 -1.76904,0.3276 -2.42424,0.91728z" id="path687781"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#efefef" fill="#efefef" stroke-miterlimit="2" stroke-width="0" d="m511.17077,71.70296l0,5.63472l0,25.5528c0,1.04832 0.26208,1.83456 0.91728,2.42424c0.6552,0.6552 1.37592,0.91728 2.2932,0.91728c1.04832,0 1.90008,-0.26208 2.55528,-0.91728c0.58968,-0.58968 0.91728,-1.37592 0.91728,-2.42424l0,-25.5528l6.68304,0c0.91728,0 1.638,-0.26208 2.22768,-0.78624c0.52416,-0.52416 0.85176,-1.17936 0.85176,-1.9656c0,-0.85176 -0.3276,-1.57248 -0.85176,-2.09664c-0.58968,-0.52416 -1.3104,-0.78624 -2.22768,-0.78624l-6.68304,0l0,-1.76904c0,-2.6208 0.72072,-4.78296 2.22768,-6.42096c1.44144,-1.57248 3.40704,-2.42424 5.8968,-2.42424c0.91728,0 1.70352,-0.26208 2.35872,-0.85176c0.6552,-0.52416 0.9828,-1.24488 0.9828,-2.16216c0,-0.85176 -0.3276,-1.57248 -0.9828,-2.16216c-0.6552,-0.52416 -1.44144,-0.85176 -2.35872,-0.85176c-2.9484,0 -5.50368,0.6552 -7.73136,1.9656c-2.22768,1.3104 -3.99672,3.07944 -5.2416,5.43816c-1.24488,2.35872 -1.83456,5.04504 -1.83456,8.12448l0,1.11384z" id="path687783"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#ebebeb" fill="#ebebeb" stroke-miterlimit="2" stroke-width="0" d="m570.36214,73.27544c0,-1.17936 -0.72072,-2.03112 -2.03112,-2.55528c-0.52416,-0.19656 -1.04832,-0.3276 -1.57248,-0.3276c-1.17936,0 -2.03112,0.6552 -2.55528,1.90008l-10.54872,23.78376l-11.99016,-23.84928c-0.6552,-1.17936 -1.57248,-1.83456 -2.75184,-1.83456c-0.52416,0 -0.91728,0.13104 -1.3104,0.26208c-0.58968,0.26208 -1.04832,0.6552 -1.37592,1.11384c-0.39312,0.52416 -0.52416,1.04832 -0.52416,1.57248c0,0.52416 0.06552,0.9828 0.3276,1.37592l14.742,27.97704l-6.552,14.742c-0.26208,0.52416 -0.39312,1.04832 -0.39312,1.57248c0,1.17936 0.6552,2.03112 1.9656,2.55528c0.58968,0.26208 1.11384,0.39312 1.57248,0.39312c1.17936,0 2.03112,-0.6552 2.55528,-2.03112l20.04912,-45.07776c0.26208,-0.58968 0.39312,-1.11384 0.39312,-1.57248z" id="path687785"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#e8e8e8" fill="#e8e8e8" stroke-miterlimit="2" stroke-width="0" d="m599.40619,85.98632c-0.6552,-0.6552 -1.44144,-0.9828 -2.35872,-0.9828l-14.61096,0c-0.9828,0 -1.76904,0.3276 -2.42424,0.9828c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872c0,0.9828 0.26208,1.76904 0.91728,2.35872c0.6552,0.6552 1.44144,0.91728 2.42424,0.91728l14.61096,0c0.91728,0 1.70352,-0.26208 2.35872,-0.91728c0.58968,-0.58968 0.91728,-1.37592 0.91728,-2.35872c0,-0.91728 -0.3276,-1.70352 -0.91728,-2.35872z" id="path687787"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#e5e5e5" fill="#e5e5e5" stroke-miterlimit="2" stroke-width="0" d="m614.20374,55.97816c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872l0,35.77392c0,2.35872 0.39312,4.45536 1.24488,6.28992c0.78624,1.83456 1.9656,3.276 3.47256,4.32432c1.50696,1.04832 3.21048,1.50696 5.11056,1.50696l0.13104,0c1.3104,0 2.35872,-0.26208 3.21048,-0.91728c0.78624,-0.58968 1.24488,-1.37592 1.24488,-2.35872c0,-0.91728 -0.3276,-1.70352 -0.85176,-2.35872c-0.52416,-0.58968 -1.24488,-0.91728 -2.09664,-0.91728l-1.638,0c-0.9828,0 -1.76904,-0.52416 -2.35872,-1.57248c-0.6552,-1.04832 -0.91728,-2.35872 -0.91728,-3.99672l0,-35.77392c0,-0.91728 -0.3276,-1.70352 -0.91728,-2.35872c-0.6552,-0.58968 -1.44144,-0.91728 -2.35872,-0.91728c-0.9828,0 -1.76904,0.3276 -2.35872,0.91728z" id="path687789"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#e1e1e1" fill="#e1e1e1" stroke-miterlimit="2" stroke-width="0" d="m673.56508,102.89048l0,-29.22192c0,-0.9828 -0.3276,-1.76904 -0.91728,-2.42424c-0.6552,-0.58968 -1.44144,-0.91728 -2.42424,-0.91728c-0.9828,0 -1.76904,0.3276 -2.42424,0.91728c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.42424l0,18.47664c0,1.638 -0.45864,3.01392 -1.3104,4.2588c-0.85176,1.3104 -2.03112,2.2932 -3.53808,3.01392c-1.50696,0.78624 -3.21048,1.11384 -4.97952,1.11384c-3.21048,0 -5.70024,-0.85176 -7.60032,-2.68632c-1.90008,-1.83456 -2.81736,-4.52088 -2.81736,-8.05896l0,-16.11792c0,-0.91728 -0.3276,-1.70352 -0.9828,-2.35872c-0.6552,-0.6552 -1.44144,-0.9828 -2.35872,-0.9828c-0.9828,0 -1.76904,0.3276 -2.42424,0.9828c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872l0,16.11792c0,3.6036 0.6552,6.61752 2.03112,9.10728c1.3104,2.48976 3.21048,4.45536 5.63472,5.70024c2.2932,1.3104 4.78296,1.9656 7.5348,2.03112c0.13104,0 5.17608,0 15.33168,0c0.85176,0 1.57248,-0.3276 2.16216,-0.91728c0.58968,-0.58968 0.91728,-1.3104 0.91728,-2.22768l0,-0.58968z" id="path687791"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#dedede" fill="#dedede" stroke-miterlimit="2" stroke-width="0" d="m717.89364,103.48016c0,-0.85176 -0.3276,-1.638 -0.91728,-2.2932l-10.41768,-12.4488l9.89352,-12.90744c0.58968,-0.78624 0.91728,-1.638 0.91728,-2.6208c0,-0.78624 -0.26208,-1.44144 -0.78624,-1.9656c-0.52416,-0.52416 -1.17936,-0.85176 -2.03112,-0.85176c-1.04832,0 -1.90008,0.39312 -2.42424,1.11384l-9.63144,12.84192l-10.74528,-12.84192c-0.6552,-0.72072 -1.44144,-1.11384 -2.48976,-1.11384c-0.91728,0 -1.638,0.26208 -2.16216,0.78624c-0.52416,0.52416 -0.72072,1.17936 -0.72072,1.90008c0,0.91728 0.3276,1.70352 0.9828,2.48976l10.8108,12.7764l-10.1556,12.71088c-0.6552,0.78624 -0.91728,1.57248 -0.91728,2.42424c0,0.78624 0.19656,1.44144 0.72072,1.9656c0.52416,0.52416 1.17936,0.78624 2.09664,0.78624c0.91728,0 1.70352,-0.3276 2.35872,-1.04832l9.89352,-12.4488l10.41768,12.4488c0.52416,0.72072 1.3104,1.04832 2.35872,1.04832c0.85176,0 1.57248,-0.26208 2.09664,-0.78624c0.52416,-0.52416 0.85176,-1.17936 0.85176,-1.9656z" id="path687793"/>
</g>
<image width="0" height="0" y="-350.55203" x="-306.10635" id="icon"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,33 @@
<svg y="551.165" x="960" version="1.1" width="412" height="67" viewBox="0 0 412 67" id="svg4578" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata id="metadata4584">image/svg+xml</metadata>
<linearGradient id="3d_gradient2-logo-be9fcf93-76f3-4195-b816-3f382377cd48" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad">
<stop offset="0%" stop-color="#ffffff" id="stop4559"/>
<stop offset="100%" stop-color="#000000" id="stop4561"/>
</linearGradient>
<linearGradient id="3d_gradient3-logo-be9fcf93-76f3-4195-b816-3f382377cd48" x1="30%" y1="120%" x2="-10%" y2="30%" spreadMethod="pad" gradientTransform="rotate(-30)">
<stop offset="0%" stop-color="#ffffff" id="stop4564"/>
<stop offset="50%" stop-color="#cccccc" id="stop4566"/>
<stop offset="100%" stop-color="#000000" id="stop4568"/>
</linearGradient>
<g id="logo-group">
<g id="logo-center">
<image width="0" height="0" y="-350.55203" x="-306.10635" id="icon_container"/>
<g text-anchor="middle" font-family="Raleway" font-size="32px" font-weight="600" font-style="normal" transform="translate(0 0)" id="slogan"/>
<g text-anchor="middle" font-family="'Comfortaa Bold Alt1'" font-size="72px" font-weight="700" font-style="normal" transform="translate(0 0)" id="title">
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#5e636e" fill="#5e636e" stroke-miterlimit="2" stroke-width="0" d="m340.17676,71.96504c-0.3276,-0.45864 -0.78624,-0.85176 -1.3104,-1.11384c-0.45864,-0.19656 -0.9828,-0.3276 -1.50696,-0.3276c-0.58968,0 -1.11384,0.19656 -1.638,0.45864c-0.52416,0.26208 -0.85176,0.6552 -1.11384,1.17936l-11.26944,24.57l-11.40048,-24.57c-0.26208,-0.52416 -0.6552,-0.91728 -1.11384,-1.17936c-0.52416,-0.26208 -0.9828,-0.45864 -1.50696,-0.45864c-0.52416,0 -0.9828,0.13104 -1.37592,0.3276c-1.24488,0.6552 -1.83456,1.50696 -1.83456,2.68632c0,0.45864 0.06552,0.85176 0.26208,1.17936l13.89024,29.28744c0.39312,0.78624 0.78624,1.37592 1.3104,1.70352c0.45864,0.3276 1.04832,0.45864 1.83456,0.45864c1.3104,0 2.35872,-0.72072 3.01392,-2.16216l13.89024,-29.28744c0.19656,-0.39312 0.3276,-0.85176 0.3276,-1.24488c0,-0.52416 -0.19656,-1.04832 -0.45864,-1.50696z" id="path4587"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#656a74" fill="#656a74" stroke-miterlimit="2" stroke-width="0" d="m386.5027,102.89048l0,-29.22192c0,-0.9828 -0.3276,-1.76904 -0.91728,-2.42424c-0.6552,-0.58968 -1.44144,-0.91728 -2.42424,-0.91728c-0.9828,0 -1.76904,0.3276 -2.42424,0.91728c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.42424l0,18.47664c0,1.638 -0.45864,3.01392 -1.3104,4.2588c-0.85176,1.3104 -2.03112,2.2932 -3.53808,3.01392c-1.50696,0.78624 -3.21048,1.11384 -4.97952,1.11384c-3.21048,0 -5.70024,-0.85176 -7.60032,-2.68632c-1.90008,-1.83456 -2.81736,-4.52088 -2.81736,-8.05896l0,-16.11792c0,-0.91728 -0.3276,-1.70352 -0.9828,-2.35872c-0.6552,-0.6552 -1.44144,-0.9828 -2.35872,-0.9828c-0.9828,0 -1.76904,0.3276 -2.42424,0.9828c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872l0,16.11792c0,3.6036 0.6552,6.61752 2.03112,9.10728c1.3104,2.48976 3.21048,4.45536 5.63472,5.70024c2.2932,1.3104 4.78296,1.9656 7.5348,2.03112c0.13104,0 5.17608,0 15.33168,0c0.85176,0 1.57248,-0.3276 2.16216,-0.91728c0.58968,-0.58968 0.91728,-1.3104 0.91728,-2.22768l0,-0.58968z" id="path4589"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#6c707b" fill="#6c707b" stroke-miterlimit="2" stroke-width="0" d="m435.96133,89.852c0.52416,-0.52416 0.85176,-1.24488 0.85176,-2.09664c0,-3.40704 -0.6552,-6.48648 -1.9656,-9.1728c-1.3104,-2.6208 -3.21048,-4.71744 -5.63472,-6.2244c-2.48976,-1.44144 -5.37264,-2.22768 -8.71416,-2.22768c-3.40704,0 -6.48648,0.78624 -9.1728,2.35872c-2.68632,1.57248 -4.78296,3.73464 -6.28992,6.48648c-1.50696,2.75184 -2.22768,5.8968 -2.22768,9.36936c0,3.53808 0.78624,6.61752 2.35872,9.36936c1.57248,2.75184 3.80016,4.914 6.68304,6.48648c2.81736,1.57248 6.02784,2.2932 9.63144,2.2932c1.9656,0 4.06224,-0.3276 6.28992,-1.11384c2.22768,-0.72072 4.06224,-1.70352 5.5692,-2.88288c0.6552,-0.52416 1.04832,-1.17936 1.04832,-1.9656c0,-0.78624 -0.39312,-1.57248 -1.17936,-2.22768c-0.52416,-0.39312 -1.17936,-0.6552 -1.9656,-0.6552c-0.85176,0 -1.57248,0.26208 -2.16216,0.72072c-0.91728,0.72072 -2.09664,1.3104 -3.53808,1.76904c-1.44144,0.52416 -2.75184,0.72072 -4.06224,0.72072c-3.34152,0 -6.15888,-0.91728 -8.45208,-2.81736c-2.2932,-1.83456 -3.66912,-4.32432 -4.12776,-7.40376l24.8976,0c0.85176,0 1.57248,-0.26208 2.16216,-0.78624zm-23.2596,-11.466c1.9656,-1.70352 4.5864,-2.6208 7.79688,-2.6208c2.88288,0 5.17608,0.91728 7.01064,2.6208c1.76904,1.76904 2.88288,4.12776 3.276,7.01064l-21.81816,0c0.52416,-2.88288 1.76904,-5.2416 3.73464,-7.01064z" id="path4591"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#727781" fill="#727781" stroke-miterlimit="2" stroke-width="0" d="m453.21376,71.70296l0,5.63472l0,16.18344c0,2.42424 0.45864,4.5864 1.50696,6.48648c0.9828,1.9656 2.35872,3.47256 4.12776,4.5864c1.76904,1.11384 3.73464,1.638 5.8968,1.638l1.17936,0c1.11384,0 2.03112,-0.26208 2.75184,-0.91728c0.72072,-0.58968 1.11384,-1.37592 1.11384,-2.35872c0,-0.91728 -0.3276,-1.70352 -0.85176,-2.35872c-0.52416,-0.58968 -1.17936,-0.91728 -1.9656,-0.91728l-2.22768,0c-1.44144,0 -2.6208,-0.58968 -3.53808,-1.76904c-0.9828,-1.17936 -1.44144,-2.6208 -1.44144,-4.38984l0,-16.18344l5.5692,0c0.91728,0 1.638,-0.26208 2.22768,-0.78624c0.52416,-0.52416 0.85176,-1.17936 0.85176,-1.9656c0,-0.85176 -0.3276,-1.57248 -0.85176,-2.09664c-0.58968,-0.52416 -1.3104,-0.78624 -2.22768,-0.78624l-5.5692,0l0,-9.43488c0,-0.91728 -0.3276,-1.70352 -0.91728,-2.35872c-0.6552,-0.58968 -1.44144,-0.91728 -2.35872,-0.91728c-0.9828,0 -1.76904,0.3276 -2.35872,0.91728c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872l0,9.43488z" id="path4593"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#797d88" fill="#797d88" stroke-miterlimit="2" stroke-width="0" d="m485.88287,71.30984c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.42424l0,29.1564c0,0.9828 0.26208,1.76904 0.91728,2.42424c0.6552,0.6552 1.44144,0.91728 2.42424,0.91728c0.9828,0 1.76904,-0.26208 2.42424,-0.91728c0.58968,-0.6552 0.91728,-1.44144 0.91728,-2.42424l0,-29.1564c0,-0.9828 -0.3276,-1.76904 -0.91728,-2.42424c-0.6552,-0.58968 -1.44144,-0.91728 -2.42424,-0.91728c-0.9828,0 -1.76904,0.3276 -2.42424,0.91728z" id="path4595"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#80848e" fill="#80848e" stroke-miterlimit="2" stroke-width="0" d="m511.17077,71.70296l0,5.63472l0,25.5528c0,1.04832 0.26208,1.83456 0.91728,2.42424c0.6552,0.6552 1.37592,0.91728 2.2932,0.91728c1.04832,0 1.90008,-0.26208 2.55528,-0.91728c0.58968,-0.58968 0.91728,-1.37592 0.91728,-2.42424l0,-25.5528l6.68304,0c0.91728,0 1.638,-0.26208 2.22768,-0.78624c0.52416,-0.52416 0.85176,-1.17936 0.85176,-1.9656c0,-0.85176 -0.3276,-1.57248 -0.85176,-2.09664c-0.58968,-0.52416 -1.3104,-0.78624 -2.22768,-0.78624l-6.68304,0l0,-1.76904c0,-2.6208 0.72072,-4.78296 2.22768,-6.42096c1.44144,-1.57248 3.40704,-2.42424 5.8968,-2.42424c0.91728,0 1.70352,-0.26208 2.35872,-0.85176c0.6552,-0.52416 0.9828,-1.24488 0.9828,-2.16216c0,-0.85176 -0.3276,-1.57248 -0.9828,-2.16216c-0.6552,-0.52416 -1.44144,-0.85176 -2.35872,-0.85176c-2.9484,0 -5.50368,0.6552 -7.73136,1.9656c-2.22768,1.3104 -3.99672,3.07944 -5.2416,5.43816c-1.24488,2.35872 -1.83456,5.04504 -1.83456,8.12448l0,1.11384z" id="path4597"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#878b94" fill="#878b94" stroke-miterlimit="2" stroke-width="0" d="m570.36214,73.27544c0,-1.17936 -0.72072,-2.03112 -2.03112,-2.55528c-0.52416,-0.19656 -1.04832,-0.3276 -1.57248,-0.3276c-1.17936,0 -2.03112,0.6552 -2.55528,1.90008l-10.54872,23.78376l-11.99016,-23.84928c-0.6552,-1.17936 -1.57248,-1.83456 -2.75184,-1.83456c-0.52416,0 -0.91728,0.13104 -1.3104,0.26208c-0.58968,0.26208 -1.04832,0.6552 -1.37592,1.11384c-0.39312,0.52416 -0.52416,1.04832 -0.52416,1.57248c0,0.52416 0.06552,0.9828 0.3276,1.37592l14.742,27.97704l-6.552,14.742c-0.26208,0.52416 -0.39312,1.04832 -0.39312,1.57248c0,1.17936 0.6552,2.03112 1.9656,2.55528c0.58968,0.26208 1.11384,0.39312 1.57248,0.39312c1.17936,0 2.03112,-0.6552 2.55528,-2.03112l20.04912,-45.07776c0.26208,-0.58968 0.39312,-1.11384 0.39312,-1.57248z" id="path4599"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#8e919b" fill="#8e919b" stroke-miterlimit="2" stroke-width="0" d="m599.40619,85.98632c-0.6552,-0.6552 -1.44144,-0.9828 -2.35872,-0.9828l-14.61096,0c-0.9828,0 -1.76904,0.3276 -2.42424,0.9828c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872c0,0.9828 0.26208,1.76904 0.91728,2.35872c0.6552,0.6552 1.44144,0.91728 2.42424,0.91728l14.61096,0c0.91728,0 1.70352,-0.26208 2.35872,-0.91728c0.58968,-0.58968 0.91728,-1.37592 0.91728,-2.35872c0,-0.91728 -0.3276,-1.70352 -0.91728,-2.35872z" id="path4601"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#9498a1" fill="#9498a1" stroke-miterlimit="2" stroke-width="0" d="m614.20374,55.97816c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872l0,35.77392c0,2.35872 0.39312,4.45536 1.24488,6.28992c0.78624,1.83456 1.9656,3.276 3.47256,4.32432c1.50696,1.04832 3.21048,1.50696 5.11056,1.50696l0.13104,0c1.3104,0 2.35872,-0.26208 3.21048,-0.91728c0.78624,-0.58968 1.24488,-1.37592 1.24488,-2.35872c0,-0.91728 -0.3276,-1.70352 -0.85176,-2.35872c-0.52416,-0.58968 -1.24488,-0.91728 -2.09664,-0.91728l-1.638,0c-0.9828,0 -1.76904,-0.52416 -2.35872,-1.57248c-0.6552,-1.04832 -0.91728,-2.35872 -0.91728,-3.99672l0,-35.77392c0,-0.91728 -0.3276,-1.70352 -0.91728,-2.35872c-0.6552,-0.58968 -1.44144,-0.91728 -2.35872,-0.91728c-0.9828,0 -1.76904,0.3276 -2.35872,0.91728z" id="path4603"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#9b9ea8" fill="#9b9ea8" stroke-miterlimit="2" stroke-width="0" d="m673.56508,102.89048l0,-29.22192c0,-0.9828 -0.3276,-1.76904 -0.91728,-2.42424c-0.6552,-0.58968 -1.44144,-0.91728 -2.42424,-0.91728c-0.9828,0 -1.76904,0.3276 -2.42424,0.91728c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.42424l0,18.47664c0,1.638 -0.45864,3.01392 -1.3104,4.2588c-0.85176,1.3104 -2.03112,2.2932 -3.53808,3.01392c-1.50696,0.78624 -3.21048,1.11384 -4.97952,1.11384c-3.21048,0 -5.70024,-0.85176 -7.60032,-2.68632c-1.90008,-1.83456 -2.81736,-4.52088 -2.81736,-8.05896l0,-16.11792c0,-0.91728 -0.3276,-1.70352 -0.9828,-2.35872c-0.6552,-0.6552 -1.44144,-0.9828 -2.35872,-0.9828c-0.9828,0 -1.76904,0.3276 -2.42424,0.9828c-0.6552,0.6552 -0.91728,1.44144 -0.91728,2.35872l0,16.11792c0,3.6036 0.6552,6.61752 2.03112,9.10728c1.3104,2.48976 3.21048,4.45536 5.63472,5.70024c2.2932,1.3104 4.78296,1.9656 7.5348,2.03112c0.13104,0 5.17608,0 15.33168,0c0.85176,0 1.57248,-0.3276 2.16216,-0.91728c0.58968,-0.58968 0.91728,-1.3104 0.91728,-2.22768l0,-0.58968z" id="path4605"/>
<path transform="translate(-306.106 -350.552) translate(0 295.491)" stroke="#a2a5ae" fill="#a2a5ae" stroke-miterlimit="2" stroke-width="0" d="m717.89364,103.48016c0,-0.85176 -0.3276,-1.638 -0.91728,-2.2932l-10.41768,-12.4488l9.89352,-12.90744c0.58968,-0.78624 0.91728,-1.638 0.91728,-2.6208c0,-0.78624 -0.26208,-1.44144 -0.78624,-1.9656c-0.52416,-0.52416 -1.17936,-0.85176 -2.03112,-0.85176c-1.04832,0 -1.90008,0.39312 -2.42424,1.11384l-9.63144,12.84192l-10.74528,-12.84192c-0.6552,-0.72072 -1.44144,-1.11384 -2.48976,-1.11384c-0.91728,0 -1.638,0.26208 -2.16216,0.78624c-0.52416,0.52416 -0.72072,1.17936 -0.72072,1.90008c0,0.91728 0.3276,1.70352 0.9828,2.48976l10.8108,12.7764l-10.1556,12.71088c-0.6552,0.78624 -0.91728,1.57248 -0.91728,2.42424c0,0.78624 0.19656,1.44144 0.72072,1.9656c0.52416,0.52416 1.17936,0.78624 2.09664,0.78624c0.91728,0 1.70352,-0.3276 2.35872,-1.04832l9.89352,-12.4488l10.41768,12.4488c0.52416,0.72072 1.3104,1.04832 2.35872,1.04832c0.85176,0 1.57248,-0.26208 2.09664,-0.78624c0.52416,-0.52416 0.85176,-1.17936 0.85176,-1.9656z" id="path4607"/>
</g>
<image width="0" height="0" y="-350.55203" x="-306.10635" id="icon"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@@ -0,0 +1,56 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { useChatStore } from "@/views/app/chat/chatStore";
const chatStore = useChatStore();
const close = () => {
chatStore.apiKeyDialog = false;
};
const key = computed({
get: () => chatStore.apiKey,
set: (value) => {
chatStore.saveApiKey(value); // 假设您有一个名为setApiKey的Pinia store mutation
},
});
const apiKeyShow = ref(false);
</script>
<template>
<v-dialog v-model="chatStore.apiKeyDialog" width="600">
<v-card>
<v-card-title class="font-weight-bold pa-5">
Input your Api Key</v-card-title
>
<hr />
<v-card-text>
<v-label class="font-weight-medium mb-2 ml-2">YOUR API KEY</v-label>
<v-text-field
color="primary"
variant="outlined"
v-model="key"
class="px-2 py-1"
placeholder="If not input , the ApiKey in the .env will be used."
prepend-inner-icon="mdi-key"
autofocus
clearable
hide-details
@click:prepend-inner="apiKeyShow = !apiKeyShow"
></v-text-field>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn variant="flat" color="primary" @click="close">OK</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,65 @@
<template>
<v-card @click="$emit('edit')" class="pa-5 mt-4 card-shadow">
<div class="d-flex align-start font-weight-bold text-title">
<span class="flex-1">{{ card.title }}</span>
<v-menu location="bottom end" transition="slide-x-transition">
<template v-slot:activator="{ props }">
<v-btn
v-bind="props"
size="small"
variant="text"
icon="mdi-dots-vertical"
rounded
color="primary"
class="my-n2"
></v-btn>
</template>
<v-list density="compact">
<v-list-item @click="$emit('edit')">
<v-list-item-title class="d-inline-flex align-center">
<Icon
icon="flat-color-icons:edit-image"
:rotate="2"
:horizontalFlip="true"
:verticalFlip="true"
class="mr-1"
/>
<span> Edit</span>
</v-list-item-title>
</v-list-item>
<v-list-item @click="$emit('delete')">
<v-list-item-title class="d-inline-flex align-center">
<Icon
icon="flat-color-icons:full-trash"
:rotate="2"
:horizontalFlip="true"
:verticalFlip="true"
:inline="true"
class="mr-1"
/>
Delete</v-list-item-title
>
</v-list-item>
</v-list>
</v-menu>
</div>
<div class="text-content">{{ props.card.description }}</div>
</v-card>
</template>
<script setup lang="ts">
import { Icon } from "@iconify/vue";
const props = defineProps({
// Card content to display
card: {
type: Object,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped>
.card-shadow {
box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px !important;
}
</style>

View File

@@ -0,0 +1,35 @@
<template>
<v-breadcrumbs
v-if="breadcrumbs.length > 0"
:items="breadcrumbs"
class="ml-n3"
>
<!-- <template v-slot:prepend>
<v-icon size="small" icon="mdi-vuetify" color="blue"></v-icon>
</template> -->
</v-breadcrumbs>
</template>
<script setup lang="ts">
const route = useRoute();
const breadcrumbs = ref<any>([]);
watchEffect(() => {
// if you go to the redirect page, do not update the breadcrumbs
// if (route.path.startsWith('/redirect/')) {
// return
// }
if (route.meta && route.meta.title) {
breadcrumbs.value = [
{
title: route.meta.category,
disabled: false,
},
{ title: route.meta.title, disabled: true },
];
} else {
breadcrumbs.value = [];
}
});
</script>

View File

@@ -0,0 +1,217 @@
<script setup lang="ts">
import { useTheme } from "vuetify";
import { useCustomizeThemeStore } from "@/stores/customizeTheme";
import { Icon } from "@iconify/vue";
interface Color {
colorId: number;
colorName: string;
colorValue: string;
}
const customizeTheme = useCustomizeThemeStore();
const theme = useTheme();
const themeDrawer = ref(false);
const currentColor = ref<Color>({
colorId: 2,
colorName: "grey",
colorValue: "#344767",
});
const primaryColors = ref([
{
colorId: 1,
colorName: "purple",
colorValue: "#CB0C9F",
},
{
colorId: 2,
colorName: "grey",
colorValue: "#344767",
},
{
colorId: 3,
colorName: "info",
colorValue: "#17C1E8",
},
{
colorId: 4,
colorName: "success",
colorValue: "#82D616",
},
{
colorId: 5,
colorName: "warning",
colorValue: "#F2825A",
},
{
colorId: 6,
colorName: "error",
colorValue: "#EA0606",
},
]);
watch(currentColor, (newVal) => {
theme.themes.value.light.colors.primary = newVal.colorValue;
theme.themes.value.dark.colors.primary = newVal.colorValue;
customizeTheme.setPrimaryColor(newVal);
});
</script>
<template>
<div>
<div class="drawer-button" @click="themeDrawer = true">
<v-icon class="text-white">mdi-cog-outline</v-icon>
</div>
<v-navigation-drawer
v-model="themeDrawer"
location="right"
temporary
width="300"
class="theme-drawer pa-8"
>
<div class="top-area">
<div class="d-flex align-center">
<b>UI Configurator</b>
<v-spacer></v-spacer>
<v-btn
variant="text"
size="small"
rounded
icon="mdi-close"
@click="themeDrawer = false"
>
</v-btn>
</div>
<div>See our dashboard options.</div>
</div>
<hr class="my-6" />
<div class="theme-area">
<b>Global Theme Mode</b>
<div class="px-3 pt-3" v-if="customizeTheme.darkTheme">
<v-btn
@click="customizeTheme.darkTheme = !customizeTheme.darkTheme"
icon
color="grey-darken-4"
class="text-white"
>
<Icon width="30" icon="line-md:moon-filled-loop" />
</v-btn>
<span class="ml-5">Dark Mode</span>
</div>
<div class="px-3 pt-3" v-else>
<v-btn
@click="customizeTheme.darkTheme = !customizeTheme.darkTheme"
icon
color="white"
class="text-red"
>
<Icon
width="30"
icon="line-md:moon-filled-alt-to-sunny-filled-loop-transition"
/>
</v-btn>
<span class="ml-5">Light Mode</span>
</div>
</div>
<hr class="my-6" />
<div class="primary-color-area">
<b>Primary Colors</b>
<v-item-group
class="mt-3"
v-model="currentColor"
selected-class="elevation-12"
mandatory
>
<v-item
v-for="color in primaryColors"
:key="color.colorId"
:value="color"
v-slot="{ isSelected, toggle }"
>
<v-btn
@click="toggle"
class="text-white mr-1"
icon
size="30"
:color="color.colorValue"
>
<Icon width="22" v-if="isSelected" icon="line-md:confirm" />
</v-btn>
</v-item>
</v-item-group>
</div>
<hr class="my-6" />
<div class="">
<b>MiniSideBar</b>
<v-switch
color="primary"
class="ml-2"
hide-details
:label="`Mini: ${customizeTheme.miniSidebar}`"
></v-switch>
</div>
<hr class="my-6" />
<div>
<v-btn color="" class="gradient info" block size="large"
>Contact Me</v-btn
>
</div>
<div class="ml-5 mt-5 d-flex align-center">
<v-icon color="primary" class="mr-6">mdi-email-outline</v-icon>
<a href="mailto:yjkbako@gmail.com">yjkbako@gmail.com</a>
</div>
<div class="ml-5 d-flex align-center">
<img src="@/assets/wechat.jpg" alt="" />
</div>
</v-navigation-drawer>
</div>
</template>
<style lang="scss" scoped>
.drawer-button {
position: fixed;
background-color: #705cf6;
top: 340px;
right: 0px;
z-index: 999;
padding: 0.5rem 1rem;
border-top-left-radius: 0.5rem;
border-bottom-left-radius: 0.5rem;
box-shadow: 1px 1px 9px #705cf6;
transition: all 0.5s;
cursor: pointer;
&:hover {
box-shadow: 1px 1px 18px #705cf6;
transition: all 0.5s;
}
.v-icon {
font-size: 1.3rem;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
}
hr {
background-image: linear-gradient(
90deg,
transparent,
rgba(0, 0, 0, 0.4),
transparent
) !important;
background-color: transparent;
opacity: 0.25;
border: none;
height: 1px;
}
</style>

View File

@@ -0,0 +1,27 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { useAppStore } from "@/stores/appStore";
import Loading from "@/components/loading/Loading02.vue";
const appStore = useAppStore();
</script>
<template>
<v-card
v-if="appStore.globalLoading"
color="white"
class="global-loading d-flex align-center justify-center"
height="100vh"
>
<Loading />
</v-card>
</template>
<style scoped lang="scss">
.main-bg {
min-height: calc(100vh - 64px);
}
</style>

View File

@@ -1,59 +0,0 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View File

@@ -0,0 +1,15 @@
<template>
<h1 class="text-h4 mt-5">{{ title }}</h1>
</template>
<script setup lang="ts">
const route = useRoute();
const title = ref("");
watchEffect(() => {
if (route.meta && route.meta.title) {
title.value = route.meta.title as string;
}
});
</script>

View File

@@ -0,0 +1,122 @@
<!--
* @Component: BackToTop
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { Icon } from "@iconify/vue";
import ChatAssistant from "@/components/ai/ChatAssistant.vue";
import TranslationAssistant from "@/components/ai/TranslationAssistant.vue";
import { useChatStore } from "@/views/app/chat/chatStore";
import ApiKeyDialog from "@/components/ApiKeyDialog.vue";
const chatStore = useChatStore();
const toolboxShow = ref(false);
</script>
<template>
<v-btn
class="toolbox-activator elevation-10"
@click="toolboxShow = !toolboxShow"
size="50"
color="white"
>
<Icon width="30" icon="ri:openai-fill" />
</v-btn>
<transition name="slide-y">
<v-card
v-if="toolboxShow"
elevation="10"
class="d-flex flex-column mb-1 toolbox"
>
<!-- ---------------------------------------------- -->
<!-- Close Btn -->
<!-- ---------------------------------------------- -->
<v-btn
@click="toolboxShow = false"
variant="text"
size="50"
color="error"
>
<v-icon size="30">mdi-close</v-icon>
<v-tooltip
activator="parent"
location="left"
text="Close Toolbox"
></v-tooltip>
</v-btn>
<hr />
<!-- ---------------------------------------------- -->
<!-- ApiKey -->
<!-- ---------------------------------------------- -->
<v-btn
@click="chatStore.apiKeyDialog = true"
variant="text"
size="50"
color="blue"
>
<v-icon size="30">mdi-key-outline</v-icon>
<v-tooltip
activator="parent"
location="left"
:text="$t('toolbox.apikey.title')"
></v-tooltip>
</v-btn>
<ApiKeyDialog />
<hr />
<!-- ---------------------------------------------- -->
<!-- Chat Assistant -->
<!-- ---------------------------------------------- -->
<ChatAssistant />
<hr />
<!-- ---------------------------------------------- -->
<!-- Translation Assistant -->
<!-- ---------------------------------------------- -->
<TranslationAssistant />
<hr />
<!-- ---------------------------------------------- -->
<!-- Code Assistant -->
<!-- ---------------------------------------------- -->
<v-btn size="50">
<v-icon size="30">mdi-code-tags</v-icon>
<v-tooltip
activator="parent"
location="left"
:text="$t('toolbox.codeAssistant.title')"
></v-tooltip>
</v-btn>
<!-- ---------------------------------------------- -->
<!-- Code Assistant -->
<!-- ---------------------------------------------- -->
<v-btn size="50" to="/playground">
<v-icon size="30">mdi-seesaw</v-icon>
<v-tooltip
activator="parent"
location="left"
:text="$t('toolbox.playGround.title')"
></v-tooltip>
</v-btn>
</v-card>
</transition>
</template>
<style scoped lang="scss">
.toolbox {
z-index: 999;
position: fixed;
bottom: 150px;
right: 20px;
}
.toolbox-activator {
position: fixed;
transition: all 0.3s ease;
bottom: 100px;
right: 20px;
z-index: 999;
padding: 0.5rem;
border-radius: 0.5rem;
transition: all 0.3s;
cursor: pointer;
}
</style>

View File

@@ -0,0 +1,69 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { useDisplay } from "vuetify";
import InputArea from "@/views/app/chat/components/InputArea.vue";
import MessageArea from "@/views/app/chat/components/MessageArea.vue";
const dialog = ref(false);
const { xs } = useDisplay();
</script>
<template>
<v-btn size="50" @click="dialog = !dialog">
<v-icon size="30">mdi-chat-outline </v-icon>
<v-tooltip
activator="parent"
location="left"
:text="$t('toolbox.chatAssistant.title')"
></v-tooltip>
</v-btn>
<teleport to="body">
<transition name="slide-y">
<v-card
v-if="dialog"
class="dialog-bottom d-flex flex-column"
:width="xs ? '100%' : '600px'"
height="500px"
>
<v-card-title>
<span class="flex-1">
<v-avatar size="40">
<img
src="https://img.icons8.com/color/96/null/filled-chat.png"
alt="alt"
/>
</v-avatar>
OpenAi Chat
</span>
<v-spacer></v-spacer>
<v-btn icon @click.stop="dialog = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<hr />
<v-card-text class="overflow-scroll">
<MessageArea />
</v-card-text>
<hr />
<v-card-actions>
<InputArea />
</v-card-actions>
</v-card>
</transition>
</teleport>
</template>
<style scoped lang="scss">
.dialog-bottom {
z-index: 999;
position: fixed;
bottom: 10px;
right: 0px;
}
</style>

View File

@@ -0,0 +1,354 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { createTranscriptionApi } from "@/api/aiApi";
import { useChatStore } from "@/views/app/chat/chatStore";
import CopyBtn from "@/components/common/CopyBtn.vue";
import { useDisplay } from "vuetify";
import { read } from "@/utils/aiUtils";
import { useSnackbarStore } from "@/stores/snackbarStore";
const snackbarStore = useSnackbarStore();
const chatStore = useChatStore();
const langs = [
{
code: "en",
name: "English",
label: "English",
},
{
code: "zh-CN",
name: "Chinese Simplified",
label: "中文(简体)",
},
{
code: "zh-TW",
name: "Chinese Traditional",
label: "中文(繁體)",
},
{
code: "ja",
name: "Japanese",
label: "日本語",
},
{
code: "ko",
name: "Korean",
label: "한국어",
},
{
code: "fr",
name: "French",
label: "Français",
},
{
code: "de",
name: "German",
label: "Deutsch",
},
{
code: "es",
name: "Spanish",
label: "Español",
},
];
const currentLang = ref({
code: "en",
name: "English",
label: "English",
});
const setLang = (lang: any) => {
currentLang.value = lang;
};
const baseContent = ref("");
const targetContent = ref("");
const prompt = computed(() => {
return `Translate into ${currentLang.value.name}`;
// return `I want you to act as an ${currentLangName.value} translator, spelling corrector and improver. I will speak to you in any language and you will detect the language, translate it and answer in the corrected and improved version of my text, in ${currentLang.value.name}. I want you to replace my simplified A0-level words and sentences with more beautiful and elegant, upper level ${currentLang.value.name} words and sentences. Keep the meaning same, but make them more literary. I want you to only reply the correction, the improvements and nothing else, do not write explanations.”`;
});
const isLoading = ref(false);
const translate = async () => {
if (baseContent.value === "") {
snackbarStore.showErrorMessage("请输入要翻译的内容");
return;
}
if (!chatStore.getApiKey) {
snackbarStore.showErrorMessage("请先输入API KEY");
return;
}
isLoading.value = true;
try {
const completion = await fetch(
"https://api.openai.com/v1/chat/completions",
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${chatStore.getApiKey}`,
},
method: "POST",
body: JSON.stringify({
messages: [
{ role: "user", content: prompt.value },
{ role: "user", content: baseContent.value },
],
model: "gpt-3.5-turbo",
stream: true,
}),
}
);
// Handle errors
if (!completion.ok) {
const errorData = await completion.json();
snackbarStore.showErrorMessage(errorData.error.message);
isLoading.value = false;
return;
}
// Create a reader
const reader = completion.body?.getReader();
if (!reader) {
snackbarStore.showErrorMessage("Cannot read the stream.");
isLoading.value = false;
}
// Clear the target content
targetContent.value = "";
// Read the stream
read(reader, targetContent);
} catch (error) {
snackbarStore.showErrorMessage(error.message);
}
isLoading.value = false;
};
const isBaseContentEmpty = ref(false);
const recorder = ref<any>();
const isRecording = ref(false);
const startRecording = async () => {
// 获取用户媒体权限,视频的话参数{audio: true, video: true}
navigator.mediaDevices
.getUserMedia({ audio: true })
.then((stream) => {
// 创建媒体流
recorder.value = new MediaRecorder(stream);
const audioChunks = <any>[];
// 录音开始
recorder.value.start();
isRecording.value = true;
// 录音数据
recorder.value.ondataavailable = (e: any) => {
audioChunks.push(e.data);
};
// 录音结束
recorder.value.onstop = async (e: any) => {
const blob = new Blob(audioChunks, { type: "audio/wav" });
const file = new File([blob], "recording.wav", {
type: "audio/wav",
});
const formData = new FormData();
formData.append("file", file);
formData.append("model", "whisper-1");
const res = await createTranscriptionApi(formData, chatStore.getApiKey);
baseContent.value = res.data.text;
};
})
.catch((error) => {
snackbarStore.showErrorMessage(error.message);
});
};
const stopRecording = () => {
if (recorder.value) {
recorder.value.stop();
isRecording.value = false;
}
};
const record = () => {
if (isRecording.value) {
stopRecording();
} else {
startRecording();
}
};
const dialog = ref(false);
const { xs } = useDisplay();
</script>
<template>
<v-btn size="50" @click="dialog = !dialog">
<v-icon size="30">mdi-google-translate</v-icon>
<v-tooltip
activator="parent"
location="left"
:text="$t('toolbox.translationAssistant.title')"
></v-tooltip>
</v-btn>
<teleport to="body">
<transition name="slide-y">
<v-card
v-if="dialog"
class="dialog-bottom d-flex flex-column"
:width="xs ? '100%' : '600px'"
>
<v-card-title>
<span class="flex-1">
<v-avatar size="40">
<img src="https://img.icons8.com/color/96/null/translation.png" />
</v-avatar>
OpenAi {{ $t("toolbox.translationAssistant.title") }}
</span>
<v-spacer></v-spacer>
<v-btn icon @click.stop="dialog = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<hr />
<v-card-actions class="px-5">
<span class="text-body-2"
>{{ $t("toolbox.translationAssistant.targetLanguage") }}:</span
>
<!-- <v-btn-toggle
v-model="currentLang"
density="compact"
variant="outlined"
color="primary"
mandatory
>
<v-btn
density="compact"
size="small"
v-for="lang in langs"
:value="lang.code"
>
{{ lang.label }}
</v-btn>
</v-btn-toggle> -->
<v-menu location="bottom end" scroll-y>
<template v-slot:activator="{ props }">
<v-btn width="108" append-icon="mdi-menu-down" v-bind="props">
<span class="text-body-2">{{ currentLang.label }}</span>
</v-btn>
</template>
<v-card>
<div v-for="lang in langs">
<v-btn block @click="setLang(lang)">{{ lang.label }}</v-btn>
</div>
</v-card>
</v-menu>
<v-spacer></v-spacer>
<v-btn
class="ml-2 text-white"
:loading="isLoading"
:disabled="isLoading"
variant="elevated"
color="primary"
@click="translate"
>{{ $t("toolbox.translationAssistant.translate") }}</v-btn
>
</v-card-actions>
<hr />
<v-card-text>
<v-row no-gutters justify="center" dense>
<v-col cols="12">
<v-card elevation="0">
<div class="pa-2">
<v-textarea
v-model="baseContent"
placeholder="Enter the text to be translated"
hide-details
variant="solo"
class="elevation-1"
color="white"
clearable
@focus="isBaseContentEmpty = false"
></v-textarea>
</div>
<v-card-actions class="bg-grey-lighten-4 text-primary">
<v-tooltip
location="bottom"
:text="$t('toolbox.translationAssistant.speech')"
>
<template #activator="{ props }">
<v-btn @click="record" v-bind="props" icon>
<v-icon v-if="isRecording">mdi-microphone</v-icon>
<v-icon v-else>mdi-microphone-outline</v-icon>
</v-btn>
</template>
</v-tooltip>
<v-tooltip
location="bottom"
:text="$t('toolbox.translationAssistant.read')"
>
<template #activator="{ props }">
<v-btn v-bind="props" icon
><v-icon>mdi-volume-high</v-icon>
</v-btn>
</template>
</v-tooltip>
<v-spacer></v-spacer>
<CopyBtn :text="baseContent" />
</v-card-actions>
</v-card>
</v-col>
<v-col cols="12">
<v-card elevation="0">
<div class="pa-2">
<v-textarea
v-model="targetContent"
hide-details
variant="solo"
class="elevation-1"
color="primary"
clearable
></v-textarea>
</div>
<v-card-actions
class="bg-grey-lighten-4 bg-grey-lighten-4 text-primary"
>
<v-tooltip
location="bottom"
:text="$t('toolbox.translationAssistant.read')"
>
<template #activator="{ props }">
<v-btn @click="" v-bind="props" icon
><v-icon>mdi-volume-high</v-icon>
</v-btn>
</template>
</v-tooltip>
<v-spacer></v-spacer>
<CopyBtn :text="targetContent" />
</v-card-actions> </v-card
></v-col> </v-row
></v-card-text>
<hr />
</v-card>
</transition>
</teleport>
</template>
<style scoped lang="scss">
.dialog-bottom {
z-index: 999;
position: fixed;
bottom: 10px;
right: 0px;
}
</style>

View File

@@ -0,0 +1,18 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { Vue3Lottie } from "vue3-lottie";
</script>
<template>
<Vue3Lottie
animationLink="https://assets2.lottiefiles.com/packages/lf20_cr9slsdh.json"
:height="500"
:width="500"
/>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,31 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { Vue3Lottie } from "vue3-lottie";
const props = defineProps({
size: {
type: Number,
default: 400,
},
});
watch(
() => props.size,
(newSize) => {
console.log(newSize);
}
);
</script>
<template>
<Vue3Lottie
animationLink="https://assets6.lottiefiles.com/packages/lf20_ofa3xwo7.json"
:height="size"
:width="size"
/>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,18 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { Vue3Lottie } from "vue3-lottie";
</script>
<template>
<Vue3Lottie
animationLink="https://assets4.lottiefiles.com/packages/lf20_zrqthn6o.json"
:height="400"
:width="400"
/>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,157 @@
const themeColors = ["#ee8a6a", "#0cb9c5", "#fec90f", "#05b187", "#fc4b6c"];
const themeColors2 = ["#4782FB", "#47C4F4", "#fec90f", "#05b187", "#fc4b6c"];
function generateDataHeatMap(count: any, yrange: any) {
var i = 0;
var series: any[] = [];
while (i < count) {
var x = "w" + (i + 1).toString();
var y =
Math.floor(Math.random() * (yrange.max - yrange.min + 1)) + yrange.min;
series.push({
x: x,
y: y,
});
i++;
}
return series;
}
export const heatMapChart = {
series: [
{
name: "Metric1",
data: generateDataHeatMap(18, {
min: 0,
max: 90,
}),
},
{
name: "Metric2",
data: generateDataHeatMap(18, {
min: 0,
max: 90,
}),
},
{
name: "Metric3",
data: generateDataHeatMap(18, {
min: 0,
max: 90,
}),
},
{
name: "Metric4",
data: generateDataHeatMap(18, {
min: 0,
max: 90,
}),
},
{
name: "Metric5",
data: generateDataHeatMap(18, {
min: 0,
max: 90,
}),
},
{
name: "Metric6",
data: generateDataHeatMap(18, {
min: 0,
max: 90,
}),
},
{
name: "Metric7",
data: generateDataHeatMap(18, {
min: 0,
max: 90,
}),
},
],
chartOptions: {
dataLabels: {
enabled: false,
},
colors: ["#1e88e5"],
tooltip: {
theme: "dark",
},
},
};
export const lineAreaChartSpline = {
series: [
{
name: "Open Rate",
data: [0, 5, 6, 8, 25, 9, 8, 24],
},
{
name: "Recurring Payments",
data: [0, 3, 1, 2, 8, 1, 5, 1],
},
],
chartOptions: {
grid: {
show: true,
borderColor: "rgba(0, 0, 0, .3)",
strokeDashArray: 3,
xaxis: {
lines: {
show: true,
},
},
yaxis: {
lines: {
show: true,
},
},
},
dataLabels: {
enabled: false,
},
chart: {
toolbar: {
show: true,
},
},
stroke: {
curve: "smooth",
width: 2,
},
colors: themeColors2,
fill: {
type: "gradient",
opacity: ["0.1", "0.1"],
},
xaxis: {
categories: ["1", "2", "3", "4", "5", "6", "7", "8"],
labels: {
style: {
cssClass: "grey--text lighten-2--text fill-color",
},
},
},
yaxis: {
labels: {
style: {
cssClass: "grey--text lighten-2--text fill-color",
},
},
},
markers: {
size: 3,
},
tooltip: {
x: {
format: "dd/MM/yy HH:mm",
},
theme: "dark",
},
legend: {
show: false,
},
},
};

View File

@@ -0,0 +1,19 @@
<!--
* @Component: ApexHeatMapCharts
* @Maintainer: J.K. Yang
* @Description: ApexHeatMapCharts
-->
<script setup lang="ts">
import { heatMapChart } from "./ApexChartsData";
</script>
<template>
<div class="">ApexHeatMapCharts</div>
<apexchart
type="heatmap"
height="310"
:options="heatMapChart.chartOptions"
:series="heatMapChart.series"
></apexchart>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,19 @@
<!--
* @Component: ApexLineAreaCharts
* @Maintainer: J.K. Yang
* @Description: ApexLineAreaCharts
-->
<script setup lang="ts">
import { lineAreaChartSpline } from "./ApexChartsData";
</script>
<template>
<h1 class="pl-5">ApexLineAreaCharts</h1>
<apexchart
type="area"
height="350"
:options="lineAreaChartSpline.chartOptions"
:series="lineAreaChartSpline.series"
></apexchart>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,58 @@
<!--
* @Component: BackToTop
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { Icon } from "@iconify/vue";
const isVisible = ref(false);
const handleScroll = () => {
isVisible.value = window.scrollY > 200;
};
onMounted(() => {
window.addEventListener("scroll", handleScroll);
});
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: "smooth" });
};
</script>
<template>
<div class="back-to-top" :class="{ visible: isVisible }" @click="scrollToTop">
<Icon class="text-white" width="30" icon="ph:rocket-light" />
</div>
</template>
<style scoped lang="scss">
.back-to-top {
position: fixed;
background-color: #705cf6;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
bottom: 50px;
right: 20px;
z-index: 999;
padding: 0.5rem;
border-radius: 0.5rem;
box-shadow: 1px 1px 9px #705cf6;
transition: all 0.5s;
cursor: pointer;
&:hover {
box-shadow: 1px 1px 18px #705cf6;
transition: all 0.5s;
}
}
.back-to-top.visible {
opacity: 1;
visibility: visible;
}
</style>

View File

@@ -0,0 +1,56 @@
<!--
* @Component: CopyLabel
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { useClipboard } from "@vueuse/core";
const { copy } = useClipboard();
// SnackBar
const snackbar = ref(false);
const timeout = ref("1000");
const copiedText = "Copied to clipboard!";
// Props
const props = defineProps({
// Text to copy to clipboard
text: {
type: String,
default: "",
},
});
// Copy Text
const copyText = () => {
console.log(props.text);
copy(props.text);
snackbar.value = true;
};
</script>
<template>
<div>
<v-snackbar v-model="snackbar" :timeout="timeout">
{{ copiedText }}
<template v-slot:actions>
<v-btn color="blue" variant="text" @click="snackbar = false">
Close
</v-btn>
</template>
</v-snackbar>
<v-btn v-bind="$attrs" icon @click="copyText()"
><v-icon>mdi-content-copy</v-icon>
<v-tooltip activator="parent" location="bottom" text="Copy"></v-tooltip>
</v-btn>
</div>
</template>
<style scoped lang="scss">
.text {
cursor: pointer;
display: inline-block;
}
</style>

View File

@@ -0,0 +1,74 @@
<!--
* @Component: CopyLabel
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { useClipboard } from "@vueuse/core";
const { copy } = useClipboard();
// ToolTip
const tooltip = ref("Copy");
// SnackBar
const snackbar = ref(false);
const timeout = ref("1000");
const copiedText = "Copied to clipboard!";
// Copy Animation Flag
const heartBeat = ref(false);
// Props
const props = defineProps({
// Text to copy to clipboard
text: {
type: String,
default: "",
},
});
const { text } = toRefs(props);
// Copy Text
const copyText = (text: string) => {
copy(text);
heartBeat.value = true;
snackbar.value = true;
tooltip.value = "Copied!";
setTimeout(() => {
heartBeat.value = false;
tooltip.value = "Copy!";
}, 1000);
};
</script>
<template>
<v-snackbar v-model="snackbar" :timeout="timeout">
{{ copiedText }}
<template v-slot:actions>
<v-btn color="blue" variant="text" @click="snackbar = false">
Close
</v-btn>
</template>
</v-snackbar>
<v-tooltip location="bottom">
<template v-slot:activator="{ props }">
<span
:class="{
heartBeat: heartBeat === true,
}"
class="text"
v-bind="props"
@click.stop.prevent="copyText(text)"
>
{{ text }}
</span>
</template>
<span>{{ tooltip }}</span>
</v-tooltip>
</template>
<style scoped lang="scss">
.text {
cursor: pointer;
display: inline-block;
border-bottom: 1px dashed;
}
</style>

View File

@@ -0,0 +1,28 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
defineProps({
value: {
type: Number,
default: 0,
},
});
</script>
<template>
<span>
<span v-if="value === 0"> {{ value }}% </span>
<span v-else-if="value > 0" class="text-success">
<v-icon small color="success">mdi-arrow-top-right</v-icon> {{ value }}%
</span>
<span v-else class="error--text">
<v-icon small color="error">mdi-arrow-bottom-right</v-icon>
{{ Math.abs(value) }}%
</span>
</span>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import { useSnackbarStore } from "@/stores/snackbarStore";
const snackbarStore = useSnackbarStore();
const getIcon = (type) => {
const icon = {
info: "mdi-information",
success: "mdi-check-circle",
error: "mdi-alert-circle",
warning: "mdi-alert",
};
return icon[type];
};
</script>
<template>
<div>
<v-snackbar
v-model="snackbarStore.isShow"
timeout="2000"
:color="snackbarStore.type"
class="elevation-10"
location="top"
multi-line
>
<div class="d-flex align-center">
<v-icon class="mr-2">{{ getIcon(snackbarStore.type) }}</v-icon>
<span> {{ snackbarStore.message }}</span>
</div>
<template v-slot:actions>
<v-btn icon variant="text" @click="snackbarStore.isShow = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</template>
</v-snackbar>
</div>
</template>

View File

@@ -0,0 +1,204 @@
<script setup lang="ts">
import { Icon } from "@iconify/vue";
import { getPublicEventsApi } from "@/api/githubApi";
import moment from "moment";
const loading = ref(false);
const username = ref("yangjiakai");
const activityList = ref([
{
id: 1,
type: "PushEvent",
user: "yangjiakai",
avatar: "https://avatars.githubusercontent.com/u/35951244?",
repo: "yangjiakai/lux-admin-vuetify3",
content: "Update Readme",
created_at: "2023-04-06T16:01:30Z",
},
{
id: 2,
type: "IssuesEvent",
user: "yangjiakai",
avatar: "https://avatars.githubusercontent.com/u/35951244?",
repo: "yangjiakai/lux-admin-vuetify3",
content: "全局的配置管理比如dev配置和pro配置隔离开",
created_at: "2023-04-06T16:01:30Z",
},
]);
const getPublicEvent = async () => {
loading.value = true;
const response = await getPublicEventsApi(username.value);
activityList.value = response.data.map((activity) => {
return {
id: activity.id,
type: activity.type,
user: activity.actor.display_login,
avatar: activity.actor.avatar_url,
repo: activity.repo?.name,
content: getContent(activity),
action:
activity.type === "IssuesEvent" ? activity.payload.action : "Commit",
created_at: activity.created_at,
};
});
setTimeout(() => {
loading.value = false;
}, 1000);
};
const getContent = (activity: any) => {
if (activity.type === "PushEvent") {
return convertToHtml(activity.payload.commits[0].message);
} else if (activity.type === "CreateEvent") {
return activity.payload.ref_type;
} else if (activity.type === "IssuesEvent") {
return activity.payload.issue.title;
} else {
return "";
}
};
const convertToHtml = (text) => {
const lines = text.split("\n");
let html = "";
lines.forEach((line) => {
if (line.startsWith("- ")) {
html += `<div><span class='mr-1'>✅</span> ${line.slice(2)}</div>`;
} else if (line.trim() === "") {
html += "<br/>";
} else {
html += `<p>${line}</p>`;
}
});
return html;
};
const getTagColor = (activity: any) => {
if (activity.type === "PushEvent") {
return "green";
} else if (activity.type === "IssuesEvent") {
return "red";
} else {
return "blue";
}
};
onMounted(() => {
getPublicEvent();
});
</script>
<template>
<!-- loading spinner -->
<div
v-if="loading"
class="h-full d-flex flex-grow-1 align-center justify-center"
>
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
<div v-else>
<h6 class="text-h6 pa-5 d-flex align-center">
<span class="flex-1 font-weight-bold">Github Activity</span>
<v-menu location="bottom end" transition="slide-x-transition">
<template v-slot:activator="{ props }">
<v-btn
v-bind="props"
size="small"
variant="text"
icon="mdi-dots-vertical"
rounded
color="primary"
class="my-n2"
></v-btn>
</template>
<v-list density="compact">
<v-list-item @click="$emit('edit')">
<v-list-item-title class="d-inline-flex align-center">
<Icon
icon="flat-color-icons:refresh"
:rotate="2"
:horizontalFlip="true"
:verticalFlip="true"
class="mr-1"
/>
<span> Refresh</span>
</v-list-item-title>
</v-list-item>
<v-list-item @click="$emit('delete')">
<v-list-item-title class="d-inline-flex align-center">
<Icon
icon="icon-park:clear-format"
:rotate="2"
:horizontalFlip="true"
:verticalFlip="true"
:inline="true"
class="mr-1"
/>
Clear</v-list-item-title
>
</v-list-item>
</v-list>
</v-menu>
</h6>
<perfect-scrollbar class="timeline-container">
<v-timeline
class="time-line text-body-2"
density="compact"
side="end"
truncate-line="start"
>
<v-timeline-item
v-for="activity in activityList"
:key="activity.id"
size="small"
>
<template v-slot:icon>
<v-avatar>
<img :src="activity.avatar" />
</v-avatar>
</template>
<template v-slot:opposite>
<span>{{ moment(activity.created_at).format("MM,DD hh:mm") }}</span>
</template>
<div class="mb-1">
<span class="text-h6 font-weight-bold">
{{ activity.user }}
</span>
<span class="ml-2 text-grey">{{
moment(activity.created_at).format("MM,DD hh:mm")
}}</span>
</div>
<v-card width="500">
<v-card-subtitle class="pt-4">
<v-chip
:color="getTagColor(activity)"
size="small"
label
class="mr-2 font-weight-bold"
>
<span>{{ activity.type }}</span>
</v-chip>
<span class="text-body-2">{{ activity.repo }}</span>
</v-card-subtitle>
<v-card-text>
<div v-html="activity.content"></div>
</v-card-text>
</v-card>
</v-timeline-item>
</v-timeline>
</perfect-scrollbar>
</div>
</template>
<style lang="scss" scoped>
.timeline-container {
height: 360px;
overflow: scroll;
}
.time-line {
margin-left: 60px;
}
</style>

View File

@@ -0,0 +1,31 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import BarChart1 from "@/views/chart/component/BarChart1.vue";
const loading = ref(true);
onMounted(() => {
setTimeout(() => {
loading.value = false;
}, 1000);
});
</script>
<template>
<!-- loading spinner -->
<div
v-if="loading"
class="h-full d-flex flex-grow-1 align-center justify-center"
>
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
<div v-else>
<h6 class="text-h6 d-flex align-center font-weight-bold">
<span class="pa-5">Chart</span>
</h6>
<v-card class="" variant="flat">
<BarChart1 />
</v-card>
</div>
</template>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,176 @@
<script lang="ts" setup>
import moment from "moment";
import { useTheme } from "vuetify";
import { formatCurrency } from "@/utils/formatCurrency";
import PercentTrend from "@/components/common/PercentTrend.vue";
const formatDate = (date: string) => {
return date ? moment(date).format("D MMM") : "";
};
const props = defineProps({
value: {
type: Number,
default: 0,
},
percentage: {
type: Number,
default: 0,
},
percentageLabel: {
type: String,
default: "vs. last week",
},
series: {
type: Array,
default: () => [
{
name: "Sales",
data: [11, 32, 45, 13],
},
],
},
xaxis: {
type: Object,
default: () => ({
type: "category",
categories: [
"2018-09-19T00:00:00.000Z",
"2018-09-20T00:00:00.000Z",
"2018-09-22T00:00:00.000Z",
"2018-09-23T00:00:00.000Z",
],
// tickAmount: 3
}),
},
label: {
type: String,
default: "dashboard.sales",
},
actionLabel: {
type: String,
default: "View Report",
},
options: {
type: Object,
default: () => ({}),
},
});
const { themes, current } = useTheme();
const chartOptions = computed(() => {
const primaryColor = current.value.dark
? themes.value["dark"].colors.primary
: themes.value["light"].colors.primary;
return {
chart: {
height: 120,
type: "area",
sparkline: {
enabled: true,
},
animations: {
speed: 400,
},
},
series: props.series,
colors: [primaryColor],
fill: {
type: "solid",
colors: [primaryColor],
opacity: 0.15,
},
stroke: {
curve: "smooth",
width: 2,
},
xaxis: props.xaxis,
tooltip: {
followCursor: true,
theme: "dark",
custom: function ({ ctx, series, seriesIndex, dataPointIndex, w }: any) {
const seriesName = w.config.series[seriesIndex].name;
return `<div class="rounded-lg pa-1 text-caption">
<div class="font-weight-bold">${formatDate(
w.globals.categoryLabels[dataPointIndex]
)}</div>
<div>${series[seriesIndex][dataPointIndex]} ${seriesName}</div>
</div>`;
},
},
...props.options,
};
});
const loading = ref(true);
onMounted(() => {
setTimeout(() => {
loading.value = false;
}, 1000);
});
</script>
<template>
<v-card class="d-flex flex-grow-1 bg-primary-darken-4 pa-3" theme="dark">
<!-- loading spinner -->
<div v-if="loading" class="d-flex flex-grow-1 align-center justify-center">
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
<!-- information -->
<div v-else class="d-flex flex-column flex-grow-1">
<v-card-title class="d-flex">
<div class="font-weight-bold">{{ $t(label) }}</div>
<v-spacer></v-spacer>
<v-btn
variant="text"
color="primary"
class="font-weight-bold"
@click="$emit('action-clicked')"
>{{ actionLabel }}</v-btn
>
</v-card-title>
<div class="d-flex flex-column flex-grow-1">
<div class="pa-2">
<div class="text-h4">
{{ formatCurrency(26358.49) }}
</div>
<div class="text-primary mt-1">
{{ formatCurrency(7123.21) }}
{{ $t("dashboard.lastweek") }}
</div>
</div>
<v-spacer></v-spacer>
<div class="px-2 pb-2">
<div class="title mb-1 font-weight-bold">
{{ $t("dashboard.weeklySales") }}
</div>
<div class="d-flex align-center">
<div class="text-h4">
{{ formatCurrency(value) }}
</div>
<v-spacer></v-spacer>
<div class="d-flex flex-column text-right">
<div class="font-weight-bold">
<percent-trend :value="percentage" />
</div>
<div class="text-caption">{{ percentageLabel }}</div>
</div>
</div>
</div>
</div>
<apexchart
type="area"
height="120"
:options="chartOptions"
:series="series"
></apexchart>
</div>
</v-card>
</template>

View File

@@ -0,0 +1,81 @@
<template>
<h6 class="text-h6 pa-5 d-flex align-center">
<span class="flex-1 font-weight-bold">Traffic Sources</span>
</h6>
<v-chart class="chart" :option="option" autoresize />
</template>
<script setup lang="ts">
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { PieChart } from "echarts/charts";
import {
TitleComponent,
TooltipComponent,
LegendComponent,
} from "echarts/components";
import VChart from "vue-echarts";
use([
CanvasRenderer,
PieChart,
TitleComponent,
TooltipComponent,
LegendComponent,
]);
const option = ref({
color: ["#73BFB8", "#3BA2D5", "#2364AA", "#FEC601", "#0096C7"],
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)",
},
legend: {
// orient: "vertical",
top: "0%",
left: "center",
data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"],
},
series: [
{
name: "Access From",
type: "pie",
radius: ["40%", "70%"],
center: ["50%", "50%"],
data: [
{ value: 335, name: "Direct" },
{ value: 310, name: "Email" },
{ value: 234, name: "Ad Networks" },
{ value: 135, name: "Video Ads" },
{ value: 1548, name: "Search Engines" },
],
label: {
show: false,
position: "center",
},
labelLine: {
show: false,
},
emphasis: {
label: {
show: true,
fontSize: 20,
fontWeight: "bold",
},
},
itemStyle: {
borderRadius: 2,
borderColor: "#fff",
borderWidth: 2,
},
},
],
});
</script>
<style lang="scss" scoped>
.chart {
height: 360px;
}
</style>

View File

@@ -0,0 +1,158 @@
<script setup lang="ts">
import CopyLabel from "@/components/common/CopyLabel.vue";
const loading = ref(true);
const headers = [
{ text: "Order Id", align: "start", value: "id" },
{
text: "User",
sortable: false,
value: "user",
},
{ text: "Date", value: "date" },
{ text: "Company", value: "company" },
{ text: "Amount", value: "amount" },
{ text: "Status", value: "status" },
{ text: "", sortable: false, align: "right", value: "action" },
];
const items = [
{
id: "2837",
user: {
name: "John Simon",
email: "johnsimon@blobhill.com",
avatar: "https://i.pravatar.cc/150?img=1",
},
date: "2020-05-10",
company: "BlobHill",
amount: 52877,
status: "PAID",
},
{
id: "2838",
user: {
name: "Greg Cool J",
email: "cool@caprimooner.com",
avatar: "https://i.pravatar.cc/150?img=2",
},
date: "2020-05-11",
company: "Caprimooner",
amount: 2123,
status: "PENDING",
},
{
id: "2839",
user: {
name: "Samantha Bush",
email: "bush@catloveisstilllove.com",
avatar: "https://i.pravatar.cc/150?img=3",
},
date: "2020-05-11",
company: "CatLovers",
amount: 12313,
status: "PENDING",
},
{
id: "2840",
user: {
name: "Ben Howard",
email: "ben@indiecoolers.com",
avatar: "https://i.pravatar.cc/150?img=4",
},
date: "2020-05-12",
company: "IndieCoolers",
amount: 9873,
status: "PAID",
},
{
id: "2841",
user: {
name: "Jack Candy",
email: "jack@candylooove.com",
avatar: "https://i.pravatar.cc/150?img=5",
},
date: "2020-05-13",
company: "CandyLooove",
amount: 29573,
status: "PAID",
},
];
const open = (item) => {};
onMounted(() => {
setTimeout(() => {
loading.value = false;
}, 1000);
});
</script>
<template>
<!-- loading spinner -->
<div
v-if="loading"
class="h-full d-flex flex-grow-1 align-center justify-center"
>
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
<div v-else>
<h6 class="text-h6 px-5 pt-5 d-flex align-center font-weight-bold">
<span class="flex-1 font-weight-bold">Table</span>
</h6>
<perfect-scrollbar style="height: 400px">
<v-table class="pa-3">
<thead>
<tr>
<th v-for="header in headers" :key="header.text">
{{ header.text }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td class="font-weight-bold">
<copy-label :text="`# ${item.id}`" />
</td>
<td>
<div class="d-flex align-center py-2">
<v-avatar size="40" class="elevation-1 grey lighten-3">
<img :src="item.user.avatar" />
</v-avatar>
<div class="ml-1">
<div class="font-weight-bold">{{ item.user.name }}</div>
<div class="text-caption">
<copy-label :text="item.user.email" />
</div>
</div>
</div>
</td>
<td>{{ item.date }}</td>
<td>{{ item.company }}</td>
<td>{{ item.amount }}</td>
<td class="font-weight-bold">
<div v-if="item.status === 'PENDING'">
<v-icon size="small" color="warning">mdi-circle-medium</v-icon>
<span>Pending</span>
</div>
<div v-if="item.status === 'PAID'">
<v-icon size="small" color="success">mdi-circle-medium</v-icon>
<span>Paid</span>
</div>
</td>
<td>
<v-btn
size="small"
variant="text"
icon="mdi-open-in-new"
@click="open(item)"
>
</v-btn>
</td>
</tr>
</tbody>
</v-table>
</perfect-scrollbar>
</div>
</template>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,176 @@
<script setup lang="ts">
import CopyLabel from "@/components/common/CopyLabel.vue";
const loading = ref(true);
const headers = [
{ text: "Ticket Id", align: "start", value: "id" },
{
text: "User",
sortable: false,
value: "user",
},
{ text: "Priority", value: "priority" },
{ text: "Status", value: "status" },
{ text: "Create Date", value: "date" },
{ text: "", sortable: false, align: "right", value: "action" },
];
const items = [
{
id: "423",
user: {
name: "John Simon",
email: "johnsimon@blobhill.com",
avatar: "https://i.pravatar.cc/150?img=1",
},
date: "2020-05-10",
priority: "Low",
status: "OPEN",
},
{
id: "424",
user: {
name: "Greg Cool J",
email: "cool@caprimooner.com",
avatar: "https://i.pravatar.cc/150?img=2",
},
date: "2020-05-11",
priority: "High",
status: "CLOSED",
},
{
id: "425",
user: {
name: "Samantha Bush",
email: "bush@catloveisstilllove.com",
avatar: "https://i.pravatar.cc/150?img=3",
},
date: "2020-05-11",
priority: "Low",
status: "CLOSED",
},
{
id: "426",
user: {
name: "Ben Howard",
email: "ben@indiecoolers.com",
avatar: "https://i.pravatar.cc/150?img=4",
},
date: "2020-05-12",
priority: "Low",
status: "OPEN",
},
{
id: "427",
user: {
name: "Jack Candy",
email: "jack@candylooove.com",
avatar: "https://i.pravatar.cc/150?img=5",
},
date: "2020-05-13",
priority: "High",
status: "OPEN",
},
];
const open = (item) => {};
onMounted(() => {
setTimeout(() => {
loading.value = false;
}, 1000);
});
</script>
<template>
<!-- loading spinner -->
<div
v-if="loading"
class="h-full d-flex flex-grow-1 align-center justify-center"
>
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
<div v-else>
<h6 class="text-h6 font-weight-bold pa-5 d-flex align-center">
<span class="flex-1">Ticket</span>
</h6>
<v-table class="pa-3">
<thead>
<tr>
<th class="text-left" v-for="header in headers" :key="header.text">
{{ header.text }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td class="font-weight-bold">
<copy-label :text="`# ${item.id}`" />
</td>
<td>
<copy-label :text="item.user.email" />
</td>
<td>
<v-chip
size="small"
:color="item.priority === 'High' ? 'pink' : 'primary'"
class="font-weight-bold"
>
{{ item.priority }}</v-chip
>
</td>
<td class="font-weight-bold">
<div v-if="item.status === 'CLOSED'" class="text-secondary">
<v-icon size="small" color="secondary">mdi-circle-medium</v-icon>
<span>Closed</span>
</div>
<div v-if="item.status === 'OPEN'" class="text-success">
<v-icon size="small" color="success">mdi-circle-medium</v-icon>
<span>Open</span>
</div>
</td>
<td>{{ item.date }}</td>
<td>
<v-btn
elevation="4"
variant="elevated"
size="small"
@click="open(item)"
>
Open Text
</v-btn>
</td>
</tr>
</tbody>
</v-table>
</div>
</template>
<style lang="scss" scoped>
.v-table {
table {
padding: 4px;
padding-bottom: 8px;
th {
text-transform: uppercase;
white-space: nowrap;
}
td {
border-bottom: 0 !important;
}
tbody {
tr {
transition: box-shadow 0.2s, transform 0.2s;
&:not(.v-data-table__selected):hover {
box-shadow: 0 3px 15px -2px rgba(0, 0, 0, 0.12);
transform: translateY(-4px);
}
}
}
}
}
</style>

View File

@@ -0,0 +1,110 @@
<script setup lang="ts">
import { useTodoStore } from "@/views/app/todo/todoStore";
const todoStore = useTodoStore();
const loading = ref(true);
onMounted(() => {
setTimeout(() => {
loading.value = false;
}, 1000);
});
const searchKey = ref("");
const filterdTodoList = computed(() => {
return todoStore.getTodoList.filter((todo) => {
return todo.title.toLowerCase().includes(searchKey.value.toLowerCase());
});
});
const getLabelColor = (id: string) => {
// Find the label by id from the labels array
const label = todoStore.labels.find((l) => l.id === id);
// Return the color for that label, or an empty string
return label ? label.color : "";
};
</script>
<template>
<!-- loading spinner -->
<div
v-if="loading"
class="h-full d-flex flex-grow-1 align-center justify-center"
>
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
<div v-else>
<v-text-field
clearable
variant="solo"
class="elevation-1 ma-3"
hide-details
prepend-inner-icon="mdi-magnify"
placeholder="Filter Tasks"
v-model="searchKey"
></v-text-field>
<perfect-scrollbar class="todo-list">
<transition-group name="fade">
<div v-for="todo in filterdTodoList" :key="todo.id">
<div class="todo-item d-flex align-center pa-5">
<v-checkbox-btn
v-model="todo.completed"
color="primary"
class="pe-2"
></v-checkbox-btn>
<v-avatar size="40">
<v-img
src="https://avatars.githubusercontent.com/u/35951244?v=4"
alt="alt"
/>
</v-avatar>
<div class="flex-1 mx-5">
<div
class="font-weight-bold"
:class="todo.completed ? 'text-decoration-line-through' : ''"
>
{{ todo.title }}
</div>
<div
:class="todo.completed ? 'text-decoration-line-through' : ''"
>
{{ todo.detail }}
</div>
<div>
<v-chip
size="x-small"
variant="outlined"
class="mr-1 mt-1"
:color="getLabelColor(tag)"
v-for="tag in todo.tags"
>
{{ tag }}
</v-chip>
</div>
</div>
<v-btn
icon="mdi-delete-outline"
variant="text"
@click="todoStore.deleteTodoById(todo.id)"
></v-btn>
</div>
</div>
</transition-group>
</perfect-scrollbar>
</div>
</template>
<style lang="scss" scoped>
.todo-list {
max-height: 400px;
overflow: scroll;
.todo-item {
transition: all 0.3s;
&:hover {
transition: all 0.3s;
background-color: rgba(99, 99, 99, 0.2);
box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px !important;
cursor: pointer;
}
}
}
</style>

View File

@@ -0,0 +1,180 @@
<template>
<!-- loading spinner -->
<div
v-if="loading"
class="h-full d-flex flex-grow-1 align-center justify-center"
>
<v-progress-circular indeterminate color="primary"></v-progress-circular>
</div>
<div v-else>
<h6 class="text-h6 pa-5 d-flex align-center">
<span class="flex-1">Table</span>
</h6>
<v-table class="pa-3">
<thead>
<tr>
<th class="text-left" v-for="header in headers" :key="header.text">
{{ header.text }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td>#{{ item.id }}</td>
<td>
<div class="d-flex align-center py-1">
<v-avatar size="40" class="elevation-1 grey lighten-3">
<img :src="item.user.avatar" />
</v-avatar>
<div class="ml-1">
<div class="font-weight-bold">{{ item.user.name }}</div>
<div class="caption">
{{ item.user.email }}
</div>
</div>
</div>
</td>
<td>{{ item.date }}</td>
<td>{{ item.company }}</td>
<td>{{ item.amount }}</td>
<td>
<div v-if="item.status === 'PENDING'" class="text-warning">
<v-icon size="small" color="warning">mdi-circle-medium</v-icon>
<span>Pending</span>
</div>
<div v-if="item.status === 'PAID'" class="text-success">
<v-icon size="small" color="success">mdi-circle-medium</v-icon>
<span>Paid</span>
</div>
</td>
<td>
<v-btn
size="small"
variant="text"
icon="mdi-open-in-new"
@click="open(item)"
>
</v-btn>
</td>
</tr>
</tbody>
</v-table>
</div>
</template>
<script setup lang="ts">
const loading = ref(true);
const headers = [
{ text: "Order Id", align: "start", value: "id" },
{
text: "User",
sortable: false,
value: "user",
},
{ text: "Date", value: "date" },
{ text: "Company", value: "company" },
{ text: "Amount", value: "amount" },
{ text: "Status", value: "status" },
{ text: "", sortable: false, align: "right", value: "action" },
];
const items = [
{
id: "2837",
user: {
name: "John Simon",
email: "johnsimon@blobhill.com",
avatar: "https://i.pravatar.cc/150?img=1",
},
date: "2020-05-10",
company: "BlobHill",
amount: 52877,
status: "PAID",
},
{
id: "2838",
user: {
name: "Greg Cool J",
email: "cool@caprimooner.com",
avatar: "https://i.pravatar.cc/150?img=2",
},
date: "2020-05-11",
company: "Caprimooner",
amount: 2123,
status: "PENDING",
},
{
id: "2839",
user: {
name: "Samantha Bush",
email: "bush@catloveisstilllove.com",
avatar: "https://i.pravatar.cc/150?img=3",
},
date: "2020-05-11",
company: "CatLovers",
amount: 12313,
status: "PENDING",
},
{
id: "2840",
user: {
name: "Ben Howard",
email: "ben@indiecoolers.com",
avatar: "https://i.pravatar.cc/150?img=4",
},
date: "2020-05-12",
company: "IndieCoolers",
amount: 9873,
status: "PAID",
},
{
id: "2841",
user: {
name: "Jack Candy",
email: "jack@candylooove.com",
avatar: "https://i.pravatar.cc/150?img=5",
},
date: "2020-05-13",
company: "CandyLooove",
amount: 29573,
status: "PAID",
},
];
const open = (item) => {};
onMounted(() => {
setTimeout(() => {
loading.value = false;
}, 1000);
});
</script>
<style lang="scss" scoped>
.v-table {
table {
padding: 4px;
padding-bottom: 8px;
th {
text-transform: uppercase;
white-space: nowrap;
}
td {
border-bottom: 0 !important;
}
tbody {
tr {
transition: box-shadow 0.2s, transform 0.2s;
&:not(.v-data-table__selected):hover {
box-shadow: 0 3px 15px -2px rgba(0, 0, 0, 0.12);
transform: translateY(-4px);
}
}
}
}
}
</style>

View File

@@ -0,0 +1,91 @@
<template>
<span class="loader"></span>
</template>
<script setup lang="ts"></script>
<style scoped>
.loader {
width: 48px;
height: 48px;
display: inline-block;
position: relative;
transform: rotate(45deg);
}
.loader::before {
content: "";
box-sizing: border-box;
width: 24px;
height: 24px;
position: absolute;
left: 0;
top: -24px;
animation: animloader 4s ease infinite;
}
.loader::after {
content: "";
box-sizing: border-box;
position: absolute;
left: 0;
top: 0;
width: 24px;
height: 24px;
background: rgba(255, 255, 255, 0.85);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
animation: animloader2 2s ease infinite;
}
@keyframes animloader {
0% {
box-shadow: 0 24px rgba(255, 255, 255, 0), 24px 24px rgba(255, 255, 255, 0),
24px 48px rgba(255, 255, 255, 0), 0px 48px rgba(255, 255, 255, 0);
}
12% {
box-shadow: 0 24px white, 24px 24px rgba(255, 255, 255, 0),
24px 48px rgba(255, 255, 255, 0), 0px 48px rgba(255, 255, 255, 0);
}
25% {
box-shadow: 0 24px white, 24px 24px white, 24px 48px rgba(255, 255, 255, 0),
0px 48px rgba(255, 255, 255, 0);
}
37% {
box-shadow: 0 24px white, 24px 24px white, 24px 48px white,
0px 48px rgba(255, 255, 255, 0);
}
50% {
box-shadow: 0 24px white, 24px 24px white, 24px 48px white, 0px 48px white;
}
62% {
box-shadow: 0 24px rgba(255, 255, 255, 0), 24px 24px white, 24px 48px white,
0px 48px white;
}
75% {
box-shadow: 0 24px rgba(255, 255, 255, 0), 24px 24px rgba(255, 255, 255, 0),
24px 48px white, 0px 48px white;
}
87% {
box-shadow: 0 24px rgba(255, 255, 255, 0), 24px 24px rgba(255, 255, 255, 0),
24px 48px rgba(255, 255, 255, 0), 0px 48px white;
}
100% {
box-shadow: 0 24px rgba(255, 255, 255, 0), 24px 24px rgba(255, 255, 255, 0),
24px 48px rgba(255, 255, 255, 0), 0px 48px rgba(255, 255, 255, 0);
}
}
@keyframes animloader2 {
0% {
transform: translate(0, 0) rotateX(0) rotateY(0);
}
25% {
transform: translate(100%, 0) rotateX(0) rotateY(180deg);
}
50% {
transform: translate(100%, 100%) rotateX(-180deg) rotateY(180deg);
}
75% {
transform: translate(0, 100%) rotateX(-180deg) rotateY(360deg);
}
100% {
transform: translate(0, 0) rotateX(0) rotateY(360deg);
}
}
</style>

View File

@@ -0,0 +1,68 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts"></script>
<template>
<span class="loader"></span>
</template>
<style scoped lang="scss">
.loader {
width: 200px;
height: 140px;
background: #979794;
box-sizing: border-box;
position: relative;
border-radius: 8px;
perspective: 1000px;
}
.loader:before {
content: "";
position: absolute;
left: 10px;
right: 10px;
top: 10px;
bottom: 10px;
border-radius: 8px;
background: #f5f5f5 no-repeat;
background-size: 60px 10px;
background-image: linear-gradient(#ddd 100px, transparent 0),
linear-gradient(#ddd 100px, transparent 0),
linear-gradient(#ddd 100px, transparent 0),
linear-gradient(#ddd 100px, transparent 0),
linear-gradient(#ddd 100px, transparent 0),
linear-gradient(#ddd 100px, transparent 0);
background-position: 15px 30px, 15px 60px, 15px 90px, 105px 30px, 105px 60px,
105px 90px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);
}
.loader:after {
content: "";
position: absolute;
width: calc(50% - 10px);
right: 10px;
top: 10px;
bottom: 10px;
border-radius: 8px;
background: #fff no-repeat;
background-size: 60px 10px;
background-image: linear-gradient(#ddd 100px, transparent 0),
linear-gradient(#ddd 100px, transparent 0),
linear-gradient(#ddd 100px, transparent 0);
background-position: 50% 30px, 50% 60px, 50% 90px;
transform: rotateY(0deg);
transform-origin: left center;
animation: paging 1s linear infinite;
}
@keyframes paging {
to {
transform: rotateY(-180deg);
}
}
</style>

View File

@@ -0,0 +1,70 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts"></script>
<template>
<span class="loader"></span>
</template>
<style scoped lang="scss">
.loader {
width: 48px;
height: 48px;
margin: auto;
position: relative;
}
.loader:before {
content: "";
width: 48px;
height: 5px;
background: #000;
opacity: 0.25;
position: absolute;
top: 60px;
left: 0;
border-radius: 50%;
animation: shadow 0.5s linear infinite;
}
.loader:after {
content: "";
width: 100%;
height: 100%;
background: #29b6f6;
animation: bxSpin 0.5s linear infinite;
position: absolute;
top: 0;
left: 0;
border-radius: 4px;
}
@keyframes bxSpin {
17% {
border-bottom-right-radius: 3px;
}
25% {
transform: translateY(9px) rotate(22.5deg);
}
50% {
transform: translateY(18px) scale(1, 0.9) rotate(45deg);
border-bottom-right-radius: 40px;
}
75% {
transform: translateY(9px) rotate(67.5deg);
}
100% {
transform: translateY(0) rotate(90deg);
}
}
@keyframes shadow {
0%,
100% {
transform: scale(1, 1);
}
50% {
transform: scale(1.2, 1);
}
}
</style>

View File

@@ -0,0 +1,104 @@
<script setup lang="ts">
import { useCustomizeThemeStore } from "@/stores/customizeTheme";
const customizeTheme = useCustomizeThemeStore();
const props = defineProps({
// Data
menu: {
type: Array<any>,
default: () => [],
},
});
onMounted(() => {});
</script>
<template>
<v-list nav dense color="primary">
<template v-for="menuArea in props.menu" :key="menuArea.key">
<div
v-if="!customizeTheme.miniSidebar && (menuArea.key || menuArea.text)"
class="pa-1 mt-2 text-overline"
>
{{ menuArea.key ? $t(menuArea.key) : menuArea.text }}
</div>
<template v-if="menuArea.items">
<template v-for="menuItem in menuArea.items" :key="menuItem.key">
<!-- menu level 1 -->
<v-list-item
v-if="!menuItem.items"
:to="menuItem.link"
:prepend-icon="menuItem.icon || 'mdi-circle-medium'"
:active-class="`active-nav-${customizeTheme.primaryColor.colorName}`"
density="compact"
>
<v-list-item-title
v-text="menuItem.key ? $t(menuItem.key) : menuItem.text"
></v-list-item-title>
</v-list-item>
<v-list-group v-else :value="menuItem.items">
<!-- subMenu activator -->
<template v-slot:activator="{ props }">
<v-list-item
v-bind="props"
:prepend-icon="menuItem.icon || 'mdi-circle-medium'"
:title="menuItem.key ? $t(menuItem.key) : menuItem.text"
>
</v-list-item>
</template>
<!-- menu level 2 -->
<v-list-item
v-for="subMenuItem in menuItem.items"
:key="subMenuItem.key"
:prepend-icon="subMenuItem.icon || 'mdi-circle-medium'"
:title="subMenuItem.key ? $t(subMenuItem.key) : subMenuItem.text"
:to="subMenuItem.link"
density="compact"
></v-list-item>
</v-list-group>
</template>
</template>
</template>
</v-list>
</template>
<style scoped>
.v-list-group .v-list-item {
padding-left: 8px !important;
}
.active-nav-grey {
border-left: 5px solid;
border-image-slice: 1;
border-image-source: linear-gradient(to bottom, #3a456c, #a4abbb);
}
.active-nav-purple {
border-left: 5px solid;
border-image-slice: 1;
border-image-source: linear-gradient(to bottom, #e82893, #954bcb);
}
.active-nav-info {
border-left: 5px solid;
border-image-slice: 1;
border-image-source: linear-gradient(to bottom, #487afa, #3fc7f3);
}
.active-nav-success {
border-left: 5px solid;
border-image-slice: 1;
border-image-source: linear-gradient(to bottom, #45b95b, #96dd4c);
}
.active-nav-warning {
border-left: 5px solid;
border-image-slice: 1;
border-image-source: linear-gradient(to bottom, #f0635d, #edc252);
}
.active-nav-error {
border-left: 5px solid;
border-image-slice: 1;
border-image-source: linear-gradient(to bottom, #ea373a, #f07285);
}
</style>

View File

@@ -0,0 +1,99 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import configs from "@/configs";
import MainMenu from "@/components/navigation/MainMenu.vue";
import { useCustomizeThemeStore } from "@/stores/customizeTheme";
import { Icon } from "@iconify/vue";
const customizeTheme = useCustomizeThemeStore();
const navigation = ref(configs.navigation);
const openGithubSite = () => {
window.open("https://github.com/yangjiakai", "_blank");
};
</script>
<template>
<v-navigation-drawer
v-model="customizeTheme.mainSidebar"
elevation="1"
id="mainMenu"
>
<!-- ---------------------------------------------- -->
<!---Top Area -->
<!-- ---------------------------------------------- -->
<template v-if="!customizeTheme.miniSidebar" v-slot:prepend>
<v-card
elevation="0"
height="100"
class="d-flex align-center justify-center"
>
<img
v-if="customizeTheme.darkTheme"
width="200"
src="@/assets/logo_dark.svg"
alt=""
/>
<img
v-else="customizeTheme.darkTheme"
width="200"
src="@/assets/logo_light.svg"
alt=""
/>
</v-card>
</template>
<!-- ---------------------------------------------- -->
<!---Nav List -->
<!-- ---------------------------------------------- -->
<perfect-scrollbar class="scrollnav">
<main-menu :menu="navigation.menu"></main-menu>
</perfect-scrollbar>
<!-- ---------------------------------------------- -->
<!---Bottom Area -->
<!-- ---------------------------------------------- -->
<template v-if="!customizeTheme.miniSidebar" v-slot:append>
<v-card theme="dark" height="225" class="pa-3" variant="text">
<v-card
class="d-flex flex-column gradient pa-2"
:class="customizeTheme.primaryColor.colorName"
height="200"
>
<v-card-title>
<v-btn
class="mr-2"
size="40"
color="white"
:class="`text-${customizeTheme.primaryColor.colorName}`"
icon
>
<Icon width="30" icon="line-md:github-loop" />
</v-btn>
Yang J.K.
</v-card-title>
<v-card-subtitle> </v-card-subtitle>
<v-card-text>
<div><b>Github:</b></div>
<div>github.com/yangjiakai</div>
</v-card-text>
<v-card-actions>
<v-btn
color="white"
block
prepend-icon="mdi-thumb-up-outline"
variant="elevated"
@click="openGithubSite"
>
Star-Me
</v-btn>
</v-card-actions>
</v-card>
</v-card>
</template>
</v-navigation-drawer>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,75 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import { useCustomizeThemeStore } from "@/stores/customizeTheme";
import ToolbarLanguage from "@/components/toolbar/ToolbarLanguage.vue";
import ToolbarNotifications from "./ToolbarNotifications.vue";
import ToolbarUser from "./ToolbarUser.vue";
import { useTodoStore } from "@/views/app/todo/todoStore";
const todoStore = useTodoStore();
const customizeTheme = useCustomizeThemeStore();
const showMobileSearch = ref(false);
</script>
<template>
<!-- ---------------------------------------------- -->
<!--App Bar -->
<!-- ---------------------------------------------- -->
<v-app-bar>
<!-- search input mobile -->
<div class="d-flex flex-grow-1 align-center" v-if="showMobileSearch">
<v-text-field
color="primary"
class="elevation-1"
variant="solo"
prepend-inner-icon="mdi-magnify"
append-inner-icon="mdi-close"
@click:append-inner="showMobileSearch = false"
hide-details
placeholder="Search"
></v-text-field>
</div>
<div v-else class="d-flex flex-grow-1 align-center">
<v-app-bar-nav-icon
@click="customizeTheme.mainSidebar = !customizeTheme.mainSidebar"
></v-app-bar-nav-icon>
<v-toolbar-title></v-toolbar-title>
<v-spacer></v-spacer>
<v-btn class="d-block d-md-none" icon @click="showMobileSearch = true">
<v-icon>mdi-magnify</v-icon>
</v-btn>
<!-- search input desktop -->
<v-text-field
color="primary"
class="d-none d-md-block elevation-1"
variant="solo"
prepend-inner-icon="mdi-magnify"
hide-details
placeholder="Search"
></v-text-field>
<v-btn class="text-none" stacked>
<v-badge dot color="success">
<v-icon>mdi-account-multiple-outline</v-icon>
</v-badge>
</v-btn>
<v-btn to="/apps/todo" class="text-none" stacked>
<v-badge :content="`${todoStore.getTodoList.length} +`" color="error">
<v-icon>mdi-calendar-check</v-icon>
</v-badge>
</v-btn>
<ToolbarLanguage />
<ToolbarNotifications />
<ToolbarUser />
</div>
</v-app-bar>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,84 @@
<!--
* @Component:
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
interface UserStatus {
code: string;
name: string;
label: string;
color: string;
}
const userStatusList = [
{
code: "online",
name: "us",
label: "Online",
color: "success",
},
{
code: "away",
name: "cn",
label: "Away",
color: "warning",
},
{
code: "busy",
name: "jp",
label: "Busy",
color: "error",
},
{
code: "offline",
name: "kr",
label: "Offline",
color: "grey",
},
];
const currentStatus = ref<UserStatus>({
code: "online",
name: "us",
label: "Online",
color: "success",
});
const setStatus = (status: string) => {
currentStatus.value = userStatusList.find(
(userStatus) => userStatus.code === status
) as UserStatus;
};
</script>
<template>
<v-menu scroll-y :close-on-content-click="false">
<template v-slot:activator="{ props }">
<v-btn
width="60"
variant="text"
size="small"
v-bind="props"
:color="currentStatus.color"
>
{{ currentStatus.label }}
</v-btn>
</template>
<v-list elevation="1">
<v-list-item
v-for="status in userStatusList"
:key="status.code"
@click="setStatus(status.code)"
density="compact"
>
<v-list-item-title class="text-body-2">
<v-icon size="small" :color="status.color">mdi-circle-medium</v-icon>
{{ status.label }}</v-list-item-title
>
</v-list-item>
</v-list>
</v-menu>
</template>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,43 @@
<template>
<v-menu scroll-y>
<template v-slot:activator="{ props }">
<v-btn width="100" v-bind="props">
<Icon :icon="`twemoji:flag-${currentLocale.name}`" class="mr-2" />
<span class="text-body-2">{{ currentLocale.label }}</span>
</v-btn>
</template>
<v-list elevation="1" nav>
<v-list-item
v-for="locale in availableLocaleList"
:key="locale.code"
@click="setLocale(locale.code)"
density="compact"
>
<template v-slot:prepend>
<Icon :icon="`twemoji:flag-${locale.name}`" class="mr-2" />
</template>
<v-list-item-title> {{ locale.label }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</template>
<script setup lang="ts">
import config from "@/configs";
import { Icon } from "@iconify/vue";
import { useLocale } from "vuetify";
const { current } = useLocale();
const { availableLocales } = config.locales;
const availableLocaleList = computed(() => {
return availableLocales.filter((item) => item.code !== current.value);
});
const currentLocale = computed(() => {
return availableLocales.filter((item) => item.code === current.value)[0];
});
const setLocale = (locale) => {
current.value = locale;
};
</script>

View File

@@ -0,0 +1,107 @@
<!--
* @Component: ToolbarNotifications
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
const messages = [
{
title: "Brunch this weekend?",
color: "primary",
icon: "mdi-account-circle",
subtitle:
"Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sint, repudiandae?",
time: "3 min",
},
{
title: "Summer BBQ",
color: "success",
icon: "mdi-email-outline",
subtitle:
"Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sint, repudiandae?",
time: "3 min",
},
{
title: "Oui oui",
color: "teal lighten-1",
icon: "mdi-airplane-landing",
subtitle:
"Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sint, repudiandae?",
time: "4 min",
},
{
title: "Disk capacity is at maximum",
color: "teal accent-3",
icon: "mdi-server",
subtitle:
"Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sint, repudiandae?",
time: "3 hr",
},
{
title: "Recipe to try",
color: "blue-grey lighten-2",
icon: "mdi-noodles",
subtitle:
"Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sint, repudiandae?",
time: "8 hr",
},
];
</script>
<template>
<v-menu location="bottom right" transition="slide-y-transition">
<!-- ---------------------------------------------- -->
<!-- Activator Btn -->
<!-- ---------------------------------------------- -->
<template v-slot:activator="{ props }">
<v-btn icon v-bind="props" class="text-none">
<v-badge content="2" color="error">
<v-icon>mdi-bell-outline</v-icon>
</v-badge>
</v-btn>
</template>
<v-list elevation="1" lines="three" density="compact" max-width="400">
<v-list-subheader>Notifications</v-list-subheader>
<v-list-item v-for="(message, i) in messages" :key="i" @click="">
<!-- ---------------------------------------------- -->
<!-- Prepend-->
<!-- ---------------------------------------------- -->
<template v-slot:prepend>
<v-avatar size="40" :color="message.color">
<v-icon color="white">{{ message.icon }}</v-icon>
</v-avatar>
</template>
<!-- ---------------------------------------------- -->
<!-- Append-->
<!-- ---------------------------------------------- -->
<template v-slot:append>
<div class="full-h d-flex align-center">
<span class="text-body-2 text-grey"> {{ message.time }}</span>
</div>
</template>
<!-- ---------------------------------------------- -->
<!-- Main Content-->
<!-- ---------------------------------------------- -->
<div>
<v-list-item-title class="font-weight-bold text-primary">{{
message.title
}}</v-list-item-title>
<v-list-item-subtitle>{{ message.subtitle }}</v-list-item-subtitle>
</div>
</v-list-item>
<!-- ---------------------------------------------- -->
<!-- See all Btn-->
<!-- ---------------------------------------------- -->
<div class="text-center py-5">
<v-btn size="small" variant="elevated" elevation="1"> See all </v-btn>
</div>
</v-list>
</v-menu>
</template>
<style scoped lang="scss">
// ::v-deep .v-list-item__append,
// ::v-deep .v-list-item__prepend {
// height: 100%;
// }
</style>

View File

@@ -0,0 +1,176 @@
<!--
* @Component: ToolbarNotifications
* @Maintainer: J.K. Yang
* @Description:
-->
<script setup lang="ts">
import StatusMenu from "./StatusMenu.vue";
import { useAuthStore } from "@/stores/authStore";
import { useRouter } from "vue-router";
const router = useRouter();
const authStore = useAuthStore();
const handleLogout = () => {
authStore.logout();
console.log("---");
console.log(router);
};
const navs = [
{
title: "Profile Details",
key: "menu.profileDetails",
link: "/profile",
icon: "mdi-account-box-outline",
},
{
title: "Plans and Billing",
key: "menu.plansAndBilling",
link: "/plans-and-billing",
icon: "mdi-credit-card-outline",
},
{
title: "Team",
key: "menu.team",
link: "/team",
icon: "mdi-account-group-outline",
},
{
title: "API Dashboard",
key: "menu.apiDashboard",
link: "/api-dashboard",
icon: "mdi-monitor-dashboard",
},
{
title: "Integrations",
key: "menu.integrations",
link: "/integrations",
icon: "mdi-puzzle-outline",
},
{
title: "Ask the Community",
key: "menu.askCommunity",
link: "/ask-the-community",
icon: "mdi-help-circle-outline",
},
];
</script>
<template>
<v-menu
:close-on-content-click="false"
location="bottom right"
transition="slide-y-transition"
>
<!-- ---------------------------------------------- -->
<!-- Activator Btn -->
<!-- ---------------------------------------------- -->
<template v-slot:activator="{ props }">
<v-btn class="mx-2" icon v-bind="props">
<v-badge content="2" color="success" dot bordered>
<v-avatar size="40">
<v-img
src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwrAiMevuwrbU9o0Ck2paVf4ufHUDb2dU48MEDrAlrQw&s"
></v-img>
</v-avatar>
</v-badge>
</v-btn>
</template>
<v-card max-width="300">
<v-list lines="three" density="compact">
<!-- ---------------------------------------------- -->
<!-- Profile Area -->
<!-- ---------------------------------------------- -->
<v-list-item to="/profile">
<template v-slot:prepend>
<v-avatar size="40">
<v-img
src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwrAiMevuwrbU9o0Ck2paVf4ufHUDb2dU48MEDrAlrQw&s"
></v-img>
</v-avatar>
</template>
<v-list-item-title class="font-weight-bold text-primary">
YANG J.K.
<StatusMenu />
</v-list-item-title>
<v-list-item-subtitle>
<!-- {{ $store.state.user.email }} -->
yjkbako@gmail.com
</v-list-item-subtitle>
</v-list-item>
</v-list>
<hr />
<!-- ---------------------------------------------- -->
<!-- Menu Area -->
<!-- ---------------------------------------------- -->
<v-list variant="flat" elevation="0" :lines="false" density="compact">
<v-list-item
color="primary"
v-for="(nav, i) in navs"
:key="i"
:to="nav.link"
link
density="compact"
>
<template v-slot:prepend>
<v-avatar size="30">
<v-icon>{{ nav.icon }}</v-icon>
</v-avatar>
</template>
<div>
<v-list-item-subtitle class="text-body-2">{{
nav.title
}}</v-list-item-subtitle>
</div>
</v-list-item>
</v-list>
<hr />
<!-- ---------------------------------------------- -->
<!-- Logout Area -->
<!-- ---------------------------------------------- -->
<v-list variant="flat" elevation="0" :lines="false" density="compact">
<v-list-item color="primary" to="nav.link" link density="compact">
<template v-slot:prepend>
<v-avatar size="30">
<v-icon>mdi-lifebuoy</v-icon>
</v-avatar>
</template>
<div>
<v-list-item-subtitle class="text-body-2">
Help Center
</v-list-item-subtitle>
</div>
</v-list-item>
<v-list-item
color="primary"
link
@click="handleLogout"
density="compact"
>
<template v-slot:prepend>
<v-avatar size="30">
<v-icon>mdi-logout</v-icon>
</v-avatar>
</template>
<div>
<v-list-item-subtitle class="text-body-2">
Logout
</v-list-item-subtitle>
</div>
</v-list-item>
</v-list>
</v-card>
</v-menu>
</template>
<style scoped lang="scss">
// ::v-deep .v-list-item__append,
// ::v-deep .v-list-item__prepend {
// height: 100%;
// }
</style>

View File

@@ -0,0 +1,34 @@
const config: CurrencyConfig.Config = {
currency: {
label: "USD",
decimalDigits: 2,
decimalSeparator: ".",
thousandsSeparator: ",",
currencySymbol: "$",
currencySymbolNumberOfSpaces: 0,
currencySymbolPosition: "left",
},
availableCurrencies: [
{
label: "USD",
decimalDigits: 2,
decimalSeparator: ".",
thousandsSeparator: ",",
currencySymbol: "$",
currencySymbolNumberOfSpaces: 0,
currencySymbolPosition: "left",
},
{
label: "EUR",
decimalDigits: 2,
decimalSeparator: ".",
thousandsSeparator: ",",
currencySymbol: "€",
currencySymbolNumberOfSpaces: 1,
currencySymbolPosition: "right",
},
],
};
export default config;

View File

@@ -0,0 +1,14 @@
import navigation from "./navigation";
import locales from "./locales";
import currency from "./currencies";
export default {
// product display information
product: {
name: "ChopperBot",
version: "1.0.0",
},
navigation,
locales,
currency,
};

Some files were not shown because too many files have changed in this diff Show More