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");
|
@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";
|
font-family: "Work Sans";
|
||||||
color: var(--white);
|
color: var(--white);
|
||||||
@@ -145,3 +141,4 @@ html, body {
|
|||||||
.secondHalfTitle {
|
.secondHalfTitle {
|
||||||
color: #f5acc9;
|
color: #f5acc9;
|
||||||
}
|
}
|
||||||
|
`;
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
import * as React from 'preact';
|
import * as React from 'preact';
|
||||||
import { readFileAsBase64 } from '../utils';
|
import { readFileAsBase64 } from '../utils';
|
||||||
import { dirname, resolve } from 'path';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import { ComponentProps } from '../base';
|
import { ComponentProps } from '../base';
|
||||||
import { fileURLToPath } from 'url';
|
import style from './twitter-preview.css';
|
||||||
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
||||||
|
|
||||||
export function splitSentence(str: string): [string, string] {
|
export function splitSentence(str: string): [string, string] {
|
||||||
const splitStr = str.split(" ");
|
const splitStr = str.split(" ");
|
||||||
@@ -42,9 +38,7 @@ export function splitSentence(str: string): [string, string] {
|
|||||||
return [str, ""];
|
return [str, ""];
|
||||||
}
|
}
|
||||||
|
|
||||||
const unicornUtterancesHead = readFileAsBase64(
|
const unicornUtterancesHead = readFileAsBase64("src/assets/unicorn_head_1024.png");
|
||||||
resolve("src/assets/unicorn_head_1024.png")
|
|
||||||
);
|
|
||||||
|
|
||||||
interface TwitterCodeScreenProps {
|
interface TwitterCodeScreenProps {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -131,9 +125,6 @@ const TwitterLargeCard = ({
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "twitter-preview",
|
name: "twitter-preview",
|
||||||
css: fs.readFileSync(
|
css: style,
|
||||||
resolve(__dirname, "./twitter-preview.css"),
|
|
||||||
"utf8"
|
|
||||||
),
|
|
||||||
Component: TwitterLargeCard,
|
Component: TwitterLargeCard,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ import remarkToRehype from "remark-rehype";
|
|||||||
import { findAllAfter } from "unist-util-find-all-after";
|
import { findAllAfter } from "unist-util-find-all-after";
|
||||||
import rehypeStringify from "rehype-stringify";
|
import rehypeStringify from "rehype-stringify";
|
||||||
|
|
||||||
|
import banner from "./layouts/banner";
|
||||||
import twitterPreview from "./layouts/twitter-preview";
|
import twitterPreview from "./layouts/twitter-preview";
|
||||||
import { Layout } from "./base";
|
import { Layout } from "./base";
|
||||||
|
|
||||||
export const layouts: Layout[] = [twitterPreview];
|
export const layouts: Layout[] = [banner, twitterPreview];
|
||||||
|
|
||||||
// https://github.com/shikijs/twoslash/issues/147
|
// https://github.com/shikijs/twoslash/issues/147
|
||||||
const remarkTwoslash =
|
const remarkTwoslash =
|
||||||
@@ -103,6 +104,8 @@ export const renderPostPreviewToString = async (
|
|||||||
</style>
|
</style>
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
width: ${heightWidth.width}px;
|
width: ${heightWidth.width}px;
|
||||||
height: ${heightWidth.height}px;
|
height: ${heightWidth.height}px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
2
public/.gitignore
vendored
2
public/.gitignore
vendored
@@ -3,5 +3,5 @@ content/**
|
|||||||
.ignored_*
|
.ignored_*
|
||||||
unicorn-profile-pic-map.ts
|
unicorn-profile-pic-map.ts
|
||||||
searchIndex.js
|
searchIndex.js
|
||||||
*.twitter-preview.png
|
generated/
|
||||||
*.epub
|
*.epub
|
||||||
|
|||||||
Reference in New Issue
Block a user