social-media-cards/generator.html

341 lines
9.4 KiB
HTML
Executable File

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Generator kart na social media</title>
<style>
@font-face {
font-family: Poppins;
src: url(./poppins.ttf);
}
* {
font-family: "Noto Sans", sans-serif;
}
p {
font-family: Poppins;
}
#container {
box-sizing: border-box;
display: flex;
flex-flow: column;
width: calc(var(--scale) * var(--width));
height: calc(var(--scale) * var(--height));
position: relative;
}
#container.overflow {
display: grid !important;
--ratio: calc(var(--width-int) / var(--height-int));
--thumbnail-width: calc(
(var(--ratio) * var(--overflow-height)) * var(--scale)
);
--full-width: calc(var(--scale) * var(--overflow-width));
--margin: calc((var(--full-width) - var(--thumbnail-width)) / 2);
grid-template-columns: var(--margin) var(--thumbnail-width) var(
--margin
);
grid-template-areas: "margin-left thumbnail margin-right" "margin-left thumbnail margin-right";
width: var(--full-width) !important;
height: calc(var(--scale) * var(--overflow-height)) !important;
grid-template-rows: 1fr 10fr;
background-color: var(--yellow);
}
#container.overflow #text_box {
grid-column: 2;
grid-row: 1;
}
#text_target {
margin: 0;
margin-top: calc(var(--scale) * var(--padding));
margin-bottom: calc(var(--scale) * var(--padding));
}
#container.overflow #image_box {
grid-column: 1/4;
grid-row: 2;
}
#text_box {
background-color: black;
color: white;
border-top: var(--padding) solid var(--yellow);
border-bottom: var(--padding) solid var(--yellow);
}
#logo {
float: right;
border-left: var(--padding) solid var(--yellow);
border-right: var(--padding) solid var(--yellow);
height: calc(var(--scale) * 4 * var(--padding));
width: auto;
margin: calc(var(--scale) * var(--padding)) 0;
}
.overlay {
border: 1px solid red;
z-index: 1;
text-align: center;
opacity: 60%;
display: none;
}
.overlay--margin {
display: none;
background-image: repeating-linear-gradient(
45deg,
#ccc,
#ccc 30px,
#dbdbdb 30px,
#dbdbdb 60px
);
}
.guides .overflow .overlay--margin,
.guides .overlay--thumbnail {
display: block;
}
.overlay--margin-right {
grid-area: margin-right;
}
.overlay--margin-left {
grid-area: margin-left;
}
.overlay--thumbnail {
grid-area: thumbnail;
color: blue;
}
.guides #container:not(.overflow) .overlay--thumbnail {
position: absolute;
height: 100%;
width: 100%;
}
</style>
</head>
<body
style="
--yellow: #ffee2c;
--scale: 2;
--padding: 20px;
--width: 100px;
--height: 100px;
--overflow-width: 150px;
--overflow-height: 150px;
display: flex;
"
class="guides"
>
<section style="margin-right: 20px">
<h1>Generator kart na social media</h1>
<textarea id="text" style="width: 600px; height: 120px">
Treść komunikatu</textarea
>
<br />
<input id="file" type="file" accept="image/png, image/jpeg" />
<br />
<select id="size" onchange="resize()"></select>
<select id="scale_picker" onchange="rescale()">
<option value="1">1x</option>
<option value="2" selected>2x</option>
<option value="3">3x</option>
</select>
<input type="checkbox" id="overflow" onchange="reoverflow()" /><label
for="overflow"
>
Tryb overflow
</label>
<input type="checkbox" id="guides" onchange="reguides()" checked /><label
for="guides"
>
Pokaż prowadnice
</label>
<pre id="stats"></pre>
</section>
<section>
<h2>Twitter</h2>
<div id="container" style="">
<div id="text_box">
<img src="./logo.png" id="logo" />
<p
id="text_target"
style="
font-size: calc(var(--scale) * 16px);
padding: 0 calc(var(--padding) * var(--scale));
line-height: calc(var(--padding) * var(--scale));
"
>
Treść komunikatu
</p>
</div>
<div
id="image_box"
style="flex-grow: 1; position: relative; overflow: hidden"
>
<div
id="image_blur"
style="
height: 100%;
width: 100%;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
position: absolute;
filter: blur(10px);
"
></div>
<div
id="image"
style="
height: 100%;
width: 100%;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
position: absolute;
"
></div>
</div>
<div class="overlay overlay--margin overlay--margin-left">
ucięte z lewej, widoczne tylko po kliknięciu
</div>
<div class="overlay overlay--margin overlay--margin-right">
ucięte z prawej, widoczne tylko po kliknięciu
</div>
<div class="overlay overlay--thumbnail">widoczne na miniaturce</div>
</div>
</section>
</body>
<script>
const body = document.querySelector("body");
const sizes = {
"Twitter - 1 zdjęcie": {
thumbnail_size: [512, 313],
overflow_size: [1024, 768],
},
"Twitter - 2 zdjęcia": {
thumbnail_size: [377, 434],
overflow_size: [1024, 768],
},
"LinkedIn - 1 zdjęcie": {
thumbnail_size: [540, 346],
overflow_size: [733, 723],
},
"LinkedIn - 2 zdjęcia": {
thumbnail_size: [250, 355],
overflow_size: [733, 723],
},
};
for (const value of Object.keys(sizes)) {
const option = document.createElement("option");
option.value = value;
option.textContent = value;
size.appendChild(option);
}
function toBase64(file) {
return new Promise((resolve) => {
const FR = new FileReader();
FR.addEventListener("load", (e) => {
resolve(e.target.result);
});
FR.readAsDataURL(file);
});
}
function refreshText() {
text_target.innerHTML = text.value.replace(/\n/, "<br/>");
restats();
}
const refreshImage = async () => {
image.style.backgroundImage = `url("${await toBase64(file.files[0])}")`;
image_blur.style.backgroundImage = `url("${await toBase64(
file.files[0]
)}")`;
};
const resize = () => {
const scale = parseInt(body.style.getPropertyValue("--scale"));
const [width, height] = sizes[size.value].thumbnail_size;
const [overflow_width, overflow_height] = sizes[size.value].overflow_size;
body.style.setProperty("--width", width + "px");
body.style.setProperty("--height", height + "px");
body.style.setProperty("--width-int", width);
body.style.setProperty("--height-int", height);
body.style.setProperty("--overflow-width", overflow_width + "px");
body.style.setProperty("--overflow-height", overflow_height + "px");
restats();
};
function rescale() {
document
.querySelector("body")
.style.setProperty("--scale", scale_picker.value);
resize();
restats();
}
function reoverflow() {
const should_overflow = overflow.checked;
if (should_overflow) {
container.classList.add("overflow");
} else {
container.classList.remove("overflow");
}
restats();
}
function reguides() {
const should_guides = guides.checked;
if (should_guides) {
body.classList.add("guides");
} else {
body.classList.remove("guides");
}
restats();
}
function restats() {
const containerRect = container.getBoundingClientRect();
const thumbnailRect = document
.querySelector(".overlay--thumbnail")
.getBoundingClientRect();
const should_overflow = overflow.checked;
const overflowWidth = body.style.getPropertyValue("--overflow-width");
const overflowHeight = body.style.getPropertyValue("--overflow-height");
const basicWidth = body.style.getPropertyValue("--width-int");
const basicHeight = body.style.getPropertyValue("--height-int");
stats.textContent = `szerokość całej grafiki: ${containerRect.width}
wysokość całej grafiki: ${containerRect.height}
propocje szer/wys całej grafiki: ${
containerRect.width / containerRect.height
}
zamierzone proporcje miniaturki (szer/wys): ${basicWidth / basicHeight}
proporcje obszaru thumbnaila (szer/wys): ${
thumbnailRect.width / thumbnailRect.height
}`;
}
refreshText();
refreshImage();
resize();
rescale();
reoverflow();
reguides();
restats();
text.oninput = refreshText;
file.onchange = refreshImage;
/* [1014, 723] -- linked in */
</script>
</html>