mirror of
https://github.com/morten-olsen/morten-olsen.github.io.git
synced 2026-02-08 01:46:28 +01:00
ci: fix build
This commit is contained in:
2
.github/workflows/publish.yml
vendored
2
.github/workflows/publish.yml
vendored
@@ -12,8 +12,6 @@ jobs:
|
|||||||
uses: actions/checkout@v2.3.1
|
uses: actions/checkout@v2.3.1
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- run: corepack enable
|
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
uses: docker://ghcr.io/morten-olsen/node-latex:main
|
uses: docker://ghcr.io/morten-olsen/node-latex:main
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
title: My home runs Redux
|
title: My home runs Redux
|
||||||
cover: cover.png
|
cover: cover.png
|
||||||
published: 2022-03-15
|
|
||||||
meta:
|
meta:
|
||||||
slug: my-home-runs-redux
|
slug: my-home-runs-redux
|
||||||
|
published: 2022-03-15
|
||||||
|
color: '#e80ccf'
|
||||||
content:
|
content:
|
||||||
- main.md
|
- main.md
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
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
|
|
||||||
meta:
|
meta:
|
||||||
slug: hiring-by-an-engineer
|
slug: hiring
|
||||||
|
published: 2022-03-16
|
||||||
|
color: "#8bae8c"
|
||||||
content:
|
content:
|
||||||
- main.md
|
- main.md
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
title: A defence for the coding challange
|
title: A defence for the coding challange
|
||||||
published: 2022-04-15
|
|
||||||
cover: cover.png
|
cover: cover.png
|
||||||
meta:
|
meta:
|
||||||
|
published: 2022-04-15
|
||||||
slug: a-defence-for-the-code-challange
|
slug: a-defence-for-the-code-challange
|
||||||
|
color: "#3d91ef"
|
||||||
content:
|
content:
|
||||||
- file: main.md
|
- file: main.md
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
title: My day is being planned by an algorithm
|
title: My day is being planned by an algorithm
|
||||||
cover: ./Cover.png
|
cover: ./Cover.png
|
||||||
published: 2022-05-06
|
|
||||||
meta:
|
meta:
|
||||||
slug: bob-the-algorithm
|
slug: bob-the-algorithm
|
||||||
|
published: 2022-05-06
|
||||||
|
color: '#e7d9ac'
|
||||||
content:
|
content:
|
||||||
- main.md
|
- main.md
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
title: A meta talk about Git strategies
|
title: A meta talk about Git strategies
|
||||||
cover: cover.png
|
cover: cover.png
|
||||||
meta:
|
meta:
|
||||||
slug: git-strategy
|
slug: a-meta-talk-about-git-strategies
|
||||||
|
published: 2022-12-05
|
||||||
|
color: '#01eeed'
|
||||||
content:
|
content:
|
||||||
- content:
|
- content:
|
||||||
- file: intro-story.md
|
- file: intro-story.md
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"cli": "yarn workspace @morten-olsen/goodwrites-cli run cli",
|
"cli": "yarn workspace @morten-olsen/goodwrites-cli run cli",
|
||||||
"dev": "yarn workspace @morten-olsen/personal-webpage next dev",
|
"dev": "yarn workspace @morten-olsen/personal-webpage next dev",
|
||||||
"build": "yarn workspace @morten-olsen/personal-webpage next build && yarn workspace @morten-olsen/personal-webpage next export",
|
"build": "tsc --build && yarn workspace @morten-olsen/personal-webpage next build && yarn workspace @morten-olsen/personal-webpage next export",
|
||||||
"postinstall": "husky install"
|
"postinstall": "husky install"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ const renderer = (outerDepth: number) => ({
|
|||||||
return `\\item{${input}}`;
|
return `\\item{${input}}`;
|
||||||
},
|
},
|
||||||
link: (href: string, text: string) => {
|
link: (href: string, text: string) => {
|
||||||
console.log('LINK TEXT', text, sanitize(href));
|
|
||||||
if (!text || text === href) {
|
if (!text || text === href) {
|
||||||
return `\\url{${sanitize(href)}}`;
|
return `\\url{${sanitize(href)}}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,11 @@
|
|||||||
"name": "@morten-olsen/personal-webpage",
|
"name": "@morten-olsen/personal-webpage",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource/black-ops-one": "^4.5.9",
|
||||||
"@fontsource/merriweather": "^4.5.14",
|
"@fontsource/merriweather": "^4.5.14",
|
||||||
"@fontsource/pacifico": "^4.5.9",
|
"@fontsource/pacifico": "^4.5.9",
|
||||||
|
"@fontsource/space-grotesk": "^4.5.10",
|
||||||
|
"@fontsource/vt323": "^4.5.10",
|
||||||
"@morten-olsen/markdown-loader": "workspace:^",
|
"@morten-olsen/markdown-loader": "workspace:^",
|
||||||
"@morten-olsen/personal-webpage-articles": "workspace:^",
|
"@morten-olsen/personal-webpage-articles": "workspace:^",
|
||||||
"@morten-olsen/personal-webpage-profile": "workspace:^",
|
"@morten-olsen/personal-webpage-profile": "workspace:^",
|
||||||
|
|||||||
76
webpage/src/components/articles/grid/index.tsx
Normal file
76
webpage/src/components/articles/grid/index.tsx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { getArticles } from '@morten-olsen/personal-webpage-articles/dist/index';
|
||||||
|
import ArticlePreview from '../preview';
|
||||||
|
import { JumboArticlePreview } from '../preview/jumbo';
|
||||||
|
import { MiniArticlePreview } from '../preview/mini';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
articles: ReturnType<typeof getArticles>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const FeaturedArticle = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 0 auto;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const FeaturedArticles = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 100%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const RemainingArticles = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ArticleGrid: React.FC<Props> = ({ articles }) => {
|
||||||
|
const sorted = useMemo(
|
||||||
|
() =>
|
||||||
|
articles.sort(
|
||||||
|
(a, b) =>
|
||||||
|
new Date(b.meta.published).getTime() -
|
||||||
|
new Date(a.meta.published).getTime()
|
||||||
|
),
|
||||||
|
[articles]
|
||||||
|
);
|
||||||
|
const featured1 = useMemo(() => sorted.slice(0, 1)[0], [sorted]);
|
||||||
|
|
||||||
|
const featured2 = useMemo(() => sorted.slice(1, 4), [sorted]);
|
||||||
|
|
||||||
|
const remaining = useMemo(() => sorted.slice(4, 12), [sorted]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
<FeaturedArticle>
|
||||||
|
<JumboArticlePreview article={featured1} />
|
||||||
|
</FeaturedArticle>
|
||||||
|
<FeaturedArticles>
|
||||||
|
{featured2.map((article) => (
|
||||||
|
<ArticlePreview key={article.title} article={article} />
|
||||||
|
))}
|
||||||
|
</FeaturedArticles>
|
||||||
|
<RemainingArticles>
|
||||||
|
{remaining.map((article) => (
|
||||||
|
<MiniArticlePreview key={article.title} article={article} />
|
||||||
|
))}
|
||||||
|
</RemainingArticles>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { ArticleGrid };
|
||||||
@@ -1,30 +1,46 @@
|
|||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Title1 } from 'typography';
|
import { Title1 } from 'typography';
|
||||||
import { getArticles } from '@morten-olsen/personal-webpage-articles/dist/index';
|
import { getArticles } from '@morten-olsen/personal-webpage-articles/dist/index';
|
||||||
|
import { createTheme } from 'theme/create';
|
||||||
|
import { ThemeProvider } from 'theme/provider';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
article: ReturnType<typeof getArticles>[number];
|
article: ReturnType<typeof getArticles>[number];
|
||||||
};
|
};
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
height: 300px;
|
height: 500px;
|
||||||
width: 300px;
|
border-right: 2px solid rgba(0, 0, 0, 0.1);
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 10px;
|
margin: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 700px) {
|
||||||
|
max-height: 300px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Title = styled(Title1)`
|
const Title = styled(Title1)`
|
||||||
background: ${({ theme }) => theme.colors.primary};
|
background: ${({ theme }) => theme.colors.primary};
|
||||||
padding: 5px 0;
|
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
|
font-family: 'Black Ops One', sans-serif;
|
||||||
|
font-size: 25px;
|
||||||
|
padding: 0 5px;
|
||||||
|
margin: 5px 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MetaWrapper = styled.div`
|
const MetaWrapper = styled.div`
|
||||||
position: absolute;
|
top: 10px;
|
||||||
top: 0;
|
|
||||||
left: 10px;
|
left: 10px;
|
||||||
|
right: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AsideWrapper = styled.aside<{
|
const AsideWrapper = styled.aside<{
|
||||||
@@ -34,7 +50,7 @@ const AsideWrapper = styled.aside<{
|
|||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
${({ image }) => (image ? `background-image: url(${image});` : '')}
|
${({ image }) => (image ? `background-image: url(${image});` : '')}
|
||||||
position: absolute;
|
flex: 1;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
@@ -43,15 +59,26 @@ const AsideWrapper = styled.aside<{
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const ArticlePreview: React.FC<Props> = ({ article }) => {
|
const ArticlePreview: React.FC<Props> = ({ article }) => {
|
||||||
|
const theme = useMemo(
|
||||||
|
() =>
|
||||||
|
createTheme({
|
||||||
|
baseColor: article.meta.color,
|
||||||
|
}),
|
||||||
|
[article.meta.color]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
<Link href={`/articles/${article.meta.slug}`}>
|
<Link href={`/articles/${article.meta.slug}`}>
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<AsideWrapper image={article.cover!} />
|
<AsideWrapper image={article.cover!} />
|
||||||
<MetaWrapper>
|
<MetaWrapper>
|
||||||
<Title>{article.title}</Title>
|
{article.title.split(' ').map((word, index) => (
|
||||||
|
<Title key={index}>{word}</Title>
|
||||||
|
))}
|
||||||
</MetaWrapper>
|
</MetaWrapper>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
</Link>
|
</Link>
|
||||||
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
82
webpage/src/components/articles/preview/jumbo.tsx
Normal file
82
webpage/src/components/articles/preview/jumbo.tsx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { Title1, Body1 } from 'typography';
|
||||||
|
import { getArticles } from '@morten-olsen/personal-webpage-articles/dist/index';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
article: ReturnType<typeof getArticles>[number];
|
||||||
|
};
|
||||||
|
|
||||||
|
const Wrapper = styled.a`
|
||||||
|
height: 300px;
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
margin: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
background: ${({ theme }) => theme.colors.background};
|
||||||
|
|
||||||
|
@media only screen and (max-width: 700px) {
|
||||||
|
flex-direction: column;
|
||||||
|
height: 500px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Title = styled(Title1)`
|
||||||
|
line-height: 40px;
|
||||||
|
font-family: 'Black Ops One', sans-serif;
|
||||||
|
font-size: 25px;
|
||||||
|
padding: 0 5px;
|
||||||
|
margin: 5px 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Summery = styled(Body1)`
|
||||||
|
max-width: 300px;
|
||||||
|
padding: 0 5px;
|
||||||
|
margin: 5px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
line-height: 2.1rem;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 700px) {
|
||||||
|
max-height: 100px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const MetaWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 40px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const AsideWrapper = styled.aside<{
|
||||||
|
image?: string;
|
||||||
|
}>`
|
||||||
|
background: ${({ theme }) => theme.colors.primary};
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
${({ image }) => (image ? `background-image: url(${image});` : '')}
|
||||||
|
flex: 1;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const JumboArticlePreview: React.FC<Props> = ({ article }) => {
|
||||||
|
return (
|
||||||
|
<Link href={`/articles/${article.meta.slug}`}>
|
||||||
|
<Wrapper>
|
||||||
|
<AsideWrapper image={article.cover!} />
|
||||||
|
<MetaWrapper>
|
||||||
|
<Title>{article.title}</Title>
|
||||||
|
<Summery>{article.content}</Summery>
|
||||||
|
</MetaWrapper>
|
||||||
|
</Wrapper>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { JumboArticlePreview };
|
||||||
83
webpage/src/components/articles/preview/mini.tsx
Normal file
83
webpage/src/components/articles/preview/mini.tsx
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { Title1 } from 'typography';
|
||||||
|
import { getArticles } from '@morten-olsen/personal-webpage-articles/dist/index';
|
||||||
|
import { createTheme } from 'theme/create';
|
||||||
|
import { ThemeProvider } from 'theme/provider';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
article: ReturnType<typeof getArticles>[number];
|
||||||
|
};
|
||||||
|
|
||||||
|
const Wrapper = styled.a`
|
||||||
|
position: relative;
|
||||||
|
margin: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
width: 220px;
|
||||||
|
height: 200px;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 700px) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Title = styled(Title1)`
|
||||||
|
line-height: 20px;
|
||||||
|
font-size: 20px;
|
||||||
|
padding: 5px 5px;
|
||||||
|
font-family: 'Black Ops One', sans-serif;
|
||||||
|
margin: 5px 0;
|
||||||
|
background: ${({ theme }) => theme.colors.background};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const MetaWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 10px;
|
||||||
|
max-width: 220px;
|
||||||
|
position: absolute;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const AsideWrapper = styled.aside<{
|
||||||
|
image?: string;
|
||||||
|
}>`
|
||||||
|
background: ${({ theme }) => theme.colors.primary};
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
${({ image }) => (image ? `background-image: url(${image});` : '')}
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const MiniArticlePreview: React.FC<Props> = ({ article }) => {
|
||||||
|
const theme = useMemo(
|
||||||
|
() =>
|
||||||
|
createTheme({
|
||||||
|
baseColor: article.meta.color,
|
||||||
|
}),
|
||||||
|
[article.meta.color]
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<Link href={`/articles/${article.meta.slug}`}>
|
||||||
|
<Wrapper>
|
||||||
|
<AsideWrapper image={article.cover!} />
|
||||||
|
<MetaWrapper>
|
||||||
|
{article.title.split(' ').map((word, index) => (
|
||||||
|
<Title key={index}>{word}</Title>
|
||||||
|
))}
|
||||||
|
</MetaWrapper>
|
||||||
|
</Wrapper>
|
||||||
|
</Link>
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { MiniArticlePreview };
|
||||||
@@ -6,7 +6,7 @@ import { ThemeProvider } from 'theme/provider';
|
|||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
background: ${({ theme }) => theme.colors.background};
|
background: ${({ theme }) => theme.colors.background};
|
||||||
color: ${({ theme }) => theme.colors.foreground};
|
color: ${({ theme }) => theme.colors.foreground};
|
||||||
min-height: 90%;
|
min-height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -14,27 +14,49 @@ const Wrapper = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const BackgroundWrapper = styled.div`
|
const BackgroundWrapper = styled.div<{
|
||||||
|
image: string;
|
||||||
|
}>`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
|
||||||
right: 0;
|
right: 0;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
opacity: 0.2;
|
||||||
|
${({ image }) => (image ? `background-image: url(${image});` : '')}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Content = styled.div`
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
max-width: 1000px;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
backgroundColor: string;
|
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
background?: ReactNode;
|
background?: string;
|
||||||
|
color?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Sheet: React.FC<Props> = ({ background, children }) => {
|
const Sheet: React.FC<Props> = ({ color, background, children }) => {
|
||||||
const theme = useMemo(() => createTheme({}), []);
|
const theme = useMemo(
|
||||||
|
() =>
|
||||||
|
createTheme({
|
||||||
|
baseColor: color,
|
||||||
|
}),
|
||||||
|
[color]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
{background && <BackgroundWrapper>{background}</BackgroundWrapper>}
|
<BackgroundWrapper image={background} />
|
||||||
{children}
|
<Content>{children}</Content>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import type { AppProps } from 'next/app';
|
|||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import '@fontsource/merriweather';
|
import '@fontsource/merriweather';
|
||||||
import '@fontsource/pacifico';
|
import '@fontsource/pacifico';
|
||||||
|
import '@fontsource/space-grotesk/700.css';
|
||||||
|
import '@fontsource/black-ops-one';
|
||||||
import { ThemeProvider } from '../theme/provider';
|
import { ThemeProvider } from '../theme/provider';
|
||||||
import { createTheme } from '../theme/create';
|
import { createTheme } from '../theme/create';
|
||||||
import chroma from 'chroma-js';
|
import chroma from 'chroma-js';
|
||||||
@@ -34,6 +36,7 @@ const GlobalStyle = createGlobalStyle`
|
|||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
import { getArticles } from '@morten-olsen/personal-webpage-articles';
|
import { getArticles } from '@morten-olsen/personal-webpage-articles';
|
||||||
import { GetStaticPaths, GetStaticProps } from 'next';
|
import { GetStaticPaths, GetStaticProps } from 'next';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { ReactMarkdown } from 'react-markdown/lib/react-markdown';
|
import { ReactMarkdown } from 'react-markdown/lib/react-markdown';
|
||||||
import { Jumbo, Overline } from 'typography';
|
import { Jumbo, Overline } from 'typography';
|
||||||
|
import { ThemeProvider } from 'theme/provider';
|
||||||
|
import { createTheme } from 'theme/create';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
article: ReturnType<typeof getArticles>[number];
|
article: ReturnType<typeof getArticles>[number];
|
||||||
};
|
};
|
||||||
|
|
||||||
const Wrapper = styled.div``;
|
const Wrapper = styled.div`
|
||||||
|
background: ${({ theme }) => theme.colors.background};
|
||||||
|
`;
|
||||||
|
|
||||||
const ArticleWrapper = styled.article`
|
const ArticleWrapper = styled.article`
|
||||||
margin-right: 40%;
|
margin-right: 40%;
|
||||||
@@ -40,7 +44,6 @@ const ArticleContent = styled.div`
|
|||||||
float: left;
|
float: left;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin: 0px 2rem;
|
margin: 0px 2rem;
|
||||||
font-weight: 100;
|
|
||||||
margin-left: 0rem;
|
margin-left: 0rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +76,7 @@ const ArticleContent = styled.div`
|
|||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
background: ${({ theme }) => theme.colors.primary};
|
background: ${({ theme }) => theme.colors.primary};
|
||||||
color: ${({ theme }) => theme.colors.foreground};
|
color: ${({ theme }) => theme.colors.foreground};
|
||||||
|
font-family: 'Black Ops One', sans-serif;
|
||||||
|
|
||||||
@media only screen and (max-width: 700px) {
|
@media only screen and (max-width: 700px) {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@@ -92,7 +96,7 @@ const AsideWrapper = styled.aside<{
|
|||||||
background: ${({ theme }) => theme.colors.primary};
|
background: ${({ theme }) => theme.colors.primary};
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
opacity: 0.5;
|
opacity: 0.7;
|
||||||
${({ image }) => (image ? `background-image: url(${image});` : '')}
|
${({ image }) => (image ? `background-image: url(${image});` : '')}
|
||||||
|
|
||||||
@media only screen and (max-width: 700px) {
|
@media only screen and (max-width: 700px) {
|
||||||
@@ -105,16 +109,23 @@ const AsideWrapper = styled.aside<{
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const Title = styled(Jumbo)`
|
const Title = styled(Jumbo)`
|
||||||
font-size: 60px;
|
font-size: 4rem;
|
||||||
line-height: 80px;
|
line-height: 4.1rem;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: ${({ theme }) => theme.colors.primary};
|
background: ${({ theme }) => theme.colors.primary};
|
||||||
color: ${({ theme }) => theme.colors.foreground};
|
color: ${({ theme }) => theme.colors.foreground};
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
|
font-family: 'Black Ops One', sans-serif;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 900px) {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
line-height: 3.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 700px) {
|
@media only screen and (max-width: 700px) {
|
||||||
|
padding: 5px;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
line-height: 2.1rem;
|
line-height: 2.1rem;
|
||||||
}
|
}
|
||||||
@@ -125,7 +136,15 @@ const Meta = styled(Overline)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const Article: React.FC<Props> = ({ article }) => {
|
const Article: React.FC<Props> = ({ article }) => {
|
||||||
|
const theme = useMemo(
|
||||||
|
() =>
|
||||||
|
createTheme({
|
||||||
|
baseColor: article.meta.color,
|
||||||
|
}),
|
||||||
|
[article.meta.color]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<ArticleWrapper>
|
<ArticleWrapper>
|
||||||
<ArticleContent>
|
<ArticleContent>
|
||||||
@@ -134,7 +153,7 @@ const Article: React.FC<Props> = ({ article }) => {
|
|||||||
))}
|
))}
|
||||||
<div>
|
<div>
|
||||||
<Meta>
|
<Meta>
|
||||||
By Morten Olsen - 5 min read{' '}
|
By Morten Olsen - {article.stats.text}{' '}
|
||||||
{article.pdf && (
|
{article.pdf && (
|
||||||
<a href={article.pdf} target="_blank">
|
<a href={article.pdf} target="_blank">
|
||||||
download as PDF
|
download as PDF
|
||||||
@@ -147,6 +166,7 @@ const Article: React.FC<Props> = ({ article }) => {
|
|||||||
</ArticleContent>
|
</ArticleContent>
|
||||||
</ArticleWrapper>
|
</ArticleWrapper>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
BIN
webpage/src/pages/cover.png
Normal file
BIN
webpage/src/pages/cover.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
@@ -5,7 +5,8 @@ import { getArticles } from '@morten-olsen/personal-webpage-articles/dist/index'
|
|||||||
import { GetStaticProps } from 'next';
|
import { GetStaticProps } from 'next';
|
||||||
import { getPositions, Position } from '@morten-olsen/personal-webpage-profile';
|
import { getPositions, Position } from '@morten-olsen/personal-webpage-profile';
|
||||||
import { Sheet } from '../components/sheet';
|
import { Sheet } from '../components/sheet';
|
||||||
import ArticlePreview from 'components/articles/preview';
|
import { ArticleGrid } from 'components/articles/grid';
|
||||||
|
const cover = require('./cover.png');
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
articles: ReturnType<typeof getArticles>;
|
articles: ReturnType<typeof getArticles>;
|
||||||
@@ -25,29 +26,48 @@ const Title = styled(Jumbo)`
|
|||||||
color: ${({ theme }) => theme.colors.foreground};
|
color: ${({ theme }) => theme.colors.foreground};
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin: 5px;
|
margin: 10px;
|
||||||
|
font-family: 'Black Ops One', sans-serif;
|
||||||
|
|
||||||
@media only screen and (max-width: 700px) {
|
@media only screen and (max-width: 700px) {
|
||||||
|
margin: 5px;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
line-height: 2.1rem;
|
line-height: 2.1rem;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ArticleList = styled.div`
|
const Arrow = styled.div`
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin: 0 auto;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
:after {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: ${({ theme }) => theme.colors.primary};
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
content: '↓';
|
||||||
|
font-size: 50px;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 700px) {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Index: FC<Props> = ({ articles, positions }) => {
|
const Index: FC<Props> = ({ articles }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Sheet backgroundColor="red">
|
<Sheet color="#c85279" background={cover}>
|
||||||
|
<Arrow />
|
||||||
<Hero>
|
<Hero>
|
||||||
{"Hi, I'm Morten Olsen".split(' ').map((char, index) => (
|
{"Hi, I'm Morten".split(' ').map((char, index) => (
|
||||||
<Title key={index}>{char}</Title>
|
<Title key={index}>{char}</Title>
|
||||||
))}
|
))}
|
||||||
</Hero>
|
</Hero>
|
||||||
@@ -57,18 +77,13 @@ const Index: FC<Props> = ({ articles, positions }) => {
|
|||||||
))}
|
))}
|
||||||
</Hero>
|
</Hero>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
<Sheet backgroundColor="#273c75">
|
<Sheet color="#ef23e2">
|
||||||
<h2>Articles</h2>
|
<Hero>
|
||||||
<ArticleList>
|
{'Table of Content'.split(' ').map((char, index) => (
|
||||||
{articles.map((article) => (
|
<Title key={index}>{char}</Title>
|
||||||
<ArticlePreview key={article.title} article={article} />
|
|
||||||
))}
|
|
||||||
</ArticleList>
|
|
||||||
</Sheet>
|
|
||||||
<Sheet backgroundColor="red">
|
|
||||||
{positions.map((position) => (
|
|
||||||
<div>{position.attributes.title}</div>
|
|
||||||
))}
|
))}
|
||||||
|
</Hero>
|
||||||
|
<ArticleGrid articles={articles} />
|
||||||
</Sheet>
|
</Sheet>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -77,7 +92,6 @@ const Index: FC<Props> = ({ articles, positions }) => {
|
|||||||
export const getStaticProps: GetStaticProps<Props> = async () => {
|
export const getStaticProps: GetStaticProps<Props> = async () => {
|
||||||
const articles = getArticles();
|
const articles = getArticles();
|
||||||
const positions = getPositions();
|
const positions = getPositions();
|
||||||
console.log(articles);
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
articles,
|
articles,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const createTheme = (options: CreateOptions = {}) => {
|
|||||||
const text = isBright(baseColor) ? BLACK : WHITE;
|
const text = isBright(baseColor) ? BLACK : WHITE;
|
||||||
const bg = isBright(baseColor)
|
const bg = isBright(baseColor)
|
||||||
? baseColor.luminance(0.9)
|
? baseColor.luminance(0.9)
|
||||||
: baseColor.luminance(0.005);
|
: baseColor.luminance(0.01);
|
||||||
const theme: Theme = {
|
const theme: Theme = {
|
||||||
typography: {
|
typography: {
|
||||||
Jumbo: {
|
Jumbo: {
|
||||||
|
|||||||
24
yarn.lock
24
yarn.lock
@@ -693,6 +693,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@fontsource/black-ops-one@npm:^4.5.9":
|
||||||
|
version: 4.5.9
|
||||||
|
resolution: "@fontsource/black-ops-one@npm:4.5.9"
|
||||||
|
checksum: 514735092abc24f1548d3acdb84f224f15977255c4fc69f3217a280d9660168e5389ce47eab26be76989c9234f824a3e7b3ef7e5ea78880b2fff08d1e3879c57
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@fontsource/merriweather@npm:^4.5.14":
|
"@fontsource/merriweather@npm:^4.5.14":
|
||||||
version: 4.5.14
|
version: 4.5.14
|
||||||
resolution: "@fontsource/merriweather@npm:4.5.14"
|
resolution: "@fontsource/merriweather@npm:4.5.14"
|
||||||
@@ -707,6 +714,20 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@fontsource/space-grotesk@npm:^4.5.10":
|
||||||
|
version: 4.5.10
|
||||||
|
resolution: "@fontsource/space-grotesk@npm:4.5.10"
|
||||||
|
checksum: 71c05e9ce7c88b9f63bf7ed1e0460fccac1339ef679218b4d5404298b27a829e6dc7fe1f4de99105dddbff57b5902dfce901b252d466795f51051339fd931ad8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@fontsource/vt323@npm:^4.5.10":
|
||||||
|
version: 4.5.10
|
||||||
|
resolution: "@fontsource/vt323@npm:4.5.10"
|
||||||
|
checksum: 99f6a1d1add1d5002b3332ccc0b3d8185c635bce8129e16d084c3a4b421a13d5f96863b293e089c77291adfb032f943123b27b1080b7cc89178e52d4d2f64e91
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@gar/promisify@npm:^1.1.3":
|
"@gar/promisify@npm:^1.1.3":
|
||||||
version: 1.1.3
|
version: 1.1.3
|
||||||
resolution: "@gar/promisify@npm:1.1.3"
|
resolution: "@gar/promisify@npm:1.1.3"
|
||||||
@@ -1205,8 +1226,11 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@morten-olsen/personal-webpage@workspace:webpage"
|
resolution: "@morten-olsen/personal-webpage@workspace:webpage"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@fontsource/black-ops-one": ^4.5.9
|
||||||
"@fontsource/merriweather": ^4.5.14
|
"@fontsource/merriweather": ^4.5.14
|
||||||
"@fontsource/pacifico": ^4.5.9
|
"@fontsource/pacifico": ^4.5.9
|
||||||
|
"@fontsource/space-grotesk": ^4.5.10
|
||||||
|
"@fontsource/vt323": ^4.5.10
|
||||||
"@morten-olsen/goodwrites-webpack-loader": "workspace:^"
|
"@morten-olsen/goodwrites-webpack-loader": "workspace:^"
|
||||||
"@morten-olsen/markdown-loader": "workspace:^"
|
"@morten-olsen/markdown-loader": "workspace:^"
|
||||||
"@morten-olsen/personal-webpage-articles": "workspace:^"
|
"@morten-olsen/personal-webpage-articles": "workspace:^"
|
||||||
|
|||||||
Reference in New Issue
Block a user