mirror of
https://github.com/Unkn0wnCat/KevinK.dev.js.git
synced 2025-05-09 23:16:57 +02:00
Add new blog components and post
This commit is contained in:
parent
b35ad08052
commit
a352600428
16 changed files with 440 additions and 5 deletions
|
@ -1,6 +1,6 @@
|
|||
@use "sass:map";
|
||||
|
||||
$layoutWidth: 1200px;
|
||||
$layoutWidth: 1100px;
|
||||
$layoutPadding: 20px;
|
||||
|
||||
$mainFont: "Fira Code", monospace;
|
||||
|
|
58
src/components/scambox/Chatblah.tsx
Normal file
58
src/components/scambox/Chatblah.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import anime, { AnimeTimelineInstance } from "animejs";
|
||||
import _uniqueId from 'lodash/uniqueId';
|
||||
import {useMediaQuery} from '@react-hook/media-query'
|
||||
|
||||
|
||||
import * as styles from "./Chatbox.module.scss";
|
||||
|
||||
const Chatblah = () => {
|
||||
const animeRef = useRef<AnimeTimelineInstance>(null)
|
||||
const [myId,] = useState(_uniqueId)
|
||||
const reduceMotion = useMediaQuery("(prefers-reduced-motion: reduce)")
|
||||
|
||||
useEffect(() => {
|
||||
if(typeof window === "undefined") return; // Don't run on static build
|
||||
if(reduceMotion) return; // Don't run the animation for users who prefer reduced motion
|
||||
|
||||
const speed = 0.25;
|
||||
const delay = anime.random(100/speed, 1000/speed);
|
||||
|
||||
animeRef.current = anime.timeline({
|
||||
targets: "#chatblah-"+myId,
|
||||
loop: true,
|
||||
easing: "easeInOutSine"
|
||||
})
|
||||
|
||||
const tl = animeRef.current
|
||||
|
||||
tl.add({
|
||||
duration: 250/speed,
|
||||
opacity: [0, .25],
|
||||
easing: "linear"
|
||||
}, delay).add({
|
||||
duration: 1000/speed,
|
||||
rotate: [anime.random(-5, 5)+"deg", anime.random(-10, 10)+"deg"],
|
||||
translateY: [0, anime.random(0, -2)+"px"],
|
||||
translateX: [0, anime.random(-2, 2)+"px"],
|
||||
}, delay).add({
|
||||
duration: 500/speed,
|
||||
opacity: [.25, 0],
|
||||
easing: "linear"
|
||||
}, delay+(500/speed))
|
||||
|
||||
return () => {
|
||||
if(animeRef.current) {
|
||||
animeRef.current.pause();
|
||||
animeRef.current = null;
|
||||
}
|
||||
}
|
||||
}, [myId, reduceMotion])
|
||||
|
||||
|
||||
return <div className={styles.chatBlah} id={"chatblah-"+myId}>
|
||||
<span>blah</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default Chatblah
|
138
src/components/scambox/Chatbox.module.scss
Normal file
138
src/components/scambox/Chatbox.module.scss
Normal file
|
@ -0,0 +1,138 @@
|
|||
@use "sass:math";
|
||||
@use "sass:map";
|
||||
@import "../../globals";
|
||||
|
||||
.screenReader {
|
||||
opacity: 0.001;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.chatbox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: $layoutPadding;
|
||||
margin: $layoutPadding (-$layoutPadding);
|
||||
background-color: rgba(gray, 0.1);
|
||||
border-radius: 10px;
|
||||
|
||||
&.openBottom {
|
||||
border-radius: 10px 10px 0 0;
|
||||
margin-bottom: 20px;
|
||||
background-image: linear-gradient(
|
||||
to top,
|
||||
$background,
|
||||
transparent 20px
|
||||
);
|
||||
}
|
||||
|
||||
&.openBoth {
|
||||
border-radius: 0;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
background-image: linear-gradient(to top, $background, transparent 20px),
|
||||
linear-gradient(to bottom, $background, transparent 20px);
|
||||
}
|
||||
|
||||
&.openTop {
|
||||
border-radius: 0 0 10px 10px;
|
||||
margin-top: 20px;
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
$background,
|
||||
transparent 20px
|
||||
);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
&.openBottom {
|
||||
background-image: linear-gradient(
|
||||
to top,
|
||||
$lightBackground,
|
||||
transparent 20px
|
||||
);
|
||||
}
|
||||
|
||||
&.openBoth {
|
||||
background-image: linear-gradient(
|
||||
to top,
|
||||
$lightBackground,
|
||||
transparent 20px
|
||||
),
|
||||
linear-gradient(to bottom, $lightBackground, transparent 20px);
|
||||
}
|
||||
|
||||
&.openTop {
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
$lightBackground,
|
||||
transparent 20px
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chatnotice {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
margin: math.div($layoutPadding, 2) $layoutPadding;
|
||||
|
||||
> span {
|
||||
max-width: 500px;
|
||||
opacity: 0.75;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.chatmsg {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
margin: 0 $layoutPadding;
|
||||
|
||||
align-items: flex-start;
|
||||
|
||||
--msg-color: #{map.get($theme, "blue")};
|
||||
|
||||
&.alignRight {
|
||||
align-items: flex-end;
|
||||
|
||||
--msg-color: #{$accentColor};
|
||||
}
|
||||
|
||||
.name {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.chatbubble {
|
||||
position: relative;
|
||||
padding: math.div($layoutPadding, 2) $layoutPadding;
|
||||
border-radius: 10px;
|
||||
border: thin solid var(--msg-color);
|
||||
max-width: 700px;
|
||||
|
||||
hr {
|
||||
display: block;
|
||||
margin: math.div($layoutPadding, 2) (-$layoutPadding);
|
||||
border: none;
|
||||
border-top: thin solid var(--msg-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chatBlah {
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
opacity: 0.25;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
11
src/components/scambox/Chatbox.module.scss.d.ts
vendored
Normal file
11
src/components/scambox/Chatbox.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
export const alignRight: string;
|
||||
export const chatBlah: string;
|
||||
export const chatbox: string;
|
||||
export const chatbubble: string;
|
||||
export const chatmsg: string;
|
||||
export const chatnotice: string;
|
||||
export const name: string;
|
||||
export const openBoth: string;
|
||||
export const openBottom: string;
|
||||
export const openTop: string;
|
||||
export const screenReader: string;
|
20
src/components/scambox/Chatbox.tsx
Normal file
20
src/components/scambox/Chatbox.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import * as styles from "./Chatbox.module.scss";
|
||||
|
||||
type ChatboxProps = {
|
||||
open?: string
|
||||
}
|
||||
|
||||
const Chatbox = ({children, open}: React.PropsWithChildren<ChatboxProps>) => {
|
||||
const {t} = useTranslation();
|
||||
|
||||
return <div className={styles.chatbox + (open === "top" ? " " + styles.openTop : "") + (open === "bottom" ? " " + styles.openBottom : "") + (open === "both" ? " " + styles.openBoth : "")}>
|
||||
<span className={styles.screenReader}>-- {open === "top" || open === "both" ? t("blog.scambox.chatbox.resume") : t("blog.scambox.chatbox.begin")} --</span>
|
||||
{children}
|
||||
<span className={styles.screenReader}>-- {open === "bottom" || open === "both" ? t("blog.scambox.chatbox.interrupt") : t("blog.scambox.chatbox.end")} --</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default Chatbox
|
27
src/components/scambox/Chatmsg.tsx
Normal file
27
src/components/scambox/Chatmsg.tsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import * as styles from "./Chatbox.module.scss"
|
||||
|
||||
type ChatmsgProps = {
|
||||
name?: string,
|
||||
timestamp?: string,
|
||||
color?: string,
|
||||
dir: string
|
||||
}
|
||||
|
||||
const Chatmsg = (props: React.PropsWithChildren<ChatmsgProps>) => {
|
||||
const {t} = useTranslation();
|
||||
|
||||
return <div className={styles.chatmsg + (props.dir === "out" ? " " + styles.alignRight : "")}>
|
||||
{props.name && <span className={styles.name}>{props.name}<span className={styles.screenReader}> {t("blog.scambox.chatbox.says")}</span></span>}
|
||||
<div className={styles.chatbubble}>
|
||||
<div>
|
||||
{props.children}
|
||||
</div>
|
||||
{props.timestamp && <span>{props.timestamp}</span>}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default Chatmsg
|
11
src/components/scambox/Chatnotice.tsx
Normal file
11
src/components/scambox/Chatnotice.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import React from "react";
|
||||
|
||||
import * as styles from "./Chatbox.module.scss"
|
||||
|
||||
const Chatnotice = (props: React.PropsWithChildren<{}>) => {
|
||||
return <div className={styles.chatnotice}>
|
||||
<span>{props.children}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default Chatnotice
|
|
@ -4,6 +4,11 @@
|
|||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
body,
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
Phone,
|
||||
} from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMediaQuery } from "@react-hook/media-query";
|
||||
//import * as particleConfig from "./index.particles.json";
|
||||
|
||||
export const query = graphql`
|
||||
|
@ -62,9 +63,11 @@ export const query = graphql`
|
|||
|
||||
const IndexPage = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const reduceMotion = useMediaQuery("(prefers-reduced-motion: reduce)")
|
||||
|
||||
React.useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
if (reduceMotion) return;
|
||||
|
||||
anime({
|
||||
targets: [
|
||||
|
@ -95,7 +98,7 @@ const IndexPage = (props) => {
|
|||
/*if (typeof window !== "undefined")
|
||||
// eslint-disable-next-line no-undef
|
||||
window.setTimeout(loadTsParticles, 1000);*/
|
||||
}, []);
|
||||
}, [reduceMotion]);
|
||||
|
||||
let meta = props.data.site.siteMetadata;
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
.postSection {
|
||||
flex-grow: 1;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
|
||||
> article {
|
||||
img {
|
||||
|
|
|
@ -22,7 +22,7 @@ const BlogPost = ({ data }) => {
|
|||
<script type="application/ld+json">
|
||||
{JSON.stringify({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "NewsArticle",
|
||||
"@type": "BlogPosting",
|
||||
headline: data.mdx.frontmatter.title,
|
||||
datePublished: data.mdx.frontmatter.publishedIso,
|
||||
dateModified: data.mdx.frontmatter.publishedIso,
|
||||
|
@ -30,6 +30,7 @@ const BlogPost = ({ data }) => {
|
|||
{
|
||||
"@type": "Person",
|
||||
name: data.mdx.frontmatter.author.name,
|
||||
url: "https://kevink.dev/blog/"
|
||||
},
|
||||
],
|
||||
})}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue