This commit is contained in:
Morten Olsen
2022-03-30 16:34:56 +02:00
committed by Morten Olsen
parent b654ba7e74
commit e6e938bd42
44 changed files with 386 additions and 263 deletions

View File

@@ -10,9 +10,9 @@ const withLatex = (nextConfig = {}) => {
outputPath = "../../"; outputPath = "../../";
} }
config.module.rules.push({ config.module.rules.push({
test: /\.png.yml$/, test: /\.gen.yml$/,
use: [{ use: [{
loader: 'file-loader', loader: require.resolve('./webpack.js'),
options: { options: {
publicPath: `${nextConfig.assetPrefix || nextConfig.basePath || ''}/_next/static/images/`, publicPath: `${nextConfig.assetPrefix || nextConfig.basePath || ''}/_next/static/images/`,
@@ -27,8 +27,6 @@ const withLatex = (nextConfig = {}) => {
}, },
esModule: nextConfig.esModule || false, esModule: nextConfig.esModule || false,
}, },
}, {
loader: require.resolve('./webpack.js'),
}], }],
}); });
if (typeof nextConfig.webpack === "function") { if (typeof nextConfig.webpack === "function") {

View File

@@ -0,0 +1,31 @@
require('reflect-metadata');
require('@babel/register')({
extensions: [".es6", ".es", ".jsx", ".js", ".mjs", ".ts"],
});
const loaderUtils = require('loader-utils');
const path = require('path');
const yaml = require('yaml');
const { generate } = require('../../../src/generators');
module.exports = function (source) {
var callback = this.async();
const location = this.resourcePath;
const definition = yaml.parse(source);
const options = this.getOptions();
generate(definition, location)
.then((output) => {
const files = Object.entries(output).reduce((output, [key, value]) => {
const { name, content } = value;
const targetName = loaderUtils.interpolateName(this, `[contenthash]/${name}`, {content: content});
const location = path.join(options.outputPath, targetName);
const publicPath = path.join(options.publicPath, targetName);
this.emitFile(location, content);
return {
...output,
[key]: publicPath,
}
}, {});
callback(null, `module.exports = ${JSON.stringify(files)}`);
})
.catch(callback);
}

View File

@@ -1,16 +0,0 @@
require('reflect-metadata');
require('@babel/register')({
extensions: [".es6", ".es", ".jsx", ".js", ".mjs", ".ts"],
});
const { generateImage } = require('../../../src/images');
module.exports = function (source) {
var callback = this.async();
const location = this.resourcePath;
generateImage(source, location)
.then((canvas) => {
const buffer = canvas.toBuffer('image/png', {})
callback(null, buffer);
})
.catch(callback);
}

View File

@@ -1,34 +0,0 @@
const withLatex = (nextConfig = {}) => {
return Object.assign({}, nextConfig, {
webpack(config, options) {
const {isServer, dev} = options;
let outputPath = '';
if (isServer && dev) {
outputPath = "../";
} else if (isServer) {
outputPath = "../../";
}
config.module.rules.push({
test: /\.tex.yml$/,
use: [{
loader: 'file-loader',
options: {
publicPath: `${nextConfig.assetPrefix || nextConfig.basePath || ''}/_next/static/images/`,
outputPath: `${outputPath}static/images/`,
name: "[name]-[hash].pdf",
esModule: nextConfig.esModule || false,
},
}, {
loader: require.resolve('./webpack.js'),
}],
});
if (typeof nextConfig.webpack === "function") {
return nextConfig.webpack(config, options);
}
return config;
},
});
}
module.exports = withLatex;

View File

@@ -1,31 +0,0 @@
require('reflect-metadata');
require('@babel/register')({
extensions: [".es6", ".es", ".jsx", ".js", ".mjs", ".ts"],
});
const latex = require("node-latex")
var Readable = require('stream').Readable
const { generateLatex } = require('../../../src/latex');
module.exports = function (source) {
var callback = this.async();
const location = this.resourcePath;
generateLatex(source, location)
.then((result) => {
const chunks = [];
const input = new Readable();
input.push(result);
input.push(null);
const latexStream = latex(input);
latexStream.on('data', (chunk) => {
chunks.push(Buffer.from(chunk));
})
latexStream.on('finish', () => {
const result = Buffer.concat(chunks);
callback(null, result);
})
latexStream.on('error', (err) => {
callback(err);
})
})
.catch(callback);
}

View File

@@ -0,0 +1,4 @@
data:
type: article
structure: ./index.yml
generator: latex

View File

@@ -1,3 +0,0 @@
data:
structure: ./index.yml
generator: article

View File

@@ -1,6 +1,6 @@
title: How to hire engineers, by an engineer title: How to hire engineers, by an engineer
cover: cover.png cover: cover.png
published: 2022-03-16 published: 2022-03-16
shareImage: ./share.png.yml shareImage: ./share.gen.yml
parts: parts:
- main.md - main.md

View File

@@ -0,0 +1,5 @@
generator: image
data:
type: share
width: 450
height: 300

View File

@@ -1,3 +0,0 @@
generator: share
width: 450
height: 300

View File

@@ -0,0 +1,4 @@
data:
structure: ./index.yml
type: article
generator: latex

View File

@@ -1,3 +0,0 @@
data:
structure: ./index.yml
generator: article

View File

@@ -0,0 +1,4 @@
data:
type: article
structure: ./index.yml
generator: latex

View File

@@ -1,3 +0,0 @@
data:
structure: ./index.yml
generator: article

View File

@@ -1,6 +1,5 @@
title: My home runs Redux title: My home runs Redux
cover: cover.png cover: cover.png
published: 2022-03-15 published: 2022-03-15
shareImage: ./share.png.yml
parts: parts:
- main.md - main.md

View File

@@ -1,3 +0,0 @@
generator: share
width: 450
height: 300

View File

@@ -0,0 +1,3 @@
generator: latex
data:
type: resume

View File

@@ -1 +0,0 @@
generator: resume

View File

@@ -0,0 +1,7 @@
generator: image
data:
type: resize
width: 780
height: 780
src: ./me.jpg
output: image/jpeg

View File

@@ -1,6 +1,7 @@
name: Morten Olsen name: Morten Olsen
tagline: “...One part genius, one part crazy” tagline: “...One part genius, one part crazy”
avatar: me.jpg avatar: ./image.gen.yml
resumeImage: ./me.jpg
email: hello@buy-me.coffee email: hello@buy-me.coffee
github: morten-olsen github: morten-olsen
location: Copenhagen, DK location: Copenhagen, DK

View File

@@ -1,8 +1,7 @@
const withPlugins = require("next-compose-plugins"); const withPlugins = require("next-compose-plugins");
const withImages = require("./config/plugins/withImages.js"); const withImages = require("./config/plugins/withImages.js");
const withLatex = require('./config/plugins/withLatex'); const withGenerator = require('./config/plugins/withGenerator');
const withImageGenerator = require('./config/plugins/withImageGenerator');
const withBundleAnalyzer = require("@next/bundle-analyzer")({ const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true", enabled: process.env.ANALYZE === "true",
}); });
@@ -11,12 +10,14 @@ const nextConfig = {
poweredByHeader: false, poweredByHeader: false,
images: { images: {
disableStaticImages: true disableStaticImages: true
} },
experimental: {
concurrentFeatures: true,
},
}; };
module.exports = withPlugins([ module.exports = withPlugins([
withLatex, withGenerator,
withImageGenerator,
[withImages,{ [withImages,{
esModule: true, // using ES modules is beneficial in the case of module concatenation and tree shaking. esModule: true, // using ES modules is beneficial in the case of module concatenation and tree shaking.
inlineImageLimit: 0, // disable image inlining to data:base64 inlineImageLimit: 0, // disable image inlining to data:base64

View File

@@ -12,10 +12,10 @@
"@react-three/drei": "^8.18.6", "@react-three/drei": "^8.18.6",
"@react-three/fiber": "^7.0.26", "@react-three/fiber": "^7.0.26",
"date-fns": "^2.28.0", "date-fns": "^2.28.0",
"next": "^12.1.0", "next": "^12.1.2",
"node-latex": "^3.1.0", "node-latex": "^3.1.0",
"react": "^17.0.2", "react": "^17",
"react-dom": "^17.0.2", "react-dom": "^17",
"react-markdown": "^8.0.1", "react-markdown": "^8.0.1",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rehype-img-size": "^1.0.1", "rehype-img-size": "^1.0.1",

View File

@@ -36,19 +36,12 @@ const Cloud = ({ texture }) => {
const ref = useRef<any>(); const ref = useRef<any>();
const width = window.innerWidth / 2; const width = window.innerWidth / 2;
const height = window.innerHeight / 2; const height = window.innerHeight / 2;
const [ready, setReady] = useState(false);
useFrame(() => { useFrame(() => {
if (!ref.current || !ready) return; if (!ref.current) return;
ref.current.rotation.z -= 0.003; ref.current.rotation.z -= 0.003;
}); });
useEffect(() => {
setTimeout(() => {
setReady(true);
}, 500)
}, []);
return ( return (
<mesh <mesh
ref={ref} ref={ref}
@@ -138,3 +131,4 @@ const HeroBackground = () => {
} }
export { HeroBackground }; export { HeroBackground };
export default HeroBackground;

View File

@@ -1,7 +1,6 @@
import React from 'react'; import React, { Suspense, useEffect, useState } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { Profile } from '../../data/repos/profile'; import { Profile } from '../../data/repos/profile';
import { HeroBackground } from './background';
import { SlideIn } from '../animations/slide-in'; import { SlideIn } from '../animations/slide-in';
type Props = { type Props = {
@@ -91,31 +90,44 @@ const SocialLogo = styled.div<{ src: string }>`
background-size: cover; background-size: cover;
` `
const Hero: React.FC<Props> = ({ profile }) => ( const Hero: React.FC<Props> = ({ profile }) => {
<Wrapper> const [background, setBackground] = useState<any>();
<Avatar src={profile.avatar}> useEffect(
<AvatarSpacer /> () => {
</Avatar> import('./background').then(({ default: HeroBackground }) => {
<Name> console.log('goo', typeof HeroBackground);
{profile.name} setBackground(<HeroBackground />);
</Name> })
<Tagline>{profile.tagline}</Tagline> },
<Social> [],
<SlideIn> )
<SocialItem href={profile.resume} target="_blank"> return (
<SocialText>Resumé</SocialText> <Wrapper>
</SocialItem> <Avatar src={profile.avatar}>
</SlideIn> <AvatarSpacer />
{profile.social.map((social) => ( </Avatar>
<SlideIn key={social.name}> <Name>
<SocialItem key={social.name} href={social.link} target="_blank"> {profile.name}
<SocialLogo src={social.logo} /> </Name>
<SocialText>{social.name}</SocialText> <Tagline>{profile.tagline}</Tagline>
</SocialItem> <Social>
<SlideIn>
<SocialItem href={profile.resume} target="_blank">
<SocialText>Resumé</SocialText>
</SocialItem>
</SlideIn> </SlideIn>
))} {profile.social.map((social) => (
</Social> <SlideIn key={social.name}>
</Wrapper> <SocialItem key={social.name} href={social.link} target="_blank">
); <SocialLogo src={social.logo} />
<SocialText>{social.name}</SocialText>
</SocialItem>
</SlideIn>
))}
</Social>
{background}
</Wrapper>
);
}
export { Hero }; export { Hero };

View File

@@ -4,7 +4,7 @@ import { AssetResolver } from './';
const assetModules = (require as any).context( const assetModules = (require as any).context(
'../../../content', '../../../content',
true, true,
/\.(png|jpe?g|svg|gif|tex\.yml|png\.yml)$/, /\.(png|jpe?g|svg|gif|gen\.yml)$/,
) )
const assets = assetModules.keys().reduce((output, key: string) => ({ const assets = assetModules.keys().reduce((output, key: string) => ({
...output, ...output,

View File

@@ -2,7 +2,7 @@ import { Service } from "typedi";
@Service() @Service()
abstract class AssetResolver { abstract class AssetResolver {
public abstract getPath(...loc: string[]): string; public abstract getPath(...loc: string[]): any;
} }
export { AssetResolver }; export { AssetResolver };

View File

@@ -72,8 +72,8 @@ export class ArticleDB {
stats, stats,
pdfs: { pdfs: {
a4: this.#assets.getPath( a4: this.#assets.getPath(
path.resolve('/', 'articles', id, 'a4.tex.yml'), path.resolve('/', 'articles', id, 'a4.gen.yml'),
) || null, )?.url || null,
} }
}; };

View File

@@ -18,7 +18,8 @@ export type Profile = {
value: string; value: string;
link: string; link: string;
logo: string; logo: string;
}[] }[];
resumeImage?: string;
platforms: { platforms: {
name: string; name: string;
level: number; level: number;
@@ -50,9 +51,16 @@ export class ProfileDB {
const image = this.#assets.getPath( const image = this.#assets.getPath(
'profile', 'profile',
structure.avatar, structure.avatar,
) )?.url
structure.avatar = image || null; structure.avatar = image || null;
} }
if (structure.resumeImage) {
const image = this.#assets.getPath(
'profile',
structure.resumeImage,
)
structure.resumeImage = image || null;
}
structure.social = structure.social.map((social) => { structure.social = structure.social.map((social) => {
const image = this.#assets.getPath('profile', social.logo); const image = this.#assets.getPath('profile', social.logo);
return { return {
@@ -62,8 +70,8 @@ export class ProfileDB {
}) })
structure.resume = this.#assets.getPath( structure.resume = this.#assets.getPath(
'profile', 'profile',
'a4.tex.yml', 'a4.gen.yml',
); )?.url || null;
return structure; return structure;
} }

View File

@@ -0,0 +1,21 @@
import { createCanvas } from 'canvas';
import { Generator } from '../types';
import { generators } from './types';
const mimeToExt = {
'image/jpeg': 'jpg',
}
export const generateImage: Generator = async (data, location) => {
const { type, output, ...rest } = data;
const canvas = createCanvas(data.width, data.height)
const generator = generators[type];
await generator(rest, location, canvas);
const ext = mimeToExt[output] || 'png';
return {
url: {
name: `img.${ext}`,
content: canvas.toBuffer(output),
}
};
}

View File

@@ -1,8 +1,10 @@
import { ImageGenerator } from "./Generator"; import { ImageGenerator } from "./types";
import { shareGenerator } from "./share"; import { shareGenerator } from "./share";
import { resizeGenerator } from "./resize";
const generators: {[name: string]: ImageGenerator} = { const generators: {[name: string]: ImageGenerator} = {
share: shareGenerator, share: shareGenerator,
resize: resizeGenerator,
}; };
export { generators }; export { generators };

View File

@@ -0,0 +1,86 @@
import { loadImage, CanvasRenderingContext2D, Image, createCanvas } from 'canvas';
import path from 'path';
import Container from "typedi";
import { AssetResolver } from "../../../data/assets";
import { ArticleDB } from "../../../data/repos/articles";
import { ImageGenerator } from "./types";
import { ProfileDB } from '../../../data/repos/profile';
const assets = {
getPath: (...source: string[]) => {
return path.join(process.cwd(), 'content', ...source);
},
}
function drawImageProp(
ctx: CanvasRenderingContext2D,
img: Image,
x?: number,
y?: number,
w?: number,
h?: number,
offsetX?: number,
offsetY?: number,
) {
if (arguments.length === 2) {
x = y = 0;
w = ctx.canvas.width;
h = ctx.canvas.height;
}
// default offset is center
offsetX = typeof offsetX === "number" ? offsetX : 0.5;
offsetY = typeof offsetY === "number" ? offsetY : 0.5;
// keep bounds [0.0, 1.0]
if (offsetX < 0) offsetX = 0;
if (offsetY < 0) offsetY = 0;
if (offsetX > 1) offsetX = 1;
if (offsetY > 1) offsetY = 1;
var iw = img.width,
ih = img.height,
r = Math.min(w / iw, h / ih),
nw = iw * r, // new prop. width
nh = ih * r, // new prop. height
cx, cy, cw, ch, ar = 1;
// decide which gap to fill
if (nw < w) ar = w / nw;
if (Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh; // updated
nw *= ar;
nh *= ar;
// calc source rectangle
cw = iw / (nw / w);
ch = ih / (nh / h);
cx = (iw - cw) * offsetX;
cy = (ih - ch) * offsetY;
// make sure source rectangle is valid
if (cx < 0) cx = 0;
if (cy < 0) cy = 0;
if (cw > iw) cw = iw;
if (ch > ih) ch = ih;
// fill image in dest. rectangle
ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h);
}
const resizeGenerator: ImageGenerator = async (data, location, canvas) => {
const dir = path.dirname(location);
const src = path.join(dir, data.src);
Container.set(AssetResolver, assets)
const ctx = canvas.getContext('2d');
ctx.antialias = 'subpixel';
const cover = await loadImage(src);
drawImageProp(
ctx,
cover,
)
};
export { resizeGenerator };

View File

@@ -1,11 +1,10 @@
import { loadImage, CanvasRenderingContext2D, Image, createCanvas } from 'canvas'; import { loadImage, CanvasRenderingContext2D, Image, createCanvas } from 'canvas';
import path from 'path'; import path from 'path';
import Container from "typedi"; import Container from "typedi";
import { AssetResolver } from "../../data/assets"; import { AssetResolver } from "../../../data/assets";
import { ArticleDB } from "../../data/repos/articles"; import { ArticleDB } from "../../../data/repos/articles";
import { ImageGenerator } from "./Generator"; import { ImageGenerator } from "./types";
import drawMultiLine from 'canvas-multiline-text'; import { ProfileDB } from '../../../data/repos/profile';
import { ProfileDB } from '../../data/repos/profile';
const assets = { const assets = {
getPath: (...source: string[]) => { getPath: (...source: string[]) => {

16
src/generators/index.ts Normal file
View File

@@ -0,0 +1,16 @@
import { Generator } from "./types";
import { generateImage } from "./images";
import { generateLatex } from "./latex";
const generators: {[name: string]: Generator} = {
image: generateImage,
latex: generateLatex,
}
const generate = async (definition: any, location: string) => {
const { data, generator } = definition;
const generatorFn = generators[generator];
const result = await generatorFn(data, location);
return result;
};
export { generate };

View File

@@ -1,7 +1,7 @@
import type { Article } from "../../../data/repos/articles"; import type { Article } from "../../../../data/repos/articles";
import fs from 'fs-extra'; import fs from 'fs-extra';
import { LatexGenerator } from "../Generator"; import { LatexGenerator } from "../Generator";
import { generate } from '../../../data/helpers/markdown'; import { generate } from '../../../../data/helpers/markdown';
import path from 'path'; import path from 'path';
import yaml from 'yaml'; import yaml from 'yaml';
import { fromMarkdown } from "../../helpers/convert"; import { fromMarkdown } from "../../helpers/convert";

View File

@@ -1,9 +1,9 @@
import path from 'path'; import path from 'path';
import { LatexGenerator } from "../Generator"; import { LatexGenerator } from "../Generator";
import Container from 'typedi'; import Container from 'typedi';
import { AssetResolver } from '../../../data/assets'; import { AssetResolver } from '../../../../data/assets';
import { ProfileDB } from '../../../data/repos/profile'; import { ProfileDB } from '../../../../data/repos/profile';
import { ExperienceDB } from '../../../data/repos/experiences'; import { ExperienceDB } from '../../../../data/repos/experiences';
import { fromMarkdown } from '../../helpers/convert'; import { fromMarkdown } from '../../helpers/convert';
const assets = { const assets = {
@@ -20,9 +20,8 @@ const resume: LatexGenerator<Data> = async (data, location) => {
const experienceDB = Container.get(ExperienceDB); const experienceDB = Container.get(ExperienceDB);
const profile = await profileDB.get(); const profile = await profileDB.get();
const avatar = profile.avatar; const avatar = profile.resumeImage;
const experiences = await experienceDB.list(); const experiences = await experienceDB.list();
console.log('a', avatar);
return ` return `
\\documentclass[10pt, a4paper]{article} \\documentclass[10pt, a4paper]{article}

View File

@@ -63,7 +63,6 @@ const renderer = (outerDepth: number) => ({
return `\\texttt{${sanitize(code)}}` return `\\texttt{${sanitize(code)}}`
}, },
image: (link: string) => { image: (link: string) => {
console.log('link', link);
if (!existsSync(link)) { if (!existsSync(link)) {
return 'Online image not supported'; return 'Online image not supported';
} }

View File

@@ -0,0 +1,37 @@
import latex from 'node-latex';
import { Readable } from 'stream';
import { Generator } from '../types';
import { generators } from "./generators";
const latexToPdf = (doc: string) => new Promise<Buffer>((resolve, reject) => {
const chunks = [];
const input = new Readable();
input.push(doc);
input.push(null);
const latexStream = latex(input);
latexStream.on('data', (chunk) => {
chunks.push(Buffer.from(chunk));
})
latexStream.on('finish', () => {
const result = Buffer.concat(chunks);
resolve(result);
})
latexStream.on('error', (err) => {
reject(err);
})
});
const generateLatex: Generator = async (data: any, location: string) => {
const { type, ...rest } = data;
const generator = generators[type];
const doc = await generator(rest, location);
const content = await latexToPdf(doc);
return {
url: {
name: 'doc.pdf',
content,
}
};
}
export { generateLatex };

7
src/generators/types.ts Normal file
View File

@@ -0,0 +1,7 @@
export type Generator<TData = any> = (data: TData, location: string) => Promise<{
[key: string]: {
name: string;
content: string | Buffer;
}
}>;

View File

@@ -1,11 +0,0 @@
import { createCanvas } from 'canvas';
import yaml from 'yaml';
import { generators } from './generator';
export const generateImage = async (source: string, location: string) => {
const definition = yaml.parse(source);
const canvas = createCanvas(definition.width * 2, definition.height * 2)
const generator = generators[definition.generator];
await generator(definition.data, location, canvas);
return canvas;
}

View File

@@ -1,12 +0,0 @@
import { generators } from "./generators";
import yaml from 'yaml';
import path from 'path';
const generateLatex = async (source: string, location: string) => {
const definition = yaml.parse(source);
const generator = generators[definition.generator];
const latex = await generator(definition.data, location);
return latex;
}
export { generateLatex };

148
yarn.lock
View File

@@ -458,65 +458,70 @@
dependencies: dependencies:
webpack-bundle-analyzer "4.3.0" webpack-bundle-analyzer "4.3.0"
"@next/env@12.1.0": "@next/env@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314" resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.2.tgz#4b0f5fd448ac60b821d2486d2987948e3a099f03"
integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ== integrity sha512-A/P4ysmFScBFyu1ZV0Mr1Y89snyQhqGwsCrkEpK+itMF+y+pMqBoPVIyakUf4LXqGWJGiGFuIerihvSG70Ad8Q==
"@next/swc-android-arm64@12.1.0": "@next/swc-android-arm-eabi@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39" resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.2.tgz#675e952d9032ac7bec02f3f413c17d33bbd90857"
integrity sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA== integrity sha512-iwalfLBhYmCIlj09czFbovj1SmTycf0AGR8CB357wgmEN8xIuznIwSsCH87AhwQ9apfNtdeDhxvuKmhS9T3FqQ==
"@next/swc-darwin-arm64@12.1.0": "@next/swc-android-arm64@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz#08e8b411b8accd095009ed12efbc2f1d4d547135" resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.2.tgz#d9710c50853235f258726b19a649df9c29a49682"
integrity sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg== integrity sha512-ZoR0Vx7czJhTgRAcFbzTKQc2n2ChC036/uc6PbgYiI/LreEnfmsV/CiREP0pUVs5ndntOX8kBA3BSbh4zCO5tQ==
"@next/swc-darwin-x64@12.1.0": "@next/swc-darwin-arm64@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz#fcd684497a76e8feaca88db3c394480ff0b007cd" resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.2.tgz#aadd21b711c82b3efa9b4ecf7665841259e1fa7e"
integrity sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug== integrity sha512-VXv7lpqFjHwkK65CZHkjvBxlSBTG+l3O0Zl2zHniHj0xHzxJZvR8VFjV2zIMZCYSfVqeQ5yt2rjwuQ9zbpGtXQ==
"@next/swc-linux-arm-gnueabihf@12.1.0": "@next/swc-darwin-x64@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz#9ec6380a27938a5799aaa6035c205b3c478468a7" resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.2.tgz#3b1a389828f5c88ecb828a6394692fdeaf175081"
integrity sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog== integrity sha512-evXxJQnXEnU+heWyun7d0UV6bhBcmoiyFGR3O3v9qdhGbeXh+SXYVxRO69juuh6V7RWRdlb1KQ0rGUNa1k0XSw==
"@next/swc-linux-arm64-gnu@12.1.0": "@next/swc-linux-arm-gnueabihf@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz#7f4196dff1049cea479607c75b81033ae2dbd093" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.2.tgz#db4371ca716bf94c94d4f6b001ac3c9d08d97d79"
integrity sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q== integrity sha512-LJV/wo6R0Ot7Y/20bZs00aBG4J333RT6H/5Q2AROE4Hnx7cenSktSnfU6WCnJgzYLSIHdbLs549LcZMULuVquw==
"@next/swc-linux-arm64-musl@12.1.0": "@next/swc-linux-arm64-gnu@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz#b445f767569cdc2dddee785ca495e1a88c025566" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.2.tgz#0e71db03b8b12ed315c8be7d15392ecefe562b7c"
integrity sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA== integrity sha512-fjlYU1Y8kVjjRKyuyQBYLHPxjGOS2ox7U8TqAvtgKvd2PxqdsgW4sP+VDovRVPrZlGXNllKoJiqMO1OoR9fB6w==
"@next/swc-linux-x64-gnu@12.1.0": "@next/swc-linux-arm64-musl@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz#67610e9be4fbc987de7535f1bcb17e45fe12f90e" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.2.tgz#f1b055793da1c12167ed3b6e32aef8289721a1fb"
integrity sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A== integrity sha512-Y1JRDMHqSjLObjyrD1hf6ePrJcOF/mkw+LbAzoNgrHL1dSuIAqcz3jYunJt8T7Yw48xSJy6LPSL9BclAHwEwOA==
"@next/swc-linux-x64-musl@12.1.0": "@next/swc-linux-x64-gnu@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz#ea19a23db08a9f2e34ac30401f774cf7d1669d31" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.2.tgz#69764ffaacb3b9b373897fff15d7dd871455efe2"
integrity sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw== integrity sha512-5N4QSRT60ikQqCU8iHfYZzlhg6MFTLsKhMTARmhn8wLtZfN9VVyTFwZrJQWjV64dZc4JFeXDANGao8fm55y6bw==
"@next/swc-win32-arm64-msvc@12.1.0": "@next/swc-linux-x64-musl@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz#eadf054fc412085659b98e145435bbba200b5283" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.2.tgz#0ddaedb5ec578c01771f83be2046dafb2f70df91"
integrity sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw== integrity sha512-b32F/xAgdYG4Pt0foFzhF+2uhvNxnEj7aJNp1R4EhZotdej2PzvFWcP/dGkc7MJl205pBz5oC3gHyILIIlW6XA==
"@next/swc-win32-ia32-msvc@12.1.0": "@next/swc-win32-arm64-msvc@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz#68faeae10c89f698bf9d28759172b74c9c21bda1" resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.2.tgz#9e17ed56d5621f8c6961193da3a0b155cea511c9"
integrity sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q== integrity sha512-hVOcGmWDeVwO00Aclopsj6MoYhfJl5zA4vjAai9KjgclQTFZa/DC0vQjgKAHHKGT5oMHgjiq/G7L6P1/UfwYnw==
"@next/swc-win32-x64-msvc@12.1.0": "@next/swc-win32-ia32-msvc@12.1.2":
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064" resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.2.tgz#ddd260cbe8bc4002fb54415b80baccf37f8db783"
integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg== integrity sha512-wnVDGIVz2pR3vIkyN6IE+1NvMSBrBj1jba11iR16m8TAPzZH/PrNsxr0a9N5VavEXXLcQpoUVvT+N7nflbRAHg==
"@next/swc-win32-x64-msvc@12.1.2":
version "12.1.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.2.tgz#37412a314bcf4c6006a74e1ef9764048344f3848"
integrity sha512-MLNcurEpQp0+7OU9261f7PkN52xTGkfrt4IYTIXau7DO/aHj927oK6piIJdl9EOHdX/KN5W6qlyErj170PSHtw==
"@polka/url@^1.0.0-next.20": "@polka/url@^1.0.0-next.20":
version "1.0.0-next.21" version "1.0.0-next.21"
@@ -2622,28 +2627,29 @@ next-mdx-remote@^4.0.0:
vfile "^5.3.0" vfile "^5.3.0"
vfile-matter "^3.0.1" vfile-matter "^3.0.1"
next@^12.1.0: next@^12.1.2:
version "12.1.0" version "12.1.2"
resolved "https://registry.yarnpkg.com/next/-/next-12.1.0.tgz#c33d753b644be92fc58e06e5a214f143da61dd5d" resolved "https://registry.yarnpkg.com/next/-/next-12.1.2.tgz#c5376a8ae17d3e404a2b691c01f94c8943306f29"
integrity sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q== integrity sha512-JHPCsnFTBO0Z4SQxSYc611UA1WA+r/3y3Neg66AH5/gSO/oksfRnFw/zGX/FZ9+oOUHS9y3wJFawNpVYR2gJSQ==
dependencies: dependencies:
"@next/env" "12.1.0" "@next/env" "12.1.2"
caniuse-lite "^1.0.30001283" caniuse-lite "^1.0.30001283"
postcss "8.4.5" postcss "8.4.5"
styled-jsx "5.0.0" styled-jsx "5.0.1"
use-subscription "1.5.1" use-subscription "1.5.1"
optionalDependencies: optionalDependencies:
"@next/swc-android-arm64" "12.1.0" "@next/swc-android-arm-eabi" "12.1.2"
"@next/swc-darwin-arm64" "12.1.0" "@next/swc-android-arm64" "12.1.2"
"@next/swc-darwin-x64" "12.1.0" "@next/swc-darwin-arm64" "12.1.2"
"@next/swc-linux-arm-gnueabihf" "12.1.0" "@next/swc-darwin-x64" "12.1.2"
"@next/swc-linux-arm64-gnu" "12.1.0" "@next/swc-linux-arm-gnueabihf" "12.1.2"
"@next/swc-linux-arm64-musl" "12.1.0" "@next/swc-linux-arm64-gnu" "12.1.2"
"@next/swc-linux-x64-gnu" "12.1.0" "@next/swc-linux-arm64-musl" "12.1.2"
"@next/swc-linux-x64-musl" "12.1.0" "@next/swc-linux-x64-gnu" "12.1.2"
"@next/swc-win32-arm64-msvc" "12.1.0" "@next/swc-linux-x64-musl" "12.1.2"
"@next/swc-win32-ia32-msvc" "12.1.0" "@next/swc-win32-arm64-msvc" "12.1.2"
"@next/swc-win32-x64-msvc" "12.1.0" "@next/swc-win32-ia32-msvc" "12.1.2"
"@next/swc-win32-x64-msvc" "12.1.2"
node-abi@^2.21.0: node-abi@^2.21.0:
version "2.30.1" version "2.30.1"
@@ -2965,7 +2971,7 @@ react-composer@^5.0.2:
dependencies: dependencies:
prop-types "^15.6.0" prop-types "^15.6.0"
react-dom@^17.0.2: react-dom@^17:
version "17.0.2" version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
@@ -3031,7 +3037,7 @@ react-use-measure@^2.1.1:
dependencies: dependencies:
debounce "^1.2.1" debounce "^1.2.1"
react@^17.0.2: react@^17:
version "17.0.2" version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
@@ -3483,10 +3489,10 @@ styled-components@^5.3.3:
shallowequal "^1.1.0" shallowequal "^1.1.0"
supports-color "^5.5.0" supports-color "^5.5.0"
styled-jsx@5.0.0: styled-jsx@5.0.1:
version "5.0.0" version "5.0.1"
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.1.tgz#78fecbbad2bf95ce6cd981a08918ce4696f5fc80"
integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== integrity sha512-+PIZ/6Uk40mphiQJJI1202b+/dYeTVd9ZnMPR80pgiWbjIwvN2zIp4r9et0BgqBuShh48I0gttPlAXA7WVvBxw==
supports-color@^5.3.0, supports-color@^5.5.0: supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0" version "5.5.0"