change layout: add tool menu
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Simon Vieille 2024-04-14 19:39:47 +02:00
parent e34262f494
commit 47a2365c60
Signed by: deblan
GPG key ID: 579388D585F70417
2 changed files with 343 additions and 269 deletions

View file

@ -1,7 +1,7 @@
<template>
<div class="">
<TopMenu />
<main class="py-6 grid grid-cols-1 gap-y-8 lg:py-12 lg:grid-cols-[1fr_2fr] lg:gap-x-20">
<main class="pt-5 grid grid-cols-1 lg:grid-cols-[1fr_2fr] lg:gap-x-20">
<RouterView />
</main>
</div>

View file

@ -1,287 +1,330 @@
<template>
<div class="md:grid md:grid-cols-12 md:col-span-12">
<div class="col-span-3 flex flex-col gap-4 lg:gap-6">
<div class="drop-shadow-md rounded-md md:border border-zinc-300 p-5">
<div>
<TextareaForm
id="heading"
v-model="heading"
label="Heading"
/>
<RangeForm
id="heading-size"
v-model="headingSize"
min="1"
max="10"
step="0.1"
/>
</div>
<div
class="col-span-3 lg:mr-4 tools"
ref="tools"
>
<div class="mb-2">
<button
class="p-3 mr-2 rounded"
:class="{'bg-slate-300': this.tool == 'heading'}"
@click="this.tool = 'heading'"
>Heading</button>
<div class="py-6">
<TextareaForm
id="subheading"
v-model="subheading"
label="Subheading"
/>
<RangeForm
id="subheading-size"
v-model="subheadingSize"
min="1"
max="10"
step="0.1"
/>
</div>
<button
class="p-3 mr-2 rounded"
:class="{'bg-slate-300': this.tool == 'author'}"
@click="this.tool = 'author'"
>Author</button>
<div class="pb-6">
<CheckboxForm
id="allow-html"
v-model="allowHtml"
label="Allow HTML"
/>
</div>
<button
class="p-3 mr-2 rounded"
:class="{'bg-slate-300': this.tool == 'background'}"
@click="this.tool = 'background'"
>Background</button>
<div class="pb-6">
<RangeForm
id="content-padding"
v-model="contentPadding"
min="0"
max="50"
step="0.05"
label="Padding"
/>
</div>
<div class="pb-3">
<InputForm
id="text-color"
v-model="textColor"
label="Text color"
type="color"
/>
</div>
<div class="pb-6">
<SelectForm
id="font"
v-model="font"
:items="fonts"
label="Font"
/>
</div>
<div>
<div class="text-center stroke-gray-400">
<AlignForm v-model="headingAlign" />
</div>
</div>
<button
class="p-3 rounded"
:class="{'bg-slate-300': this.tool == 'size'}"
@click="this.tool = 'size'"
>Size</button>
</div>
<div class="drop-shadow-md rounded-md md:border border-zinc-300 p-5">
<div>
<InputForm
id="author"
v-model="author"
label="Author"
/>
</div>
<div class="py-6">
<FileForm
id="avatar"
v-model="avatar"
label="Avatar"
/>
</div>
<div>
<FileForm
id="logo"
v-model="logo"
label="Logo"
/>
</div>
<div class="stroke-gray-400 py-6">
<RangeForm
id="author-margin-bottom"
v-model="authorMarginBottom"
min="0"
max="500"
step="0.1"
label="Position"
/>
<RangeForm
id="author-padding"
v-model="authorPadding"
min="0"
max="50"
step="0.05"
label="Padding"
/>
</div>
<div class="pb-3">
<InputForm
id="author-text-color"
v-model="authorTextColor"
label="Text color"
type="color"
/>
</div>
<div>
<InputForm
id="background-color"
v-model="authorBackgroundColor"
label="Background color"
type="color"
/>
<RangeForm
id="author-background-opacity"
v-model="authorBackgroundOpacity"
min="0"
max="1"
step="0.05"
/>
</div>
<div>
<div class="text-center stroke-gray-400 pt-5">
<AlignForm v-model="authorAlign" />
</div>
</div>
</div>
</div>
<div class="col-span-3 md:px-10 flex flex-col gap-4 lg:gap-6">
<div class="drop-shadow-md rounded-md md:border border-zinc-300 p-5">
<div class="py-6">
<FileForm
id="background"
v-model="background"
label="Background"
/>
</div>
<div>
<InputForm
id="background-hover"
v-model="backgroundHover"
label="Background hover"
type="color"
/>
<RangeForm
id="background-hover-opacity"
v-model="backgroundHoverOpacity"
min="0"
max="1"
step="0.05"
/>
</div>
</div>
<div class="drop-shadow-md rounded-md md:border border-zinc-300 p-5">
<div>
<label
class="block text-sm font-medium text-gray-700"
for="width"
>Size and quality</label>
<div class="grid grid-cols-2 gap-x-4">
<InputForm
id="width"
v-model="width"
type="number"
<div
:class="{hidden: this.tool !== 'heading'}"
class="drop-shadow-md rounded-md md:border border-zinc-300 tool"
>
<div class="p-5">
<div>
<TextareaForm
id="heading"
v-model="heading"
label="Heading"
/>
<InputForm
id="height"
v-model="height"
type="number"
<RangeForm
id="heading-size"
v-model="headingSize"
min="1"
max="20"
step="0.1"
/>
</div>
<RangeForm
id="quality"
v-model="quality"
min="0"
max="1"
step="0.05"
/>
<div class="py-6">
<TextareaForm
id="subheading"
v-model="subheading"
label="Subheading"
/>
<RangeForm
id="subheading-size"
v-model="subheadingSize"
min="1"
max="20"
step="0.1"
/>
</div>
<div class="pb-6">
<CheckboxForm
id="allow-html"
v-model="allowHtml"
label="Allow HTML"
/>
</div>
<div class="pb-6">
<RangeForm
id="content-padding"
v-model="contentPadding"
min="0"
max="300"
step="0.05"
label="Padding"
/>
</div>
<div class="pb-3">
<InputForm
id="text-color"
v-model="textColor"
label="Text color"
type="color"
/>
</div>
<div class="pb-6">
<SelectForm
id="font"
v-model="font"
:items="fonts"
label="Font"
/>
</div>
<div>
<div class="text-center stroke-gray-400">
<AlignForm v-model="headingAlign" />
</div>
</div>
</div>
</div>
<div
:class="{hidden: this.tool !== 'author'}"
class="drop-shadow-md rounded-md md:border border-zinc-300 tool"
>
<div class="p-5">
<div>
<InputForm
id="author"
v-model="author"
label="Author"
/>
</div>
<div class="py-6">
<FileForm
id="avatar"
v-model="avatar"
label="Avatar"
/>
</div>
<div>
<FileForm
id="logo"
v-model="logo"
label="Logo"
/>
</div>
<div class="stroke-gray-400 py-6">
<RangeForm
id="author-margin-bottom"
v-model="authorMarginBottom"
min="0"
max="500"
step="0.1"
label="Position"
/>
<RangeForm
id="author-padding"
v-model="authorPadding"
min="0"
max="50"
step="0.05"
label="Padding"
/>
</div>
<div class="pb-3">
<InputForm
id="author-text-color"
v-model="authorTextColor"
label="Text color"
type="color"
/>
</div>
<div>
<InputForm
id="background-color"
v-model="authorBackgroundColor"
label="Background color"
type="color"
/>
<RangeForm
id="author-background-opacity"
v-model="authorBackgroundOpacity"
min="0"
max="1"
step="0.05"
/>
</div>
<div>
<div class="text-center stroke-gray-400 pt-5">
<AlignForm v-model="authorAlign" />
</div>
</div>
</div>
</div>
<div
:class="{hidden: this.tool !== 'background'}"
class="drop-shadow-md rounded-md md:border border-zinc-300 tool"
>
<div class="p-5">
<div class="pb-6">
<FileForm
id="background"
v-model="background"
label="Background"
/>
</div>
<div>
<InputForm
id="background-hover"
v-model="backgroundHover"
label="Background hover"
type="color"
/>
<RangeForm
id="background-hover-opacity"
v-model="backgroundHoverOpacity"
min="0"
max="1"
step="0.05"
/>
</div>
</div>
</div>
<div
:class="{hidden: this.tool !== 'size'}"
class="drop-shadow-md rounded-md md:border border-zinc-300 tool"
>
<div class="p-5">
<div>
<label
class="block text-sm font-medium text-gray-700"
for="width"
>Size</label>
<div class="grid grid-cols-2 gap-x-4">
<InputForm
id="width"
v-model="width"
type="number"
/>
<InputForm
id="height"
v-model="height"
type="number"
/>
</div>
</div>
</div>
</div>
</div>
<div
ref="ogwrapper"
class="col-span-6 space-y-6"
class="og-wrapper col-span-9 lg:pl-10"
>
<div
ref="og"
class="og"
:style="ogStyle()"
>
<div class="og-wrapper-content">
<div
class="og-image"
:style="ogImageStyle()"
ref="og"
class="og"
:style="ogStyle()"
>
<div
class="og-image-hover"
:style="ogImageHoverStyle()"
class="og-image"
ref="ogimage"
:style="ogImageStyle()"
>
<div
class="h-full flex flex-col justify-between"
:style="ogContentStyle()"
class="og-image-hover"
:style="ogImageHoverStyle()"
>
<div v-if="allowHtml">
<h1
class="leading-none"
:style="ogHeadingStyle()"
v-html="heading"
/>
<p
class="mt-10 mb-16 leading-tight"
:style="ogSubheadingStyle()"
v-html="subheading"
/>
</div>
<div v-else>
<h1
class="leading-none"
:style="ogHeadingStyle()"
v-text="heading"
/>
<p
class="mt-10 mb-16 leading-tight"
:style="ogSubheadingStyle()"
v-text="subheading"
/>
</div>
<div
class="w-full flex flex-row items-center og-image--footer"
:style="ogAuthorStyle()"
class="h-full flex flex-col justify-between"
:style="ogContentStyle()"
>
<img
v-if="avatar"
class="h-10 w-10 rounded-full"
:src="avatar"
>
<div v-if="allowHtml">
<h1
class="leading-none"
:style="ogHeadingStyle()"
v-html="heading"
/>
<p
class="mt-10 mb-16 leading-tight"
:style="ogSubheadingStyle()"
v-html="subheading"
/>
</div>
<div v-else>
<h1
class="leading-none"
:style="ogHeadingStyle()"
v-text="heading"
/>
<p
class="mt-10 mb-16 leading-tight"
:style="ogSubheadingStyle()"
v-text="subheading"
/>
</div>
<span
class="mx-4"
:style="ogAuthorTextStyle()"
v-text="author"
/>
<img
v-if="logo"
class="h-10 w-10 rounded-full"
:src="logo"
<div
class="w-full flex flex-row items-center og-image--footer"
:style="ogAuthorStyle()"
>
<img
v-if="avatar"
class="h-10 w-10 rounded-full"
:src="avatar"
>
<span
class="mx-4"
:style="ogAuthorTextStyle()"
v-text="author"
/>
<img
v-if="logo"
class="h-10 w-10 rounded-full"
:src="logo"
>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="text-center">
<div class="text-center mt-3">
<DownloadButton
class="rounded-l-md"
label="PNG"
@ -294,6 +337,8 @@
/>
</div>
</div>
<div id="bottom"></div>
</div>
</template>
@ -322,6 +367,7 @@ export default {
},
data() {
return {
tool: localStorage.getItem('tool') ?? 'heading',
author: localStorage.getItem('author'),
authorPadding: localStorage.getItem('authorPadding') ?? 0,
authorAlign: localStorage.getItem('authorAlign') ?? 'left',
@ -343,7 +389,6 @@ export default {
subheadingSize: localStorage.getItem('subheadingSize') ?? 2,
width: localStorage.getItem('width') ?? 1920,
height: localStorage.getItem('height') ?? 1080,
quality: localStorage.getItem('quality') ?? 0.9,
contentPadding: localStorage.getItem('contentPadding') ?? 2.5,
allowHtml: localStorage.getItem('allowHtml'),
ogMaxWidth: 100,
@ -363,6 +408,9 @@ export default {
}
},
watch: {
tool(value) {
localStorage.setItem('tool', value)
},
author(value) {
localStorage.setItem('author', value)
},
@ -423,9 +471,6 @@ export default {
height(value) {
localStorage.setItem('height', value)
},
quality(value) {
localStorage.setItem('quality', value)
},
contentPadding(value) {
localStorage.setItem('contentPadding', value)
},
@ -444,18 +489,25 @@ export default {
ogStyle() {
return {
color: this.textColor,
width: `${this.width}px`,
maxWidth: `${this.ogMaxWidth}px`,
fontFamily: this.font,
maxHeight: `${this.ogMaxHeight}px`,
maxWidth: `${this.ogMaxWidth}px !important`,
aspectRatio: `${this.width}/${this.height}`,
}
},
ogImageStyle() {
if (this.background) {
return {
background: `url(${this.background}) center`,
backgroundSize: 'cover',
}
let value = {
maxHeight: `${this.ogMaxHeight}px`,
maxWidth: `${this.ogMaxWidth}px`,
aspectRatio: `${this.width}/${this.height}`,
}
if (this.background) {
value.background = `url(${this.background}) center`
value.backgroundSize = 'cover'
}
return value
},
ogHeadingStyle() {
return {
@ -513,7 +565,9 @@ export default {
return {
background,
aspectRatio: `${this.width}/${this.height}`
aspectRatio: `${this.width}/${this.height}`,
maxHeight: `${this.ogMaxHeight}px`,
maxWidth: `${this.ogMaxWidth}px`,
}
},
ogContentStyle() {
@ -530,12 +584,12 @@ export default {
return this.download(toJpeg, 'image.jpg')
},
download(callback, filename) {
const element = this.$refs.og
const element = this.$refs.ogimage
callback(this.$refs.og, {
callback(element, {
canvasWidth: this.width,
canvasHeight: this.height,
quality: this.quality,
quality: 1,
})
.then((dataUrl) => {
const link = document.createElement('a')
@ -552,7 +606,8 @@ export default {
},
updateOgMaxWidth() {
this.$refs.og.style.display = 'none'
this.ogMaxWidth = this.$refs.ogwrapper.offsetWidth
this.ogMaxWidth = this.$refs.ogwrapper.offsetWidth - 30
this.ogMaxHeight = this.$refs.tools.offsetHeight - 50
this.$refs.og.style.display = 'block'
},
}
@ -560,12 +615,31 @@ export default {
</script>
<style>
#bottom {
position: fixed;
bottom: 0;
}
.tool {
max-height: calc(100vh - 250px);
overflow: auto;
}
.tools {
height: calc(100vh - 250px);
}
.og {
background: #cecece;
max-width: 10px;
margin: auto;
}
.og-wrapper-content {
background-color: #c1c1c1;
background-image: linear-gradient(45deg, #646464 25%, transparent 25%, transparent 75%, #646464 75%), linear-gradient(45deg, #646464 25%, transparent 25%, transparent 75%, #646464 75%);
background-size: 20px 20px;
background-position: 0 0, 10px 10px;
}
.og-heading {
font-size: 5em;
}