refactor(blog): move content gen code to its own package
This commit is contained in:
parent
c9c8cd35c1
commit
5ab6b93fa3
66 changed files with 460 additions and 380 deletions
|
@ -1,35 +0,0 @@
|
||||||
import fs from "fs"
|
|
||||||
|
|
||||||
import {
|
|
||||||
contentDirectoryPath,
|
|
||||||
iconsDirectoryPath,
|
|
||||||
mapFilePath,
|
|
||||||
portfolioFilePath,
|
|
||||||
searchIndexFilePath,
|
|
||||||
} from "./config"
|
|
||||||
|
|
||||||
export default function clean() {
|
|
||||||
deleteDirectory(contentDirectoryPath)
|
|
||||||
deleteDirectory(iconsDirectoryPath)
|
|
||||||
|
|
||||||
deleteFile(mapFilePath)
|
|
||||||
deleteFile(portfolioFilePath)
|
|
||||||
deleteFile(searchIndexFilePath)
|
|
||||||
|
|
||||||
deleteFile("./public/img/skills.svg")
|
|
||||||
deleteFile("./public/img/projects.svg")
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteDirectory(path: string) {
|
|
||||||
try {
|
|
||||||
fs.rmSync(path, { recursive: true })
|
|
||||||
// eslint-disable-next-line no-empty
|
|
||||||
} catch (err) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function deleteFile(path: string) {
|
|
||||||
try {
|
|
||||||
fs.unlinkSync(path)
|
|
||||||
// eslint-disable-next-line no-empty
|
|
||||||
} catch (err) {}
|
|
||||||
}
|
|
|
@ -3,12 +3,13 @@
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"generate": "ts-node -O '{\"module\":\"commonjs\"}' --files ./generate",
|
"cp": "cp -a ../../packages/blog-content/dist/public/. ./public",
|
||||||
"dev": "pnpm run generate && react-scripts start",
|
"dev": "pnpm cp && react-scripts start",
|
||||||
"build": "pnpm run generate && react-scripts build",
|
"build": "pnpm cp && react-scripts build",
|
||||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf build"
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@developomp-site/blog-content": "workspace:*",
|
||||||
"@developomp-site/theme": "workspace:*",
|
"@developomp-site/theme": "workspace:*",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||||
|
@ -37,12 +38,10 @@
|
||||||
"@developomp-site/eslint-config": "workspace:*",
|
"@developomp-site/eslint-config": "workspace:*",
|
||||||
"@developomp-site/tsconfig": "workspace:*",
|
"@developomp-site/tsconfig": "workspace:*",
|
||||||
"@styled/typescript-styled-plugin": "^1.0.0",
|
"@styled/typescript-styled-plugin": "^1.0.0",
|
||||||
"@types/ejs": "^3.1.1",
|
|
||||||
"@types/elasticlunr": "^0.9.5",
|
"@types/elasticlunr": "^0.9.5",
|
||||||
"@types/highlight.js": "^10.1.0",
|
"@types/highlight.js": "^10.1.0",
|
||||||
"@types/jsdom": "^20.0.1",
|
"@types/jsdom": "^20.0.1",
|
||||||
"@types/katex": "^0.14.0",
|
"@types/katex": "^0.14.0",
|
||||||
"@types/markdown-it": "^12.2.3",
|
|
||||||
"@types/node": "^18.11.11",
|
"@types/node": "^18.11.11",
|
||||||
"@types/react": "^18.0.26",
|
"@types/react": "^18.0.26",
|
||||||
"@types/react-collapse": "^5.0.1",
|
"@types/react-collapse": "^5.0.1",
|
||||||
|
@ -50,29 +49,10 @@
|
||||||
"@types/react-dom": "^18.0.9",
|
"@types/react-dom": "^18.0.9",
|
||||||
"@types/react-select": "^5.0.1",
|
"@types/react-select": "^5.0.1",
|
||||||
"@types/styled-components": "^5.1.26",
|
"@types/styled-components": "^5.1.26",
|
||||||
"@types/svgo": "^3.0.0",
|
|
||||||
"@types/tinycolor2": "^1.4.3",
|
|
||||||
"ejs": "^3.1.8",
|
|
||||||
"gray-matter": "^4.0.3",
|
|
||||||
"jsdom": "^20.0.3",
|
"jsdom": "^20.0.3",
|
||||||
"jspdf": "^2.5.1",
|
"jspdf": "^2.5.1",
|
||||||
"markdown-it": "^13.0.1",
|
|
||||||
"markdown-it-anchor": "^8.6.5",
|
|
||||||
"markdown-it-attrs": "^4.1.4",
|
|
||||||
"markdown-it-footnote": "^3.0.3",
|
|
||||||
"markdown-it-highlight-lines": "^1.0.2",
|
|
||||||
"markdown-it-mark": "^3.0.1",
|
|
||||||
"markdown-it-sub": "^1.0.0",
|
|
||||||
"markdown-it-sup": "^1.0.0",
|
|
||||||
"markdown-it-task-checkbox": "^1.0.6",
|
|
||||||
"markdown-it-texmath": "^1.0.0",
|
|
||||||
"markdown-toc": "^1.2.0",
|
|
||||||
"prettier": "^2.8.1",
|
"prettier": "^2.8.1",
|
||||||
"read-time-estimate": "^0.0.3",
|
|
||||||
"simple-icons": "^7.21.0",
|
"simple-icons": "^7.21.0",
|
||||||
"svgo": "^3.0.2",
|
|
||||||
"tinycolor2": "^1.4.2",
|
|
||||||
"ts-node": "^10.9.1",
|
|
||||||
"tslint-config-prettier": "^1.18.0",
|
"tslint-config-prettier": "^1.18.0",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import dark from "@developomp-site/theme/dist/dark.json"
|
import dark from "@developomp-site/theme/dist/dark.json"
|
||||||
import light from "@developomp-site/theme/dist/light.json"
|
import light from "@developomp-site/theme/dist/light.json"
|
||||||
|
|
||||||
|
import { Badge } from "@developomp-site/blog-content/src/types/types"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
|
|
||||||
|
@ -34,23 +35,16 @@ const StyledSVG = styled.div<{ isDark: boolean }>`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export interface Badge {
|
|
||||||
svg: string
|
|
||||||
hex: string
|
|
||||||
isDark: boolean
|
|
||||||
title: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BadgeProps {
|
interface BadgeProps {
|
||||||
slug: string
|
slug: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const Badge = (props: BadgeProps) => {
|
export default (props: BadgeProps) => {
|
||||||
const [badgeData, setBadgeData] = useState<Badge | undefined>(undefined)
|
const [badgeData, setBadgeData] = useState<Badge | undefined>(undefined)
|
||||||
const { slug } = props
|
const { slug } = props
|
||||||
|
|
||||||
const getBadgeData = async () => {
|
const getBadgeData = async () => {
|
||||||
return await require(`../data/icons/${slug}.json`)
|
return await require(`@developomp-site/blog-content/dist/icons/${slug}.json`)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -71,5 +65,3 @@ const Badge = (props: BadgeProps) => {
|
||||||
</StyledBadge>
|
</StyledBadge>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Badge
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import { Link } from "react-router-dom"
|
import { Link } from "react-router-dom"
|
||||||
|
|
||||||
import { PostData } from "../../types/types"
|
import { PostData } from "@developomp-site/blog-content/src/types/types"
|
||||||
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
import {
|
import {
|
||||||
|
|
6
apps/blog/src/contentMap.ts
Normal file
6
apps/blog/src/contentMap.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import contentMapJson from "@developomp-site/blog-content/dist/map.json"
|
||||||
|
import { ContentMap } from "@developomp-site/blog-content/src/types/types"
|
||||||
|
|
||||||
|
const contentMap: ContentMap = contentMapJson
|
||||||
|
|
||||||
|
export default contentMap
|
|
@ -2,7 +2,6 @@
|
||||||
* PostList.tsx
|
* PostList.tsx
|
||||||
* show posts in recent order
|
* show posts in recent order
|
||||||
*/
|
*/
|
||||||
import type { Map } from "../../../types/types"
|
|
||||||
|
|
||||||
import { useCallback, useEffect, useState } from "react"
|
import { useCallback, useEffect, useState } from "react"
|
||||||
import { Helmet } from "react-helmet-async"
|
import { Helmet } from "react-helmet-async"
|
||||||
|
@ -11,9 +10,7 @@ import styled from "styled-components"
|
||||||
import PostCard from "../../components/PostCard"
|
import PostCard from "../../components/PostCard"
|
||||||
import ShowMoreButton from "./ShowMoreButton"
|
import ShowMoreButton from "./ShowMoreButton"
|
||||||
|
|
||||||
import _map from "../../data/map.json"
|
import contentMap from "../../contentMap"
|
||||||
|
|
||||||
const map: Map = _map
|
|
||||||
|
|
||||||
const PostList = styled.div`
|
const PostList = styled.div`
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -32,23 +29,23 @@ export default () => {
|
||||||
let postCount = 0
|
let postCount = 0
|
||||||
const postCards = [] as JSX.Element[]
|
const postCards = [] as JSX.Element[]
|
||||||
|
|
||||||
for (const date of Object.keys(map.date).reverse()) {
|
for (const date of Object.keys(contentMap.date).reverse()) {
|
||||||
if (postCount >= howMany) break
|
if (postCount >= howMany) break
|
||||||
|
|
||||||
const length = map.date[date].length
|
const length = contentMap.date[date].length
|
||||||
|
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
if (postCount >= howMany) break
|
if (postCount >= howMany) break
|
||||||
|
|
||||||
postCount++
|
postCount++
|
||||||
const content_id = map.date[date][length - i - 1]
|
const content_id = contentMap.date[date][length - i - 1]
|
||||||
|
|
||||||
postCards.push(
|
postCards.push(
|
||||||
<PostCard
|
<PostCard
|
||||||
key={content_id}
|
key={content_id}
|
||||||
postData={{
|
postData={{
|
||||||
content_id: content_id,
|
content_id: content_id,
|
||||||
...map.posts[content_id],
|
...contentMap.posts[content_id],
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -60,7 +57,7 @@ export default () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadPostCards()
|
loadPostCards()
|
||||||
setPostsLength(Object.keys(map.posts).length)
|
setPostsLength(Object.keys(contentMap.posts).length)
|
||||||
}, [howMany])
|
}, [howMany])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
faHourglass,
|
faHourglass,
|
||||||
} from "@fortawesome/free-solid-svg-icons"
|
} from "@fortawesome/free-solid-svg-icons"
|
||||||
|
|
||||||
import { PageData } from "../../../types/types"
|
import { PageData } from "@developomp-site/blog-content/src/types/types"
|
||||||
|
|
||||||
const StyledMetaContainer = styled.div`
|
const StyledMetaContainer = styled.div`
|
||||||
color: ${({ theme }) => theme.theme.color.text.gray};
|
color: ${({ theme }) => theme.theme.color.text.gray};
|
||||||
|
|
|
@ -22,11 +22,9 @@ import {
|
||||||
import Meta from "./Meta"
|
import Meta from "./Meta"
|
||||||
import Toc from "./Toc"
|
import Toc from "./Toc"
|
||||||
|
|
||||||
import type { PageData, Map } from "../../../types/types"
|
import type { PageData } from "@developomp-site/blog-content/src/types/types"
|
||||||
|
|
||||||
import _map from "../../data/map.json"
|
import contentMap from "../../contentMap"
|
||||||
|
|
||||||
const map: Map = _map
|
|
||||||
|
|
||||||
const StyledTitle = styled.h1<{ pageType: PageType }>`
|
const StyledTitle = styled.h1<{ pageType: PageType }>`
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
@ -159,7 +157,7 @@ export default function Page() {
|
||||||
key={post}
|
key={post}
|
||||||
postData={{
|
postData={{
|
||||||
content_id: post,
|
content_id: post,
|
||||||
...map.posts[post],
|
...contentMap.posts[post],
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import portfolio from "../../data/portfolio.json"
|
import portfolio from "@developomp-site/blog-content/dist/portfolio.json"
|
||||||
import _map from "../../data/map.json"
|
|
||||||
|
|
||||||
import type { Map, PageData } from "../../../types/types"
|
import type { PageData } from "@developomp-site/blog-content/src/types/types"
|
||||||
|
|
||||||
const map: Map = _map
|
import contentMap from "../../contentMap"
|
||||||
|
|
||||||
export enum PageType {
|
export enum PageType {
|
||||||
POST,
|
POST,
|
||||||
|
@ -16,9 +15,13 @@ export enum PageType {
|
||||||
export async function fetchContent(pageType: PageType, url: string) {
|
export async function fetchContent(pageType: PageType, url: string) {
|
||||||
try {
|
try {
|
||||||
if (pageType == PageType.UNSEARCHABLE) {
|
if (pageType == PageType.UNSEARCHABLE) {
|
||||||
return await import(`../../data/content/unsearchable${url}.json`)
|
return await import(
|
||||||
|
`@developomp-site/blog-content/dist/content/unsearchable${url}.json`
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
return await import(`../../data/content${url}.json`)
|
return await import(
|
||||||
|
`@developomp-site/blog-content/dist/content${url}.json`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return
|
return
|
||||||
|
@ -78,7 +81,7 @@ export function parsePageData(
|
||||||
// load and parse content differently depending on the content type
|
// load and parse content differently depending on the content type
|
||||||
switch (pageType) {
|
switch (pageType) {
|
||||||
case PageType.POST: {
|
case PageType.POST: {
|
||||||
const post = map.posts[content_id]
|
const post = contentMap.posts[content_id]
|
||||||
|
|
||||||
pageData.content = fetched_content.content
|
pageData.content = fetched_content.content
|
||||||
pageData.toc = fetched_content.toc
|
pageData.toc = fetched_content.toc
|
||||||
|
@ -95,11 +98,11 @@ export function parsePageData(
|
||||||
case PageType.SERIES: {
|
case PageType.SERIES: {
|
||||||
const seriesURL = content_id.slice(0, content_id.lastIndexOf("/"))
|
const seriesURL = content_id.slice(0, content_id.lastIndexOf("/"))
|
||||||
|
|
||||||
const curr = map.series[seriesURL].order.indexOf(content_id)
|
const curr = contentMap.series[seriesURL].order.indexOf(content_id)
|
||||||
const prev = curr - 1
|
const prev = curr - 1
|
||||||
const next = curr + 1
|
const next = curr + 1
|
||||||
|
|
||||||
const post = map.posts[content_id]
|
const post = contentMap.posts[content_id]
|
||||||
|
|
||||||
pageData.content = fetched_content.content
|
pageData.content = fetched_content.content
|
||||||
pageData.toc = fetched_content.toc
|
pageData.toc = fetched_content.toc
|
||||||
|
@ -111,17 +114,18 @@ export function parsePageData(
|
||||||
pageData.tags = post.tags || []
|
pageData.tags = post.tags || []
|
||||||
|
|
||||||
pageData.seriesHome = seriesURL
|
pageData.seriesHome = seriesURL
|
||||||
pageData.prev = prev >= 0 ? map.series[seriesURL].order[prev] : undefined
|
pageData.prev =
|
||||||
|
prev >= 0 ? contentMap.series[seriesURL].order[prev] : undefined
|
||||||
pageData.next =
|
pageData.next =
|
||||||
next < map.series[seriesURL].order.length
|
next < contentMap.series[seriesURL].order.length
|
||||||
? map.series[seriesURL].order[next]
|
? contentMap.series[seriesURL].order[next]
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case PageType.SERIES_HOME: {
|
case PageType.SERIES_HOME: {
|
||||||
const seriesData = map.series[content_id]
|
const seriesData = contentMap.series[content_id]
|
||||||
|
|
||||||
pageData.title = seriesData.title
|
pageData.title = seriesData.title
|
||||||
pageData.content = fetched_content.content
|
pageData.content = fetched_content.content
|
||||||
|
@ -152,7 +156,7 @@ export function parsePageData(
|
||||||
}
|
}
|
||||||
|
|
||||||
case PageType.UNSEARCHABLE: {
|
case PageType.UNSEARCHABLE: {
|
||||||
pageData.title = map.unsearchable[content_id].title
|
pageData.title = contentMap.unsearchable[content_id].title
|
||||||
pageData.content = fetched_content.content
|
pageData.content = fetched_content.content
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
|
@ -5,9 +5,9 @@ import MainContent from "../../components/MainContent"
|
||||||
import Badge from "../../components/Badge"
|
import Badge from "../../components/Badge"
|
||||||
import ProjectCard from "./ProjectCard"
|
import ProjectCard from "./ProjectCard"
|
||||||
|
|
||||||
import portfolio from "../../data/portfolio.json"
|
import portfolio from "@developomp-site/blog-content/dist/portfolio.json"
|
||||||
|
|
||||||
import type { PortfolioProject } from "../../../types/types"
|
import type { PortfolioProject } from "@developomp-site/blog-content/src/types/types"
|
||||||
|
|
||||||
const Portfolio = () => {
|
const Portfolio = () => {
|
||||||
const [projects, setProjects] = useState<JSX.Element[]>([])
|
const [projects, setProjects] = useState<JSX.Element[]>([])
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Link } from "react-router-dom"
|
||||||
import Badge from "../../components/Badge"
|
import Badge from "../../components/Badge"
|
||||||
import { cardCSS } from "../../components/Card"
|
import { cardCSS } from "../../components/Card"
|
||||||
|
|
||||||
import { PortfolioProject } from "../../../types/types"
|
import { PortfolioProject } from "@developomp-site/blog-content/src/types/types"
|
||||||
|
|
||||||
const StyledProjectCard = styled.div`
|
const StyledProjectCard = styled.div`
|
||||||
${cardCSS}
|
${cardCSS}
|
||||||
|
|
|
@ -6,8 +6,7 @@ import { Range } from "react-date-range"
|
||||||
|
|
||||||
import elasticlunr from "elasticlunr" // search engine
|
import elasticlunr from "elasticlunr" // search engine
|
||||||
|
|
||||||
import _map from "../../data/map.json"
|
import searchData from "@developomp-site/blog-content/dist/search.json"
|
||||||
import searchData from "../../data/search.json"
|
|
||||||
|
|
||||||
import Loading from "../../components/Loading"
|
import Loading from "../../components/Loading"
|
||||||
import PostCard from "../../components/PostCard"
|
import PostCard from "../../components/PostCard"
|
||||||
|
@ -17,13 +16,11 @@ import SearchBar from "./SearchBar"
|
||||||
import TagSelect, { TagsData } from "./TagSelect"
|
import TagSelect, { TagsData } from "./TagSelect"
|
||||||
import { ClearDateButton, DateRangeControl, StyledDateRange } from "./DateRange"
|
import { ClearDateButton, DateRangeControl, StyledDateRange } from "./DateRange"
|
||||||
|
|
||||||
|
import contentMap from "../../contentMap"
|
||||||
|
|
||||||
import "react-date-range/dist/styles.css"
|
import "react-date-range/dist/styles.css"
|
||||||
import "react-date-range/dist/theme/default.css"
|
import "react-date-range/dist/theme/default.css"
|
||||||
|
|
||||||
import type { Map } from "../../../types/types"
|
|
||||||
|
|
||||||
const map: Map = _map
|
|
||||||
|
|
||||||
const searchIndex = elasticlunr.Index.load(searchData as never)
|
const searchIndex = elasticlunr.Index.load(searchData as never)
|
||||||
|
|
||||||
export interface SearchParams {
|
export interface SearchParams {
|
||||||
|
@ -112,7 +109,7 @@ const Search = () => {
|
||||||
try {
|
try {
|
||||||
const _postCards: JSX.Element[] = []
|
const _postCards: JSX.Element[] = []
|
||||||
for (const res of searchIndex.search(searchInput)) {
|
for (const res of searchIndex.search(searchInput)) {
|
||||||
const postData = map.posts[res.ref]
|
const postData = contentMap.posts[res.ref]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
postData && // if post data exists
|
postData && // if post data exists
|
||||||
|
|
|
@ -2,13 +2,9 @@ import { useContext } from "react"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import Select from "react-select"
|
import Select from "react-select"
|
||||||
|
|
||||||
import _map from "../../data/map.json"
|
import contentMap from "../../contentMap"
|
||||||
import { globalContext } from "../../globalContext"
|
import { globalContext } from "../../globalContext"
|
||||||
|
|
||||||
import type { Map } from "../../../types/types"
|
|
||||||
|
|
||||||
const map: Map = _map
|
|
||||||
|
|
||||||
const StyledReactTagsContainer = styled.div`
|
const StyledReactTagsContainer = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
|
@ -19,7 +15,7 @@ export interface TagsData {
|
||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const options: TagsData[] = map.meta.tags.map((elem) => ({
|
const options: TagsData[] = contentMap.meta.tags.map((elem) => ({
|
||||||
value: elem,
|
value: elem,
|
||||||
label: elem,
|
label: elem,
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -24,5 +24,5 @@
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx"
|
"jsx": "react-jsx"
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", "types/**/*", "generate/**/*"]
|
"include": ["src/**/*", "types/**/*"]
|
||||||
}
|
}
|
||||||
|
|
42
packages/blog-content/package.json
Normal file
42
packages/blog-content/package.json
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"name": "@developomp-site/blog-content",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"files": [
|
||||||
|
"dist/**"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "ts-node -O '{\"module\":\"commonjs\"}' --files ./src",
|
||||||
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@developomp-site/tsconfig": "workspace:*",
|
||||||
|
"@types/ejs": "^3.1.1",
|
||||||
|
"@types/katex": "^0.14.0",
|
||||||
|
"@types/markdown-it": "^12.2.3",
|
||||||
|
"@types/svgo": "^3.0.0",
|
||||||
|
"@types/tinycolor2": "^1.4.3",
|
||||||
|
"canvas": "^2.11.2",
|
||||||
|
"ejs": "^3.1.8",
|
||||||
|
"gray-matter": "^4.0.3",
|
||||||
|
"markdown-it": "^13.0.1",
|
||||||
|
"markdown-it-anchor": "^8.6.5",
|
||||||
|
"markdown-it-attrs": "^4.1.4",
|
||||||
|
"markdown-it-footnote": "^3.0.3",
|
||||||
|
"markdown-it-highlight-lines": "^1.0.2",
|
||||||
|
"markdown-it-mark": "^3.0.1",
|
||||||
|
"markdown-it-sub": "^1.0.0",
|
||||||
|
"markdown-it-sup": "^1.0.0",
|
||||||
|
"markdown-it-task-checkbox": "^1.0.6",
|
||||||
|
"markdown-it-texmath": "^1.0.0",
|
||||||
|
"markdown-toc": "^1.2.0",
|
||||||
|
"read-time-estimate": "^0.0.3",
|
||||||
|
"simple-icons": "^7.21.0",
|
||||||
|
"svgo": "^3.0.2",
|
||||||
|
"tinycolor2": "^1.4.2",
|
||||||
|
"typescript": "^4.9.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/read-time-estimate": "^0.0.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
export const markdownPath = "./markdown" // where it will look for markdown documents
|
export const markdownPath = "./markdown" // where it will look for markdown documents
|
||||||
export const outPath = "./src/data" // path to the json database
|
export const outPath = "./dist" // path to the json database
|
||||||
|
|
||||||
export const contentDirectoryPath = `${outPath}/content`
|
export const contentDirectoryPath = `${outPath}/content`
|
||||||
export const iconsDirectoryPath = `${outPath}/icons`
|
export const iconsDirectoryPath = `${outPath}/icons`
|
|
@ -12,11 +12,10 @@ import { mapFilePath, markdownPath, portfolioFilePath } from "./config"
|
||||||
import { recursiveParse } from "./recursiveParse"
|
import { recursiveParse } from "./recursiveParse"
|
||||||
import { saveIndex } from "./searchIndex"
|
import { saveIndex } from "./searchIndex"
|
||||||
import postProcess from "./postProcess"
|
import postProcess from "./postProcess"
|
||||||
import clean from "./clean"
|
|
||||||
|
|
||||||
import { Map, ParseMode, SeriesMap, PortfolioData } from "../types/types"
|
import { ContentMap, ParseMode, PortfolioData, SeriesMap } from "./types/types"
|
||||||
|
|
||||||
export const map: Map = {
|
export const contentMap: ContentMap = {
|
||||||
date: {},
|
date: {},
|
||||||
tags: {},
|
tags: {},
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -36,7 +35,10 @@ export const portfolioData: PortfolioData = {
|
||||||
* Delete previously generated files
|
* Delete previously generated files
|
||||||
*/
|
*/
|
||||||
|
|
||||||
clean()
|
try {
|
||||||
|
fs.rmSync("dist", { recursive: true })
|
||||||
|
// eslint-disable-next-line no-empty
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checking
|
* Checking
|
||||||
|
@ -73,7 +75,7 @@ postProcess()
|
||||||
* Save results
|
* Save results
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fs.writeFileSync(mapFilePath, JSON.stringify(map))
|
fs.writeFileSync(mapFilePath, JSON.stringify(contentMap))
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
portfolioFilePath,
|
portfolioFilePath,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
@ -81,4 +83,5 @@ fs.writeFileSync(
|
||||||
skills: Array.from(portfolioData.skills),
|
skills: Array.from(portfolioData.skills),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
saveIndex()
|
saveIndex()
|
|
@ -18,7 +18,7 @@ import "katex/contrib/mhchem" // chemical formula
|
||||||
import { JSDOM } from "jsdom" // HTML DOM parsing
|
import { JSDOM } from "jsdom" // HTML DOM parsing
|
||||||
|
|
||||||
import { nthIndex } from "./util"
|
import { nthIndex } from "./util"
|
||||||
import { MarkdownData, ParseMode } from "../types/types"
|
import { MarkdownData, ParseMode } from "./types/types"
|
||||||
|
|
||||||
const md = markdownIt({
|
const md = markdownIt({
|
||||||
// https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md
|
// https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md
|
Before Width: | Height: | Size: 639 B After Width: | Height: | Size: 639 B |
|
@ -4,10 +4,12 @@ import { readFileSync, writeFileSync } from "fs"
|
||||||
import icons from "simple-icons/icons"
|
import icons from "simple-icons/icons"
|
||||||
import tinycolor from "tinycolor2"
|
import tinycolor from "tinycolor2"
|
||||||
|
|
||||||
import { map, seriesMap } from "."
|
import { contentMap, seriesMap } from "."
|
||||||
import { Badge } from "../src/components/Badge"
|
|
||||||
|
import { Badge } from "./types/types"
|
||||||
|
|
||||||
import skills from "./portfolio/skills.json"
|
import skills from "./portfolio/skills.json"
|
||||||
|
import { writeToFile } from "./util"
|
||||||
|
|
||||||
export default function postProcess() {
|
export default function postProcess() {
|
||||||
sortDates()
|
sortDates()
|
||||||
|
@ -17,17 +19,17 @@ export default function postProcess() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortDates() {
|
function sortDates() {
|
||||||
const TmpDate = map.date
|
const TmpDate = contentMap.date
|
||||||
map.date = {}
|
contentMap.date = {}
|
||||||
Object.keys(TmpDate)
|
Object.keys(TmpDate)
|
||||||
.sort()
|
.sort()
|
||||||
.forEach((sortedDateKey) => {
|
.forEach((sortedDateKey) => {
|
||||||
map.date[sortedDateKey] = TmpDate[sortedDateKey]
|
contentMap.date[sortedDateKey] = TmpDate[sortedDateKey]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillTags() {
|
function fillTags() {
|
||||||
map.meta.tags = Object.keys(map.tags)
|
contentMap.meta.tags = Object.keys(contentMap.tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseSeries() {
|
function parseSeries() {
|
||||||
|
@ -43,8 +45,10 @@ function parseSeries() {
|
||||||
|
|
||||||
// series length and order
|
// series length and order
|
||||||
for (const seriesURL in seriesMap) {
|
for (const seriesURL in seriesMap) {
|
||||||
map.series[seriesURL].length = seriesMap[seriesURL].length
|
contentMap.series[seriesURL].length = seriesMap[seriesURL].length
|
||||||
map.series[seriesURL].order = seriesMap[seriesURL].map((item) => item.url)
|
contentMap.series[seriesURL].order = seriesMap[seriesURL].map(
|
||||||
|
(item) => item.url
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +59,7 @@ function generatePortfolioSVGs() {
|
||||||
|
|
||||||
// todo: wait add ejs once it's available
|
// todo: wait add ejs once it's available
|
||||||
|
|
||||||
const style = readFileSync("./generate/portfolio/style.css", "utf-8")
|
const style = readFileSync("./src/portfolio/style.css", "utf-8")
|
||||||
|
|
||||||
const data: {
|
const data: {
|
||||||
[key: string]: Badge[] | { [key: string]: Badge[] }
|
[key: string]: Badge[] | { [key: string]: Badge[] }
|
||||||
|
@ -104,13 +108,13 @@ function generatePortfolioSVGs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderedSVG = ejs.render(
|
const renderedSVG = ejs.render(
|
||||||
readFileSync("./generate/portfolio/skills.ejs", "utf-8"),
|
readFileSync("./src/portfolio/skills.ejs", "utf-8"),
|
||||||
{ style, data },
|
{ style, data },
|
||||||
{ views: ["./generate/portfolio"] }
|
{ views: ["./src/portfolio"] }
|
||||||
)
|
)
|
||||||
|
|
||||||
writeFileSync(
|
writeToFile(
|
||||||
"./public/img/skills.svg",
|
"./dist/public/img/skills.svg",
|
||||||
optimize(renderedSVG, { multipass: true }).data
|
optimize(renderedSVG, { multipass: true }).data
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -4,12 +4,13 @@ import readTimeEstimate from "read-time-estimate" // post read time estimation
|
||||||
import { path2FileOrFolderName, path2URL } from "../util"
|
import { path2FileOrFolderName, path2URL } from "../util"
|
||||||
import parseMarkdown from "../parseMarkdown"
|
import parseMarkdown from "../parseMarkdown"
|
||||||
|
|
||||||
import { ParseMode } from "../../types/types"
|
|
||||||
import parsePost from "./parsePost"
|
import parsePost from "./parsePost"
|
||||||
import parseSeries from "./parseSeries"
|
import parseSeries from "./parseSeries"
|
||||||
import parseUnsearchable from "./parseUnsearchable"
|
import parseUnsearchable from "./parseUnsearchable"
|
||||||
import parsePortfolio from "./parsePortfolio"
|
import parsePortfolio from "./parsePortfolio"
|
||||||
|
|
||||||
|
import { ParseMode } from "../types/types"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data that's passed from {@link parseFile} to other function
|
* Data that's passed from {@link parseFile} to other function
|
||||||
*/
|
*/
|
|
@ -1,11 +1,12 @@
|
||||||
import { contentDirectoryPath } from "../config"
|
import { contentDirectoryPath } from "../config"
|
||||||
import { generateToc } from "../parseMarkdown"
|
import { generateToc } from "../parseMarkdown"
|
||||||
import { PostData } from "../../types/types"
|
|
||||||
import { addDocument } from "../searchIndex"
|
import { addDocument } from "../searchIndex"
|
||||||
import { writeToFile } from "../util"
|
import { writeToFile } from "../util"
|
||||||
import { map } from ".."
|
import { contentMap } from ".."
|
||||||
import { DataToPass } from "."
|
import { DataToPass } from "."
|
||||||
|
|
||||||
|
import { PostData } from "../types/types"
|
||||||
|
|
||||||
export default function parsePost(data: DataToPass): void {
|
export default function parsePost(data: DataToPass): void {
|
||||||
const { urlPath, markdownRaw, markdownData, humanizedDuration, totalWords } =
|
const { urlPath, markdownRaw, markdownData, humanizedDuration, totalWords } =
|
||||||
data
|
data
|
||||||
|
@ -30,10 +31,10 @@ export default function parsePost(data: DataToPass): void {
|
||||||
})
|
})
|
||||||
|
|
||||||
const YYYY_MM_DD = postDate.toISOString().split("T")[0]
|
const YYYY_MM_DD = postDate.toISOString().split("T")[0]
|
||||||
if (map.date[YYYY_MM_DD]) {
|
if (contentMap.date[YYYY_MM_DD]) {
|
||||||
map.date[YYYY_MM_DD].push(urlPath)
|
contentMap.date[YYYY_MM_DD].push(urlPath)
|
||||||
} else {
|
} else {
|
||||||
map.date[YYYY_MM_DD] = [urlPath]
|
contentMap.date[YYYY_MM_DD] = [urlPath]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,10 +44,10 @@ export default function parsePost(data: DataToPass): void {
|
||||||
postData.tags = markdownData.tags as string[]
|
postData.tags = markdownData.tags as string[]
|
||||||
if (postData.tags) {
|
if (postData.tags) {
|
||||||
postData.tags.forEach((tag) => {
|
postData.tags.forEach((tag) => {
|
||||||
if (map.tags[tag]) {
|
if (contentMap.tags[tag]) {
|
||||||
map.tags[tag].push(urlPath)
|
contentMap.tags[tag].push(urlPath)
|
||||||
} else {
|
} else {
|
||||||
map.tags[tag] = [urlPath]
|
contentMap.tags[tag] = [urlPath]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -55,7 +56,7 @@ export default function parsePost(data: DataToPass): void {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
map.posts[urlPath] = postData
|
contentMap.posts[urlPath] = postData
|
||||||
addDocument({
|
addDocument({
|
||||||
title: markdownData.title,
|
title: markdownData.title,
|
||||||
body: markdownData.content,
|
body: markdownData.content,
|
|
@ -1,10 +1,11 @@
|
||||||
import { contentDirectoryPath } from "../config"
|
import { contentDirectoryPath } from "../config"
|
||||||
import { generateToc } from "../parseMarkdown"
|
import { generateToc } from "../parseMarkdown"
|
||||||
import { PostData } from "../../types/types"
|
|
||||||
import { addDocument } from "../searchIndex"
|
import { addDocument } from "../searchIndex"
|
||||||
import { writeToFile } from "../util"
|
import { writeToFile } from "../util"
|
||||||
import { map, seriesMap } from ".."
|
import { contentMap, seriesMap } from ".."
|
||||||
|
|
||||||
import { DataToPass } from "."
|
import { DataToPass } from "."
|
||||||
|
import { PostData } from "../types/types"
|
||||||
|
|
||||||
export default function parseSeries(data: DataToPass): void {
|
export default function parseSeries(data: DataToPass): void {
|
||||||
const {
|
const {
|
||||||
|
@ -63,10 +64,10 @@ export default function parseSeries(data: DataToPass): void {
|
||||||
})
|
})
|
||||||
|
|
||||||
const YYYY_MM_DD = postDate.toISOString().split("T")[0]
|
const YYYY_MM_DD = postDate.toISOString().split("T")[0]
|
||||||
if (map.date[YYYY_MM_DD]) {
|
if (contentMap.date[YYYY_MM_DD]) {
|
||||||
map.date[YYYY_MM_DD].push(urlPath)
|
contentMap.date[YYYY_MM_DD].push(urlPath)
|
||||||
} else {
|
} else {
|
||||||
map.date[YYYY_MM_DD] = [urlPath]
|
contentMap.date[YYYY_MM_DD] = [urlPath]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,10 +77,10 @@ export default function parseSeries(data: DataToPass): void {
|
||||||
postData.tags = markdownData.tags as string[]
|
postData.tags = markdownData.tags as string[]
|
||||||
if (postData.tags) {
|
if (postData.tags) {
|
||||||
postData.tags.forEach((tag) => {
|
postData.tags.forEach((tag) => {
|
||||||
if (map.tags[tag]) {
|
if (contentMap.tags[tag]) {
|
||||||
map.tags[tag].push(urlPath)
|
contentMap.tags[tag].push(urlPath)
|
||||||
} else {
|
} else {
|
||||||
map.tags[tag] = [urlPath]
|
contentMap.tags[tag] = [urlPath]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -94,18 +95,18 @@ export default function parseSeries(data: DataToPass): void {
|
||||||
url: urlPath,
|
url: urlPath,
|
||||||
})
|
})
|
||||||
|
|
||||||
map.posts[urlPath] = postData
|
contentMap.posts[urlPath] = postData
|
||||||
|
|
||||||
// series markdown starting with 0 is a series descriptor
|
// series markdown starting with 0 is a series descriptor
|
||||||
if (isFileDescriptor) {
|
if (isFileDescriptor) {
|
||||||
map.series[urlPath] = {
|
contentMap.series[urlPath] = {
|
||||||
...postData,
|
...postData,
|
||||||
order: [],
|
order: [],
|
||||||
length: 0,
|
length: 0,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// put series post in appropriate series
|
// put series post in appropriate series
|
||||||
for (const key of Object.keys(map.series)) {
|
for (const key of Object.keys(contentMap.series)) {
|
||||||
if (urlPath.includes(key)) {
|
if (urlPath.includes(key)) {
|
||||||
const index = parseInt(
|
const index = parseInt(
|
||||||
_urlPath.slice(
|
_urlPath.slice(
|
|
@ -1,7 +1,7 @@
|
||||||
import { contentDirectoryPath } from "../config"
|
import { contentDirectoryPath } from "../config"
|
||||||
import { addDocument } from "../searchIndex"
|
import { addDocument } from "../searchIndex"
|
||||||
import { writeToFile } from "../util"
|
import { writeToFile } from "../util"
|
||||||
import { map } from ".."
|
import { contentMap } from ".."
|
||||||
import { DataToPass } from "."
|
import { DataToPass } from "."
|
||||||
|
|
||||||
export default function parseUnsearchable(data: DataToPass): void {
|
export default function parseUnsearchable(data: DataToPass): void {
|
||||||
|
@ -17,7 +17,7 @@ export default function parseUnsearchable(data: DataToPass): void {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Parse data that will be written to map.js
|
// Parse data that will be written to map.js
|
||||||
map.unsearchable[urlPath] = {
|
contentMap.unsearchable[urlPath] = {
|
||||||
title: markdownData.title as string,
|
title: markdownData.title as string,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export interface Map {
|
export interface ContentMap {
|
||||||
// key: YYYY-MM-DD
|
// key: YYYY-MM-DD
|
||||||
// value: url
|
// value: url
|
||||||
date: { [key: string]: string[] }
|
date: { [key: string]: string[] }
|
||||||
|
@ -81,6 +81,13 @@ export interface PageData {
|
||||||
repo: string
|
repo: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Badge {
|
||||||
|
svg: string
|
||||||
|
hex: string
|
||||||
|
isDark: boolean
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Series
|
* Series
|
||||||
*/
|
*/
|
8
packages/blog-content/tsconfig.json
Normal file
8
packages/blog-content/tsconfig.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "@developomp-site/tsconfig/node16.json",
|
||||||
|
"include": ["src"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"exclude": ["dist", "node_modules"]
|
||||||
|
}
|
516
pnpm-lock.yaml
generated
516
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue