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

V2.4.0 finish readymade themes

This commit is contained in:
trendschau
2024-05-16 07:05:25 +02:00
parent 50fd905ef8
commit 815c4cabb4
9 changed files with 481 additions and 150 deletions

View File

@@ -8,6 +8,7 @@ use Typemill\Models\Validation;
use Typemill\Models\Extension;
use Typemill\Models\Settings;
use Typemill\Static\Translations;
use Typemill\Static\Slug;
class ControllerApiSystemThemes extends Controller
{
@@ -69,4 +70,124 @@ class ControllerApiSystemThemes extends Controller
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
}
public function updateReadymade(Request $request, Response $response)
{
$params = $request->getParsedBody();
$themename = $params['theme'] ?? false;
$themeinput = $params['settings'] ?? false;
$readymadetitle = $params['readymadetitle'] ?? false;
$readymadedesc = $params['readymadedesc'] ?? false;
$extension = new Extension();
$formdefinitions = $extension->getThemeDefinition($themename);
$formdefinitions = $this->addDatasets($formdefinitions['forms']['fields']);
$themedata = [];
# validate input
$validator = new Validation();
$validatedOutput = $validator->recursiveValidation($formdefinitions, $themeinput);
if(!empty($validator->errors))
{
$response->getBody()->write(json_encode([
'message' => Translations::translate('Please correct your input.'),
'errors' => $validator->errors
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$validator = $validator->returnValidator(['themename' => $themename, 'title' => $readymadetitle, 'description' => $readymadedesc]);
$validator->rule('required', ['themename', 'title', 'description']);
$validator->rule('lengthBetween', 'description', 3, 100)->message("Length between 3 - 100");
$validator->rule('noHTML', 'description')->message(" contains HTML");
$validator->rule('regex', 'themename', '/^[a-zA-Z0-9\-]{3,40}$/')->message("only a-zA-Z0-9 with 3 - 40 chars allowed");
$validator->rule('regex', 'title', '/^[a-zA-Z0-9\-\_ ]{3,20}$/')->message("only a-zA-Z0-9 with 3 - 20 chars allowed");
if(!$validator->validate())
{
$message = 'There was an error, please try again';
$errors = $validator->errors();
$firstKey = array_key_first($errors);
if(isset($errors[$firstKey][0]))
{
$message = $firstKey . ': ' . $errors[$firstKey][0];
}
$response->getBody()->write(json_encode([
'message' => $message
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$readymadeSlug = Slug::createSlug($readymadetitle);
$readymade = [
$readymadeSlug => [
'name' => $readymadetitle,
'description' => $readymadedesc,
'delete' => true,
'settings' => $validatedOutput
]
];
$extension->storeThemeReadymade($themename, $readymadeSlug, $readymade);
$response->getBody()->write(json_encode([
'message' => Translations::translate('Readymade has been saved'),
'readymade' => $readymade,
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
}
public function deleteReadymade(Request $request, Response $response)
{
$params = $request->getParsedBody();
$themename = $params['theme'] ?? false;
$readymadeslug = $params['readymadeslug'] ?? false;
$validation = new Validation();
$validator = $validation->returnValidator($params);
$validator->rule('required', ['theme', 'readymadeslug']);
$validator->rule('regex', 'theme', '/^[a-zA-Z0-9\-]{3,40}$/')->message("only a-zA-Z0-9 with 3 - 40 chars allowed");
$validator->rule('regex', 'readymadeslug', '/^[a-zA-Z0-9\-\_ ]{3,20}$/')->message("only a-zA-Z0-9 with 3 - 20 chars allowed");
if(!$validator->validate())
{
$message = 'There was an error, please try again';
$errors = $validator->errors();
$firstKey = array_key_first($errors);
if(isset($errors[$firstKey][0]))
{
$message = $firstKey . ': ' . $errors[$firstKey][0];
}
$response->getBody()->write(json_encode([
'message' => $message
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$extension = new Extension();
$result = $extension->deleteThemeReadymade($themename, $readymadeslug);
if($result !== true)
{
$response->getBody()->write(json_encode([
'message' => Translations::translate('We could not delete the readymade.'),
'errors' => $result
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
}
$response->getBody()->write(json_encode([
'message' => Translations::translate('readymade has been deleted')
]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
}
}

View File

@@ -74,7 +74,6 @@ class ControllerWebSystem extends Controller
$extension = new Extension();
$themeDefinitions = $extension->getThemeDetails($this->settings['theme']);
$themeSettings = $extension->getThemeSettings($this->settings['themes']);
$readymades = [];
# add userroles and other datasets
foreach($themeDefinitions as $name => $definitions)
@@ -95,10 +94,10 @@ class ControllerWebSystem extends Controller
}
}
if(isset($definitions['readymades']))
{
$readymades[$name] = $definitions['readymades'];
}
# get stored indvidual readymades
$builtinReadymades = $definitions['readymades'] ?? [];
$individualReadymades = $extension->getThemeReadymades($name);
$themeDefinitions[$name]['readymades'] = $builtinReadymades + $individualReadymades;
}
$license = [];
@@ -115,7 +114,6 @@ class ControllerWebSystem extends Controller
'systemnavi' => $systemNavigation,
'settings' => $themeSettings,
'definitions' => $themeDefinitions,
'readymades' => $readymades,
'theme' => $this->settings['theme'],
'license' => $license,
'labels' => $this->c->get('translations'),

View File

@@ -99,6 +99,50 @@ class Extension
return $themeSettings;
}
public function getThemeReadymades($themeName)
{
$folder = 'readymades' . DIRECTORY_SEPARATOR . $themeName;
$readymadeFolder = $this->storage->getFolderPath('dataFolder', $folder);
$readymadeFiles = scandir($readymadeFolder);
$readymades = [];
foreach($readymadeFiles as $readymadeFile)
{
if (!in_array($readymadeFile, array(".","..")) && substr($readymadeFile, 0, 1) != '.')
{
$readymadeData = $this->storage->getYaml('dataFolder', $folder, $readymadeFile);
if($readymadeData && !empty($readymadeData))
{
$readymades = $readymades + $readymadeData;
}
}
}
return $readymades;
}
public function storeThemeReadymade($themeName, $readymadeName, $data)
{
$folder = 'readymades' . DIRECTORY_SEPARATOR . $themeName;
$result = $this->storage->updateYaml('dataFolder', $folder, $readymadeName . '.yaml', $data);
}
public function deleteThemeReadymade($themeName, $readymadeName)
{
$folder = 'readymades' . DIRECTORY_SEPARATOR . $themeName;
$result = $this->storage->deleteFile('dataFolder', $folder, $readymadeName . '.yaml');
if(!$result)
{
return $this->storage->getError();
}
return true;
}
public function getPluginDetails($userSettings = NULL)
{
$plugins = $this->getPlugins();

View File

@@ -32,7 +32,6 @@
opacity: 0;
}
.fade-enter-active {
transition: opacity 0.2s ease;
}
@@ -46,6 +45,19 @@
opacity: 0;
}
.fade-item {
transition: opacity 0.5s ease-in-out;
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s ease-in-out;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
.editableinput {
border: none;
outline: none;

View File

@@ -718,6 +718,18 @@ video {
top: 2.5rem;
}
.left-1 {
left: 0.25rem;
}
.right-1 {
right: 0.25rem;
}
.bottom-1 {
bottom: 0.25rem;
}
.z-10 {
z-index: 10;
}
@@ -746,6 +758,10 @@ video {
margin: 0.25rem;
}
.m-2 {
margin: 0.5rem;
}
.my-2 {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
@@ -826,6 +842,10 @@ video {
margin-top: 0.5rem;
}
.ml-2 {
margin-left: 0.5rem;
}
.mb-16 {
margin-bottom: 4rem;
}
@@ -850,10 +870,6 @@ video {
margin-bottom: 1.25rem;
}
.ml-2 {
margin-left: 0.5rem;
}
.mb-3 {
margin-bottom: 0.75rem;
}
@@ -886,6 +902,10 @@ video {
margin-top: 1.75rem;
}
.mt-auto {
margin-top: auto;
}
.block {
display: block;
}
@@ -962,6 +982,14 @@ video {
height: 12rem;
}
.h-64 {
height: 16rem;
}
.h-40 {
height: 10rem;
}
.max-h-80 {
max-height: 20rem;
}
@@ -1038,14 +1066,14 @@ video {
width: 83.333333%;
}
.w-10 {
width: 2.5rem;
}
.w-3\/5 {
width: 60%;
}
.w-7 {
width: 1.75rem;
}
.w-3\/4 {
width: 75%;
}
@@ -1066,8 +1094,8 @@ video {
width: 91.666667%;
}
.w-7 {
width: 1.75rem;
.w-10 {
width: 2.5rem;
}
.max-w-md {
@@ -1102,6 +1130,10 @@ video {
flex-grow: 1;
}
.grow {
flex-grow: 1;
}
.border-collapse {
border-collapse: collapse;
}
@@ -1216,10 +1248,6 @@ video {
white-space: nowrap;
}
.rounded {
border-radius: 0.25rem;
}
.border {
border-width: 1px;
}
@@ -1662,10 +1690,6 @@ video {
padding-top: 0.75rem;
}
.pb-1 {
padding-bottom: 0.25rem;
}
.text-left {
text-align: left;
}
@@ -1798,16 +1822,16 @@ video {
color: rgb(120 113 108 / var(--tw-text-opacity));
}
.text-stone-300 {
--tw-text-opacity: 1;
color: rgb(214 211 209 / var(--tw-text-opacity));
}
.text-stone-700 {
--tw-text-opacity: 1;
color: rgb(68 64 60 / var(--tw-text-opacity));
}
.text-stone-300 {
--tw-text-opacity: 1;
color: rgb(214 211 209 / var(--tw-text-opacity));
}
.text-red-500 {
--tw-text-opacity: 1;
color: rgb(239 68 68 / var(--tw-text-opacity));
@@ -2013,6 +2037,11 @@ video {
background-color: rgb(202 138 4 / var(--tw-bg-opacity));
}
.hover\:bg-rose-600:hover {
--tw-bg-opacity: 1;
background-color: rgb(225 29 72 / var(--tw-bg-opacity));
}
.hover\:text-stone-800:hover {
--tw-text-opacity: 1;
color: rgb(41 37 36 / var(--tw-text-opacity));
@@ -2047,6 +2076,12 @@ video {
opacity: 1;
}
.hover\:shadow-lg:hover {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.focus\:border-blue-600:focus {
--tw-border-opacity: 1;
border-color: rgb(37 99 235 / var(--tw-border-opacity));
@@ -2321,6 +2356,10 @@ video {
width: 25%;
}
.lg\:w-full {
width: 100%;
}
.lg\:flex-row {
flex-direction: row;
}

View File

@@ -2,7 +2,7 @@ const app = Vue.createApp({
template: `<Transition name="initial" appear>
<div class="w-full">
<ul>
<li v-for="(theme,themename) in formDefinitions" class="w-full my-8 bg-stone-100 dark:bg-stone-700 border border-stone-200">
<li v-for="(theme,themename) in formDefinitions" :key="themename" class="w-full my-8 bg-stone-100 dark:bg-stone-700 border border-stone-200">
<p v-if="versions[themename] !== undefined"><a href="https://themes.typemill.net" class="block p-2 text-center bg-rose-500 text-white">Please update to version {{ versions[themename].version }}</a></p>
<div class="flex justify-between w-full px-8 py-3 border-b border-white" :class="getActiveClass(themename)">
<p class="py-2">License: {{ theme.license }}</p>
@@ -35,31 +35,56 @@ const app = Vue.createApp({
</div>
</div>
<form class="w-full p-8" v-if="current == themename">
<!-- <div v-if="theme.readymadesNext">
<fieldset class="flex flex-wrap justify-between block border-2 border-stone-200 p-4 my-8">
<div v-if="theme.readymades">
<fieldset class="block border-2 border-stone-200 p-4 my-8">
<legend class="text-lg font-medium">Readymades</legend>
<p class="w-full bg-stone-200 mb p-2">Readymades help you to setup your theme with prefilled settings. Load some readymades, check out the frontend and adjust the settings as needed. Find more informations about specific readymades on the <a class="text-teal-500" :href="themeurl(themename)">theme's website.</p>
<p class="w-full text-center mb-4 p-2 bg-rose-500 text-white">If you load and save a readymade, then your individual settins will be overwritten and are lost!</p>
<ul class="flex flex-wrap justify-between">
<li class="w-1/3 p-2 flex">
<div class="border-2 border-stone-200">
<button class="w-full center bg-stone-200 p-2 hover:bg-stone-300 transition duration-100" @click.prevent="loadReadymade('individual')">Load individual</button>
<div class="p-3">
<p>Load your stored individual settings.</p>
<p class="w-full mb p-2">Readymades are predefined settings. Store your own readymades or load readymades to quickly setup your theme.</p>
<ul>
<transition-group name="fade" tag="ul" class="flex flex-wrap">
<li class="w-1/3 p-2" v-for="(readysetup,readyname) in theme.readymades" :key="readyname" class="fade-item">
<div class="border-2 border-stone-200 hover:shadow-lg transition duration-100 ease-in-out">
<div class="w-full font-medium p-2 text-center bg-stone-200">{{ readysetup.name }}</div>
<div class="p-3 h-40">
<p>{{ readysetup.description }}</p>
</div>
<div v-if="readysetup.delete" class="mt-auto w-full flex">
<button v-if="readysetup.delete" class="w-1/2 p-2 text-center bg-rose-500 text-stone-50 hover:bg-rose-600"
@click.prevent="deleteReadymade(readyname)"
>delete</button>
<button class="w-1/2 p-2 bg-stone-700 text-white text-center hover:bg-stone-900"
@click.prevent="loadReadymade(readyname)"
>load</button>
</div>
<div v-else class="mt-auto w-full">
<button class="p-2 w-full bg-stone-700 text-white text-center hover:bg-stone-900"
@click.prevent="loadReadymade(readyname)"
>load</button>
</div>
</div>
</div>
</li>
<li class="w-1/3 p-2 flex" v-for="(readysetup,readyname) in theme.readymades">
<div class="border-2 border-stone-200">
<button class="w-full center bg-stone-200 p-2 hover:bg-stone-300 transition duration-100" @click.prevent="loadReadymade(readyname)">Load {{ readysetup.name }}</button>
<div class="p-3">
<p>{{ readysetup.description }}</p>
</li>
<li class="w-1/3 p-2" :key="'addnewreadymade'">
<div class="flex flex-col border-2 border-stone-200 hover:shadow-lg transition duration-100 ease-in-out">
<input
type = "text"
v-model = "readymadeTitle"
@input = "checkTitle()"
placeholder = "Add a title"
class = "w-full font-medium p-2 text-center bg-stone-200">
<textarea
v-model = "readymadeDescription"
class = "p-3 h-40"
@input = "checkDescription()"
placeholder = "Add a description and store the current settings as a new readymade."></textarea>
<button class="p-2 w-full bg-stone-700 text-white text-center hover:bg-stone-900"
@click.prevent="storeReadymade()"
>store as readymade</button>
</div>
</div>
</li>
</li>
</transition-group>
</ul>
<div v-if="readymadeError" class="w-100 p-2 m-2 text-stone-50 text-center bg-rose-500">{{ readymadeError }}</div>
</fieldset>
</div> -->
</div>
<div v-for="(fieldDefinition, fieldname) in theme.forms.fields">
<fieldset class="flex flex-wrap justify-between border-2 border-stone-200 p-4 my-8" v-if="fieldDefinition.type == 'fieldset'">
<legend class="text-lg font-medium">{{ fieldDefinition.legend }}</legend>
@@ -111,19 +136,21 @@ const app = Vue.createApp({
</Transition>`,
data() {
return {
current: '',
formDefinitions: data.definitions,
formData: data.settings,
readymades: data.readymades,
theme: data.theme,
license: data.license,
message: '',
messageClass: '',
errors: {},
versions: false,
userroles: false,
showModal: false,
modalMessage: 'default',
current: '',
formDefinitions: data.definitions,
formData: data.settings,
readymadeTitle: '',
readymadeDescription: '',
readymadeError: false,
theme: data.theme,
license: data.license,
message: '',
messageClass: '',
errors: {},
versions: false,
userroles: false,
showModal: false,
modalMessage: 'default',
}
},
components: {
@@ -247,6 +274,8 @@ const app = Vue.createApp({
},
loadReadymade(name)
{
this.readymadeError = false;
if(this.readymades[this.current] && this.readymades[this.current].individual === undefined)
{
this.readymades[this.current].individual = { 'settings' : this.formData[this.current] };
@@ -258,6 +287,88 @@ const app = Vue.createApp({
eventBus.$emit('codeareaupdate');
}
},
checkTitle()
{
if(this.readymadeTitle.length > 20)
{
this.readymadeTitle = this.readymadeTitle.substring(0, 20);
}
if(this.readymadeTitle.match(/^[a-zA-Z0-9\- ]*$/))
{
this.readymadeError = false;
}
else
{
this.readymadeError = "Only characters [a-zA-Z0-9- ] are allowed."
}
},
checkDescription()
{
if(this.readymadeDescription.length > 100)
{
this.readymadeDescription = this.readymadeDescription.substring(0, 100);
}
},
storeReadymade()
{
this.readymadeError = false;
var rself = this;
tmaxios.post('/api/v1/treadymade',{
'theme': this.current,
'settings': this.formData[this.current],
'readymadetitle': this.readymadeTitle,
'readymadedesc': this.readymadeDescription
})
.then(function (response)
{
if(response.data.readymade !== undefined)
{
rself.formDefinitions[rself.current].readymades = Object.assign(rself.formDefinitions[rself.current].readymades, response.data.readymade);
rself.readymadeTitle = '';
rself.readymadeDescription = '';
}
})
.catch(function (error)
{
if(error.response)
{
if(error.response.data.message !== undefined)
{
rself.readymadeError = error.response.data.message;
}
}
});
},
deleteReadymade(name)
{
this.readymadeError = false;
var rself = this;
tmaxios.delete('/api/v1/treadymade',{
data: {
'theme': this.current,
'readymadeslug': name
}
})
.then(function (response)
{
delete rself.formDefinitions[rself.current].readymades[name];
})
.catch(function (error)
{
if(error.response)
{
if(error.response.data.message !== undefined)
{
rself.readymadeError = error.response.data.message;
}
}
});
},
save()
{
this.reset();
@@ -316,9 +427,10 @@ const app = Vue.createApp({
},
reset()
{
this.readymadeError = false;
this.errors = {};
this.message = '';
this.messageClass = '';
this.messageClass = '';
}
},
})

View File

@@ -34,6 +34,8 @@ $app->group('/api/v1', function (RouteCollectorProxy $group) use ($acl) {
$group->post('/licensetestcall', ControllerApiSystemLicense::class . ':testLicenseServerCall')->setName('api.license.testcall')->add(new ApiAuthorization($acl, 'user', 'update')); # admin
$group->post('/themecss', ControllerApiSystemThemes::class . ':updateThemeCss')->setName('api.themecss.set')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
$group->post('/theme', ControllerApiSystemThemes::class . ':updateTheme')->setName('api.theme.set')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
$group->post('/treadymade', ControllerApiSystemThemes::class . ':updateReadymade')->setName('api.treadymade.set')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
$group->delete('/treadymade', ControllerApiSystemThemes::class . ':deleteReadymade')->setName('api.treadymade.delete')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
$group->post('/plugin', ControllerApiSystemPlugins::class . ':updatePlugin')->setName('api.plugin.set')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
$group->post('/extensions', ControllerApiSystemExtensions::class . ':activateExtension')->setName('api.extension.activate')->add(new ApiAuthorization($acl, 'system', 'update')); # manager
$group->post('/versioncheck', ControllerApiSystemVersions::class . ':checkVersions')->setName('api.versioncheck')->add(new ApiAuthorization($acl, 'system', 'update')); # manager

View File

@@ -1,6 +1,6 @@
name: Cyanine Theme
version: 2.1.0
description: Cyanine is a modern and flexible multi-purpose theme and the standard theme for typemill.
version: 2.2.0
description: 'Cyanine is a modern and flexible multi-purpose theme and the standard theme for Typemill.'
author: Trendschau
homepage: https://trendschau.net
license: MIT
@@ -213,43 +213,66 @@ forms:
bloghomepage:
type: fieldset
legend: Post Configuration (Blog or News)
legend: 'Post Configuration (Blog or News)'
fields:
blogimage:
type: checkbox
label: Hero Images
checkboxlabel: Show hero images in all lists of posts
label: 'Hero Images'
checkboxlabel: 'Show hero images in all lists of posts'
blog:
type: checkbox
label: Homepage Posts
checkboxlabel: Show posts on the homepage
label: 'Posts on Homepage'
checkboxlabel: 'Show posts on the homepage'
blogfolder:
type: text
label: Homepage Posts Folder
placeholder: /blog
description: Add the relative pasts to the folder with posts that should appear on the homepage
label: 'Folder for Posts on Homepage'
placeholder: '/blog'
description: 'Add the relative pasts to the folder with posts that should appear on the homepage'
blogintro:
type: checkbox
label: Homepage Intro Text
checkboxlabel: Show the text of the homepage before the list of posts
label: 'Homepage Intro Text'
checkboxlabel: 'Show the text of the homepage and list posts below'
landing:
type: fieldset
legend: Landingpage
legend: 'Landingpage'
fields:
landingpage:
type: checkbox
checkboxlabel: Activate a landing page with segments on the homepage
checkboxlabel: 'Activate a landing page with different segments on the homepage. Configure the segments in the fieldsets below.'
introPosition:
type: number
label: 'Position of Intro Segment'
description: 'A intro segment with a title, a slogan, a call to action, and a background-image. Use 0 to disable this section.'
css: 'lg:w-full'
infoPosition:
type: number
label: 'Position of Info Segment'
description: 'A content segment with pure makrdown. Use 0 to disable the section.'
css: 'lg:w-full'
teaserPosition:
type: number
label: 'Position of Teaser Segment'
description: 'Use up to three horizontal teasers with call to action buttons. Use 0 to disable the section.'
css: 'lg:w-full'
contrastPosition:
type: number
label: 'Position of Contrast Segment'
description: 'A content segment wiht pure markdown and inverted colors for contrast. Use 0 to disable the section.'
naviPosition:
type: number
label: 'Position of Navigation Segment'
description: 'A segment with the navigation/table of contents. Use 0 to disable the section.'
newsPosition:
type: number
label: 'Position of News Segment'
description: 'A segment with three content-teasers for latest news or posts from a folder. Use 0 to disable the section.'
css: 'lg:w-full'
landingpageIntro:
type: fieldset
legend: Landingpage Intro Segment
legend: 'Landingpage Intro Segment'
fields:
introPosition:
type: number
label: Position of Intro Segment
description: Use 0 to disable the section
css: 'lg:w-full'
introFullsize:
type: checkbox
label: Full Screen
@@ -280,7 +303,7 @@ forms:
type: text
label: Background Image Opacity
placeholder: 0.8
description: 0 is fully transparent, 1 is without transparency
description: 0 is without transparency, 1 is fully transparent and invisible
introImageBlendmode:
type: select
label: Blend mode for background image
@@ -308,10 +331,6 @@ forms:
type: fieldset
legend: Landingpage Info Segment
fields:
infoPosition:
type: number
label: Position of Info Segment
description: Use 0 to disable the section
infoMarkdown:
type: textarea
label: Use Markdown
@@ -320,10 +339,6 @@ forms:
type: fieldset
legend: Landingpage Teaser Segment
fields:
teaserPosition:
type: number
label: Position of Teaser Segment
description: Use 0 to disable the section
teaser1title:
type: text
label: Teaser 1 Title
@@ -377,10 +392,6 @@ forms:
type: fieldset
legend: Landingpage Contrast Segment
fields:
contrastPosition:
type: number
label: Position of Contrast Segment
description: Use 0 to disable the section
contrastTitle:
type: text
label: Title
@@ -400,10 +411,6 @@ forms:
type: fieldset
legend: Landingpage Navigation Segment
fields:
naviPosition:
type: number
label: Position of Navi Segment
description: Use 0 to disable the section
naviTitle:
type: text
label: Title for navigation
@@ -415,27 +422,22 @@ forms:
type: fieldset
legend: Landingpage News Segment
fields:
newsPosition:
type: number
label: Position of News Segment
description: Use 0 to disable the section
css: 'lg:w-half'
newsHeadline:
type: text
label: Headline for news-segment
placeholder: News
css: 'lg:w-half'
css: 'lg:w-full'
newsFolder:
type: text
label: List entries from folder
placeholder: /blog
description: Add a path to a folder from which you want to list entries
css: 'lg:w-half'
css: 'lg:w-full'
newsLabel:
type: text
label: Label for read more link
placeholder: All News
css: 'lg:w-half'
css: 'lg:w-full'
fieldsetAuthor:
type: fieldset

View File

@@ -7,7 +7,7 @@
<aside class="grid-header ph3 pv3">
<header>
<div class="logo">
<p class="pa0 ma0">
<a class="link f1 fw9" href="{{ base_url }}" title="My Title">
@@ -44,50 +44,51 @@
<header>
<h1>{{ title }}</h1>
{% if (settings.themes.cyanine.datePosition.top or settings.themes.cyanine.authorPosition.top or settings.themes.cyanine.gitPosition.top or settings.themes.cyanine.printPosition.top) %}
<div class="f5 pv1 flex justify-between">
<div class="byline">
{% if settings.themes.cyanine.datePosition.top %}
<time pubdate datetime="{{ published }}" class="pr2">{{ settings.themes.cyanine.dateIntro }} {{ published|date(settings.themes.cyanine.dateFormat) }}</time>
{% endif %}
{% if settings.themes.cyanine.authorPosition.top %}
<adress class="pr2">{{ settings.themes.cyanine.authorIntro }} {{ metatabs.meta.author|default(settings.author) }}</adress>
{% endif %}
</div>
<div class="funcicons">
{% if settings.themes.cyanine.gitPosition.top %}
<a class="link" title="edit on github" href="{{ settings.themes.cyanine.gitLink }}{{ item.path }}">{% if settings.themes.cyanine.editIcon %}<svg class="icon baseline icon-edit"><use xlink:href="#icon-edit"></use></svg>{% else %}{{ settings.themes.cyanine.editText }}{% endif %}</a>
{% endif %}
{% if settings.themes.cyanine.printPosition.top %}
<a class="link" title="open printer dialogue" href="#" onclick="if (window.print) {window.print();}">{% if settings.themes.cyanine.printIcon %}<svg class="icon baseline icon-printer"><use xlink:href="#icon-printer"></use></svg>{% else %}{{ settings.themes.cyanine.printText }}{% endif %}</a>
{% endif %}
</div>
</div>
{% if ("top" in settings.themes.cyanine.datePosition or "top" in settings.themes.cyanine.authorPosition or "top" in settings.themes.cyanine.gitPosition or "top" in settings.themes.cyanine.printPosition) %}
<div class="f5 pv1 flex justify-between">
<div class="byline">
{% if "top" in settings.themes.cyanine.datePosition %}
<time pubdate datetime="{{ published }}" class="pr2">{{ settings.themes.cyanine.dateIntro }} {{ published|date(settings.themes.cyanine.dateFormat) }}</time>
{% endif %}
{% if "top" in settings.themes.cyanine.authorPosition %}
<adress class="pr2">{{ settings.themes.cyanine.authorIntro }} {{ metatabs.meta.author|default(settings.author) }}</adress>
{% endif %}
</div>
<div class="funcicons">
{% if "top" in settings.themes.cyanine.gitPosition %}
<a class="link" title="edit on github" href="{{ settings.themes.cyanine.gitLink }}{{ item.path }}">{% if settings.themes.cyanine.editIcon %}<svg class="icon baseline icon-pencil"><use xlink:href="#icon-pencil"></use></svg>{% else %}{{ settings.themes.cyanine.editText }}{% endif %}</a>
{% endif %}
{% if "top" in settings.themes.cyanine.printPosition %}
<a class="link" title="open printer dialogue" href="#" onclick="if (window.print) {window.print();}">{% if settings.themes.cyanine.printIcon %}<svg class="icon baseline icon-printer"><use xlink:href="#icon-printer"></use></svg>{% else %}{{ settings.themes.cyanine.printText }}{% endif %}</a>
{% endif %}
</div>
</div>
{% endif %}
</header>
{{ content }}
{% if (settings.themes.cyanine.datePosition.bottom or settings.themes.cyanine.authorPosition.bottom or settings.themes.cyanine.gitPosition.bottom or settings.themes.cyanine.printPosition.bottom) %}
<div class="f5 pv1 flex justify-between">
<div class="byline">
{% if settings.themes.cyanine.datePosition.bottom %}
<time pubdate datetime="{{ published }}" class="pr2">{{ settings.themes.cyanine.dateIntro }} {{ published|date(settings.themes.cyanine.dateFormat) }}</time>
{% endif %}
{% if settings.themes.cyanine.authorPosition.bottom %}
<adress class="pr2">{{ settings.themes.cyanine.authorIntro }} {{ metatabs.meta.author|default(settings.author) }}</adress>
{% endif %}
</div>
<div class="funcicons">
{% if settings.themes.cyanine.gitPosition.bottom %}
<a class="link" title="edit on github" href="{{ settings.themes.cyanine.gitLink }}{{ item.path }}">{% if settings.themes.cyanine.editIcon %}<svg class="icon baseline icon-edit"><use xlink:href="#icon-edit"></use></svg>{% else %}{{ settings.themes.cyanine.editText }}{% endif %}</a>
{% endif %}
{% if settings.themes.cyanine.printPosition.bottom %}
<a class="link" title="open printer dialogue" href="#" onclick="if (window.print) {window.print();}">{% if settings.themes.cyanine.printIcon %}<svg class="icon baseline icon-printer"><use xlink:href="#icon-printer"></use></svg>{% else %}{{ settings.themes.cyanine.printText }}{% endif %}</a>
{% endif %}
</div>
</div>
{% if ("bottom" in settings.themes.cyanine.datePosition or "bottom" in settings.themes.cyanine.authorPosition or "bottom" in settings.themes.cyanine.gitPosition or "bottom" in settings.themes.cyanine.printPosition) %}
<div class="f5 pv1 flex justify-between">
<div class="byline">
{% if "bottom" in settings.themes.cyanine.datePosition %}
<time pubdate datetime="{{ published }}" class="pr2">{{ settings.themes.cyanine.dateIntro }} {{ published|date(settings.themes.cyanine.dateFormat) }}</time>
{% endif %}
{% if "bottom" in settings.themes.cyanine.authorPosition %}
<adress class="pr2">{{ settings.themes.cyanine.authorIntro }} {{ metatabs.meta.author|default(settings.author) }}</adress>
{% endif %}
</div>
<div class="funcicons">
{% if "bottom" in settings.themes.cyanine.gitPosition %}
<a class="link" title="edit on github" href="{{ settings.themes.cyanine.gitLink }}{{ item.path }}">{% if settings.themes.cyanine.editIcon %}<svg class="icon baseline icon-pencil"><use xlink:href="#icon-pencil"></use></svg>{% else %}{{ settings.themes.cyanine.editText }}{% endif %}</a>
{% endif %}
{% if "bottom" in settings.themes.cyanine.printPosition %}
<a class="link" title="open printer dialogue" href="#" onclick="if (window.print) {window.print();}">{% if settings.themes.cyanine.printIcon %}<svg class="icon baseline icon-printer"><use xlink:href="#icon-printer"></use></svg>{% else %}{{ settings.themes.cyanine.printText }}{% endif %}</a>
{% endif %}
</div>
</div>
{% endif %}
</article>