Skip to content

Commit fdaaf8e

Browse files
authored
Merge pull request #83 from object-t/release/0.0.4
Release/0.0.4
2 parents 3add2d4 + 45768da commit fdaaf8e

File tree

15 files changed

+891
-24
lines changed

15 files changed

+891
-24
lines changed

.githooks/pre-commit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func main() {
2525
os.Exit(0)
2626
}
2727

28-
fileList := strings.Join(files, " ")
28+
fileList := strings.ReplaceAll(strings.Join(files, " "), `$`, `\$`)
2929
eslintCmdStr := fmt.Sprintf("npx eslint --fix %s", fileList)
3030
var eslintCmd *exec.Cmd
3131
if runtime.GOOS == "windows" {

_routes.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"version": 1,
3+
"include": ["/blog/*"],
4+
"exclude": [
5+
"/assets/*",
6+
"/**/*.js",
7+
"/**/*.css",
8+
"/**/*.map",
9+
"/**/*.woff",
10+
"/**/*.woff2",
11+
"/**/*.ttf",
12+
"/**/*.svg",
13+
"/**/*.webp",
14+
"/**/*.ico"
15+
]
16+
}

app/components/Tag/Tag.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@ import './tag.css';
22
import { tagColorMap } from './tag-color-map';
33
import {useTranslation} from "react-i18next";
44

5-
export type TagKind = "hackathon" | "recruitment" | "urgent";
5+
export type TagKind = "hackathon" | "recruitment" | "urgent" | string;
66

77
export interface TagProps {
88
kind: TagKind;
9+
className?: string;
910
}
1011

11-
export const Tag = ({ kind }: TagProps) => {
12+
export const Tag = ({ kind, className }: TagProps) => {
1213
const {text,backgroundColor} = tagColorMap[kind] || '#9e9e9e';
1314
const { t } = useTranslation();
1415
return (
15-
<span className="tag" style={{ backgroundColor }}>
16-
{t(text)}
16+
<span className={["tag", className].join(" ")} style={{ backgroundColor: backgroundColor ?? "#42f5b0" }}>
17+
{ text ? t(text) : kind }
1718
</span>
1819
);
1920
};

app/routes.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,10 @@ export default [
44
index("routes/home.tsx"),
55
{
66
path: "blog",
7-
file: "routes/blog/index.tsx" }
7+
file: "routes/blog/index.tsx",
8+
},
9+
{
10+
path: "blog/:id",
11+
file: "routes/blog/$id.tsx"
12+
}
813
] satisfies RouteConfig;

app/routes/blog/$id.module.scss

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
.container {
2+
width: 100%;
3+
height: 100%;
4+
min-height: 100vh;
5+
display: flex;
6+
flex-direction: row-reverse;
7+
justify-content: center;
8+
background-color: #F5F5F5;
9+
10+
.article {
11+
padding-top: 64px;
12+
width: 100%;
13+
max-width: 1200px;
14+
}
15+
16+
.side {
17+
padding-top: 200px;
18+
width: 20%;
19+
}
20+
21+
ul {
22+
top: 200px;
23+
list-style: none;
24+
position: sticky;
25+
}
26+
27+
li {
28+
font-size: 16px;
29+
}
30+
31+
.h1-table {
32+
color: #616161;
33+
}
34+
.h2-table {
35+
color: #8a8a8a;
36+
li {
37+
padding-left: 24px;
38+
}
39+
}
40+
41+
.article-container {
42+
padding-top: 100px;
43+
padding-bottom: 200px;
44+
width: 60%;
45+
height: auto;
46+
display: flex;
47+
justify-content: center;
48+
align-items: center;
49+
flex-direction: column;
50+
}
51+
52+
.header-img {
53+
object-fit: cover;
54+
width: 100%;
55+
max-width: 1200px;
56+
border-radius: 12px;
57+
box-shadow: 0 10px 10px #20202011;
58+
}
59+
60+
h1 {
61+
color: var(--main-text-color);
62+
font-weight: 900;
63+
font-size: 52px;
64+
}
65+
66+
h2 {
67+
color: var(--main-text-color);
68+
font-weight: 700;
69+
font-size: 32px;
70+
}
71+
72+
h3 {
73+
color: var(--main-text-color);
74+
font-weight: 600;
75+
font-size: 24px;
76+
}
77+
78+
h1, h2, h3, h4, h5, h6 {
79+
padding-left: 8px;
80+
padding-bottom: 4px;
81+
margin-bottom: 24px;
82+
margin-top: 24px;
83+
position: relative;
84+
color: var(--main-text-color);
85+
text-box-edge: cap alphabetic;
86+
}
87+
88+
h1::before, h2::before {
89+
content: "";
90+
position: absolute;
91+
display: block;
92+
left: -24px;
93+
width: 12px;
94+
height: 100%;
95+
background-color: var(--primery-color);
96+
}
97+
98+
p {
99+
color: var(--main-text-color);
100+
letter-spacing: 2px;
101+
font-size: 20px;
102+
margin: 20px 0;
103+
}
104+
}
105+
106+
@media screen and (max-width: 700px) {
107+
.container {
108+
.article-container {
109+
width: 90% !important;
110+
}
111+
}
112+
}

app/routes/blog/$id.tsx

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import hljs from "highlight.js";
2+
import 'highlight.js/styles/github-dark.css';
3+
import './custom-highlight.scss'
4+
import { useEffect, useState, type JSX } from "react";
5+
import { Header } from "~/components/Header/Header";
6+
import styles from "./$id.module.scss"
7+
import { useParams } from "react-router";
8+
import { useIsMobile } from "~/hooks/useIsMobile";
9+
import { custom_markdown_convert } from "~/utils/convert";
10+
11+
export default function Blog(): JSX.Element {
12+
const { id } = useParams();
13+
const [thumbnail] = useState<string | null>(null);
14+
const [markdownSource, setMarkdownSource] = useState<string>("");
15+
const [table, setTable] = useState<JSX.Element[]>([]);
16+
const isMobile = useIsMobile();
17+
18+
const handleAnchorClick = (id: string) => (e: React.MouseEvent) => {
19+
e.preventDefault();
20+
const target = document.getElementById(id);
21+
if (target) {
22+
window.scrollTo({
23+
top: target.getBoundingClientRect().top + window.scrollY - 80,
24+
behavior: 'smooth',
25+
});
26+
}
27+
};
28+
29+
useEffect(() => {
30+
const script = document.createElement("script");
31+
script.src = "https://cdn.jsdelivr.net/gh/rsms/[email protected]/dist/markdown.js";
32+
script.async = true;
33+
34+
document.body.appendChild(script);
35+
36+
script.onload = async () => {
37+
await markdown.ready;
38+
await fetch(`https://raw.githubusercontent.com/object-t/object-t-blog/refs/heads/main/articles/${id}.md`)
39+
.then((res) => res.text())
40+
.then((md) => {
41+
const html = markdown.parse(custom_markdown_convert(md));
42+
const container = document.createElement("div");
43+
container.innerHTML = html;
44+
45+
const headings = container.querySelectorAll("h1, h2");
46+
headings.forEach((heading, i) => {
47+
const text = heading.textContent ?? `heading-${i}`;
48+
const id = text.replace(/\s+/g, "-").toLowerCase();
49+
heading.id = id;
50+
});
51+
setTable(
52+
Array.from(headings).map((d, i) => {
53+
const id = (d.textContent ?? `heading-${i}`).replace(/\s+/g, "-").toLowerCase();
54+
return (
55+
<a
56+
key={i}
57+
className={styles[`${d.tagName.toLowerCase()}-table`]}
58+
href={"#" + id}
59+
onClick={handleAnchorClick(id)}
60+
>
61+
<li>{d.textContent}</li>
62+
</a>
63+
)
64+
}
65+
)
66+
);
67+
68+
container.querySelectorAll("pre code").forEach((code) => {
69+
hljs.highlightElement(code as HTMLElement);
70+
});
71+
72+
setMarkdownSource(container.innerHTML);
73+
})
74+
.catch((err) => console.error("読み込みエラー:", err));
75+
};
76+
}, [id]);
77+
78+
return (
79+
<div className={styles.container}>
80+
<Header />
81+
{
82+
!isMobile &&
83+
<div className={styles.side}>
84+
<ul>
85+
{
86+
table
87+
}
88+
</ul>
89+
</div>
90+
}
91+
<div className={styles["article-container"]}>
92+
<img src={thumbnail ? thumbnail : "/assets/images/headers/blog.webp"} className={styles["header-img"]} />
93+
<div
94+
className={[styles.article, isMobile && styles.mobile].join(" ")}
95+
dangerouslySetInnerHTML={
96+
{
97+
__html: markdownSource
98+
}
99+
}
100+
/>
101+
</div>
102+
</div>
103+
)
104+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
pre {
2+
display: block;
3+
border-radius: 8px;
4+
overflow-x: hidden;
5+
font-size: 20px;
6+
width: 100%;
7+
8+
background-color: #0f1a2b;
9+
box-shadow: 0 12px 30px #3a3a3a3f;
10+
}
11+
12+
code.hljs {
13+
width: calc(100% - 24px);
14+
font-size: 16px;
15+
font-family: Menlo, monospace;
16+
line-height: 1.8em;
17+
padding: 0 24px;
18+
19+
background-color: transparent;
20+
21+
span.hljs-addition {
22+
line-height: 0 !important;
23+
padding: 1em 0;
24+
display: inline-block;
25+
// width: 100%;
26+
}
27+
}
28+
29+
.filename-label {
30+
background-color: #2a554c;
31+
width: max-content;
32+
padding: 4px 12px 4px 12px;
33+
color: var(--accent-color);
34+
display: flex;
35+
justify-content: center;
36+
align-items: center;
37+
font-size: 12px;
38+
letter-spacing: 2px;
39+
40+
border-top-left-radius: 4px;
41+
border-top-right-radius: 4px;
42+
43+
& + pre {
44+
border-top-left-radius: 0;
45+
}
46+
}

app/routes/blog/index.module.css

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)