diff --git a/apps/blog/.eslintrc b/apps/blog/.eslintrc index f10ad67..22421e2 100644 --- a/apps/blog/.eslintrc +++ b/apps/blog/.eslintrc @@ -24,7 +24,6 @@ "rules": { "@typescript-eslint/no-empty-interface": "off", "@typescript-eslint/explicit-module-boundary-types": "off", - "react/jsx-uses-vars": "error", "react/react-in-jsx-scope": ["off"] } } diff --git a/apps/blog/package.json b/apps/blog/package.json index e9f1f9a..2078ea7 100644 --- a/apps/blog/package.json +++ b/apps/blog/package.json @@ -9,6 +9,7 @@ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf build" }, "dependencies": { + "@developomp-site/theme": "workspace:*", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-regular-svg-icons": "^6.2.1", @@ -33,8 +34,8 @@ "styled-components": "^5.3.6" }, "devDependencies": { - "@developomp-site/tsconfig": "workspace:0.0.0", - "@developomp-site/eslint-config": "workspace:0.0.0", + "@developomp-site/eslint-config": "workspace:*", + "@developomp-site/tsconfig": "workspace:*", "@types/ejs": "^3.1.1", "@types/elasticlunr": "^0.9.5", "@types/highlight.js": "^10.1.0", diff --git a/apps/blog/src/App.tsx b/apps/blog/src/App.tsx index f97b2cb..69c4a25 100644 --- a/apps/blog/src/App.tsx +++ b/apps/blog/src/App.tsx @@ -1,3 +1,6 @@ +import darkTheme from "@developomp-site/theme/dist/dark.json" +import lightTheme from "@developomp-site/theme/dist/light.json" + import { useContext, useEffect, useState } from "react" import { Routes, Route, useNavigate, useLocation } from "react-router-dom" import styled, { ThemeProvider } from "styled-components" @@ -5,7 +8,7 @@ import { Helmet } from "react-helmet-async" import { isIE } from "react-device-detect" import Loading from "./components/Loading" -import Navbar from "./components/Navbar" +import Header from "./components/Header" import Footer from "./components/Footer" import Home from "./pages/Home" @@ -14,17 +17,16 @@ import Page from "./pages/Page" import NotFound from "./pages/NotFound" import Portfolio from "./pages/Portfolio" -import theming from "./styles/theming" import GlobalStyle from "./styles/globalStyle" -import { ActionsEnum, globalContext } from "./globalContext" +import { globalContext } from "./globalContext" const IENotSupported = styled.p` margin: auto; font-size: 2rem; margin-top: 2rem; text-align: center; - font-family: ${theming.font.regular}; + font-family: ${(props) => props.theme.theme.font.sansSerif}; ` const StyledContentContainer = styled.div` @@ -34,7 +36,7 @@ const StyledContentContainer = styled.div` ` export default function App() { - const { globalState, dispatch } = useContext(globalContext) + const { globalState } = useContext(globalContext) const { locale } = globalState const navigate = useNavigate() @@ -73,10 +75,8 @@ export default function App() { return ( @@ -87,7 +87,7 @@ export default function App() { - +
{isLoading ? ( diff --git a/apps/blog/src/components/Badge.tsx b/apps/blog/src/components/Badge.tsx index ff7cbbb..750b476 100644 --- a/apps/blog/src/components/Badge.tsx +++ b/apps/blog/src/components/Badge.tsx @@ -1,8 +1,9 @@ +import dark from "@developomp-site/theme/dist/dark.json" +import light from "@developomp-site/theme/dist/light.json" + import { useEffect, useState } from "react" import styled from "styled-components" -import theming from "../styles/theming" - const StyledBadge = styled.div<{ color: string; isDark: boolean }>` vertical-align: middle; display: inline-block; @@ -15,7 +16,7 @@ const StyledBadge = styled.div<{ color: string; isDark: boolean }>` background-color: ${(props) => props.color}; color: ${(props) => - props.isDark ? theming.dark.color1 : theming.light.color1}; + props.isDark ? dark.color.text.default : light.color.text.default}; ` const StyledSVG = styled.div<{ isDark: boolean }>` @@ -27,7 +28,9 @@ const StyledSVG = styled.div<{ isDark: boolean }>` svg { height: 16px; fill: ${(props) => - props.isDark ? theming.dark.color1 : theming.light.color1} !important; + props.isDark + ? dark.color.text.default + : light.color.text.default} !important; } ` diff --git a/apps/blog/src/components/Card.tsx b/apps/blog/src/components/Card.tsx index 061385c..07def93 100644 --- a/apps/blog/src/components/Card.tsx +++ b/apps/blog/src/components/Card.tsx @@ -1,29 +1,22 @@ import styled, { css } from "styled-components" -import theming from "../styles/theming" - export const cardCSS = css` margin: auto; - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "white", - dark: theming.dark.backgroundColor2, - })}; + background-color: ${({ theme }) => + theme.currentTheme ? theme.theme.component.card.color.background : "white"}; padding: 2rem; border-radius: 6px; - box-shadow: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "0 4px 10px rgb(0 0 0 / 5%), 0 0 1px rgb(0 0 0 / 10%);", - dark: "0 4px 10px rgb(0 0 0 / 30%), 0 0 1px rgb(0 0 0 / 30%);", - })}; + box-shadow: ${({ theme }) => + theme.currentTheme === "dark" + ? "0 4px 10px rgb(0 0 0 / 30%), 0 0 1px rgb(0 0 0 / 30%)" + : "0 4px 10px rgb(0 0 0 / 5%), 0 0 1px rgb(0 0 0 / 10%)"}; - @media screen and (max-width: ${theming.size.screen_size1}) { + @media screen and (max-width: ${({ theme }) => + theme.theme.maxDisplayWidth.mobile}) { padding: 1rem; } ` -const Card = styled.div` +export default styled.div` ${cardCSS} ` - -export default Card diff --git a/apps/blog/src/components/Footer/Footer.tsx b/apps/blog/src/components/Footer/Footer.tsx index f798390..964d58b 100644 --- a/apps/blog/src/components/Footer/Footer.tsx +++ b/apps/blog/src/components/Footer/Footer.tsx @@ -1,6 +1,5 @@ import styled from "styled-components" -import theming from "../../styles/theming" import GithubLinkIcon from "../GithubLinkIcon" const StyledFooter = styled.footer` @@ -13,17 +12,8 @@ const StyledFooter = styled.footer` align-items: center; justify-content: center; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "black", - dark: "white", - })}; - - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "white", - dark: "black", - })}; + background-color: ${({ theme }) => + theme.theme.component.footer.color.background}; ` const StyledFooterContainer = styled.div` @@ -35,10 +25,10 @@ const StyledFooterContainer = styled.div` color: gray; width: 100%; - max-width: ${theming.size.screen_size2}; + max-width: ${({ theme }) => theme.theme.maxDisplayWidth.desktop}; ` -const Footer = () => { +export default () => { return ( @@ -51,5 +41,3 @@ const Footer = () => { ) } - -export default Footer diff --git a/apps/blog/src/components/GithubLinkIcon.tsx b/apps/blog/src/components/GithubLinkIcon.tsx index 95c7772..819b8d7 100644 --- a/apps/blog/src/components/GithubLinkIcon.tsx +++ b/apps/blog/src/components/GithubLinkIcon.tsx @@ -4,39 +4,27 @@ import styled from "styled-components" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { faGithub } from "@fortawesome/free-brands-svg-icons" -import theming from "../styles/theming" - const StyledGithubLink = styled.a<{ size?: string }>` font-size: ${(props) => props.size || "2.5rem"}; - - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "lightgrey", - dark: "grey", - })}; + color: ${({ theme }) => + theme.currentTheme === "dark" ? "grey" : "lightgrey"}; :hover { - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color0, - dark: theming.dark.color0, - })}; + color: ${({ theme }) => theme.theme.color.text.highContrast}; } ` -interface GithubLinkIconProps { +interface Props { link: string size?: string children?: ReactNode } -const GithubLinkIcon = (props: GithubLinkIconProps) => { +export default ({ link, size, children }: Props) => { return ( - + - {props.children} + {children} ) } - -export default GithubLinkIcon diff --git a/apps/blog/src/components/Header/Buttons/Buttons.tsx b/apps/blog/src/components/Header/Buttons/Buttons.tsx new file mode 100644 index 0000000..0dc9020 --- /dev/null +++ b/apps/blog/src/components/Header/Buttons/Buttons.tsx @@ -0,0 +1,21 @@ +import styled from "styled-components" + +import LocaleToggleButton from "./LocaleToggleButton" +import ThemeToggleButton from "./ThemeToggleButton" +import SearchButton from "./SearchButton" + +const RightButtons = styled.div` + display: flex; + height: 100%; + margin-left: auto; +` + +export default () => { + return ( + + + + + + ) +} diff --git a/apps/blog/src/components/Navbar/LocaleToggleButton.tsx b/apps/blog/src/components/Header/Buttons/LocaleToggleButton.tsx similarity index 66% rename from apps/blog/src/components/Navbar/LocaleToggleButton.tsx rename to apps/blog/src/components/Header/Buttons/LocaleToggleButton.tsx index efc1e25..dd39304 100644 --- a/apps/blog/src/components/Navbar/LocaleToggleButton.tsx +++ b/apps/blog/src/components/Header/Buttons/LocaleToggleButton.tsx @@ -1,3 +1,5 @@ +import type { SiteLocale } from "../../../globalContext" + import { useContext } from "react" import styled from "styled-components" import ReactTooltip from "react-tooltip" @@ -5,29 +7,28 @@ import ReactTooltip from "react-tooltip" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { faLanguage } from "@fortawesome/free-solid-svg-icons" -import { ActionsEnum, globalContext } from "../../globalContext" -import theming from "../../styles/theming" +import { ActionsEnum, globalContext } from "../../../globalContext" +import { HeaderButtonCSS } from "../HeaderButton" -import type { SiteLocale } from "../../globalContext" - -interface StyledLocaleToggleButtonProps { +interface Props { locale: SiteLocale } -const StyledLocaleToggleButton = styled.button` - ${theming.styles.navbarButtonStyle} +const LocaleToggleButton = styled.button` + ${HeaderButtonCSS} + border: none; width: 72px; ${(props) => (props.locale == "en" ? "" : "transform: scaleX(-1);")}; ` -function LocaleToggleButton() { +export default () => { const { globalState, dispatch } = useContext(globalContext) return ( <> - { @@ -39,12 +40,10 @@ function LocaleToggleButton() { locale={globalState.locale} > - + {globalState.locale == "en" ? "English" : "한국어"} ) } - -export default LocaleToggleButton diff --git a/apps/blog/src/components/Navbar/SearchButton.tsx b/apps/blog/src/components/Header/Buttons/SearchButton.tsx similarity index 83% rename from apps/blog/src/components/Navbar/SearchButton.tsx rename to apps/blog/src/components/Header/Buttons/SearchButton.tsx index 5da8d31..f522884 100644 --- a/apps/blog/src/components/Navbar/SearchButton.tsx +++ b/apps/blog/src/components/Header/Buttons/SearchButton.tsx @@ -2,12 +2,11 @@ import { useContext } from "react" import { Link } from "react-router-dom" import ReactTooltip from "react-tooltip" +import HeaderButton from "../HeaderButton" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { faSearch } from "@fortawesome/free-solid-svg-icons" -import { StyledLink } from "./Navbar" - -import { globalContext } from "../../globalContext" +import { globalContext } from "../../../globalContext" const SearchButton = () => { const { globalState } = useContext(globalContext) @@ -17,9 +16,9 @@ const SearchButton = () => { <>
- + - +
diff --git a/apps/blog/src/components/Navbar/ThemeToggleButton.tsx b/apps/blog/src/components/Header/Buttons/ThemeToggleButton.tsx similarity index 79% rename from apps/blog/src/components/Navbar/ThemeToggleButton.tsx rename to apps/blog/src/components/Header/Buttons/ThemeToggleButton.tsx index ad4c3a8..f1f726f 100644 --- a/apps/blog/src/components/Navbar/ThemeToggleButton.tsx +++ b/apps/blog/src/components/Header/Buttons/ThemeToggleButton.tsx @@ -6,24 +6,21 @@ import ReactTooltip from "react-tooltip" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { faMoon, faSun } from "@fortawesome/free-solid-svg-icons" -import theming from "../../styles/theming" -import { ActionsEnum, globalContext } from "../../globalContext" +import { ActionsEnum, globalContext } from "../../../globalContext" +import { HeaderButtonCSS } from "../HeaderButton" const StyledThemeButton = styled.button` - ${theming.styles.navbarButtonStyle} + ${HeaderButtonCSS} border: none; width: 72px; - ${(props) => - theming.theme(props.theme.currentTheme, { - light: "", - dark: "transform: scaleX(-1);", - })}; + ${({ theme }) => + theme.currentTheme === "dark" ? "transform: scaleX(-1)" : ""}; ` const ThemeToggleButton = () => { const { globalState, dispatch } = useContext(globalContext) - const theme = globalState.theme + const theme = globalState.currentTheme return ( <> diff --git a/apps/blog/src/components/Header/Buttons/index.ts b/apps/blog/src/components/Header/Buttons/index.ts new file mode 100644 index 0000000..ed5b780 --- /dev/null +++ b/apps/blog/src/components/Header/Buttons/index.ts @@ -0,0 +1,3 @@ +import Buttons from "./Buttons" + +export default Buttons diff --git a/apps/blog/src/components/Header/Header.tsx b/apps/blog/src/components/Header/Header.tsx new file mode 100644 index 0000000..199c882 --- /dev/null +++ b/apps/blog/src/components/Header/Header.tsx @@ -0,0 +1,63 @@ +import { useContext } from "react" +import { Link } from "react-router-dom" +import styled from "styled-components" +import ReadProgress from "./ReadProgress" + +import Nav from "./Nav" + +import Sidebar from "../Sidebar" + +import { globalContext } from "../../globalContext" +import Buttons from "./Buttons" + +const Header = styled.header` + /* set z index to arbitrarily high value to prevent other components from drawing over it */ + z-index: 9999; + + position: fixed; + width: 100%; + + background-color: ${({ theme }) => + theme.theme.component.ui.color.background.default}; + color: ${({ theme }) => theme.theme.color.text.default}; + box-shadow: 0 4px 10px rgb(0 0 0 / 5%); +` + +const Container = styled.div` + margin: 0 auto; + align-items: center; + display: flex; + height: 4rem; + + /* account for 20px scrollbar width */ + @media only screen and (min-width: calc(${({ theme }) => + theme.theme.maxDisplayWidth.desktop} + 20px)) { + width: calc(${({ theme }) => theme.theme.maxDisplayWidth.desktop} - 20px); + } +` + +const Icon = styled.img` + height: 2.5rem; + + display: block; + margin: 1rem; +` + +export default () => { + const { globalState } = useContext(globalContext) + const { locale } = globalState + + return ( +
+ + + + +
+ ) +} diff --git a/apps/blog/src/components/Header/HeaderButton.tsx b/apps/blog/src/components/Header/HeaderButton.tsx new file mode 100644 index 0000000..988a1a4 --- /dev/null +++ b/apps/blog/src/components/Header/HeaderButton.tsx @@ -0,0 +1,43 @@ +/** + * @file Manages the configuration settings for the widget. + */ + +import styled, { css } from "styled-components" + +export const HeaderButtonCSS = css` + /* style */ + + display: flex; + cursor: pointer; + align-items: center; + justify-content: center; + + /* size */ + + height: 100%; + min-width: 2.5rem; + margin: 0; + padding: 0 1rem 0 1rem; + + /* text */ + + text-decoration: none; + + /* color */ + + color: ${({ theme }) => theme.theme.color.text.default}; + background-color: ${({ theme }) => + theme.theme.component.ui.color.background.default}; + + /* animation */ + + transition: transform 0.1s linear; + &:hover { + background-color: ${({ theme }) => + theme.theme.component.ui.color.background.hover}; + } +` + +export default styled.div` + ${HeaderButtonCSS} +` diff --git a/apps/blog/src/components/Navbar/NavLinks.tsx b/apps/blog/src/components/Header/Nav.tsx similarity index 62% rename from apps/blog/src/components/Navbar/NavLinks.tsx rename to apps/blog/src/components/Header/Nav.tsx index 1c69a44..5aa192d 100644 --- a/apps/blog/src/components/Navbar/NavLinks.tsx +++ b/apps/blog/src/components/Header/Nav.tsx @@ -2,35 +2,33 @@ import { useContext } from "react" import styled from "styled-components" import { Link } from "react-router-dom" -import { StyledLink } from "./Navbar" +import HeaderButton from "./HeaderButton" import NavbarData from "../../data/NavbarData" -import theming from "../../styles/theming" import { globalContext } from "../../globalContext" -const StyledNavLinks = styled.div` +const Nav = styled.div` display: flex; height: 100%; - @media only screen and (max-width: ${theming.size.screen_size1}) { + @media only screen and (max-width: ${({ theme }) => + theme.theme.maxDisplayWidth.mobile}) { display: none; } ` -const NavLinks = () => { +export default () => { const { globalState } = useContext(globalContext) return ( - + ) } - -export default NavLinks diff --git a/apps/blog/src/components/Navbar/ReadProgress.tsx b/apps/blog/src/components/Header/ReadProgress.tsx similarity index 66% rename from apps/blog/src/components/Navbar/ReadProgress.tsx rename to apps/blog/src/components/Header/ReadProgress.tsx index b7170ab..439380d 100644 --- a/apps/blog/src/components/Navbar/ReadProgress.tsx +++ b/apps/blog/src/components/Header/ReadProgress.tsx @@ -2,24 +2,16 @@ import { useCallback, useEffect, useState } from "react" import { useLocation } from "react-router-dom" import styled from "styled-components" -import theming from "../../styles/theming" - -const StyledReadProgressBackground = styled.div` +const Background = styled.div` height: 0.2rem; - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "silver", - dark: "darkslategrey", - })}; + background-color: ${({ theme }) => + theme.theme.component.scrollProgressBar.color.background}; ` -const StyledReadProgress = styled.div` +const ProgressBar = styled.div` height: 100%; - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color0, - dark: theming.dark.color2, - })}; + background-color: ${({ theme }) => + theme.theme.component.scrollProgressBar.color.foreground}; ` const st = "scrollTop" @@ -58,9 +50,9 @@ const ReadProgress = () => { }, [location]) return ( - - - + + + ) } diff --git a/apps/blog/src/components/Header/index.ts b/apps/blog/src/components/Header/index.ts new file mode 100644 index 0000000..f90205a --- /dev/null +++ b/apps/blog/src/components/Header/index.ts @@ -0,0 +1,3 @@ +import Navbar from "./Header" + +export default Navbar diff --git a/apps/blog/src/components/Loading.tsx b/apps/blog/src/components/Loading.tsx index c3821f1..8e13c7b 100644 --- a/apps/blog/src/components/Loading.tsx +++ b/apps/blog/src/components/Loading.tsx @@ -6,8 +6,6 @@ import styled from "styled-components" import MainContent from "./MainContent" -import theming from "../styles/theming" - const StyledContainer = styled(MainContent)` display: flex; flex-direction: column; @@ -30,11 +28,7 @@ const StyledContainer = styled(MainContent)` ` const StyledSVG = styled.svg` - --color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color1, - dark: theming.dark.color1, - })}; + --color: ${({ theme }) => theme.theme.color.text.default}; display: block; margin: 1rem; diff --git a/apps/blog/src/components/MainContent.tsx b/apps/blog/src/components/MainContent.tsx index 3436f23..82226f7 100644 --- a/apps/blog/src/components/MainContent.tsx +++ b/apps/blog/src/components/MainContent.tsx @@ -1,5 +1,4 @@ import styled, { css } from "styled-components" -import theming from "../styles/theming" import Card from "./Card" @@ -15,7 +14,8 @@ export const mainContentCSS = css` max-width: fit-content; } - @media screen and (max-width: ${theming.size.screen_size1}) { + @media screen and (max-width: ${({ theme }) => + theme.theme.maxDisplayWidth.mobile}) { width: auto; margin: 1rem; } diff --git a/apps/blog/src/components/Navbar/Navbar.tsx b/apps/blog/src/components/Navbar/Navbar.tsx deleted file mode 100644 index d10f072..0000000 --- a/apps/blog/src/components/Navbar/Navbar.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { useContext } from "react" -import styled from "styled-components" -import { Link } from "react-router-dom" - -import NavLinks from "./NavLinks" -import LocaleToggleButton from "./LocaleToggleButton" -import ThemeToggleButton from "./ThemeToggleButton" -import SearchButton from "./SearchButton" -import ReadProgress from "./ReadProgress" -import Sidebar from "../Sidebar" - -import theming from "../../styles/theming" - -import { globalContext } from "../../globalContext" - -const StyledNav = styled.nav` - /* set z index to arbitrarily high value to prevent other components from drawing over the navbar */ - z-index: 9999; - position: fixed; - width: 100%; - - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.backgroundColor0, - dark: theming.dark.backgroundColor0, - })}; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color0, - dark: theming.dark.color0, - })}; - box-shadow: 0 4px 10px rgb(0 0 0 / 5%); -` - -const StyledContainer = styled.div` - margin: 0 auto; - align-items: center; - display: flex; - height: 4rem; - - /* account for 20px scrollbar width */ - @media only screen and (min-width: calc(${theming.size - .screen_size2} + 20px)) { - width: calc(${theming.size.screen_size2} - 20px); - } -` - -const RightButtons = styled.div` - display: flex; - height: 100%; - margin-left: auto; -` - -const StyledImg = styled.img` - height: 2.5rem; - - display: block; - margin: 1rem; -` - -export const StyledLink = styled.div` - ${theming.styles.navbarButtonStyle} -` - -const Navbar = () => { - const { globalState } = useContext(globalContext) - const { locale } = globalState - - return ( - - - {/* icon */} - - - - - {/* nav links */} - - - {/* right buttons */} - - - - - - - {/* etc */} - - - - - ) -} - -export default Navbar diff --git a/apps/blog/src/components/Navbar/index.ts b/apps/blog/src/components/Navbar/index.ts deleted file mode 100644 index 4a022d6..0000000 --- a/apps/blog/src/components/Navbar/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Navbar from "./Navbar" - -export default Navbar diff --git a/apps/blog/src/components/PostCard.tsx b/apps/blog/src/components/PostCard.tsx index 37e0e8c..c5a4572 100644 --- a/apps/blog/src/components/PostCard.tsx +++ b/apps/blog/src/components/PostCard.tsx @@ -15,57 +15,41 @@ import Tag from "./Tag" import TagList from "./TagList" import MainContent from "./MainContent" -import theming from "../styles/theming" import { globalContext } from "../globalContext" +const PostCard = styled(MainContent)` + box-shadow: 0 4px 10px rgb(0 0 0 / 10%); + text-align: left; + margin-bottom: 2rem; + + :hover { + cursor: pointer; + box-shadow: 0 4px 10px + ${({ theme }) => theme.theme.component.card.color.hoverGlow}; + } +` + const PostCardContainer = styled(Link)` display: block; padding: 2rem; text-decoration: none; padding: 0; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color2, - dark: theming.dark.color2, - })}; - + /* override link color */ + color: ${({ theme }) => theme.theme.color.text.gray}; &:hover { - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color2, - dark: theming.dark.color2, - })}; + color: ${({ theme }) => theme.theme.color.text.gray}; } ` -const StyledPostCard = styled(MainContent)` - box-shadow: 0 4px 10px rgb(0 0 0 / 10%); - text-align: left; - margin-bottom: 2rem; - - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color1, - dark: theming.dark.color1, - })}; - - ${theming.styles.hoverCard} -` - -const StyledTitle = styled.h1` +const Title = styled.h1` font-size: 2rem; font-style: bold; margin: 0; margin-bottom: 1rem; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color2, - dark: theming.dark.color2, - })}; ` -const StyledMetaContainer = styled.small`` +const MetaContainer = styled.small`` interface PostCardData extends PostData { content_id: string @@ -75,26 +59,26 @@ interface Props { postData: PostCardData } -const PostCard = (props: Props) => { +export default (props: Props) => { const { postData } = props const { content_id, wordCount, date, readTime, title, tags } = postData const { globalState } = useContext(globalContext) return ( - + - + {title || "No title"} {/* show "(series)" for urls that matches regex "/series/<series-title>" */} {/\/series\/[^/]*$/.test(content_id) && " (series)"} - </StyledTitle> +
- + {tags && tags.map((tag) => { @@ -115,10 +99,8 @@ const PostCard = (props: Props) => { {typeof wordCount === "number" ? wordCount + " words" : "unknown length"} - +
-
+ ) } - -export default PostCard diff --git a/apps/blog/src/components/Sidebar/Sidebar.tsx b/apps/blog/src/components/Sidebar/Sidebar.tsx index 0c5fb12..225b6f7 100644 --- a/apps/blog/src/components/Sidebar/Sidebar.tsx +++ b/apps/blog/src/components/Sidebar/Sidebar.tsx @@ -9,14 +9,15 @@ import { faEllipsisV, faTimes } from "@fortawesome/free-solid-svg-icons" import SubMenu from "./SubMenu" import NavbarData from "../../data/NavbarData" -import theming from "../../styles/theming" +import HeaderButton from "../Header/HeaderButton" const CommonSidebarToggleButtonStyle = css` - ${theming.styles.navbarButtonStyle} + ${HeaderButton} width: 1.5rem; text-align: center; - cursor: pointer; - @media only screen and (min-width: ${theming.size.screen_size1}) { + + @media only screen and (min-width: ${({ theme }) => + theme.theme.maxDisplayWidth.mobile}) { display: none; } ` @@ -65,16 +66,9 @@ const SidebarNav = styled.nav<{ isSidebarOpen: boolean }>` z-index: 30; overflow-x: hidden; overflow-y: scroll; - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.backgroundColor0, - dark: theming.dark.backgroundColor0, - })}; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color0, - dark: theming.dark.color0, - })}; + background-color: ${({ theme }) => + theme.theme.component.header.color.background}; + color: ${({ theme }) => theme.theme.component.header.color.text}; ` const SidebarWrap = styled.div` diff --git a/apps/blog/src/components/Sidebar/SubMenu.tsx b/apps/blog/src/components/Sidebar/SubMenu.tsx index 3c77945..c27dee4 100644 --- a/apps/blog/src/components/Sidebar/SubMenu.tsx +++ b/apps/blog/src/components/Sidebar/SubMenu.tsx @@ -2,17 +2,17 @@ * @file Submenu item for sidebar */ +import type { Item } from "../../data/NavbarData" + import { useCallback, useContext, useState } from "react" import { Link } from "react-router-dom" import styled from "styled-components" -import theming from "../../styles/theming" import { globalContext } from "../../globalContext" - -import type { Item } from "../../data/NavbarData" +import button from "../../styles/button" const SidebarLink = styled(Link)` - ${theming.styles.navbarButtonStyle}; + ${button}; display: flex; width: 100%; margin: 0; diff --git a/apps/blog/src/components/Tag.tsx b/apps/blog/src/components/Tag.tsx index eeafcdb..7abecc4 100644 --- a/apps/blog/src/components/Tag.tsx +++ b/apps/blog/src/components/Tag.tsx @@ -4,19 +4,13 @@ import styled from "styled-components" import { faHashtag } from "@fortawesome/free-solid-svg-icons" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" -import theming from "../styles/theming" - -const StyledTag = styled.div` +const Tag = styled.div` text-align: center; margin-right: 0.8rem; border-radius: 10px; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color2, - dark: theming.dark.color2, - })}; + color: ${({ theme }) => theme.theme.color.text.gray}; ` interface Props { @@ -24,12 +18,10 @@ interface Props { onClick?: (event: MouseEvent) => void } -const Tag = (props: Props) => { +export default (props: Props) => { return ( - +  {props.text} - + ) } - -export default Tag diff --git a/apps/blog/src/globalContext.tsx b/apps/blog/src/globalContext.tsx index a05859e..e744b30 100644 --- a/apps/blog/src/globalContext.tsx +++ b/apps/blog/src/globalContext.tsx @@ -1,8 +1,11 @@ +import type { Dispatch, ReactNode, ReactElement } from "react" +import type { Theme } from "@developomp-site/theme" + +import darkTheme from "@developomp-site/theme/dist/dark.json" +import lightTheme from "@developomp-site/theme/dist/light.json" import { createContext, useEffect, useReducer } from "react" import storage from "local-storage-fallback" -import type { Dispatch, ReactNode, ReactElement } from "react" - export type SiteLocale = "en" | "kr" export type SiteTheme = "dark" | "light" @@ -11,11 +14,6 @@ export enum ActionsEnum { UPDATE_LOCALE, } -export interface IGlobalState { - locale: SiteLocale - theme: SiteTheme -} - export type GlobalAction = | { type: ActionsEnum.UPDATE_THEME @@ -26,6 +24,12 @@ export type GlobalAction = payload: SiteLocale } +export interface IGlobalState { + locale: SiteLocale + currentTheme: SiteTheme + theme: Theme +} + export interface IGlobalContext { globalState: IGlobalState dispatch: Dispatch @@ -40,7 +44,11 @@ function getDefaultLocale(): SiteLocale { const defaultState: IGlobalState = { locale: getDefaultLocale(), - theme: (storage.getItem("theme") || "dark") as SiteTheme, + currentTheme: (storage.getItem("theme") || "dark") as SiteTheme, + theme: + ((storage.getItem("theme") || "dark") as SiteTheme) === "dark" + ? darkTheme + : lightTheme, } export const globalContext = createContext({} as IGlobalContext) @@ -48,7 +56,8 @@ export const globalContext = createContext({} as IGlobalContext) function reducer(state = defaultState, action: GlobalAction): IGlobalState { switch (action.type) { case ActionsEnum.UPDATE_THEME: - state.theme = action.payload + state.currentTheme = action.payload + state.theme = state.currentTheme === "dark" ? darkTheme : lightTheme break case ActionsEnum.UPDATE_LOCALE: @@ -67,8 +76,8 @@ export function GlobalStore(props: { children: ReactNode }): ReactElement { // save theme when it is changed useEffect(() => { - storage.setItem("theme", globalState.theme) - }, [globalState.theme]) + storage.setItem("theme", globalState.currentTheme) + }, [globalState.currentTheme]) // save locale when it is changed useEffect(() => { diff --git a/apps/blog/src/pages/Home/Home.tsx b/apps/blog/src/pages/Home/Home.tsx index b8d43cb..c963b1f 100644 --- a/apps/blog/src/pages/Home/Home.tsx +++ b/apps/blog/src/pages/Home/Home.tsx @@ -2,8 +2,9 @@ * PostList.tsx * show posts in recent order */ +import type { Map } from "../../../types/types" -import { useContext, useEffect, useState } from "react" +import { useCallback, useContext, useEffect, useState } from "react" import { Helmet } from "react-helmet-async" import styled from "styled-components" @@ -11,25 +12,20 @@ import PostCard from "../../components/PostCard" import ShowMoreButton from "./ShowMoreButton" import _map from "../../data/map.json" -import theming from "../../styles/theming" import { globalContext } from "../../globalContext" -import type { Map } from "../../../types/types" - const map: Map = _map -const StyledPostList = styled.div` +const PostList = styled.div` + flex-direction: column; + align-items: center; text-align: center; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "#111111", - dark: "#EEEEEE", - })}; + color: ${({ theme }) => theme.theme.color.text.default}; ` -const Home = () => { +export default () => { const { globalState } = useContext(globalContext) const { locale } = globalState @@ -37,7 +33,7 @@ const Home = () => { const [postsLength, setPostsLength] = useState(0) const [postCards, setPostCards] = useState([]) - function loadPostCards() { + const loadPostCards = useCallback(() => { let postCount = 0 const postCards = [] as JSX.Element[] @@ -65,7 +61,7 @@ const Home = () => { } setPostCards(postCards) - } + }, [howMany, postCards]) useEffect(() => { loadPostCards() @@ -81,9 +77,11 @@ const Home = () => { - +

{locale == "en" ? "Recent Posts" : "최근 포스트"}

+ {postCards} + {postsLength > howMany && ( { @@ -91,9 +89,7 @@ const Home = () => { }} /> )} -
+ ) } - -export default Home diff --git a/apps/blog/src/pages/Home/ShowMoreButton.tsx b/apps/blog/src/pages/Home/ShowMoreButton.tsx index 6d373a2..2804ec6 100644 --- a/apps/blog/src/pages/Home/ShowMoreButton.tsx +++ b/apps/blog/src/pages/Home/ShowMoreButton.tsx @@ -1,54 +1,21 @@ import { useContext } from "react" import styled from "styled-components" -import theming from "../../styles/theming" import { globalContext } from "../../globalContext" +import buttonStyle from "../../styles/button" const Button = styled.button` - /* size */ + ${buttonStyle} - padding: 1rem; - - /* styling */ - - display: inline-block; - border: none; - cursor: pointer; - border-radius: 0.5rem; - - /* text */ - - text-align: center; - text-decoration: none; - font-size: 1rem; - - /* colors */ - - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "black", - dark: "#CFD0D0", - })}; - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.backgroundColor2, - dark: theming.dark.backgroundColor2, - })}; - - :hover { - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.backgroundColor0, - dark: theming.dark.backgroundColor0, - })}; - } + /* center div */ + margin: 0 auto; ` interface Props { action(): void } -const ShowMoreButton = (props: Props) => { +export default (props: Props) => { const { globalState } = useContext(globalContext) return ( @@ -57,5 +24,3 @@ const ShowMoreButton = (props: Props) => { ) } - -export default ShowMoreButton diff --git a/apps/blog/src/pages/Page/Meta.tsx b/apps/blog/src/pages/Page/Meta.tsx index 3a34642..f7761ed 100644 --- a/apps/blog/src/pages/Page/Meta.tsx +++ b/apps/blog/src/pages/Page/Meta.tsx @@ -8,14 +8,9 @@ import { } from "@fortawesome/free-solid-svg-icons" import { PageData } from "../../../types/types" -import theming from "../../styles/theming" const StyledMetaContainer = styled.div` - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "#555", - dark: "#CCC", - })}; + color: ${({ theme }) => theme.theme.color.text.gray}; ` const Meta = (props: { fetchedPage: PageData }) => { diff --git a/apps/blog/src/pages/Page/SeriesControlButtons.tsx b/apps/blog/src/pages/Page/SeriesControlButtons.tsx index ace2825..7ab7586 100644 --- a/apps/blog/src/pages/Page/SeriesControlButtons.tsx +++ b/apps/blog/src/pages/Page/SeriesControlButtons.tsx @@ -1,5 +1,5 @@ import { useContext } from "react" -import styled, { css } from "styled-components" +import styled from "styled-components" import { Link } from "react-router-dom" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" @@ -9,8 +9,7 @@ import { faListUl, } from "@fortawesome/free-solid-svg-icons" -import theming from "../../styles/theming" - +import buttonStyle from "../../styles/button" import { globalContext } from "../../globalContext" const Container = styled.div` @@ -18,26 +17,6 @@ const Container = styled.div` justify-content: space-between; ` -const buttonStyle = css` - ${theming.styles.navbarButtonStyle} - - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - dark: "#202225", - light: "#EEEEEE", - })}; - border-radius: 0.5rem; - height: 3rem; - - &:hover { - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - dark: theming.dark.backgroundColor1, - light: theming.light.backgroundColor2, - })}; - } -` - const Button = styled.div` ${buttonStyle} ` @@ -47,14 +26,6 @@ const DisabledButton = styled.div` color: grey; cursor: default; - - &:hover { - background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - dark: "#202225", - light: "#EEEEEE", - })}; - } ` interface Props { diff --git a/apps/blog/src/pages/Page/Toc.tsx b/apps/blog/src/pages/Page/Toc.tsx index 35dfbe4..9b9aedc 100644 --- a/apps/blog/src/pages/Page/Toc.tsx +++ b/apps/blog/src/pages/Page/Toc.tsx @@ -6,7 +6,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { faCaretDown, faCaretUp } from "@fortawesome/free-solid-svg-icons" import styled from "styled-components" -import theming from "../../styles/theming" import { globalContext } from "../../globalContext" const StyledTocToggleButton = styled.button` @@ -16,11 +15,7 @@ const StyledTocToggleButton = styled.button` background-color: rgba(0, 0, 0, 0); width: 100%; padding: 0.5rem; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "black", - dark: "white", - })}; + color: ${({ theme }) => theme.theme.color.text.highContrast}; ` const StyledCollapseContainer = styled.div` diff --git a/apps/blog/src/pages/Portfolio/ProjectCard.tsx b/apps/blog/src/pages/Portfolio/ProjectCard.tsx index f2b7b20..0d57885 100644 --- a/apps/blog/src/pages/Portfolio/ProjectCard.tsx +++ b/apps/blog/src/pages/Portfolio/ProjectCard.tsx @@ -6,21 +6,21 @@ import Badge from "../../components/Badge" import { cardCSS } from "../../components/Card" import { PortfolioProject } from "../../../types/types" -import theming from "../../styles/theming" import { globalContext } from "../../globalContext" const StyledProjectCard = styled.div` ${cardCSS} - ${theming.styles.hoverCard} + color: ${(props) => props.theme.theme.color.text.default}; margin-bottom: 2rem; word-wrap: break-word; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color1, - dark: theming.dark.color1, - })}; + :hover { + cursor: pointer; + + box-shadow: 0 4px 10px + ${(props) => props.theme.theme.component.card.color.hoverGlow}; + } ` const StyledImg = styled.img` diff --git a/apps/blog/src/pages/Search/DateRange.tsx b/apps/blog/src/pages/Search/DateRange.tsx index 12c4a67..65c0023 100644 --- a/apps/blog/src/pages/Search/DateRange.tsx +++ b/apps/blog/src/pages/Search/DateRange.tsx @@ -1,12 +1,11 @@ import { DateRange } from "react-date-range" import styled from "styled-components" -import theming from "../../styles/theming" - export const DateRangeControl = styled.div` width: 350px; - @media screen and (max-width: ${theming.size.screen_size2}) { + @media screen and (max-width: ${(props) => + props.theme.theme.maxDisplayWidth.mobile}) { margin-top: 2rem; } ` diff --git a/apps/blog/src/pages/Search/Search.tsx b/apps/blog/src/pages/Search/Search.tsx index 698a8b6..ac0d9a7 100644 --- a/apps/blog/src/pages/Search/Search.tsx +++ b/apps/blog/src/pages/Search/Search.tsx @@ -1,6 +1,4 @@ -/* eslint-disable react/prop-types */ - -import { useContext, useEffect, useState } from "react" +import { useCallback, useContext, useEffect, useState } from "react" import styled from "styled-components" import { useSearchParams } from "react-router-dom" import { Helmet } from "react-helmet-async" @@ -10,7 +8,6 @@ import elasticlunr from "elasticlunr" // search engine import _map from "../../data/map.json" import searchData from "../../data/search.json" -import theming from "../../styles/theming" import Loading from "../../components/Loading" import PostCard from "../../components/PostCard" @@ -54,7 +51,8 @@ const StyledSearchContainer = styled.div` display: flex; align-items: flex-start; - @media screen and (max-width: ${theming.size.screen_size2}) { + @media screen and (max-width: ${(props) => + props.theme.theme.maxDisplayWidth.mobile}) { flex-direction: column-reverse; align-items: center; } @@ -64,7 +62,8 @@ const StyledSearchControlContainer = styled.div` width: 100%; margin-left: 1rem; - @media screen and (max-width: ${theming.size.screen_size2}) { + @media screen and (max-width: ${(props) => + props.theme.theme.maxDisplayWidth.mobile}) { margin-top: 2rem; margin-left: 0; } @@ -113,6 +112,38 @@ const Search = () => { const [postCards, setPostCards] = useState([]) + const doSearch = useCallback(() => { + try { + const _postCards: JSX.Element[] = [] + for (const res of searchIndex.search(searchInput)) { + const postData = map.posts[res.ref] + + if ( + postData && // if post data exists + isDateInRange(postData.date, dateRange[0]) && // date is within range + isSelectedTagsInPost(selectedTags, postData.tags) // if post include tags + ) { + _postCards.push( + + ) + } + } + + // apply search result + setPostCards(_postCards) + + // eslint-disable-next-line no-empty + } catch (err) { + console.error(err) + } + }, [dateRange, selectedTags, searchInput]) + // parse search parameters useEffect(() => { for (const [key, value] of URLSearchParams.entries()) { @@ -186,38 +217,6 @@ const Search = () => { return () => clearTimeout(delayDebounceFn) }, [searchInput]) - function doSearch() { - try { - const _postCards: JSX.Element[] = [] - for (const res of searchIndex.search(searchInput)) { - const postData = map.posts[res.ref] - - if ( - postData && // if post data exists - isDateInRange(postData.date, dateRange[0]) && // date is within range - isSelectedTagsInPost(selectedTags, postData.tags) // if post include tags - ) { - _postCards.push( - - ) - } - } - - // apply search result - setPostCards(_postCards) - - // eslint-disable-next-line no-empty - } catch (err) { - console.error(err) - } - } - if (!initialized) return return ( diff --git a/apps/blog/src/pages/Search/SearchBar.tsx b/apps/blog/src/pages/Search/SearchBar.tsx index d0bc6d4..ecffbdc 100644 --- a/apps/blog/src/pages/Search/SearchBar.tsx +++ b/apps/blog/src/pages/Search/SearchBar.tsx @@ -1,32 +1,30 @@ import styled from "styled-components" -import theming from "../../styles/theming" - -const StyledSearchBar = styled.input` +export default styled.input` width: 100%; border-radius: 100px; /* arbitrarily large value */ height: 2.5rem; text-align: center; font-size: 1.2rem; outline: none; - - border: ${(props) => - theming.theme(props.theme.currentTheme, { - light: "1px solid #ccc", - dark: "1px solid #555", - })}; - + color: ${({ theme }) => theme.theme.color.text.default}; + border: 1px solid + ${(props) => props.theme.theme.component.input.color.border.default}; background-color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.dark.color1, - dark: theming.dark.backgroundColor1, - })}; + props.theme.theme.component.input.color.background.default}; - color: ${(props) => - theming.theme(props.theme.currentTheme, { - light: theming.light.color1, - dark: theming.dark.color1, - })}; + ::placeholder { + color: ${(props) => props.theme.theme.component.input.color.placeHolder}; + opacity: 1; + } + + &:hover { + border: 1px solid + ${({ theme }) => theme.theme.component.input.color.border.hover}; + } + + &:focus { + border: 1px solid + ${({ theme }) => theme.theme.component.input.color.border.focus}; + } ` - -export default StyledSearchBar diff --git a/apps/blog/src/pages/Search/TagSelect.tsx b/apps/blog/src/pages/Search/TagSelect.tsx index d4a8daa..668e53c 100644 --- a/apps/blog/src/pages/Search/TagSelect.tsx +++ b/apps/blog/src/pages/Search/TagSelect.tsx @@ -2,8 +2,6 @@ import { useContext } from "react" import styled from "styled-components" import Select from "react-select" -import theming from "../../styles/theming" - import _map from "../../data/map.json" import { globalContext } from "../../globalContext" @@ -33,24 +31,19 @@ interface TagSelectProps { const TagSelect = (props: TagSelectProps) => { const { globalState } = useContext(globalContext) + const { theme } = globalState const locale = globalState.locale - const currentTheme = globalState.theme const { onChange, defaultValue: selectedTags } = props return ( +
+ + 🌒 + + ) +} + +export default DarkMode diff --git a/apps/blog/tsconfig.json b/apps/blog/tsconfig.json index f4c0f8f..a8db452 100644 --- a/apps/blog/tsconfig.json +++ b/apps/blog/tsconfig.json @@ -1,5 +1,11 @@ { "compilerOptions": { + "plugins": [ + { + "name": "typescript-styled-plugin", + "validate": false + } + ], "target": "es5", "module": "esnext", "lib": ["dom", "dom.iterable", "esnext"], diff --git a/apps/blog/types/styled-components.ts b/apps/blog/types/styled-components.ts index db2c3e9..c07561a 100644 --- a/apps/blog/types/styled-components.ts +++ b/apps/blog/types/styled-components.ts @@ -1,9 +1,10 @@ import "styled-components" -import type { SiteTheme } from "../src/globalContext" +import type { Theme } from "@developomp-site/theme" +import { SiteTheme } from "../src/globalContext" declare module "styled-components" { export interface DefaultTheme { currentTheme: SiteTheme - setTheme(setThemeTo: SiteTheme): void + theme: Theme } } diff --git a/apps/style/stories/docs/2.Colors.stories.mdx b/apps/style/stories/docs/2.Colors.stories.mdx index 319f30b..152572f 100644 --- a/apps/style/stories/docs/2.Colors.stories.mdx +++ b/apps/style/stories/docs/2.Colors.stories.mdx @@ -1,5 +1,5 @@ import { Meta, ColorPalette, ColorItem } from "@storybook/addon-docs" -import darkTheme from "@developomp-site/theme/dark" +import darkTheme from "@developomp-site/theme/dist/dark.json" diff --git a/packages/theme/.eslintrc b/packages/theme/.eslintrc new file mode 100644 index 0000000..5e14571 --- /dev/null +++ b/packages/theme/.eslintrc @@ -0,0 +1,5 @@ +{ + "env": { + "node": true + } +} diff --git a/packages/theme/build.ts b/packages/theme/build.ts new file mode 100644 index 0000000..87533bd --- /dev/null +++ b/packages/theme/build.ts @@ -0,0 +1,9 @@ +import { writeFileSync, mkdirSync, existsSync } from "fs" + +import dark from "./src/dark" +import light from "./src/light" + +if (!existsSync("dist")) mkdirSync("dist") + +writeFileSync("dist/dark.json", JSON.stringify(dark)) +writeFileSync("dist/light.json", JSON.stringify(light)) diff --git a/packages/theme/dark/index.ts b/packages/theme/dark/index.ts deleted file mode 100644 index a12d778..0000000 --- a/packages/theme/dark/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -const theme: Theme = { - font: { - sansSerif: "'Noto Sans KR', sans-serif", // https://fonts.google.com/noto/specimen/Noto+Sans+KR - monospace: "'Source Code Pro', monospace", - }, - - maxDisplayWidth: { - mobile: "1024px", // max-w-screen-lg - desktop: "1536px", // max-w-screen-2xl - }, - - component: { - scrollbar: { - width: "8px", // w-2 - borderRadius: "4px", // rounded - }, - - header: { - color: { - background: "#202225", // custom - hover: "#3f3f46", // zinc-700 - text: "#d4d4d8", // zinc-300 - }, - height: "16px", // h-4 - }, - - scrollProgressBar: { - color: { - background: "#52525b", // zinc 600 - foreground: "#d4d4d8", // zinc-300 - }, - }, - - card: { - color: { - background: "#2f3136", - }, - }, - - footer: { - color: { - background: "", - text: "", - }, - }, - - ui: { - color: { - background: { - interactive: "", - }, - text: { - on1: "", - link: "#66AAFF", - linkActive: "#4592F7", - }, - }, - }, - }, -} - -export default theme diff --git a/packages/theme/index.d.ts b/packages/theme/index.d.ts new file mode 100644 index 0000000..46657aa --- /dev/null +++ b/packages/theme/index.d.ts @@ -0,0 +1,143 @@ +export interface Theme { + font: { + sansSerif: string + monospace: string + } + + color: { + text: { + highContrast: string + default: string + gray: string + } + background: string + } + + maxDisplayWidth: { + mobile: string + desktop: string + } + + component: { + anchor: { + color: { + default: string + hover: string + active: string + header: string + } + } + + blockQuote: { + color: { + background: string + borderLeft: string + } + } + + card: { + color: { + background: string + hoverGlow: string + } + } + + code: { + inline: { + color: { + text: string + background: string + border: string + } + } + block: { + color: { + border: string + highlight: string + } + style: string + } + } + + footer: { + color: { + background: string + text: string + } + } + + header: { + color: { + background: string + hover: string + text: string + } + height: string + } + + input: { + color: { + background: { + default: string + itemHover: string + } + border: { + default: string + hover: string + focus: string + } + placeHolder: string + } + } + + kbd: { + color: { + text: string + border: string + outerShadow: string + innerShadow: string + background: string + } + } + + mark: { + color: { + text: string + background: string + } + } + + scrollbar: { + color: { + track: string + thumb: string + } + width: string + borderRadius: string + } + + scrollProgressBar: { + color: { + background: string + foreground: string + } + } + + table: { + color: { + border: string + even: string + } + } + + ui: { + color: { + background: { + default: string + hover: string + } + border: string + } + } + } +} diff --git a/packages/theme/light/index.ts b/packages/theme/light/index.ts deleted file mode 100644 index a2ffcc7..0000000 --- a/packages/theme/light/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import BaseTheme from "../dark" - -const theme: Theme = { ...BaseTheme } - -export default theme diff --git a/packages/theme/package.json b/packages/theme/package.json index 92706dd..47c107e 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,9 +1,22 @@ { "name": "@developomp-site/theme", "version": "0.0.0", + "types": "./index.d.ts", "private": true, "license": "MIT", + "scripts": { + "dev": "nodemon --ignore dist/ --exec pnpm build", + "build": "npx ts-node ./build.ts", + "clean": "rm -rf dist && rm -rf node_modules" + }, "devDependencies": { - "tailwindcss": "^3.1.4" + "@types/merge-deep": "^3.0.0", + "@types/node": "^18.11.10", + "merge-deep": "^3.0.3", + "nodemon": "^2.0.20", + "tailwindcss": "^3.1.4", + "ts-node": "^10.9.1", + "tsup": "^5.10.1", + "utility-types": "^3.10.0" } } diff --git a/packages/theme/dark/codeblock.css b/packages/theme/src/dark/codeblock.css similarity index 100% rename from packages/theme/dark/codeblock.css rename to packages/theme/src/dark/codeblock.css diff --git a/packages/theme/src/dark/index.ts b/packages/theme/src/dark/index.ts new file mode 100644 index 0000000..88182c9 --- /dev/null +++ b/packages/theme/src/dark/index.ts @@ -0,0 +1,167 @@ +import type { Theme } from "../.." + +import { readFileSync } from "fs" + +export default { + font: { + sansSerif: "'Noto Sans KR', sans-serif", // https://fonts.google.com/noto/specimen/Noto+Sans+KR + monospace: "'Source Code Pro', monospace", + }, + + color: { + text: { + highContrast: "#FFFFFF", + default: "#EEEEEE", + gray: "#CCC", + }, + background: "#36393F", + }, + + maxDisplayWidth: { + mobile: "1024px", // max-w-screen-lg + desktop: "1536px", // max-w-screen-2xl + }, + + component: { + anchor: { + color: { + default: "#66AAFF", + hover: "#4592F7", + active: "#4592F7", + header: "#778899", + }, + }, + + blockQuote: { + color: { + background: "#FFFFFF12", + borderLeft: "#FFFFFF4D", + }, + }, + + card: { + color: { + background: "#2F3136", + hoverGlow: "#FFFFFF33", + }, + }, + + code: { + inline: { + color: { + text: "#FFFFFF", + background: "#444", + border: "#666", + }, + }, + block: { + color: { + border: "#555", + highlight: "#14161A", + }, + style: readFileSync(__dirname + "/codeblock.css", "utf-8"), + }, + }, + + footer: { + color: { + background: "#000000", + text: "", + }, + }, + + header: { + color: { + background: "#202225", // custom + hover: "#3F3F46", // zinc-700 + text: "#D4D4D8", // zinc-300 + }, + height: "16px", // h-4 + }, + + input: { + color: { + background: { + default: "#36393f", + itemHover: "#202225", + }, + border: { + default: "#555555", + hover: "#808080", + focus: "#a3a3a3", // neutral-400 + }, + placeHolder: "#A9A9A9", + }, + }, + + kbd: { + color: { + text: "#FFFFFF", + border: "#555555", + outerShadow: "#FFFFFF4D", + innerShadow: "#000000", + background: "#000000", + }, + }, + + mark: { + color: { + text: "#FFFFFF", + background: "#FFFF0080", + }, + }, + + scrollbar: { + color: { + track: "#18181B", + thumb: "#888888", + }, + width: "8px", // w-2 + borderRadius: "4px", // rounded + }, + + scrollProgressBar: { + color: { + background: "#52525B", // zinc 600 + foreground: "#D4D4D8", // zinc-300 + }, + }, + + table: { + color: { + border: "#777777", + even: "#21272E", + }, + }, + + ui: { + color: { + background: { + default: "#202225", + hover: "#3F3F46", // zinc-700 + }, + border: "#555", + }, + }, + }, +} as Theme + +/* + dark: { + backgroundColor0: "#18181b", + backgroundColor1: "#36393F", + backgroundColor2: "#2F3136", + color0: "#FFFFFF", + color1: "#EEEEEE", + color2: "#CCC", + } + + light: { + backgroundColor0: "#FFFFFF", + backgroundColor1: "#F7F7F7", + backgroundColor2: "#DDDDDD", + color0: "#000000", + color1: "#111111", + color2: "#555", + } +*/ diff --git a/packages/theme/light/codeblock.css b/packages/theme/src/light/codeblock.css similarity index 100% rename from packages/theme/light/codeblock.css rename to packages/theme/src/light/codeblock.css diff --git a/packages/theme/src/light/index.ts b/packages/theme/src/light/index.ts new file mode 100644 index 0000000..5e384b0 --- /dev/null +++ b/packages/theme/src/light/index.ts @@ -0,0 +1,126 @@ +import type { Theme } from "../.." + +import { readFileSync } from "fs" +import merge from "merge-deep" +import { DeepPartial } from "utility-types" + +import BaseTheme from "../dark" + +export default merge>(BaseTheme, { + color: { + text: { + highContrast: "#000000", + default: "#111111", + gray: "#555", + }, + background: "#F7F7F7", + }, + component: { + anchor: { + color: { + header: "#D3D3D3", + }, + }, + + blockQuote: { + color: { + background: "#0000000D", + borderLeft: "#0000001A", + }, + }, + + card: { + color: { + background: "#FFFFFF", + hoverGlow: "#00000040", + }, + }, + + code: { + inline: { + color: { + text: "#000000", + background: "#EEE", + border: "#BBB", + }, + }, + block: { + color: { + border: "#BBB", + highlight: "#DDDDDD", + }, + style: readFileSync(__dirname + "/codeblock.css", "utf-8"), + }, + }, + + footer: { + color: { + background: "#FFFFFF", + text: "", + }, + }, + + input: { + color: { + background: { + default: "#EEEEEE", + itemHover: "#FFFFFF", + }, + border: { + default: "#CCCCCC", + hover: "#808080", + focus: "#000000", + }, + placeHolder: "#777777", + }, + }, + + kbd: { + color: { + text: "#333333", + border: "#CCCCCC", + outerShadow: "#00000033", + innerShadow: "#FFFFFF", + background: "#F7F7F7", + }, + }, + + mark: { + color: { + text: "#000000", + background: "#FFFF00BF", + }, + }, + + scrollbar: { + color: { + track: "#FFFFFF", + thumb: "#DDDDDD", + }, + }, + + scrollProgressBar: { + color: { + background: "#d4d4d8", // zinc-300 + foreground: "#52525b", // zinc-600 + }, + }, + + table: { + color: { + border: "#DDD", + even: "#F2F2F2", + }, + }, + + ui: { + color: { + background: { + default: "#FFFFFF", + hover: "#EEEEEE", + }, + border: "#CCC", + }, + }, + }, +}) as Theme diff --git a/packages/theme/tsconfig.json b/packages/theme/tsconfig.json new file mode 100644 index 0000000..3153233 --- /dev/null +++ b/packages/theme/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "types": ["node"], + "moduleResolution": "Node", + "esModuleInterop": true + }, + "include": ["src"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/theme/types/index.d.ts b/packages/theme/types/index.d.ts deleted file mode 100644 index e285e70..0000000 --- a/packages/theme/types/index.d.ts +++ /dev/null @@ -1,60 +0,0 @@ -interface Theme extends Object { - font: { - sansSerif: string - monospace: string - } - - maxDisplayWidth: { - mobile: string - desktop: string - } - - component: { - scrollbar: { - width: string - borderRadius: string - } - - header: { - color: { - background: string - hover: string - text: string - } - height: string - } - - scrollProgressBar: { - color: { - background: string - foreground: string - } - } - - card: { - color: { - background: string - } - } - - footer: { - color: { - background: string - text: string - } - } - - ui: { - color: { - background: { - interactive: string - } - text: { - on1: string - link: string - linkActive: string - } - } - } - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 03c1213..a216288 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,9 @@ importers: apps/blog: specifiers: - '@developomp-site/eslint-config': workspace:0.0.0 - '@developomp-site/tsconfig': workspace:0.0.0 + '@developomp-site/eslint-config': workspace:* + '@developomp-site/theme': workspace:* + '@developomp-site/tsconfig': workspace:* '@fortawesome/fontawesome-svg-core': ^6.2.1 '@fortawesome/free-brands-svg-icons': ^6.2.1 '@fortawesome/free-regular-svg-icons': ^6.2.1 @@ -81,6 +82,7 @@ importers: tslint-config-prettier: ^1.18.0 typescript: ^4.9.3 dependencies: + '@developomp-site/theme': link:../../packages/theme '@fortawesome/fontawesome-svg-core': 6.2.1 '@fortawesome/free-brands-svg-icons': 6.2.1 '@fortawesome/free-regular-svg-icons': 6.2.1 @@ -234,9 +236,23 @@ importers: packages/theme: specifiers: + '@types/merge-deep': ^3.0.0 + '@types/node': ^18.11.10 + merge-deep: ^3.0.3 + nodemon: ^2.0.20 tailwindcss: ^3.1.4 + ts-node: ^10.9.1 + tsup: ^5.10.1 + utility-types: ^3.10.0 devDependencies: - tailwindcss: 3.2.4_postcss@8.4.19 + '@types/merge-deep': 3.0.0 + '@types/node': 18.11.11 + merge-deep: 3.0.3 + nodemon: 2.0.20 + tailwindcss: 3.2.4_v776zzvn44o7tpgzieipaairwm + ts-node: 10.9.1_bspv7bpieoza2i5ctiw2ofswem + tsup: 5.12.9_h63whvv5d2b4avkcl4ixnozygi + utility-types: 3.10.0 packages/tsconfig: specifiers: {} @@ -4372,6 +4388,10 @@ packages: resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==} dev: true + /@types/merge-deep/3.0.0: + resolution: {integrity: sha512-t5B5UfacpaP8opUvFGUwT0uQetFrD+qm1/I2ksxokJFLT0Tb4B2NI2G2LYz3ugMDKOE7adkNBZ6coK7RW6MAqA==} + dev: true + /@types/mime/3.0.1: resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} dev: false @@ -5003,6 +5023,10 @@ packages: /abab/2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + /abbrev/1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true + /accepts/1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -6451,6 +6475,17 @@ packages: wrap-ansi: 7.0.0 dev: true + /clone-deep/0.2.4: + resolution: {integrity: sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==} + engines: {node: '>=0.10.0'} + dependencies: + for-own: 0.1.5 + is-plain-object: 2.0.4 + kind-of: 3.2.2 + lazy-cache: 1.0.4 + shallow-clone: 0.1.2 + dev: true + /clone-deep/4.0.1: resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} engines: {node: '>=6'} @@ -7206,6 +7241,18 @@ packages: dependencies: ms: 2.1.3 + /debug/3.2.7_supports-color@5.5.0: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 5.5.0 + dev: true + /debug/4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -8953,11 +9000,23 @@ packages: optional: true dev: false + /for-in/0.1.8: + resolution: {integrity: sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==} + engines: {node: '>=0.10.0'} + dev: true + /for-in/1.0.2: resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} engines: {node: '>=0.10.0'} dev: true + /for-own/0.1.5: + resolution: {integrity: sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==} + engines: {node: '>=0.10.0'} + dependencies: + for-in: 1.0.2 + dev: true + /foreground-child/2.0.0: resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} engines: {node: '>=8.0.0'} @@ -9914,6 +9973,10 @@ packages: resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==} dev: true + /ignore-by-default/1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + dev: true + /ignore/4.0.6: resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} engines: {node: '>= 4'} @@ -11279,6 +11342,13 @@ packages: commander: 8.3.0 dev: false + /kind-of/2.0.1: + resolution: {integrity: sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg==} + engines: {node: '>=0.10.0'} + dependencies: + is-buffer: 1.1.6 + dev: true + /kind-of/3.2.2: resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} engines: {node: '>=0.10.0'} @@ -11320,6 +11390,16 @@ packages: language-subtag-registry: 0.3.22 dev: false + /lazy-cache/0.2.7: + resolution: {integrity: sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ==} + engines: {node: '>=0.10.0'} + dev: true + + /lazy-cache/1.0.4: + resolution: {integrity: sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==} + engines: {node: '>=0.10.0'} + dev: true + /lazy-cache/2.0.2: resolution: {integrity: sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==} engines: {node: '>=0.10.0'} @@ -11776,6 +11856,15 @@ packages: dev: true optional: true + /merge-deep/3.0.3: + resolution: {integrity: sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==} + engines: {node: '>=0.10.0'} + dependencies: + arr-union: 3.1.0 + clone-deep: 0.2.4 + kind-of: 3.2.2 + dev: true + /merge-descriptors/1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} @@ -11982,6 +12071,14 @@ packages: is-extendable: 1.0.1 dev: true + /mixin-object/2.0.1: + resolution: {integrity: sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==} + engines: {node: '>=0.10.0'} + dependencies: + for-in: 0.1.8 + is-extendable: 0.1.1 + dev: true + /mkdirp/0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -12150,6 +12247,30 @@ packages: /node-releases/2.0.6: resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} + /nodemon/2.0.20: + resolution: {integrity: sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==} + engines: {node: '>=8.10.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + debug: 3.2.7_supports-color@5.5.0 + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 5.7.1 + simple-update-notifier: 1.1.0 + supports-color: 5.5.0 + touch: 3.1.0 + undefsafe: 2.0.5 + dev: true + + /nopt/1.0.10: + resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: true + /normalize-package-data/2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -13080,7 +13201,6 @@ packages: postcss: 8.4.19 ts-node: 10.9.1_bspv7bpieoza2i5ctiw2ofswem yaml: 1.10.2 - dev: false /postcss-loader/4.3.0_gzaxsinx64nntyd3vmdqwl7coe: resolution: {integrity: sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==} @@ -13748,6 +13868,10 @@ packages: /psl/1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + /pstree.remy/1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + dev: true + /public-encrypt/4.0.3: resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} dependencies: @@ -14944,6 +15068,11 @@ packages: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true + /semver/7.0.0: + resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} + hasBin: true + dev: true + /semver/7.3.8: resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} @@ -15094,6 +15223,16 @@ packages: safe-buffer: 5.2.1 dev: true + /shallow-clone/0.1.2: + resolution: {integrity: sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==} + engines: {node: '>=0.10.0'} + dependencies: + is-extendable: 0.1.1 + kind-of: 2.0.1 + lazy-cache: 0.2.7 + mixin-object: 2.0.1 + dev: true + /shallow-clone/3.0.1: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} @@ -15149,6 +15288,13 @@ packages: engines: {node: '>=0.12.18'} dev: true + /simple-update-notifier/1.1.0: + resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} + engines: {node: '>=8.10.0'} + dependencies: + semver: 7.0.0 + dev: true + /sisteransi/1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -15858,7 +16004,6 @@ packages: resolve: 1.22.1 transitivePeerDependencies: - ts-node - dev: false /tapable/1.1.3: resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} @@ -16105,6 +16250,13 @@ packages: resolution: {integrity: sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ==} dev: true + /touch/3.1.0: + resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} + hasBin: true + dependencies: + nopt: 1.0.10 + dev: true + /tough-cookie/4.1.2: resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} engines: {node: '>=6'} @@ -16237,6 +16389,42 @@ packages: hasBin: true dev: true + /tsup/5.12.9_h63whvv5d2b4avkcl4ixnozygi: + resolution: {integrity: sha512-dUpuouWZYe40lLufo64qEhDpIDsWhRbr2expv5dHEMjwqeKJS2aXA/FPqs1dxO4T6mBojo7rvo3jP9NNzaKyDg==} + hasBin: true + peerDependencies: + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: ^4.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 3.1.2_esbuild@0.14.54 + cac: 6.7.14 + chokidar: 3.5.3 + debug: 4.3.4 + esbuild: 0.14.54 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss: 8.4.19 + postcss-load-config: 3.1.4_v776zzvn44o7tpgzieipaairwm + resolve-from: 5.0.0 + rollup: 2.79.1 + source-map: 0.8.0-beta.0 + sucrase: 3.29.0 + tree-kill: 1.2.2 + typescript: 4.9.4 + transitivePeerDependencies: + - supports-color + - ts-node + dev: true + /tsup/5.12.9_o6pf6py3ttho7dpy7mshkpxque: resolution: {integrity: sha512-dUpuouWZYe40lLufo64qEhDpIDsWhRbr2expv5dHEMjwqeKJS2aXA/FPqs1dxO4T6mBojo7rvo3jP9NNzaKyDg==} hasBin: true @@ -16469,6 +16657,10 @@ packages: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 + /undefsafe/2.0.5: + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + dev: true + /unfetch/4.2.0: resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} dev: true @@ -16733,6 +16925,11 @@ packages: /utila/0.4.0: resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} + /utility-types/3.10.0: + resolution: {integrity: sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==} + engines: {node: '>= 4'} + dev: true + /utils-merge/1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'}