445 lines
11 KiB
Vue
445 lines
11 KiB
Vue
<template>
|
|
<div class="grid grid-cols-12 col-span-12">
|
|
<div class="col-span-3 flex flex-col gap-4 lg:gap-6">
|
|
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
|
<div>
|
|
<InputForm
|
|
id="heading"
|
|
v-model="heading"
|
|
label="Heading"
|
|
/>
|
|
<RangeForm
|
|
id="heading-size"
|
|
v-model="headingSize"
|
|
min="1"
|
|
max="10"
|
|
step="0.1"
|
|
/>
|
|
</div>
|
|
|
|
<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>
|
|
|
|
<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 class="drop-shadow-md rounded-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>
|
|
</div>
|
|
<div class="col-span-3 px-10 flex flex-col gap-4 lg:gap-6">
|
|
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
|
<div>
|
|
<InputForm
|
|
id="text-color"
|
|
v-model="textColor"
|
|
label="Text color"
|
|
type="color"
|
|
/>
|
|
</div>
|
|
|
|
<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 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"
|
|
/>
|
|
<InputForm
|
|
id="height"
|
|
v-model="height"
|
|
type="number"
|
|
/>
|
|
</div>
|
|
|
|
<RangeForm
|
|
id="quality"
|
|
v-model="quality"
|
|
min="0"
|
|
max="1"
|
|
step="0.05"
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<RangeForm
|
|
id="content-padding"
|
|
v-model="contentPadding"
|
|
min="2.5"
|
|
max="10"
|
|
step="0.05"
|
|
label="Box padding"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
ref="ogwrapper"
|
|
class="col-span-6 space-y-6"
|
|
>
|
|
<div
|
|
ref="og"
|
|
class="og"
|
|
:style="ogStyle()"
|
|
>
|
|
<div
|
|
class="og-image"
|
|
:style="ogImageStyle()"
|
|
>
|
|
<div
|
|
class="og-image-hover"
|
|
:style="ogImageHoverStyle()"
|
|
>
|
|
<div
|
|
class="h-full flex flex-col justify-between"
|
|
:style="ogContentStyle()"
|
|
>
|
|
<div>
|
|
<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">
|
|
<img
|
|
v-if="avatar"
|
|
class="mr-4 h-10 w-10 rounded-full"
|
|
:src="avatar"
|
|
>
|
|
|
|
<span
|
|
class="mr-auto"
|
|
v-text="author"
|
|
/>
|
|
|
|
<img
|
|
v-if="logo"
|
|
class="mr-4 h-10 w-10 rounded-full"
|
|
:src="logo"
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-center">
|
|
<DownloadButton
|
|
class="rounded-l-md"
|
|
label="PNG"
|
|
@click="downloadAsPng"
|
|
/>
|
|
<DownloadButton
|
|
class="rounded-r-md"
|
|
label="JPEG"
|
|
@click="downloadAsJpeg"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { hexToRgb } from '../util/color'
|
|
import { toPng, toJpeg } from 'html-to-image'
|
|
import InputForm from '../ui/InputForm'
|
|
import RangeForm from '../ui/RangeForm'
|
|
import TextareaForm from '../ui/TextareaForm'
|
|
import FileForm from '../ui/FileForm'
|
|
import SelectForm from '../ui/SelectForm'
|
|
import AlignForm from '../ui/AlignForm'
|
|
import DownloadButton from '../ui/DownloadButton'
|
|
|
|
export default {
|
|
components: {
|
|
InputForm,
|
|
RangeForm,
|
|
TextareaForm,
|
|
FileForm,
|
|
SelectForm,
|
|
AlignForm,
|
|
DownloadButton,
|
|
},
|
|
data() {
|
|
return {
|
|
author: localStorage.getItem('author'),
|
|
heading: localStorage.getItem('heading'),
|
|
subheading: localStorage.getItem('subheading'),
|
|
headingAlign: localStorage.getItem('headingAlign') ?? 'left',
|
|
font: localStorage.getItem('font') ?? 'Trebuchet MS',
|
|
avatar: localStorage.getItem('avatar'),
|
|
logo: localStorage.getItem('logo'),
|
|
textColor: localStorage.getItem('textColor') ?? '#333333',
|
|
background: localStorage.getItem('background'),
|
|
backgroundHover: localStorage.getItem('backgroundHover') ?? '#000000',
|
|
backgroundHoverOpacity: localStorage.getItem('backgroundHoverOpacity') ?? 0,
|
|
headingSize: localStorage.getItem('headingSize') ?? 4,
|
|
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,
|
|
ogMaxWidth: 100,
|
|
|
|
fonts: [
|
|
{label: 'Arial (sans-serif)', value : 'Arial'},
|
|
{label: 'Brush Script MT (cursive)', value : 'Brush Script MT'},
|
|
{label: 'Calibri (sans-serif)', value : 'Calibri'},
|
|
{label: 'Courier New (monospace)', value : 'Courier New'},
|
|
{label: 'Garamond (serif)', value : 'Garamond'},
|
|
{label: 'Georgia (serif)', value : 'Georgia'},
|
|
{label: 'Tahoma (sans-serif)', value : 'Tahoma'},
|
|
{label: 'Times New Roman (serif)', value : 'Times New Roman'},
|
|
{label: 'Trebuchet MS (sans-serif)', value : 'Trebuchet MS'},
|
|
{label: 'Verdana (sans-serif)', value : 'Verdana'},
|
|
],
|
|
}
|
|
},
|
|
watch: {
|
|
author(value) {
|
|
localStorage.setItem('author', value)
|
|
},
|
|
heading(value) {
|
|
localStorage.setItem('heading', value)
|
|
},
|
|
subheading(value) {
|
|
localStorage.setItem('subheading', value)
|
|
},
|
|
avatar(value) {
|
|
localStorage.setItem('avatar', value)
|
|
},
|
|
logo(value) {
|
|
localStorage.setItem('logo', value)
|
|
},
|
|
textColor(value) {
|
|
localStorage.setItem('textColor', value)
|
|
},
|
|
background(value) {
|
|
localStorage.setItem('background', value)
|
|
},
|
|
backgroundHover(value) {
|
|
localStorage.setItem('backgroundHover', value)
|
|
},
|
|
backgroundHoverOpacity(value) {
|
|
localStorage.setItem('backgroundHoverOpacity', value)
|
|
},
|
|
headingSize(value) {
|
|
localStorage.setItem('headingSize', value)
|
|
},
|
|
subheadingSize(value) {
|
|
localStorage.setItem('subheadingSize', value)
|
|
},
|
|
headingAlign(value) {
|
|
localStorage.setItem('headingAlign', value)
|
|
},
|
|
width(value) {
|
|
localStorage.setItem('width', value)
|
|
},
|
|
height(value) {
|
|
localStorage.setItem('height', value)
|
|
},
|
|
quality(value) {
|
|
localStorage.setItem('quality', value)
|
|
},
|
|
contentPadding(value) {
|
|
localStorage.setItem('contentPadding', value)
|
|
},
|
|
font(value) {
|
|
localStorage.setItem('font', value)
|
|
},
|
|
},
|
|
mounted() {
|
|
this.updateOgMaxWidth()
|
|
window.addEventListener('resize', this.updateOgMaxWidth, false)
|
|
},
|
|
methods: {
|
|
ogStyle() {
|
|
return {
|
|
color: this.textColor,
|
|
width: `${this.width}px`,
|
|
maxWidth: `${this.ogMaxWidth}px`,
|
|
fontFamily: this.font,
|
|
}
|
|
},
|
|
ogImageStyle() {
|
|
if (this.background) {
|
|
return {
|
|
background: `url(${this.background}) center`,
|
|
backgroundSize: 'cover',
|
|
}
|
|
}
|
|
},
|
|
ogHeadingStyle() {
|
|
return {
|
|
fontSize: `${this.headingSize}em`,
|
|
textAlign: this.headingAlign,
|
|
}
|
|
},
|
|
ogSubheadingStyle() {
|
|
return {
|
|
fontSize: `${this.subheadingSize}em`,
|
|
textAlign: this.headingAlign,
|
|
}
|
|
},
|
|
ogImageHoverStyle() {
|
|
let background = 'none'
|
|
|
|
if (this.backgroundHover) {
|
|
const colors = hexToRgb(this.backgroundHover)
|
|
background = `rgba(${colors.red}, ${colors.green}, ${colors.blue}, ${this.backgroundHoverOpacity})`
|
|
}
|
|
|
|
return {
|
|
background,
|
|
aspectRatio: `${this.width}/${this.height}`
|
|
}
|
|
},
|
|
ogContentStyle() {
|
|
return {
|
|
padding: `${this.contentPadding}em`,
|
|
}
|
|
},
|
|
downloadAsPng() {
|
|
return this.download(toPng, 'image.png')
|
|
},
|
|
downloadAsJpeg() {
|
|
return this.download(toJpeg, 'image.jpg')
|
|
},
|
|
download(callback, filename) {
|
|
const element = this.$refs.og
|
|
|
|
callback(this.$refs.og, {
|
|
canvasWidth: this.width,
|
|
canvasHeight: this.height,
|
|
quality: this.quality,
|
|
})
|
|
.then((dataUrl) => {
|
|
const link = document.createElement('a')
|
|
|
|
link.setAttribute('href', dataUrl)
|
|
link.setAttribute('download', filename)
|
|
link.click()
|
|
})
|
|
.catch((error) => {
|
|
element.classList.toggle('og--scale', false)
|
|
|
|
console.error('oops, something went wrong!', error);
|
|
})
|
|
},
|
|
updateOgMaxWidth() {
|
|
this.$refs.og.style.display = 'none'
|
|
this.ogMaxWidth = this.$refs.ogwrapper.offsetWidth
|
|
this.$refs.og.style.display = 'block'
|
|
},
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.og {
|
|
background: #cecece;
|
|
max-width: 10px;
|
|
margin: auto;
|
|
}
|
|
|
|
.og-heading {
|
|
font-size: 5em;
|
|
}
|
|
|
|
.og-subheading {
|
|
font-size: 3em;
|
|
}
|
|
|
|
.og-image--footer {
|
|
font-size: 1.3em;
|
|
}
|
|
|
|
.og-image-hover {
|
|
overflow: hidden;
|
|
}
|
|
</style>
|