mirror of
https://github.com/LukeHagar/unicorn-utterances.git
synced 2025-12-06 04:21:55 +00:00
add banner card generator layout
This commit is contained in:
104
build-scripts/social-previews/layouts/banner.css.ts
Normal file
104
build-scripts/social-previews/layouts/banner.css.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
export default `
|
||||
.codeScreenBg {
|
||||
perspective: 200px;
|
||||
perspective-origin: center;
|
||||
}
|
||||
|
||||
.codeScreenBg {
|
||||
background: url('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCABIAIADASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAECAwQFBv/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHhWUyNsqZRozlhDTXvDldLnCzW01KcbCmF9ImmSIotuy2G3veW9DFnC73mxUaM1XW5WTqATTGIG0iWvER2OWoggpNMQwBAwAJXGeWpmRa4mUtgQbiA0DAd4FgAAKIEEBCICiB//8QAIxAAAQQBBAIDAQAAAAAAAAAAAQACAxESECEwMSAyBBMiI//aAAgBAQABBQIbK9ogpRsw4optlRsNy+jk/rRyPg12zjaeaR9Gdtbala5SDUJ6LdtR2U0onaHuJv5LLMyDb0j9p+28AdivjzD63yU2U26/56ONnzvSGXFfbm1x/XM11c+JWJ5KKDfAhYqvOkBw0sVjp//EABQRAQAAAAAAAAAAAAAAAAAAAFD/2gAIAQMBAT8BI//EABQRAQAAAAAAAAAAAAAAAAAAAFD/2gAIAQIBAT8BI//EABsQAAMAAwEBAAAAAAAAAAAAAAABIRARIDBg/9oACAEBAAY/AsTEzCi4XSRpEzti96QvF8abS+Y//8QAHxAAAwACAgMBAQAAAAAAAAAAAAERITEQQSBRYTBx/9oACAEBAAE/IWC7RjVT+sQ6XuFc9cs31ntiNwbcLJazs2b2dHYsHZoy2ZZfPRCaIX7iGoZzgXitG4nklwQSmy2W24fC0jCkE5p+I2TIdbRTr2IXSlSsCpPCQgfxxmtImDrPkQ8jdSd8D2Yg2HRn9D2JxpmQL43hZDdKUmqkN25xdFm/ajMEbf4rjriNnwIdeM807oStkS65Sx+o2XKXgrFr8WrI4Q//2gAMAwEAAgADAAAAELF3261HEKNNDcYDWOBNCizLMDBPOYaJPPIXfHfYXP/EABQRAQAAAAAAAAAAAAAAAAAAAFD/2gAIAQMBAT8QI//EABkRAQACAwAAAAAAAAAAAAAAAAEAESAwQP/aAAgBAgEBPxDWwzSBXJ//xAAeEAEAAwEBAAMBAQAAAAAAAAABABEhMUEQUWFxgf/aAAgBAQABPxBVDED24YAfYyo4Vw9juZZ/JELbL2D6mBShKHOuv3GodNltJsiUZSpo9fs6H3KhChxss1ucJ1nsVy8nbiuBOJl0z1BayVAKHr1ZRwAL/s5eWwPZWWR4djk0u7KVMAz9jqksb3Iz9RGEuFpEos5HSyDaDOZdRcnnsESg3m+T0oTFTarZYzl9RL4obCNxQk17P9gDFr3ZQKyZYADyHRZKilpeX8FXZH7IKWx0n3LICBabuMc0mn7iGReseW6sijAKNXexalcOkfslgnXZyH8g7MMuIWuWLZX14mU5SzEZi3TRBTjHWDVkLj2XPIYQdiCuxorbi1LghuBKZFVftj1jjk9tgk9jRCPZ18ZFCwRQX8Ytahl/cI6/k/Jgh+x35DdyBbkcqN7TDkHws6Z/scbU6gxT6grjLJWwiEREEFLYQZfww/Y5EGeRP22IDrCs/9k='), radial-gradient(ellipse 200% 100%, #EEE, #FFF);
|
||||
background-blend-mode: screen;
|
||||
background-size: cover;
|
||||
z-index: -4;
|
||||
}
|
||||
|
||||
.codeScreenBg.blur {
|
||||
--gradient: linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,1));
|
||||
-webkit-mask-image: var(--gradient);
|
||||
mask-image: var(--gradient);
|
||||
filter: blur(5px);
|
||||
}
|
||||
|
||||
.codeScreen, .rect {
|
||||
--z: 0px;
|
||||
transform: rotateX(var(--rotX)) rotateY(21deg) rotateZ(336deg) translate(25%, -20%) translateZ(var(--z));
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.codeScreen {
|
||||
height: 1000px;
|
||||
overflow: hidden;
|
||||
background-color: #FFF;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 20%;
|
||||
right: 0;
|
||||
box-shadow: 0 0 180px 0 #0002;
|
||||
border-radius: 20px;
|
||||
border-left: 10px solid #CCC;
|
||||
}
|
||||
|
||||
.rect {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
background-color: #8885;
|
||||
backdrop-filter: blur(2px);
|
||||
border: 4px solid #FFF;
|
||||
box-shadow: -80px -10px 30px #0005;
|
||||
|
||||
--x: 0px;
|
||||
--y: 0px;
|
||||
--z: 80px;
|
||||
|
||||
position: absolute;
|
||||
top: calc(50% + var(--y));
|
||||
left: calc(50% + var(--x));
|
||||
}
|
||||
|
||||
.rect img {
|
||||
margin: 20px;
|
||||
width: calc(100% - 40px);
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.tags {
|
||||
position: absolute;
|
||||
top: 25%;
|
||||
left: 5%;
|
||||
font-size: 10rem;
|
||||
font-family: monospace;
|
||||
text-transform: uppercase;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.tags span {
|
||||
display: block;
|
||||
color: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
pre {
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
pre code span {
|
||||
text-shadow: currentColor 1px 0 10px;
|
||||
}
|
||||
|
||||
.absoluteFill {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.codeScreenOverlay {
|
||||
background: linear-gradient(340deg, rgba(0,0,0,.5), rgba(0,0,0,0)), url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600"><filter id="noiseFilter"><feTurbulence type="fractalNoise" baseFrequency="0.65" numOctaves="3" stitchTiles="stitch"/></filter><rect width="100%" height="100%" filter="url(%23noiseFilter)"/></svg>');
|
||||
background-blend-mode: screen;
|
||||
filter: contrast(800%) brightness(200%) saturate(0%);
|
||||
opacity: 0.1;
|
||||
z-index: -2;
|
||||
}
|
||||
`;
|
||||
60
build-scripts/social-previews/layouts/banner.tsx
Normal file
60
build-scripts/social-previews/layouts/banner.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import * as React from 'preact';
|
||||
import { readFileAsBase64 } from '../utils';
|
||||
import * as fs from 'fs';
|
||||
import { ComponentProps } from '../base';
|
||||
import style from './banner.css';
|
||||
import classnames from 'classnames';
|
||||
|
||||
const unicornFile = readFileAsBase64("src/assets/unicorn_utterances_sticker_512.png");
|
||||
|
||||
function BannerCodeScreen({
|
||||
post,
|
||||
postHtml,
|
||||
blur,
|
||||
}: {
|
||||
post: ComponentProps['post'],
|
||||
postHtml: string,
|
||||
blur?: boolean,
|
||||
}) {
|
||||
const rotX = (post.description.length % 30) - 10;
|
||||
|
||||
return <>
|
||||
<div class={classnames("absoluteFill", "codeScreenBg", blur && "blur")} style={`--rotX: ${rotX}deg;`}>
|
||||
<div class="codeScreen">
|
||||
<pre dangerouslySetInnerHTML={{ __html: postHtml }} />
|
||||
<div class="tags">
|
||||
{
|
||||
post.tags.map((tag) => (
|
||||
<span key={tag}>{tag}</span>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="rect" style="--z: 60px; --x: -80px; --y: -150px;">
|
||||
<img src={unicornFile} />
|
||||
</div>
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
|
||||
function Banner({
|
||||
post,
|
||||
postHtml,
|
||||
}: ComponentProps) {
|
||||
return <>
|
||||
<BannerCodeScreen post={post} postHtml={postHtml} />
|
||||
<BannerCodeScreen post={post} postHtml={postHtml} blur />
|
||||
<div
|
||||
className="absoluteFill codeScreenOverlay"
|
||||
style={{
|
||||
zIndex: -1,
|
||||
}}
|
||||
/>
|
||||
</>;
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "banner",
|
||||
css: style,
|
||||
Component: Banner,
|
||||
};
|
||||
@@ -1,10 +1,6 @@
|
||||
export default `
|
||||
@import url("https://fonts.googleapis.com/css2?family=Work+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: "Work Sans";
|
||||
color: var(--white);
|
||||
@@ -145,3 +141,4 @@ html, body {
|
||||
.secondHalfTitle {
|
||||
color: #f5acc9;
|
||||
}
|
||||
`;
|
||||
@@ -1,11 +1,7 @@
|
||||
import * as React from 'preact';
|
||||
import { readFileAsBase64 } from '../utils';
|
||||
import { dirname, resolve } from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { ComponentProps } from '../base';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
import style from './twitter-preview.css';
|
||||
|
||||
export function splitSentence(str: string): [string, string] {
|
||||
const splitStr = str.split(" ");
|
||||
@@ -42,9 +38,7 @@ export function splitSentence(str: string): [string, string] {
|
||||
return [str, ""];
|
||||
}
|
||||
|
||||
const unicornUtterancesHead = readFileAsBase64(
|
||||
resolve("src/assets/unicorn_head_1024.png")
|
||||
);
|
||||
const unicornUtterancesHead = readFileAsBase64("src/assets/unicorn_head_1024.png");
|
||||
|
||||
interface TwitterCodeScreenProps {
|
||||
title: string;
|
||||
@@ -131,9 +125,6 @@ const TwitterLargeCard = ({
|
||||
|
||||
export default {
|
||||
name: "twitter-preview",
|
||||
css: fs.readFileSync(
|
||||
resolve(__dirname, "./twitter-preview.css"),
|
||||
"utf8"
|
||||
),
|
||||
css: style,
|
||||
Component: TwitterLargeCard,
|
||||
};
|
||||
|
||||
@@ -12,10 +12,11 @@ import remarkToRehype from "remark-rehype";
|
||||
import { findAllAfter } from "unist-util-find-all-after";
|
||||
import rehypeStringify from "rehype-stringify";
|
||||
|
||||
import banner from "./layouts/banner";
|
||||
import twitterPreview from "./layouts/twitter-preview";
|
||||
import { Layout } from "./base";
|
||||
|
||||
export const layouts: Layout[] = [twitterPreview];
|
||||
export const layouts: Layout[] = [banner, twitterPreview];
|
||||
|
||||
// https://github.com/shikijs/twoslash/issues/147
|
||||
const remarkTwoslash =
|
||||
@@ -103,6 +104,8 @@ export const renderPostPreviewToString = async (
|
||||
</style>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: ${heightWidth.width}px;
|
||||
height: ${heightWidth.height}px;
|
||||
position: relative;
|
||||
|
||||
2
public/.gitignore
vendored
2
public/.gitignore
vendored
@@ -3,5 +3,5 @@ content/**
|
||||
.ignored_*
|
||||
unicorn-profile-pic-map.ts
|
||||
searchIndex.js
|
||||
*.twitter-preview.png
|
||||
generated/
|
||||
*.epub
|
||||
|
||||
Reference in New Issue
Block a user