Add global save button

This commit is contained in:
philipp lang 2022-12-04 23:40:35 +01:00
parent b1c8fb6dd1
commit f2d4ad5674
11 changed files with 107 additions and 54 deletions

15
package-lock.json generated
View File

@ -9,6 +9,7 @@
"@inertiajs/inertia-vue": "^0.8.0", "@inertiajs/inertia-vue": "^0.8.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"merge": "^2.1.1", "merge": "^2.1.1",
"portal-vue": "^2.1.7",
"postcss-import": "^14.0.1", "postcss-import": "^14.0.1",
"query-string": "^7.0.0", "query-string": "^7.0.0",
"svg-sprite": "^2.0.2", "svg-sprite": "^2.0.2",
@ -7791,6 +7792,14 @@
"url": "https://opencollective.com/popperjs" "url": "https://opencollective.com/popperjs"
} }
}, },
"node_modules/portal-vue": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/portal-vue/-/portal-vue-2.1.7.tgz",
"integrity": "sha512-+yCno2oB3xA7irTt0EU5Ezw22L2J51uKAacE/6hMPMoO/mx3h4rXFkkBkT4GFsMDv/vEe8TNKC3ujJJ0PTwb6g==",
"peerDependencies": {
"vue": "^2.5.18"
}
},
"node_modules/portfinder": { "node_modules/portfinder": {
"version": "1.0.28", "version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@ -16790,6 +16799,12 @@
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
}, },
"portal-vue": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/portal-vue/-/portal-vue-2.1.7.tgz",
"integrity": "sha512-+yCno2oB3xA7irTt0EU5Ezw22L2J51uKAacE/6hMPMoO/mx3h4rXFkkBkT4GFsMDv/vEe8TNKC3ujJJ0PTwb6g==",
"requires": {}
},
"portfinder": { "portfinder": {
"version": "1.0.28", "version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",

View File

@ -27,6 +27,7 @@
"@inertiajs/inertia-vue": "^0.8.0", "@inertiajs/inertia-vue": "^0.8.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"merge": "^2.1.1", "merge": "^2.1.1",
"portal-vue": "^2.1.7",
"postcss-import": "^14.0.1", "postcss-import": "^14.0.1",
"query-string": "^7.0.0", "query-string": "^7.0.0",
"svg-sprite": "^2.0.2", "svg-sprite": "^2.0.2",

View File

@ -0,0 +1 @@
<svg viewBox="0 0 60 60" width="480" height="480" xmlns="http://www.w3.org/2000/svg"><path d="m59.707 8.293-8-8A1 1 0 0 0 51 0H5a5.006 5.006 0 0 0-5 5v50a5.006 5.006 0 0 0 5 5h50a5.006 5.006 0 0 0 5-5V9a1 1 0 0 0-.293-.707ZM46 2v16a1 1 0 0 1-1 1H15a1 1 0 0 1-1-1V2ZM8 58V33a3 3 0 0 1 3-3h38a3 3 0 0 1 3 3v25zm50-3a3 3 0 0 1-3 3h-1V33a5.006 5.006 0 0 0-5-5H11a5.006 5.006 0 0 0-5 5v25H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h7v16a3 3 0 0 0 3 3h30a3 3 0 0 0 3-3V2h2.586L58 9.414Z"/><path d="M37 17h6a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1zm1-11h4v9h-4zM45 43H15a1 1 0 0 0 0 2h30a1 1 0 0 0 0-2zM45 37H15a1 1 0 0 0 0 2h30a1 1 0 0 0 0-2zM45 49H15a1 1 0 0 0 0 2h30a1 1 0 0 0 0-2z"/></svg>

After

Width:  |  Height:  |  Size: 699 B

15
resources/js/app.js vendored
View File

@ -2,10 +2,6 @@ import Vue from 'vue';
import {App as InertiaApp, plugin, Link as ILink} from '@inertiajs/inertia-vue'; import {App as InertiaApp, plugin, Link as ILink} from '@inertiajs/inertia-vue';
import SvgSprite from './components/SvgSprite.js'; import SvgSprite from './components/SvgSprite.js';
import FText from './components/FText.vue';
import FSwitch from './components/FSwitch.vue';
import FSelect from './components/FSelect.vue';
import FTextarea from './components/FTextarea.vue';
import VPages from './components/VPages.vue'; import VPages from './components/VPages.vue';
import VLabel from './components/VLabel.vue'; import VLabel from './components/VLabel.vue';
import VBool from './components/VBool.vue'; import VBool from './components/VBool.vue';
@ -14,19 +10,22 @@ import Heading from './components/Heading.vue';
import AppLayout from './layouts/AppLayout.vue'; import AppLayout from './layouts/AppLayout.vue';
import VTooltip from 'v-tooltip'; import VTooltip from 'v-tooltip';
import hasModule from './mixins/hasModule.js'; import hasModule from './mixins/hasModule.js';
import PortalVue from 'portal-vue';
Vue.use(plugin); Vue.use(plugin);
Vue.use(PortalVue);
Vue.use(VTooltip); Vue.use(VTooltip);
Vue.component('f-text', FText); Vue.component('f-text', () => import(/* webpackChunkName: "form" */ './components/FText'));
Vue.component('f-switch', FSwitch); Vue.component('f-switch', () => import(/* webpackChunkName: "form" */ './components/FSwitch'));
Vue.component('f-select', FSelect); Vue.component('f-select', () => import(/* webpackChunkName: "form" */ './components/FSelect'));
Vue.component('f-textarea', FTextarea); Vue.component('f-textarea', () => import(/* webpackChunkName: "form" */ './components/FTextarea'));
Vue.component('SvgSprite', SvgSprite); Vue.component('SvgSprite', SvgSprite);
Vue.component('VPages', VPages); Vue.component('VPages', VPages);
Vue.component('v-bool', VBool); Vue.component('v-bool', VBool);
Vue.component('v-label', VLabel); Vue.component('v-label', VLabel);
Vue.component('box', Box); Vue.component('box', Box);
Vue.component('heading', Heading); Vue.component('heading', Heading);
Vue.component('save-button', () => import(/* webpackChunkName: "form" */ './components/SaveButton'));
const el = document.getElementById('app'); const el = document.getElementById('app');

View File

@ -0,0 +1,22 @@
<template>
<portal to="toolbar-right">
<button
:form="form"
type="submit"
class="flex items-center transition-all justify-center w-8 h-8 bg-primary-700 hover:bg-primary-600 rounded"
v-tooltip="`speichern`"
>
<svg-sprite class="w-4 h-4 text-white" src="save"></svg-sprite>
</button>
</portal>
</template>
<script>
export default {
props: {
form: {
required: true,
},
},
};
</script>

View File

@ -2,11 +2,22 @@
<div class="h-16 px-6 flex justify-between items-center border-b border-solid border-gray-500"> <div class="h-16 px-6 flex justify-between items-center border-b border-solid border-gray-500">
<div class="flex items-center"> <div class="flex items-center">
<span class="mr-1 text-xl font-semibold leading-none text-white" v-html="title"></span> <span class="mr-1 text-xl font-semibold leading-none text-white" v-html="title"></span>
<a v-for="link, index in links.filter(link => link.icon === undefined)" :key="index" @click.prevent="$emit(link.event)" href="#" class="btn label btn-primary-light"> <a
v-for="(link, index) in links.filter((link) => link.icon === undefined)"
:key="index"
@click.prevent="$emit(link.event)"
href="#"
class="btn label btn-primary-light"
>
<span v-if="link.label" v-text="link.label"></span> <span v-if="link.label" v-text="link.label"></span>
<svg-sprite v-if="link.icon" :src="link.icon"></svg-sprite> <svg-sprite v-if="link.icon" :src="link.icon"></svg-sprite>
</a> </a>
<a v-for="link, index in links.filter(link => link.icon !== undefined)" :key="index" :href="link.href" class="btn label icon btn-primary-light ml-1"> <a
v-for="(link, index) in links.filter((link) => link.icon !== undefined)"
:key="index"
:href="link.href"
class="btn label icon btn-primary-light ml-1"
>
<span v-if="link.label" v-text="link.label"></span> <span v-if="link.label" v-text="link.label"></span>
<svg-sprite v-if="link.icon" :src="link.icon"></svg-sprite> <svg-sprite v-if="link.icon" :src="link.icon"></svg-sprite>
</a> </a>
@ -23,11 +34,15 @@
export default { export default {
props: { props: {
links: { links: {
default: function() { return []; } default: function () {
return [];
},
}, },
title: { title: {
default: function() { return ''; } default: function () {
} return '';
} },
},
},
}; };
</script> </script>

View File

@ -36,8 +36,7 @@
class="grow bg-gray-900 flex flex-col transition-all" class="grow bg-gray-900 flex flex-col transition-all"
:class="{'ml-56': menuVisible, 'ml-0': !menuVisible}" :class="{'ml-56': menuVisible, 'ml-0': !menuVisible}"
> >
<div class="h-16 px-6 flex justify-between items-center border-b border-gray-600"> <div class="h-16 px-6 flex items-center space-x-3 border-b border-gray-600">
<div class="flex space-x-3 items-center">
<a href="#" @click.prevent="menuOverflowVisible = !menuOverflowVisible" class="lg:hidden"> <a href="#" @click.prevent="menuOverflowVisible = !menuOverflowVisible" class="lg:hidden">
<svg-sprite src="menu" class="text-gray-100 w-5 h-5"></svg-sprite> <svg-sprite src="menu" class="text-gray-100 w-5 h-5"></svg-sprite>
</a> </a>
@ -45,7 +44,6 @@
class="text-sm md:text-xl font-semibold text-white leading-none" class="text-sm md:text-xl font-semibold text-white leading-none"
v-html="$page.props.title" v-html="$page.props.title"
></span> ></span>
<div class="flex ml-4">
<i-link <i-link
v-for="(link, index) in filterMenu" v-for="(link, index) in filterMenu"
:key="index" :key="index"
@ -57,15 +55,17 @@
<svg-sprite v-show="link.icon" class="w-3 h-3 xl:mr-2" :src="link.icon"></svg-sprite> <svg-sprite v-show="link.icon" class="w-3 h-3 xl:mr-2" :src="link.icon"></svg-sprite>
<span class="hidden xl:inline" v-text="link.label"></span> <span class="hidden xl:inline" v-text="link.label"></span>
</i-link> </i-link>
</div> <div class="flex grow justify-between">
<portal-target name="toolbar-left"> </portal-target>
<portal-target name="toolbar-right"> </portal-target>
</div> </div>
<label <label
for="search" for="search"
:class="{'opacity-0 sm:opacity-100': !searchVisible, 'opacity-100': searchVisible}" :class="{'opacity-0 sm:opacity-100': !searchVisible, 'opacity-100': searchVisible}"
class="absolute left-14 sm:static transition-all" class="absolute left-10 sm:static transition-all"
> >
<input <input
class="shadow-lg bg-gray-800 rounded-lg py-2 px-3 text-gray-300 hover:bg-gray-700 focus:bg-gray-700 placeholder-gray-400" class="shadow-lg bg-gray-800 rounded-lg py-2 px-3 h-10 text-gray-300 hover:bg-gray-700 focus:bg-gray-700 placeholder-gray-400"
placeholder="Suchen…" placeholder="Suchen…"
name="search" name="search"
v-model="isearch" v-model="isearch"

View File

@ -1,5 +1,6 @@
<template> <template>
<form class="flex grow relative" @submit.prevent="submit"> <form class="flex grow relative" id="memberedit" @submit.prevent="submit">
<save-button form="memberedit"></save-button>
<popup heading="Ein Konflikt ist aufgetreten" v-if="conflict === true"> <popup heading="Ein Konflikt ist aufgetreten" v-if="conflict === true">
<div> <div>
<p class="mt-4"> <p class="mt-4">
@ -164,9 +165,6 @@
required required
></f-select> ></f-select>
</div> </div>
<div>
<button type="submit" class="mt-3 btn btn-sm inline-block btn-primary">Speichern</button>
</div>
</div> </div>
</box> </box>
<box heading="Prävention"> <box heading="Prävention">

View File

@ -1,5 +1,10 @@
<template> <template>
<form class="grow p-6 grid grid-cols-2 gap-3 items-start content-start" @submit.prevent="submit"> <form
id="billsettingform"
class="grow p-6 grid grid-cols-2 gap-3 items-start content-start"
@submit.prevent="submit"
>
<save-button form="billsettingform"></save-button>
<f-text <f-text
label="Absender" label="Absender"
hint="Absender-Name in Kurzform, i.d.R. der kurze Stammesname" hint="Absender-Name in Kurzform, i.d.R. der kurze Stammesname"
@ -26,10 +31,6 @@
<f-text label="Webseite" v-model="inner.website" name="website" id="website"></f-text> <f-text label="Webseite" v-model="inner.website" name="website" id="website"></f-text>
<f-text label="IBAN" v-model="inner.iban" name="iban" id="iban"></f-text> <f-text label="IBAN" v-model="inner.iban" name="iban" id="iban"></f-text>
<f-text label="BIC" v-model="inner.bic" name="bic" id="bic"></f-text> <f-text label="BIC" v-model="inner.bic" name="bic" id="bic"></f-text>
<div>
<button type="submit" class="mt-3 btn block btn-primary">Speichern</button>
</div>
</form> </form>
</template> </template>

View File

@ -1,5 +1,10 @@
<template> <template>
<form class="grow p-6 grid grid-cols-2 gap-3 items-start content-start" @submit.prevent="submit"> <form
id="mailmansettingform"
class="grow p-6 grid grid-cols-2 gap-3 items-start content-start"
@submit.prevent="submit"
>
<save-button form="mailmansettingform"></save-button>
<div class="col-span-full text-gray-100 mb-3"> <div class="col-span-full text-gray-100 mb-3">
<p class="text-sm"> <p class="text-sm">
Scoutrobot kann automatisch Mailinglisten erstellen, wenn es mit einem existierenden Scoutrobot kann automatisch Mailinglisten erstellen, wenn es mit einem existierenden
@ -49,9 +54,6 @@
:options="lists" :options="lists"
></f-select> ></f-select>
<div></div> <div></div>
<div>
<button type="submit" class="mt-3 btn block btn-primary">Speichern</button>
</div>
</form> </form>
</template> </template>

View File

@ -1,5 +1,6 @@
<template> <template>
<form class="p-6 grid gap-4 justify-start" @submit.prevent="submit"> <form id="subedit" class="p-6 grid gap-4 justify-start" @submit.prevent="submit">
<save-button form="subedit"></save-button>
<f-text id="name" v-model="inner.name" label="Name" required></f-text> <f-text id="name" v-model="inner.name" label="Name" required></f-text>
<f-select <f-select
id="fee_id" id="fee_id"
@ -10,8 +11,6 @@
required required
></f-select> ></f-select>
<f-text id="amount" v-model="inner.amount" label="Interner Beitrag" mode="area" required></f-text> <f-text id="amount" v-model="inner.amount" label="Interner Beitrag" mode="area" required></f-text>
<button type="submit" class="btn btn-primary">Absenden</button>
</form> </form>
</template> </template>