refactor menus with separated components

This commit is contained in:
Simon Vieille 2020-10-16 11:04:03 +02:00
parent ae148aba02
commit 7edd6d6d84
Signed by: deblan
GPG Key ID: 03383D15A1D31745
10 changed files with 270 additions and 104 deletions

9
src/CloserButton.vue Normal file
View File

@ -0,0 +1,9 @@
<template>
<button class="side-menu-opener side-menu-closer"></button>
</template>
<script>
export default {
name: 'CloserButton',
}
</script>

26
src/Loader.vue Normal file
View File

@ -0,0 +1,26 @@
<template>
<div class="side-menu-loader">
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="2">
<circle stroke-opacity=".5" cx="18" cy="18" r="18"/>
<path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>
</div>
</template>
<script>
export default {
name: 'Loader',
}
</script>

21
src/Logo.vue Normal file
View File

@ -0,0 +1,21 @@
<template>
<div v-bind:class="classes">
<img v-bind:src="image">
</div>
</template>
<script>
export default {
name: 'Logo',
props: {
image: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
},
}
</script>

9
src/OpenerButton.vue Normal file
View File

@ -0,0 +1,9 @@
<template>
<button class="side-menu-opener"></button>
</template>
<script>
export default {
name: 'OpenerButton',
}
</script>

31
src/SettingsButton.vue Normal file
View File

@ -0,0 +1,31 @@
<template>
<div class="side-menu-settings">
<a v-bind:href="href">
{{ label }}
<span class="avatardiv avatardiv-shown">
<img v-bind:src="avatar" v-bind:alt="name" v-bind:title="name">
</span>
</a>
</div>
</template>
<script>
export default {
name: 'SettingsButton',
props: {
label: {
type: String,
required: true
},
href: {
type: String,
required: true
},
avatar: {
type: String,
required: true
},
},
}
</script>

View File

@ -17,33 +17,27 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<template>
<div id="side-menu">
<div class="side-menu-header">
<div class="side-menu-settings" v-if="settings">
<a v-bind:href="settings.href">
{{ settings.name }}
<SettingsButton
v-if="settings"
v-bind:href="settings.href"
v-bind:label="settings.name"
v-bind:avatar="settings.avatar" />
<span class="avatardiv avatardiv-shown">
<img v-bind:src="settings.avatar" v-bind:alt="settings.name" v-bind:title="settings.name">
</span>
</a>
</div>
<OpenerButton />
<button class="side-menu-opener"></button>
<div v-if="!avatar && logo" v-bind:class="{'side-menu-logo': true, 'avatardiv': false}">
<img v-bind:src="logo">
</div>
<div v-if="avatar" v-bind:class="{'side-menu-logo': true, 'avatardiv': true}">
<img v-bind:src="avatar">
</div>
<Logo v-if="!avatar && logo" v-bind:classes="{'side-menu-logo': true, 'avatardiv': false}" v-bind:image="logo" />
<Logo v-if="avatar" v-bind:classes="{'side-menu-logo': true, 'avatardiv': true}" v-bind:image="avatar" />
</div>
<ul class="side-menu-apps-list">
<li v-for="app in apps" v-bind:class="{'side-menu-app': true, 'active': app.active}">
<a v-bind:href="app.href" :target="targetBlankApps.indexOf(app.id) !== -1 ? '_blank' : undefined" v-bind:title="app.name">
<span class="side-menu-app-icon" v-html="app.icon"></span>
<span class="side-menu-app-text" v-html="app.name"></span>
</a>
</li>
<SideMenuApp
v-for="app in apps"
v-bind:classes="{'side-menu-app': true, 'active': app.active}"
v-bind:icon="app.icon"
v-bind:label="app.name"
v-bind:href="app.href"
v-bind:target="targetBlankApps.indexOf(app.id) !== -1 ? '_blank' : undefined"
/>
</ul>
</div>
</template>
@ -51,9 +45,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<script>
import trim from 'trim'
import axios from 'axios'
import OpenerButton from './OpenerButton'
import SettingsButton from './SettingsButton'
import SideMenuApp from './SideMenuApp'
import Logo from './Logo'
export default {
name: 'SideMenu',
components: {
SettingsButton,
OpenerButton,
SideMenuApp,
Logo,
},
data() {
return {
apps: [],

36
src/SideMenuApp.vue Normal file
View File

@ -0,0 +1,36 @@
<template>
<li v-bind:class="classes">
<a v-bind:href="href" :target="target" v-bind:title="label">
<span class="side-menu-app-icon" v-html="icon"></span>
<span class="side-menu-app-text" v-html="label"></span>
</a>
</li>
</template>
<script>
export default {
name: 'SideMenuApp',
props: {
label: {
type: String,
required: true
},
icon: {
type: String,
required: true
},
href: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
target: {
type: String,
required: false
},
},
}
</script>

View File

@ -17,52 +17,34 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<template>
<div id="side-menu" class="side-menu-big">
<div class="side-menu-header">
<button class="side-menu-opener side-menu-closer"></button>
<CloserButton />
<div class="side-menu-settings" v-if="settings">
<a v-bind:href="settings.href">
{{ settings.name }}
<SettingsButton
v-if="settings"
v-bind:href="settings.href"
v-bind:label="settings.name"
v-bind:avatar="settings.avatar"
/>
<span class="avatardiv avatardiv-shown">
<img v-bind:src="settings.avatar" v-bind:alt="settings.name" v-bind:title="settings.name">
</span>
</a>
</div>
<button class="side-menu-opener"></button>
<OpenerButton />
</div>
<div class="side-menu-categories-wrapper">
<div class="side-menu-categories">
<div v-if="!items.length" class="side-menu-loader">
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="2">
<circle stroke-opacity=".5" cx="18" cy="18" r="18"/>
<path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>
</div>
<Loader v-if="!items.length" />
<div class="side-menu-category" v-for="category in items">
<h2 class="side-menu-category-title" v-if="category.name != ''" v-html="category.name"></h2>
<ul class="side-menu-apps-list">
<li v-bind:class="{'side-menu-app': true, 'active': activeApp === appId}" v-for="(app, appId) in category.apps">
<a v-bind:href="app.href" :target="targetBlankApps.indexOf(appId) !== -1 ? '_blank' : undefined" v-bind:title="app.name">
<img class="side-menu-app-icon" v-bind:src="app.icon"></span>
<span class="side-menu-app-text" v-html="app.name"></span>
</a>
</li>
<SideMenuBigApp
v-for="(app, appId) in category.apps"
v-bind:classes="{'side-menu-app': true, 'active': activeApp === appId}"
v-bind:icon="app.icon"
v-bind:label="app.name"
v-bind:href="app.href"
v-bind:target="targetBlankApps.indexOf(app.id) !== -1 ? '_blank' : undefined"
/>
</ul>
</div>
</div>
@ -73,9 +55,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<script>
import trim from 'trim'
import axios from 'axios'
import OpenerButton from './OpenerButton'
import CloserButton from './CloserButton'
import SettingsButton from './SettingsButton'
import Loader from './Loader'
import SideMenuBigApp from './SideMenuBigApp'
export default {
name: 'SideMenuBig',
components: {
SettingsButton,
OpenerButton,
CloserButton,
Loader,
SideMenuBigApp,
},
data() {
return {
items: [],

36
src/SideMenuBigApp.vue Normal file
View File

@ -0,0 +1,36 @@
<template>
<li v-bind:class="classes">
<a v-bind:href="href" :target="target" v-bind:title="label">
<img class="side-menu-app-icon" v-bind:src="icon"></span>
<span class="side-menu-app-text" v-html="label"></span>
</a>
</li>
</template>
<script>
export default {
name: 'SideMenuBigApp',
props: {
label: {
type: String,
required: true
},
icon: {
type: String,
required: true
},
href: {
type: String,
required: true
},
classes: {
type: Object,
required: true
},
target: {
type: String,
required: false
},
},
}
</script>

View File

@ -3,51 +3,51 @@ const { VueLoaderPlugin } = require('vue-loader')
const StyleLintPlugin = require('stylelint-webpack-plugin')
module.exports = {
entry: {
'admin': path.join(__dirname, 'src', 'admin.js'),
'sideMenu': path.join(__dirname, 'src', 'SideMenu.js'),
},
output: {
path: path.resolve(__dirname, './js'),
publicPath: '/js',
filename: '[name].js?v=[hash]',
chunkFilename: 'chunks/[name]-[hash].js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: ['vue-style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader',
options: {
name: '[name].[ext]?[hash]',
limit: 8192,
},
},
],
},
plugins: [
new VueLoaderPlugin(),
new StyleLintPlugin(),
],
resolve: {
extensions: ['*', '.js', '.vue'],
symlinks: false,
},
entry: {
'admin': path.join(__dirname, 'src', 'admin.js'),
'sideMenu': path.join(__dirname, 'src', 'SideMenu.js'),
},
output: {
path: path.resolve(__dirname, './js'),
publicPath: '/js',
filename: '[name].js?v=[hash]',
chunkFilename: 'chunks/[name]-[hash].js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: ['vue-style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader',
options: {
name: '[name].[ext]?[hash]',
limit: 8192,
},
},
],
},
plugins: [
new VueLoaderPlugin(),
new StyleLintPlugin(),
],
resolve: {
extensions: ['*', '.js', '.vue'],
symlinks: false,
},
}