diff --git a/package.json b/package.json index c7e859d..6aa2f48 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "react-dom": "^17.0.2", "react-router-dom": "^5.3.0", "react-transition-group": "^4.4.2", + "react-twemoji": "^0.3.0", "ress": "^4.0.0", "webpack-dev-middleware": "^5.2.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c737535..000d96c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,6 +33,7 @@ specifiers: react-dom: ^17.0.2 react-router-dom: ^5.3.0 react-transition-group: ^4.4.2 + react-twemoji: ^0.3.0 ress: ^4.0.0 sass: ^1.39.0 sass-loader: ^12.1.0 @@ -55,6 +56,7 @@ dependencies: react-dom: 17.0.2_react@17.0.2 react-router-dom: 5.3.0_react@17.0.2 react-transition-group: 4.4.2_react-dom@17.0.2+react@17.0.2 + react-twemoji: 0.3.0_react-dom@17.0.2+react@17.0.2 ress: 4.0.0 webpack-dev-middleware: 5.2.1_webpack@5.52.0 @@ -3322,6 +3324,15 @@ packages: engines: {node: '>= 0.6'} dev: true + /fs-extra/8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.8 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + /fs-monkey/1.0.3: resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} @@ -4042,6 +4053,20 @@ packages: dependencies: minimist: 1.2.5 + /jsonfile/4.0.0: + resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=} + optionalDependencies: + graceful-fs: 4.2.8 + dev: false + + /jsonfile/5.0.0: + resolution: {integrity: sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==} + dependencies: + universalify: 0.1.2 + optionalDependencies: + graceful-fs: 4.2.8 + dev: false + /jsx-ast-utils/3.2.0: resolution: {integrity: sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==} engines: {node: '>=4.0'} @@ -4111,6 +4136,10 @@ packages: /lodash.debounce/4.0.8: resolution: {integrity: sha1-gteb/zCmfEAF/9XiUVMArZyk168=} + /lodash.isequal/4.5.0: + resolution: {integrity: sha1-QVxEePK8wwEgwizhDtMib30+GOA=} + dev: false + /lodash.merge/4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -5036,6 +5065,20 @@ packages: react-dom: 17.0.2_react@17.0.2 dev: false + /react-twemoji/0.3.0_react-dom@17.0.2+react@17.0.2: + resolution: {integrity: sha512-y2ZQD3KvpZklETxz9c1NycRdUVF5nKsJ0bPNW3SaRJT+ReK36sMcneYwRPfv9EK2p3s9ph/NczDglnB8wbMJ0g==} + engines: {node: '>=5.0'} + peerDependencies: + react: ^16.4.2 + react-dom: ^16.4.2 + dependencies: + lodash.isequal: 4.5.0 + prop-types: 15.7.2 + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 + twemoji: 13.1.0 + dev: false + /react/17.0.2: resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} engines: {node: '>=0.10.0'} @@ -5960,6 +6003,19 @@ packages: typescript: 4.4.2 dev: true + /twemoji-parser/13.1.0: + resolution: {integrity: sha512-AQOzLJpYlpWMy8n+0ATyKKZzWlZBJN+G0C+5lhX7Ftc2PeEVdUU/7ns2Pn2vVje26AIZ/OHwFoUbdv6YYD/wGg==} + dev: false + + /twemoji/13.1.0: + resolution: {integrity: sha512-e3fZRl2S9UQQdBFLYXtTBT6o4vidJMnpWUAhJA+yLGR+kaUTZAt3PixC0cGvvxWSuq2MSz/o0rJraOXrWw/4Ew==} + dependencies: + fs-extra: 8.1.0 + jsonfile: 5.0.0 + twemoji-parser: 13.1.0 + universalify: 0.1.2 + dev: false + /type-check/0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -6061,6 +6117,11 @@ packages: '@types/unist': 2.0.6 dev: true + /universalify/0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: false + /unpipe/1.0.0: resolution: {integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=} engines: {node: '>= 0.8'} diff --git a/src/comps/shared/Emoji.module.scss b/src/comps/shared/Emoji.module.scss new file mode 100644 index 0000000..631afde --- /dev/null +++ b/src/comps/shared/Emoji.module.scss @@ -0,0 +1,7 @@ +.emoji-default { + height: 1em; + + img { + height: 100%; + } +} diff --git a/src/comps/shared/Emoji.tsx b/src/comps/shared/Emoji.tsx new file mode 100644 index 0000000..ea082bd --- /dev/null +++ b/src/comps/shared/Emoji.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import Twemoji from "react-twemoji"; + +import styles from "./Emoji.module.scss"; + +export type EmojiProps = React.HTMLAttributes & { + emoji: string; +}; +export const Emoji = ({ emoji, className, ...props }: EmojiProps) => ( + + + {emoji} + + +); diff --git a/src/comps/shared/Heading.module.scss b/src/comps/shared/Heading.module.scss new file mode 100644 index 0000000..6291ce5 --- /dev/null +++ b/src/comps/shared/Heading.module.scss @@ -0,0 +1,29 @@ +@use "~/styling/font.module.scss"; +@use "~/styling/color.module.scss"; + +.heading { + display: grid; + grid-gap: 0.5rem; + + grid-auto-flow: column; + grid-auto-columns: max-content; + align-items: end; + + width: 100%; + margin-bottom: 1.25em; + padding-bottom: 0.25em; + + border-bottom: 2px solid color.get-theme-color(text-color-accent-primary); + + * { + line-height: 100%; + } +} + +.sub-text { + @include font.use-set(monospace); + color: color.get-theme-color(text-color-secondary); + + font-size: 0.85rem; + font-weight: normal; +} diff --git a/src/comps/shared/Heading.tsx b/src/comps/shared/Heading.tsx new file mode 100644 index 0000000..cd72540 --- /dev/null +++ b/src/comps/shared/Heading.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { Emoji } from "./Emoji"; + +import styles from "./Heading.module.scss"; + +export type HeadingProps = { + children: string; + emoji: string; + sub: string; +}; +export const Heading = ({ children, emoji, sub }: HeadingProps) => ( +

+ + {children} + {/* eslint-disable-next-line react/jsx-no-comment-textnodes */} + // {sub} +

+); diff --git a/src/pages/about/About.module.scss b/src/pages/about/About.module.scss new file mode 100644 index 0000000..9f744e7 --- /dev/null +++ b/src/pages/about/About.module.scss @@ -0,0 +1,11 @@ +@use "~/styling/color.module.scss"; +@use "~/styling/layout.module.scss"; + +.container { + display: grid; + grid-auto-flow: column; + grid-auto-columns: 1fr 2fr; + grid-gap: 1.5em; + width: 100%; +} + diff --git a/src/pages/about/About.tsx b/src/pages/about/About.tsx new file mode 100644 index 0000000..cc75481 --- /dev/null +++ b/src/pages/about/About.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import { PageWrapper } from "~/comps/layout/PageWrapper"; +import { Heading } from "~/comps/shared/Heading"; + +import styles from "./About.module.scss"; +import { Avatar } from "./Avatar"; +import { Introduction } from "./Introduction"; + +export const About = () => ( + + + 自己紹介 + +
+ + +
+
+); diff --git a/src/pages/about/Avatar.module.scss b/src/pages/about/Avatar.module.scss new file mode 100644 index 0000000..d0c09b6 --- /dev/null +++ b/src/pages/about/Avatar.module.scss @@ -0,0 +1,18 @@ +@use "~/styling/color.module.scss"; + +.avatar { + img { + margin-bottom: -15px; + width: 100%; + + animation: 5s ease-in-out alternate infinite shake; + } + + overflow: hidden; + border-bottom: 2px solid color.get-theme-color(text-color-accent-primary); +} + +@keyframes shake { + from { transform: rotate(-2deg); } + to { transform: rotate(2deg); } +} diff --git a/src/pages/about/Avatar.tsx b/src/pages/about/Avatar.tsx new file mode 100644 index 0000000..85b9454 --- /dev/null +++ b/src/pages/about/Avatar.tsx @@ -0,0 +1,16 @@ +import React from "react"; +import styles from "./Avatar.module.scss"; + +export const Avatar = () => ( +
+
+ +
+ + Icon by: + + @unios103i + + +
+); diff --git a/src/pages/about/Introduction.module.scss b/src/pages/about/Introduction.module.scss new file mode 100644 index 0000000..27fe315 --- /dev/null +++ b/src/pages/about/Introduction.module.scss @@ -0,0 +1,34 @@ +@use "~/styling/color.module.scss"; +@use "~/styling/font.module.scss"; + +.wrapper { + display: flex; + flex-direction: column; + gap: 0.5em; +} + +.name, .affiriation { + display: flex; + flex-direction: column; +} + +.primary { + @include font.use-set("heading"); + + font-size: 3em; + font-weight: 600; + line-height: 110%; +} + +.element { + display: flex; + flex-direction: column; +} + +.aka { + color: color.get-theme-color(text-color-secondary) +} + +.location { + font-size: 1.25em; +} diff --git a/src/pages/about/Introduction.tsx b/src/pages/about/Introduction.tsx new file mode 100644 index 0000000..a5ba67d --- /dev/null +++ b/src/pages/about/Introduction.tsx @@ -0,0 +1,23 @@ +import React from "react"; + +import styles from "./Introduction.module.scss"; + +export const Introduction = () => ( +
+
+ フライさん + Flisan / loxygen.K +
+
+
+ 茨城工業高等専門学校 + 3 年 情報系 +
+
+ 茨城工業高等専門学校 + 3 年 情報系 +
+
+ フライさんです. +
+); diff --git a/src/pages/router/routing.ts b/src/pages/router/routing.ts index 7dbc9d0..1d4be6e 100644 --- a/src/pages/router/routing.ts +++ b/src/pages/router/routing.ts @@ -1,8 +1,10 @@ import { RouteProps } from "react-router-dom"; import { Splash } from "~/pages/splash/Splash"; import { Main } from "~/pages/main/Main"; +import { About } from "../about/About"; export const routingTable: RouteProps[] = [ { path: "/", component: Splash, exact: true }, { path: "/me", component: Main, exact: true }, + { path: "/about", component: About, exact: true }, ]; diff --git a/src/styling/base.module.scss b/src/styling/base.module.scss index 0b9e906..03e7c27 100644 --- a/src/styling/base.module.scss +++ b/src/styling/base.module.scss @@ -1,4 +1,5 @@ @use "./font.module.scss"; +@use "./color.module.scss"; body { @include font.use-set(base); @@ -11,6 +12,14 @@ body { } a { - color: unset; + color: color.get-theme-color(text-color-accent-secondary); text-decoration: none; + + &:hover { + text-decoration: underline; + } +} + +h1, h2, h3, h4, h5, h6 { + @include font.use-set(heading); } diff --git a/src/styling/font.module.scss b/src/styling/font.module.scss index 949918e..dd9ca80 100644 --- a/src/styling/font.module.scss +++ b/src/styling/font.module.scss @@ -2,10 +2,16 @@ @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;600&display=swap'); @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=M+PLUS+1p:wght@400;500&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c:wght@300;400&display=swap'); +$__set-base: "IBM Plex Sans", "M PLUS Rounded 1c"; +$__set-heading: "IBM Plex Sans", "M PLUS 1p"; +$__set-monospace: IBM Plex Mono; $font-set: ( - "base": "IBM Plex Sans", - "monospace": "IBM Plex Mono", + "base": $__set-base, + "heading": $__set-heading, + "monospace": $__set-monospace, ); @mixin use-set($name) { diff --git a/src/typedef.d.ts b/src/typedef.d.ts index c608e9b..f53e6d7 100644 --- a/src/typedef.d.ts +++ b/src/typedef.d.ts @@ -12,3 +12,12 @@ declare module "*.svg" { ) => React.ReactElement; export default component; } + +declare module "react-twemoji" { + const Twemoji: (props: { + children: React.ReactNode; + noWrapper?: boolean; + tag?: string; + }) => React.ReactElement; + export default Twemoji; +} diff --git a/static/loxygen_k.png b/static/loxygen_k.png new file mode 100644 index 0000000..9974b01 Binary files /dev/null and b/static/loxygen_k.png differ diff --git a/webpack.config.ts b/webpack.config.ts index 61729ac..ab03c5e 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -74,7 +74,7 @@ const configuration: Configuration = { new CopyWebpackPlugin({ patterns: [ { - from: path.resolve(__dirname, "asset/static"), + from: path.resolve(__dirname, "static"), to: path.resolve(__dirname, "dist/static/"), noErrorOnMissing: true, },