1
0
mirror of https://github.com/typemill/typemill.git synced 2025-07-31 19:30:40 +02:00

V2 responsive system

This commit is contained in:
trendschau
2023-09-11 18:09:36 +02:00
parent 7056e15afa
commit 3393fd9065
18 changed files with 376 additions and 189 deletions

View File

@@ -26,7 +26,8 @@ class ControllerWebSystem extends Controller
$userrole = $request->getAttribute('c_userrole'),
$acl = $this->c->get('acl'),
$urlinfo = $this->c->get('urlinfo'),
$dispatcher = $this->c->get('dispatcher')
$dispatcher = $this->c->get('dispatcher'),
$parser = $this->routeParser
);
$settingsModel = new Settings();
@@ -41,10 +42,10 @@ class ControllerWebSystem extends Controller
# 'basicauth' => $user->getBasicAuth(),
'settings' => $this->settings,
'mainnavi' => $mainNavigation,
'systemnavi' => $systemNavigation,
'jsdata' => [
'settings' => $this->settings,
'system' => $systemfields,
'systemnavi' => $systemNavigation,
'labels' => $this->c->get('translations'),
'urlinfo' => $this->c->get('urlinfo')
]
@@ -65,7 +66,8 @@ class ControllerWebSystem extends Controller
$userrole = $request->getAttribute('c_userrole'),
$acl = $this->c->get('acl'),
$urlinfo = $this->c->get('urlinfo'),
$dispatcher = $this->c->get('dispatcher')
$dispatcher = $this->c->get('dispatcher'),
$parser = $this->routeParser
);
$extension = new Extension();
@@ -91,8 +93,8 @@ class ControllerWebSystem extends Controller
return $this->c->get('view')->render($response, 'system/themes.twig', [
'settings' => $this->settings,
'mainnavi' => $mainNavigation,
'systemnavi' => $systemNavigation,
'jsdata' => [
'systemnavi' => $systemNavigation,
'settings' => $themeSettings,
'definitions' => $themeDefinitions,
'theme' => $this->settings['theme'],
@@ -118,6 +120,7 @@ class ControllerWebSystem extends Controller
$acl = $this->c->get('acl'),
$urlinfo = $this->c->get('urlinfo'),
$dispatcher = $this->c->get('dispatcher'),
$parser = $this->routeParser
);
$extension = new Extension();
@@ -143,8 +146,8 @@ class ControllerWebSystem extends Controller
return $this->c->get('view')->render($response, 'system/plugins.twig', [
'settings' => $this->settings,
'mainnavi' => $mainNavigation,
'systemnavi' => $systemNavigation,
'jsdata' => [
'systemnavi' => $systemNavigation,
'settings' => $pluginSettings,
'definitions' => $pluginDefinitions,
'license' => $license,
@@ -169,6 +172,7 @@ class ControllerWebSystem extends Controller
$acl = $this->c->get('acl'),
$urlinfo = $this->c->get('urlinfo'),
$dispatcher = $this->c->get('dispatcher'),
$parser = $this->routeParser
);
$license = new License();
@@ -185,8 +189,8 @@ class ControllerWebSystem extends Controller
return $this->c->get('view')->render($response, 'system/license.twig', [
'settings' => $this->settings,
'mainnavi' => $mainNavigation,
'systemnavi' => $systemNavigation,
'jsdata' => [
'systemnavi' => $systemNavigation,
'licensedata' => $licensedata,
'licensefields' => $licensefields,
'labels' => $this->c->get('translations'),
@@ -209,6 +213,7 @@ class ControllerWebSystem extends Controller
$acl = $this->c->get('acl'),
$urlinfo = $this->c->get('urlinfo'),
$dispatcher = $this->c->get('dispatcher'),
$parser = $this->routeParser
);
$username = $request->getAttribute('c_username');
@@ -221,8 +226,8 @@ class ControllerWebSystem extends Controller
return $this->c->get('view')->render($response, 'system/account.twig', [
'settings' => $this->settings,
'mainnavi' => $mainNavigation,
'systemnavi' => $systemNavigation,
'jsdata' => [
'systemnavi' => $systemNavigation,
'userdata' => $userdata,
'userfields' => $userfields,
'userroles' => $this->c->get('acl')->getRoles(),
@@ -247,6 +252,7 @@ class ControllerWebSystem extends Controller
$acl = $this->c->get('acl'),
$urlinfo = $this->c->get('urlinfo'),
$dispatcher = $this->c->get('dispatcher'),
$parser = $this->routeParser
);
$user = new User();
@@ -264,8 +270,8 @@ class ControllerWebSystem extends Controller
return $this->c->get('view')->render($response, 'system/users.twig', [
'settings' => $this->settings,
'mainnavi' => $mainNavigation,
'systemnavi' => $systemNavigation,
'jsdata' => [
'systemnavi' => $systemNavigation,
'totalusers' => count($usernames),
'usernames' => $usernames,
'userdata' => $userdata,
@@ -291,6 +297,7 @@ class ControllerWebSystem extends Controller
$acl = $this->c->get('acl'),
$urlinfo = $this->c->get('urlinfo'),
$dispatcher = $this->c->get('dispatcher'),
$parser = $this->routeParser
);
$user = new User();
@@ -307,8 +314,8 @@ class ControllerWebSystem extends Controller
return $this->c->get('view')->render($response, 'system/user.twig', [
'settings' => $this->settings,
'mainnavi' => $mainNavigation,
'systemnavi' => $systemNavigation,
'jsdata' => [
'systemnavi' => $systemNavigation,
'userdata' => $userdata,
'userfields' => $userfields,
'userroles' => $this->c->get('acl')->getRoles(),
@@ -333,13 +340,14 @@ class ControllerWebSystem extends Controller
$acl = $this->c->get('acl'),
$urlinfo = $this->c->get('urlinfo'),
$dispatcher = $this->c->get('dispatcher'),
$parser = $this->routeParser
);
return $this->c->get('view')->render($response, 'system/usernew.twig', [
'settings' => $this->settings,
'mainnavi' => $mainNavigation,
'systemnavi' => $systemNavigation,
'jsdata' => [
'systemnavi' => $systemNavigation,
'userroles' => $this->c->get('acl')->getRoles(),
'labels' => $this->c->get('translations'),
'urlinfo' => $this->c->get('urlinfo')
@@ -365,7 +373,8 @@ class ControllerWebSystem extends Controller
$userrole = $request->getAttribute('c_userrole'),
$acl = $this->c->get('acl'),
$urlinfo = $this->c->get('urlinfo'),
$dispatcher = $this->c->get('dispatcher')
$dispatcher = $this->c->get('dispatcher'),
$parser = $this->routeParser
);
$pluginDefinitions = false;
@@ -379,8 +388,8 @@ class ControllerWebSystem extends Controller
return $this->c->get('view')->render($response, 'layouts/layoutSystemBlank.twig', [
'settings' => $this->settings,
'mainnavi' => $mainNavigation,
'systemnavi' => $systemNavigation,
'jsdata' => [
'systemnavi' => $systemNavigation,
'settings' => $this->settings,
'labels' => $this->c->get('translations'),
'urlinfo' => $this->c->get('urlinfo'),

View File

@@ -110,7 +110,7 @@ class Navigation extends Folder
return $allowedmainnavi;
}
public function getSystemNavigation($userrole, $acl, $urlinfo, $dispatcher)
public function getSystemNavigation($userrole, $acl, $urlinfo, $dispatcher, $routeparser)
{
$systemnavi = $this->storage->getYaml('systemSettings', '', 'systemnavi.yaml');
$systemnavi = $dispatcher->dispatch(new OnSystemnaviLoaded($systemnavi), 'onSystemnaviLoaded')->getData();
@@ -119,9 +119,9 @@ class Navigation extends Folder
foreach($systemnavi as $name => $naviitem)
{
# check if the navi-item is active (e.g if segments like "content" or "system" is in current url)
# a bit fragile because url-segment and name/key in systemnavi.yaml and plugins have to be the same
if(strpos($urlinfo['route'], 'tm/' . $name))
$naviitem['url'] = $routeparser->urlFor($naviitem['routename']);
if(strpos( trim($naviitem['url'], '/'), trim($urlinfo['route'], '/')))
{
$naviitem['active'] = true;
}
@@ -131,7 +131,7 @@ class Navigation extends Folder
$allowedsystemnavi[$name] = $naviitem;
}
}
return $allowedsystemnavi;
}

View File

@@ -850,6 +850,10 @@ video {
margin-left: 0.5rem;
}
.mb-3 {
margin-bottom: 0.75rem;
}
.ml-5 {
margin-left: 1.25rem;
}
@@ -866,10 +870,6 @@ video {
margin-top: 2rem;
}
.mb-3 {
margin-bottom: 0.75rem;
}
.ml-3 {
margin-left: 0.75rem;
}
@@ -882,10 +882,6 @@ video {
margin-top: 1.75rem;
}
.mr-4 {
margin-right: 1rem;
}
.block {
display: block;
}
@@ -1148,6 +1144,10 @@ video {
list-style-type: disc;
}
.flex-row {
flex-direction: row;
}
.flex-col {
flex-direction: column;
}
@@ -1354,11 +1354,6 @@ video {
border-color: rgb(234 179 8 / var(--tw-border-opacity));
}
.border-rose-100 {
--tw-border-opacity: 1;
border-color: rgb(255 228 230 / var(--tw-border-opacity));
}
.border-cyan-500 {
--tw-border-opacity: 1;
border-color: rgb(6 182 212 / var(--tw-border-opacity));
@@ -1369,6 +1364,11 @@ video {
border-color: rgb(226 232 240 / var(--tw-border-opacity));
}
.border-rose-100 {
--tw-border-opacity: 1;
border-color: rgb(255 228 230 / var(--tw-border-opacity));
}
.border-x-transparent {
border-left-color: transparent;
border-right-color: transparent;
@@ -1935,16 +1935,16 @@ video {
border-color: rgb(231 229 228 / var(--tw-border-opacity));
}
.hover\:border-rose-500:hover {
--tw-border-opacity: 1;
border-color: rgb(244 63 94 / var(--tw-border-opacity));
}
.hover\:border-teal-500:hover {
--tw-border-opacity: 1;
border-color: rgb(20 184 166 / var(--tw-border-opacity));
}
.hover\:border-rose-500:hover {
--tw-border-opacity: 1;
border-color: rgb(244 63 94 / var(--tw-border-opacity));
}
.hover\:bg-stone-50:hover {
--tw-bg-opacity: 1;
background-color: rgb(250 250 249 / var(--tw-bg-opacity));
@@ -2120,6 +2120,16 @@ video {
}
}
@media (min-width: 640px) {
.sm\:table-row {
display: table-row;
}
.sm\:flex-none {
flex: none;
}
}
@media (min-width: 768px) {
.md\:max-w-md {
max-width: 28rem;
@@ -2127,14 +2137,38 @@ video {
}
@media (min-width: 1024px) {
.lg\:mr-2 {
margin-right: 0.5rem;
}
.lg\:mt-4 {
margin-top: 1rem;
}
.lg\:mt-0 {
margin-top: 0px;
}
.lg\:block {
display: block;
}
.lg\:inline {
display: inline;
}
.lg\:flex {
display: flex;
}
.lg\:hidden {
display: none;
}
.lg\:h-12 {
height: 3rem;
}
.lg\:w-1\/2 {
width: 50%;
}
@@ -2147,6 +2181,10 @@ video {
width: 75%;
}
.lg\:w-half {
width: 48%;
}
.lg\:flex-row {
flex-direction: row;
}

View File

@@ -0,0 +1,116 @@
let typemillUtilities = {
setYoutubeItems: function()
{
this.youtubeItems = document.querySelectorAll( ".youtube" );
},
addYoutubePlayButtons: function(){
if(this.youtubeItems)
{
for(var i = 0; i < this.youtubeItems.length; i++)
{
var youtubeItem = this.youtubeItems[i];
this.addYoutubePlayButton(youtubeItem);
}
}
},
addYoutubePlayButton: function(element)
{
element.classList.add("video-container");
var youtubePlaybutton = document.createElement("button");
youtubePlaybutton.classList.add("play-video");
youtubePlaybutton.value = "Play";
element.appendChild(youtubePlaybutton);
},
listenToClick: function(){
document.addEventListener('click', function (event) {
/* listen to youtube */
if (event.target.matches('.play-video')) {
var youtubeID = event.target.parentNode.id;
event.preventDefault();
event.stopPropagation();
var iframe = document.createElement( "iframe" );
iframe.setAttribute( "frameborder", "0" );
iframe.setAttribute( "allowfullscreen", "" );
iframe.setAttribute( "width", "560" );
iframe.setAttribute( "height", "315" );
iframe.setAttribute( "src", "https://www.youtube-nocookie.com/embed/" + youtubeID + "?rel=0&showinfo=0&autoplay=1" );
var videocontainer = event.target.parentNode;
videocontainer.innerHTML = "";
videocontainer.appendChild( iframe );
}
if (event.target.matches('.function-delete-img')) {
event.preventDefault();
event.stopPropagation();
var imgUploadField = event.target.closest(".img-upload");
var imgSrc = imgUploadField.getElementsByClassName("function-img-src")[0];
imgSrc.src = '';
var imgUrl = imgUploadField.getElementsByClassName("function-img-url")[0];
imgUrl.value = '';
}
}, true);
},
listenToChange: function()
{
document.addEventListener('change', function (changeevent) {
/* listen to youtube */
if (changeevent.target.matches('.function-img-file')) {
if(changeevent.target.files.length > 0)
{
let imageFile = changeevent.target.files[0];
let size = imageFile.size / 1024 / 1024;
if (!imageFile.type.match('image.*'))
{
// publishController.errors.message = "Only images are allowed.";
}
else if (size > this.maxsize)
{
// publishController.errors.message = "The maximal size of images is " + this.maxsize + " MB";
}
else
{
let reader = new FileReader();
reader.readAsDataURL(imageFile);
reader.onload = function(fileevent)
{
var imgUploadField = changeevent.target.closest(".img-upload");
var imgSrc = imgUploadField.getElementsByClassName("function-img-src")[0];
imgSrc.src = fileevent.target.result;
var imgUrl = imgUploadField.getElementsByClassName("function-img-url")[0];
imgUrl.value = imageFile.name;
}
}
}
}
}, true);
},
start: function(){
this.setYoutubeItems();
this.addYoutubePlayButtons();
this.listenToClick();
this.listenToChange();
},
};

View File

@@ -1,6 +1,6 @@
app.component('component-text', {
props: ['id', 'description', 'maxlength', 'hidden', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'css', 'errors'],
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<input type="text" class="h-12 w-full border px-2 py-3" :class="errors[name] ? ' border-red-500 bg-red-100' : ' border-stone-300 bg-stone-200'"
:id="id"
@@ -26,7 +26,7 @@ app.component('component-text', {
app.component('component-textarea', {
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'css', 'value', 'errors'],
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<textarea rows="8" class="w-full border border-stone-300 bg-stone-200 px-2 py-3"
:id="id"
@@ -67,7 +67,7 @@ app.component('component-codearea', {
highlighted: '',
}
},
template: `<div :class="css ? css : 'w-full'" class="plain mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full plain mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<div class="codearea">
<textarea data-el="editor" class="editor" ref="editor"
@@ -126,7 +126,7 @@ app.component('component-codearea', {
app.component('component-select', {
props: ['id', 'description', 'readonly', 'required', 'disabled', 'label', 'name', 'type', 'css', 'options', 'value', 'errors', 'dataset', 'userroles'],
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<select class="form-select block w-full border border-stone-300 bg-stone-200 px-2 py-3 h-12 transition ease-in-out"
:id="id"
@@ -156,7 +156,7 @@ app.component('component-checkbox', {
checked: false
}
},
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<div class="block mb-1 font-medium">{{ $filters.translate(label) }}</div>
<label :for="name" class="inline-flex items-start">
<input type="checkbox" class="w-6 h-6"
@@ -194,7 +194,7 @@ app.component('component-checkboxlist', {
checkedoptions: []
}
},
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<div class="block mb-1 font-medium">{{ $filters.translate(label) }}</div>
<label class="flex items-start mb-2 mt-2" v-for="option, optionvalue in options" >
<input type="checkbox" class="w-6 h-6"
@@ -229,7 +229,7 @@ app.component('component-radio', {
picked: this.value
}
},
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<div class="block mb-1 font-medium">{{ $filters.translate(label) }}</div>
<label class="flex items-start mb-2 mt-2" v-for="option,optionvalue in options">
<input type="radio" class="w-6 h-6"
@@ -256,7 +256,7 @@ app.component('component-radio', {
app.component('component-number', {
props: ['id', 'description', 'min', 'max', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'css', 'value', 'errors'],
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<input type="number" class="h-12 w-full border border-stone-300 bg-stone-200 px-2 py-3"
:id="id"
@@ -283,7 +283,7 @@ app.component('component-number', {
app.component('component-date', {
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'css', 'value', 'errors'],
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
@@ -314,7 +314,7 @@ app.component('component-date', {
app.component('component-email', {
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'css', 'value', 'errors'],
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
@@ -347,7 +347,7 @@ app.component('component-email', {
app.component('component-tel', {
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'css', 'value', 'errors'],
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
@@ -379,7 +379,7 @@ app.component('component-tel', {
app.component('component-url', {
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'css', 'value', 'errors'],
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
@@ -412,7 +412,7 @@ app.component('component-url', {
app.component('component-color', {
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'css', 'value', 'errors'],
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
@@ -449,7 +449,7 @@ app.component('component-password', {
fieldType: "password"
};
},
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
@@ -572,7 +572,7 @@ app.component('component-customfields', {
cfvalue: [{}]
}
},
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<p v-if="fielderrors" class="text-xs text-red-500">{{ fielderrors }}</p>
<p v-else class="text-xs">{{ $filters.translate(description) }}</p>
@@ -731,15 +731,15 @@ app.component('component-image', {
qualitylabel: false,
}
},
template: `<div :class="css ? css : 'w-full'" class="mt-5 mb-5">
template: `<div :class="css ? css : ''" class="w-full mt-5 mb-5">
<label :for="name" class="block mb-1 font-medium">{{ $filters.translate(label) }}</label>
<div class="flex flex-wrap items-start">
<div class="w-half">
<div class="lg:w-half w-full">
<div class="w-80 h-80 table-cell align-middle bg-chess">
<img :src="imagepreview" class="max-w-xs max-h-80 table mx-auto">
</div>
</div>
<div class="w-half ph3 lh-copy f6 relative">
<div class="lg:w-half w-full ph3 lh-copy f6 relative">
<div class="relative w-full bg-stone-700 hover:bg-stone-900">
<p class="relative w-full text-white text-center px-2 py-3"><svg class="icon icon-upload baseline"><use xlink:href="#icon-upload"></use></svg> {{ $filters.translate('upload an image') }}</p>
<input class="absolute w-full top-0 opacity-0 bg-stone-900 cursor-pointer px-2 py-3" type="file" name="image" accept="image/*" @change="onFileChange( $event )" />

View File

@@ -2,8 +2,8 @@ const app = Vue.createApp({
template: `<Transition name="initial" appear>
<form class="inline-block w-full">
<p v-if="version.system !== undefined"><a href="https://typemill.net" class="block p-2 text-center bg-rose-500 text-white">Please update typemill to version {{ version.system }}</a></p>
<ul class="flex mt-4 mb-4">
<li v-for="tab in tabs" class="">
<ul class="flex flex-wrap mt-4 mb-4">
<li v-for="tab in tabs">
<button class="px-2 py-2 border-b-2 border-stone-200 hover:border-stone-700 transition duration-100" :class="(tab == currentTab) ? 'border-stone-700' : ''" @click.prevent="activateTab(tab)">{{ $filters.translate(tab) }}</button>
</li>
</ul>

View File

@@ -0,0 +1,39 @@
const systemnavi = Vue.createApp({
template: `
<ul class="lg:mr-2 border-l-2 border-stone-200">
<button @click="toggle" class="lg:hidden w-full flex-1 flex items-center justify-center space-x-4 p-2 mb-2 bg-stone-700 hover:bg-stone-900 text-white cursor-pointer transition duration-100">
<span>{{ $filters.translate('Menu') }}</span>
<span :class="expanded ? 'border-b-8 border-b-white' : 'border-t-8 border-t-white'" class="h-0 w-0 border-x-8 border-x-transparent"></span>
</button>
<div class="lg:block" :class="expanded ? '' : 'hidden'">
<li v-for="(navitem, name) in systemnavi" :key="name" class="mb-1">
<a :href="navitem.url" class="block p-2 border-l-4 hover:bg-stone-50 hover:border-teal-500 transition duration-100" :class="navitem.active ? ' active bg-stone-50 border-cyan-500' : ' border-slate-200'">
<svg class="icon {{ navitem.icon }} mr-2"><use xlink:href="#{{ navitem.icon }}"></use></svg> {{ $filters.translate(navitem.title) }}
</a>
</li>
</div>
</ul>
`,
data() {
return {
systemnavi: data.systemnavi,
baseurl: data.urlinfo.baseurl,
expanded: false,
}
},
mounted() {
},
methods: {
toggle()
{
if(this.expanded)
{
this.expanded = false;
}
else
{
this.expanded = true;
}
}
},
})

View File

@@ -15,13 +15,13 @@ const app = Vue.createApp({
</div>
</div>
<div class="w-full p-8">
<div class="flex pb-4">
<div class="w-1/2">
<div class="lg:flex pb-4">
<div class="lg:w-1/2 w-full">
<h2 class="text-xl font-bold mb-3">{{theme.name}}</h2>
<div class="text-xs my-3">author: <a :href="theme.homepage" class="hover:underline text-teal-500">{{theme.author}}</a> | version: {{theme.version}}</div>
<p>{{theme.description}}</p>
</div>
<div class="w-1/2 h-48 overflow-hidden">
<div class="lg:w-1/2 w-full h-48 overflow-hidden">
<img :src="theme.preview" class="w-full">
</div>
</div>

View File

@@ -183,14 +183,14 @@ app.component('searchbox', {
<button @click.prevent="setFilter('userrole')" :class="checkActive('userrole')" class="px-2 py-2 border-b-4 hover:bg-stone-200 hover:border-stone-700 transition duration-100">{{ $filters.translate('userrole') }}</button>
<button @click.prevent="setFilter('usermail')" :class="checkActive('usermail')" class="px-2 py-2 border-b-4 hover:bg-stone-200 hover:border-stone-700 transition duration-100">{{ $filters.translate('e-mail') }}</button>
</div>
<div class="w-100 flex">
<select v-if="this.filter == 'userrole'" v-model="searchterm" class="w-3/4 h-12 px-2 py-3 border border-stone-300 bg-stone-200">
<div class="w-100 lg:flex">
<select v-if="this.filter == 'userrole'" v-model="searchterm" class="lg:w-3/4 w-full h-12 px-2 py-3 border border-stone-300 bg-stone-200">
<option v-for="role in userroles">{{role}}</option>
</select>
<input v-else type="text" v-model="searchterm" class="w-3/4 h-12 px-2 py-3 border border-stone-300 bg-stone-200">
<div class="w-1/4 flex justify-around">
<button class="w-half bg-stone-200 hover:bg-stone-100" @click.prevent="clearSearch()">{{ $filters.translate('Clear') }}</button>
<button class="w-half bg-stone-700 hover:bg-stone-900 text-white" @click.prevent="startSearch()">{{ $filters.translate('Search') }}</button>
<input v-else type="text" v-model="searchterm" class="lg:w-3/4 w-full h-12 px-2 py-3 border border-stone-300 bg-stone-200">
<div class="lg:w-1/4 lg:mt-0 mt-2 w-full flex justify-around">
<button class="p-2 w-1/2 bg-stone-200 hover:bg-stone-100" @click.prevent="clearSearch()">{{ $filters.translate('Clear') }}</button>
<button class="p-2 w-1/2 bg-stone-700 hover:bg-stone-900 text-white" @click.prevent="startSearch()">{{ $filters.translate('Search') }}</button>
</div>
</div>
<div v-if="error" class="error pt1 f6">{{error}}</div>
@@ -240,24 +240,28 @@ app.component('searchbox', {
app.component('usertable', {
props: ['userdata'],
template: `<table class="w-full mt-8" cellspacing="0">
<tr>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('Username') }}</th>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('Userrole') }}</th>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('E-Mail') }}</th>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('Edit') }}</th>
</tr>
<tr v-for="user,index in userdata" key="username">
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.username }}</td>
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.userrole }}</td>
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.email }}</td>
<td class="bg-stone-100 border-2 border-white text-center hover:bg-teal-500 hover:text-white pointer transition duration-100"><a :href="getEditLink(user.username)" class="block w-full p-3">{{ $filters.translate('edit') }}</a></td>
</tr>
<tr>
<td class="p-3 bg-stone-100 border-2 border-white"><a class="text-teal-500 hover:underline" :href="getNewUserLink()">{{ $filters.translate('New user') }}</a></td>
<td class="p-3 bg-stone-100 border-2 border-white"></td>
<td class="p-3 bg-stone-100 border-2 border-white"></td>
<td class="bg-stone-100 border-2 border-white text-center text-teal-500 hover:bg-teal-500 hover:text-white transition duration-100"><a class="block w-full p-3" :href="getNewUserLink()">{{ $filters.translate('add') }}</a></td>
</tr>
<thead>
<tr>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('Username') }}</th>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('Userrole') }}</th>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('E-Mail') }}</th>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('Edit') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="user,index in userdata" key="username">
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.username }}</td>
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.userrole }}</td>
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.email }}</td>
<td class="bg-stone-100 border-2 border-white text-center hover:bg-teal-500 hover:text-white pointer transition duration-100"><a :href="getEditLink(user.username)" class="block w-full p-3">{{ $filters.translate('edit') }}</a></td>
</tr>
<tr>
<td class="p-3 bg-stone-100 border-2 border-white"><a class="text-teal-500 hover:underline" :href="getNewUserLink()">{{ $filters.translate('New user') }}</a></td>
<td class="p-3 bg-stone-100 border-2 border-white"></td>
<td class="p-3 bg-stone-100 border-2 border-white"></td>
<td class="bg-stone-100 border-2 border-white text-center text-teal-500 hover:bg-teal-500 hover:text-white transition duration-100"><a class="block w-full p-3" :href="getNewUserLink()">{{ $filters.translate('add') }}</a></td>
</tr>
</tbody>
</table>`,
methods: {
getEditLink: function(username){

View File

@@ -68,6 +68,7 @@
<script>
navigation.config.globalProperties.$filters = translatefilter;
navigation.mount('#contentNavigation');
loginform.config.globalProperties.$filters = translatefilter;
loginform.mount("#loginform");
</script>
{% block javascript %}{% endblock %}

View File

@@ -36,7 +36,7 @@
<div class="max-w-6xl m-auto mt-7 flex flex-col lg:flex-row justify-between" id="main" data-url="{{ base_url() }}">
<aside class="lg:w-1/4">
{% include 'partials/systemNavi.twig' %}
{% include 'partials/systemNavi.twig' %}
</aside>
<article class="lg:w-3/4 bg-stone-50 shadow-md p-8">
{% block content %}{% endblock %}
@@ -56,15 +56,21 @@
tmaxios.defaults.baseURL = "{{ base_url() }}";
/* header for session authentication in middleware */
tmaxios.defaults.headers.common['X-Session-Auth'] = "true";
/* tmaxios.defaults.headers.common['Authorization'] = "Basic {{ basicauth }}"; */
</script>
<script src="{{ base_url() }}/system/typemill/author/js/vue.js?v={{ settings.version }}"></script>
<script src="{{ base_url() }}/system/typemill/author/js/vue-eventbus.js?v={{ settings.version }}"></script>
<script src="{{ base_url() }}/system/typemill/author/js/vue-shared.js?v={{ settings.version }}"></script>
<script src="{{ base_url() }}/system/typemill/author/js/vue-systemnavi.js?v={{ settings.version }}"></script>
<script src="{{ base_url() }}/system/typemill/author/js/vue-medialib.js?v={{ settings.version }}"></script>
<script>
/* kixote.mount('#kixote'); */
systemnavi.config.globalProperties.$filters = translatefilter;
systemnavi.mount('#systemNavigation');
loginform.config.globalProperties.$filters = translatefilter;
loginform.mount("#loginform");
</script>
{% block javascript %}{% endblock %}

View File

@@ -28,22 +28,17 @@
{% include 'partials/symbols.twig' %}
<header class="border-b-2 border-stone-200">
<header class="border-b-2 border-stone-200">
{% include 'partials/mainNavi.twig' %}
</header>
<div class="max-w-6xl m-auto mt-7 flex justify-between" id="main" data-url="{{ base_url() }}">
<aside class="w-1/4">
<div class="max-w-6xl m-auto mt-7 flex flex-col lg:flex-row justify-between" id="main" data-url="{{ base_url() }}">
<aside class="lg:w-1/4">
{% include 'partials/systemNavi.twig' %}
</aside>
<article class="w-3/4 bg-stone-50 shadow-md p-8">
<article class="lg:w-3/4 bg-stone-50 shadow-md p-8">
<div id="system" v-cloak></div>
</article>
</div>
<div id="loginform"></div>
@@ -62,6 +57,7 @@
<script src="{{ base_url() }}/system/typemill/author/js/vue.js?v={{ settings.version }}"></script>
<script src="{{ base_url() }}/system/typemill/author/js/vue-eventbus.js?v={{ settings.version }}"></script>
<script src="{{ base_url() }}/system/typemill/author/js/vue-shared.js?v={{ settings.version }}"></script>
<script src="{{ base_url() }}/system/typemill/author/js/vue-systemnavi.js?v={{ settings.version }}"></script>
<script src="{{ base_url() }}/system/typemill/author/js/vue-medialib.js?v={{ settings.version }}"></script>
{% block javascript %}{% endblock %}
@@ -74,6 +70,10 @@
app.config.globalProperties.$filters = translatefilter;
app.mount('#system');
systemnavi.config.globalProperties.$filters = translatefilter;
systemnavi.mount('#systemNavigation');
loginform.config.globalProperties.$filters = translatefilter;
loginform.mount("#loginform");
/* kixote.mount('#kixote'); */

View File

@@ -1,14 +1,3 @@
<nav id="sidebar-menu" class="sidebar-menu">
<div id="mobile-menu" class="lg:hidden menu-action">{{ translate('Menu') }} <span class="button-arrow"></span></div>
<ul class="mr-4">
{% for name, navitem in systemnavi %}
<li class="mb-1">
<a class="block p-2 border-l-4 hover:bg-stone-50 hover:border-teal-500 transition duration-100{{ navitem.active ? ' active bg-stone-50 border-cyan-500' : ' border-slate-200' }}" href="{{ url_for(navitem.routename) }}">
<svg class="icon {{ navitem.icon }} mr-2"><use xlink:href="#{{ navitem.icon }}"></use></svg> {{ translate(navitem.title) }}
</a>
</li>
{% endfor %}
</ul>
</nav>
<nav class="max-w-6xl m-auto flex justify-between">
<div id="systemNavigation" v-cloak class="w-full"></div>
</nav>

View File

@@ -6,16 +6,16 @@ fieldsetsystem:
type: text
label: Website Title
maxlength: 60
css: w-half
css: lg:w-half
author:
type: text
label: Author
css: w-half
css: lg:w-half
maxlength: 60
copyright:
type: select
label: Copyright
css: w-half
css: lg:w-half
maxlength: 60
options:
'©': '©'
@@ -28,12 +28,12 @@ fieldsetsystem:
year:
type: text
label: Year
css: w-half
css: lg:w-half
maxlength: 4
language:
type: select
label: Language (author area)
css: w-half
css: lg:w-half
maxlength: 60
options:
'en': 'English'
@@ -45,13 +45,13 @@ fieldsetsystem:
langattr:
type: text
label: Language attribute (website)
css: w-half
css: lg:w-half
maxlength: 5
description: Please use ISO 639-1 codes like "en"
sitemap:
type: text
label: Google sitemap (readonly)
css: w-half
css: lg:w-half
disabled: true
fieldsetmedia:
type: fieldset
@@ -68,32 +68,28 @@ fieldsetmedia:
label: Standard width for live pictures
placeholder: 820
description: Default width of live images is 820px. Changes will apply to future uploads.
css: w-half
css: lg:w-half
liveimageheight:
type: number
label: Standard height for live pictures
description: If you add a value for the height, then the image will be cropped.
css: w-half
css: lg:w-half
maximageuploads:
type: number
label: Maximum size for image uploads in MB
description: The maximum image size might be limited by your server settings.
css: w-full
allowsvg:
type: checkbox
label: Allow svg
checkboxlabel: Allow the upload of svg images
css: w-full
convertwebp:
type: checkbox
label: Convert to webp
checkboxlabel: Try to convert uploaded images into the webp-format
css: w-full
maxfileuploads:
type: number
label: Maximum size for file uploads in MB
description: The maximum file size might be limited by your server settings.
css: w-full
fieldsetwriting:
type: fieldset
legend: Writing
@@ -101,14 +97,14 @@ fieldsetwriting:
editor:
type: radio
label: Standard editor mode
css: w-half
css: lg:w-half
options:
'visual': 'visual editor'
'raw': 'raw editor'
formats:
type: checkboxlist
label: Format options for visual editor
css: w-half
css: lg:w-half
options:
'markdown': 'markdown'
'headline': 'headline'
@@ -129,12 +125,10 @@ fieldsetwriting:
type: checkbox
label: Headline anchors
checkboxlabel: Show anchors next to headline in frontend
css: w-full
urlschemes:
type: text
label: Url schemes
description: Add more url schemes for external links e.g. like dict:// (comma separated list)
css: w-full
maxlength: 60
fieldsetaccess:
type: fieldset
@@ -144,27 +138,22 @@ fieldsetaccess:
type: checkbox
label: Website restriction
checkboxlabel: Show the website only to authenticated users and redirect all other users to the login page.
css: w-full
pageaccess:
type: checkbox
label: Page restriction
checkboxlabel: Activate individual restrictions for pages in the meta-tab of each page.
css: w-full
hrdelimiter:
type: checkbox
label: Content break
checkboxlabel: Cut restricted content after the first hr-element on a page (per default content will be cut after title).
css: w-full
restrictionnotice:
type: textarea
label: Restriction notice (use markdown)
css: w-full
maxlength: 2000
wraprestrictionnotice:
type: checkbox
label: Wrap restriction notice
checkboxlabel: Wrap the restriction notice above into a notice-4 element (which can be designed as special box)
css: w-full
fieldsetrecovery:
type: fieldset
legend: PW recovery
@@ -173,23 +162,19 @@ fieldsetrecovery:
type: checkbox
label: Recover password
checkboxlabel: Activate the password recovery.
css: w-full
recoverfrom:
type: text
label: Sender email
placeholder: your@email.org
css: w-full
maxlength: 60
recoversubject:
type: text
label: Email subject
placeholder: Recover your password
css: w-full
maxlength: 60
recovermessage:
type: textarea
label: Text before recover link in email message
css: w-full
maxlength: 2000
fieldsetdeveloper:
type: fieldset
@@ -199,33 +184,26 @@ fieldsetdeveloper:
type: checkbox
label: Error reporting
checkboxlabel: Display application errors
css: w-full
securitylog:
type: checkbox
label: Security log
checkboxlabel: Track spam and suspicious actions in a logfile
css: w-full
twigcache:
type: checkbox
label: Twig cache
checkboxlabel: Activate the cache for twig templates
css: w-full
refreshcache:
type: checkbox
label: Refresh cache
checkboxlabel: Refresh the cache every 10 minutes. Use this option if you change content-files via FTP.
css: w-full
proxy:
type: checkbox
label: Proxy
checkboxlabel: Use x-forwarded-header.
css: w-full
trustedproxies:
type: text
label: Trusted IPs for proxies (comma separated)
css: w-full
headersoff:
type: checkbox
label: Disable headers
checkboxlabel: Disable the typemill headers and send your owwn
css: w-full
checkboxlabel: Disable the typemill headers and send your owwn