mirror of
https://github.com/rubickCenter/rubick
synced 2025-12-24 11:31:44 +08:00
✨ 支持ui插件下载&运行
This commit is contained in:
@@ -1,30 +1,87 @@
|
||||
<template>
|
||||
<div id="nav">
|
||||
<router-link to="/">Home</router-link> |
|
||||
<router-link to="/about">About</router-link>
|
||||
<div class="main-container">
|
||||
<div class="slider-bar">
|
||||
<div class="top">
|
||||
<div class="menu-item avatar">
|
||||
<a-avatar shape="square" :size="30">
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</div>
|
||||
<div class="menu-item" @click="changeMenu('market')">
|
||||
<AppstoreOutlined :class="active === 'market' && 'active'" style="font-size: 24px;" />
|
||||
</div>
|
||||
<div class="menu-item" @click="changeMenu('installed')">
|
||||
<HeartOutlined :class="active === 'installed' && 'active'" style="font-size: 24px;" />
|
||||
</div>
|
||||
<div class="menu-item" @click="changeMenu('settings')">
|
||||
<SettingOutlined :class="active === 'installed' && 'active'" style="font-size: 24px;" />
|
||||
</div>
|
||||
<div class="menu-item" @click="changeMenu('dev')">
|
||||
<BugOutlined :class="active === 'installed' && 'active'" style="font-size: 24px;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="menu-item bottom" @click="changeMenu('more')">
|
||||
<MenuOutlined style="font-size: 24px;" />
|
||||
</div>
|
||||
</div>
|
||||
<router-view />
|
||||
</div>
|
||||
<router-view />
|
||||
</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 { ref } from "vue";
|
||||
import { HeartOutlined, UserOutlined, SearchOutlined, MenuOutlined, AppstoreOutlined, SettingOutlined, BugOutlined } from "@ant-design/icons-vue";
|
||||
|
||||
const active = ref("market");
|
||||
|
||||
</script>
|
||||
<style lang="less">
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#nav {
|
||||
padding: 30px;
|
||||
}
|
||||
.main-container {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
background: #F2EFEF;
|
||||
|
||||
#nav a {
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
}
|
||||
.slider-bar {
|
||||
-webkit-app-region: drag;
|
||||
width: 60px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding-top: 15px;
|
||||
height: 100vh;
|
||||
background-image: linear-gradient(to top right, rgba(255, 159, 180, 0.3), rgba(255, 159, 180, 0.2));
|
||||
color: #7D7170;
|
||||
box-sizing: border-box;
|
||||
|
||||
#nav a.router-link-exact-active {
|
||||
color: #42b983;
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
cursor: pointer;
|
||||
margin-bottom: 40px;
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
.active {
|
||||
color: #ff4ea4;
|
||||
}
|
||||
|
||||
&.avatar {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
5
feature/src/assets/ant-reset.less
Normal file
5
feature/src/assets/ant-reset.less
Normal file
@@ -0,0 +1,5 @@
|
||||
@import '~ant-design-vue/dist/antd.less'; // 引入官方提供的 less 样式入口文件
|
||||
|
||||
@primary-color: #ff4ea4; // 全局主色
|
||||
@link-color: #ff4ea4; // 链接色
|
||||
@error-color: #ff4ea4; // 错误色
|
||||
17
feature/src/assets/request/index.ts
Normal file
17
feature/src/assets/request/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
async getTotalPlugins() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/total-plugins.json"
|
||||
);
|
||||
return res.data;
|
||||
},
|
||||
|
||||
async getFinderDetail() {
|
||||
const res = await axios.get(
|
||||
"https://gitee.com/monkeyWang/rubick-database/raw/master/plugins/finder.json"
|
||||
);
|
||||
return res.data;
|
||||
},
|
||||
};
|
||||
@@ -1,140 +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>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>eslint</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>typescript</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 lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
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>
|
||||
@@ -1,6 +1,8 @@
|
||||
import { createApp } from "vue";
|
||||
import Antd from "ant-design-vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
import "./assets/ant-reset.less";
|
||||
|
||||
createApp(App).use(store).use(router).mount("#app");
|
||||
createApp(App).use(store).use(Antd).use(router).mount("#app");
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
|
||||
import Home from "../views/Home.vue";
|
||||
import Market from "../views/market/index.vue";
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/",
|
||||
name: "Home",
|
||||
component: Home,
|
||||
},
|
||||
{
|
||||
path: "/about",
|
||||
name: "About",
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (about.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "about" */ "../views/About.vue"),
|
||||
},
|
||||
name: "Market",
|
||||
component: Market,
|
||||
}
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
|
||||
2
feature/src/shims-vue.d.ts
vendored
2
feature/src/shims-vue.d.ts
vendored
@@ -4,3 +4,5 @@ declare module '*.vue' {
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
|
||||
declare module 'axios'
|
||||
|
||||
@@ -1,8 +1,73 @@
|
||||
import { createStore } from "vuex";
|
||||
import request from "@/assets/request";
|
||||
|
||||
const isDownload = (item: any, targets: any[]) => {
|
||||
let isDownload = false;
|
||||
targets.some((plugin) => {
|
||||
if (plugin.name === item.name) {
|
||||
isDownload = true;
|
||||
}
|
||||
return isDownload;
|
||||
});
|
||||
return isDownload;
|
||||
};
|
||||
|
||||
export default createStore({
|
||||
state: {},
|
||||
mutations: {},
|
||||
actions: {},
|
||||
state: {
|
||||
totalPlugins: [],
|
||||
localPlugins: [],
|
||||
},
|
||||
mutations: {
|
||||
commonUpdate(state: any, payload) {
|
||||
Object.keys(payload).forEach((key) => {
|
||||
state[key] = payload[key];
|
||||
});
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async init({ commit }) {
|
||||
const totalPlugins = await request.getTotalPlugins();
|
||||
const localPlugins = (window as any).rubick.getLocalPlugins();
|
||||
|
||||
totalPlugins.forEach(
|
||||
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
|
||||
origin.isdwonload = isDownload(origin, localPlugins);
|
||||
origin.isloading = false;
|
||||
}
|
||||
);
|
||||
|
||||
commit("commonUpdate", {
|
||||
localPlugins,
|
||||
totalPlugins,
|
||||
});
|
||||
},
|
||||
startDownload({ commit, state }, name) {
|
||||
const totalPlugins = JSON.parse(JSON.stringify(state.totalPlugins));
|
||||
totalPlugins.forEach(
|
||||
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
commit("commonUpdate", {
|
||||
totalPlugins,
|
||||
});
|
||||
},
|
||||
successDownload({ commit, state }, name) {
|
||||
const totalPlugins = JSON.parse(JSON.stringify(state.totalPlugins));
|
||||
totalPlugins.forEach(
|
||||
(origin: { isdwonload?: any; name?: any; isloading: boolean }) => {
|
||||
if (origin.name === name) {
|
||||
origin.isloading = false;
|
||||
origin.isdwonload = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
commit("commonUpdate", {
|
||||
totalPlugins,
|
||||
});
|
||||
},
|
||||
},
|
||||
modules: {},
|
||||
});
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
<img alt="Vue logo" src="../assets/logo.png" />
|
||||
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src
|
||||
|
||||
export default defineComponent({
|
||||
name: "Home",
|
||||
components: {
|
||||
HelloWorld,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
13
feature/src/views/market/components/devlopment.vue
Normal file
13
feature/src/views/market/components/devlopment.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "devlopment"
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
115
feature/src/views/market/components/finder.vue
Normal file
115
feature/src/views/market/components/finder.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div class="finder">
|
||||
<a-carousel arrows>
|
||||
<template #prevArrow>
|
||||
<div class="custom-slick-arrow" style="left: 10px; z-index: 1">
|
||||
<left-circle-outlined />
|
||||
</div>
|
||||
</template>
|
||||
<template #nextArrow>
|
||||
<div class="custom-slick-arrow" style="right: 10px">
|
||||
<right-circle-outlined />
|
||||
</div>
|
||||
</template>
|
||||
<div :key="index" v-for="(banner, index) in (data.banners || [])">
|
||||
<img @click="jumpTo(banner.link)" width="100%" :src="banner.src" />
|
||||
</div>
|
||||
</a-carousel>
|
||||
<PluginList @downloadSuccess="downloadSuccess" title="推荐" :list="recommend || []" />
|
||||
<PluginList title="最近更新" :list="newList || []" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
LeftCircleOutlined,
|
||||
RightCircleOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { ref, computed } from "vue";
|
||||
import request from "../../../assets/request/index";
|
||||
import PluginList from "./plugin-list.vue";
|
||||
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
const data = ref([]);
|
||||
|
||||
request.getFinderDetail().then(res => {
|
||||
data.value = res;
|
||||
});
|
||||
|
||||
const recommend = computed(() => {
|
||||
const defaultData = data.value.recommend || [];
|
||||
if (!defaultData.length) return [];
|
||||
return defaultData.map((plugin) => {
|
||||
let searchInfo = null;
|
||||
totalPlugins.value.forEach((t) => {
|
||||
if (t.name === plugin) {
|
||||
searchInfo = t;
|
||||
}
|
||||
});
|
||||
return searchInfo;
|
||||
});
|
||||
});
|
||||
|
||||
const newList = computed(() => {
|
||||
const defaultData = data.value.new || [];
|
||||
if (!defaultData.length) return [];
|
||||
return defaultData.map((plugin) => {
|
||||
let searchInfo = null;
|
||||
totalPlugins.value.forEach((t) => {
|
||||
if (t.name === plugin) {
|
||||
searchInfo = t;
|
||||
}
|
||||
});
|
||||
return searchInfo;
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.finder {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow-x: hidden;
|
||||
box-sizing: border-box;
|
||||
|
||||
.ant-carousel .slick-slide {
|
||||
text-align: center;
|
||||
height: 235px;
|
||||
line-height: 160px;
|
||||
overflow: hidden;
|
||||
border-radius: 4px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 235px;
|
||||
}
|
||||
}
|
||||
.ant-carousel .custom-slick-arrow {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
font-size: 25px;
|
||||
color: #fff;
|
||||
background-color: rgba(31, 45, 61, 0.11);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.ant-carousel .custom-slick-arrow.slick-next:focus {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ant-carousel .custom-slick-arrow:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-carousel .custom-slick-arrow:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.ant-carousel .slick-slide h3 {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
13
feature/src/views/market/components/image.vue
Normal file
13
feature/src/views/market/components/image.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "image"
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
165
feature/src/views/market/components/plugin-list.vue
Normal file
165
feature/src/views/market/components/plugin-list.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div class="panel-item">
|
||||
<h3 class="title">{{ title }}</h3>
|
||||
<div class="list-item">
|
||||
<a-list :grid="{ gutter: 16, column: 2 }" :data-source="list">
|
||||
<template #renderItem="{ item, index }">
|
||||
<a-list-item @click="visible=true">
|
||||
<template #actions>
|
||||
<a-button style="color: #ff4ea4;" type="text" :loading="item.isloading">
|
||||
<CloudDownloadOutlined
|
||||
v-show="!item.isloading && !item.isdwonload"
|
||||
@click.stop="downloadPlugin(item, index)"
|
||||
style="font-size: 20px; cursor: pointer"
|
||||
/>
|
||||
</a-button>
|
||||
</template>
|
||||
<a-list-item-meta
|
||||
:description="item.description"
|
||||
>
|
||||
<template #title>
|
||||
<span>{{ item.pluginName }}</span>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar :src="item.logo" />
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</div>
|
||||
</div>
|
||||
<a-drawer
|
||||
width="100%"
|
||||
placement="right"
|
||||
:closable="false"
|
||||
:visible="visible"
|
||||
:get-container="false"
|
||||
class="plugin-info"
|
||||
:style="{ position: 'absolute' }"
|
||||
@close="visible=false"
|
||||
>
|
||||
<template #title>
|
||||
<div class="plugin-title-info">
|
||||
<div class="back-icon" @click="visible=false">
|
||||
<ArrowLeftOutlined />
|
||||
</div>
|
||||
<div class="info">
|
||||
<img src="https://static.91jkys.com/activity/img/2adb63c2e5d54dc1b26001958fcdb044.jpg"
|
||||
class="plugin-icon" />
|
||||
<div class="plugin-desc">
|
||||
<div class="title">
|
||||
备忘快贴
|
||||
</div>
|
||||
<div class="desc">
|
||||
适合每个人的专业图像编辑软件
|
||||
</div>
|
||||
<a-button shape="round" type="primary">
|
||||
<template #icon>
|
||||
<CloudDownloadOutlined />
|
||||
</template>
|
||||
获取
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
CloudDownloadOutlined,
|
||||
ArrowLeftOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
|
||||
import { computed, defineProps, ref } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const startDownload = (name) => store.dispatch("startDownload", name);
|
||||
const successDownload = (name) => store.dispatch("successDownload", name);
|
||||
|
||||
defineProps({
|
||||
list: {
|
||||
type: [Array],
|
||||
default: () => [],
|
||||
},
|
||||
title: String,
|
||||
});
|
||||
|
||||
const downloadPlugin = async (plugin) => {
|
||||
startDownload(plugin.name);
|
||||
await window.rubick.downloadPlugin(plugin);
|
||||
successDownload(plugin.name);
|
||||
};
|
||||
|
||||
const visible = ref(false);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.panel-item {
|
||||
margin: 20px 0;
|
||||
.title {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
&:after{
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border-bottom: 1px solid #eee;
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
.ant-list-item {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
.plugin-info {
|
||||
width: 100%;
|
||||
|
||||
.ant-drawer-content-wrapper {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.plugin-title-info {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
.back-icon {
|
||||
font-size: 16px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.plugin-icon {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.plugin-desc {
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
13
feature/src/views/market/components/tools.vue
Normal file
13
feature/src/views/market/components/tools.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "tools"
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
13
feature/src/views/market/components/worker.vue
Normal file
13
feature/src/views/market/components/worker.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "worker"
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
125
feature/src/views/market/index.vue
Normal file
125
feature/src/views/market/index.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div class="market">
|
||||
<div class="left-menu">
|
||||
<div class="search-container">
|
||||
<a-input-search
|
||||
v-model:value="searchValue"
|
||||
placeholder="搜索插件"
|
||||
style="width: 100%"
|
||||
@search="onSearch"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<a-menu v-model:selectedKeys="current" mode="inline">
|
||||
<a-menu-item key="finder">
|
||||
<template #icon>
|
||||
<StarOutlined />
|
||||
</template>
|
||||
探索
|
||||
</a-menu-item>
|
||||
<a-menu-item key="worker">
|
||||
<template #icon>
|
||||
<SendOutlined style="transform: rotate(-45deg)" />
|
||||
</template>
|
||||
效率
|
||||
</a-menu-item>
|
||||
<a-menu-item key="tools">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
搜索工具
|
||||
</a-menu-item>
|
||||
<a-menu-item key="image">
|
||||
<template #icon>
|
||||
<FileImageOutlined />
|
||||
</template>
|
||||
图像
|
||||
</a-menu-item>
|
||||
<a-menu-item key="dev">
|
||||
<template #icon>
|
||||
<CodeOutlined />
|
||||
</template>
|
||||
开发
|
||||
</a-menu-item>
|
||||
<a-menu-item key="system">
|
||||
<template #icon>
|
||||
<DatabaseOutlined />
|
||||
</template>
|
||||
系统
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
<div class="container">
|
||||
<component :totalPlugins="totalPlugins" :is="Components[current[0]]" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
StarOutlined,
|
||||
SendOutlined,
|
||||
SearchOutlined,
|
||||
FileImageOutlined,
|
||||
DatabaseOutlined,
|
||||
CodeOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { reactive, toRefs, computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import Finder from "./components/finder.vue";
|
||||
|
||||
const Components = {
|
||||
finder: Finder,
|
||||
};
|
||||
|
||||
const state = reactive({
|
||||
searchValue: "",
|
||||
current: ["finder"],
|
||||
});
|
||||
|
||||
const store = useStore();
|
||||
const init = () => store.dispatch("init");
|
||||
init();
|
||||
const totalPlugins = computed(() => store.state.totalPlugins);
|
||||
|
||||
const { searchValue, current } = toRefs(state);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.market {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background: #F3EFEF;
|
||||
.left-menu {
|
||||
width: 200px;
|
||||
height: 100vh;
|
||||
.search-container {
|
||||
padding: 10px;
|
||||
}
|
||||
.ant-input-affix-wrapper {
|
||||
border: none;
|
||||
}
|
||||
.ant-menu {
|
||||
background: #F3EFEF;
|
||||
.ant-menu-item-selected {
|
||||
background-color: #E2E2E2;
|
||||
color: #141414;
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.container {
|
||||
background: #fff;
|
||||
width: calc(~'100% - 200px');
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
padding: 10px 20px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user