From 39d01e7a55af211e7e3a0c4eef9b9d19505b6121 Mon Sep 17 00:00:00 2001 From: Patrick Alvin Alcala Date: Thu, 28 Aug 2025 16:54:24 +0800 Subject: [PATCH] Moved files --- .../components/Background/Background.sass | 1 + .../components/Background/Background.tsx | 50 ++++ src/templates/components/Button/Button.sass | 223 ++++++++++++++++++ src/templates/components/Button/Button.tsx | 65 +++++ src/templates/components/Image/Image.tsx | 36 +++ src/templates/components/Link/Link.tsx | 14 ++ src/templates/components/Logo/Logo.tsx | 19 ++ .../Optimizer/OptimizeBackground.tsx | 17 ++ .../components/Optimizer/OptimizeLogo.tsx | 22 ++ src/templates/components/Page/Page.sass | 15 ++ src/templates/components/Page/Page.tsx | 20 ++ src/templates/images/no-background.webp | Bin 0 -> 11314 bytes 12 files changed, 482 insertions(+) create mode 100644 src/templates/components/Background/Background.sass create mode 100644 src/templates/components/Background/Background.tsx create mode 100644 src/templates/components/Button/Button.sass create mode 100644 src/templates/components/Button/Button.tsx create mode 100644 src/templates/components/Image/Image.tsx create mode 100644 src/templates/components/Link/Link.tsx create mode 100644 src/templates/components/Logo/Logo.tsx create mode 100644 src/templates/components/Optimizer/OptimizeBackground.tsx create mode 100644 src/templates/components/Optimizer/OptimizeLogo.tsx create mode 100644 src/templates/components/Page/Page.sass create mode 100644 src/templates/components/Page/Page.tsx create mode 100644 src/templates/images/no-background.webp diff --git a/src/templates/components/Background/Background.sass b/src/templates/components/Background/Background.sass new file mode 100644 index 0000000..1e0b5bc --- /dev/null +++ b/src/templates/components/Background/Background.sass @@ -0,0 +1 @@ +@use '/src/styles/classes.sass' diff --git a/src/templates/components/Background/Background.tsx b/src/templates/components/Background/Background.tsx new file mode 100644 index 0000000..e33e37d --- /dev/null +++ b/src/templates/components/Background/Background.tsx @@ -0,0 +1,50 @@ +import './Background.sass' +import { Show, createSignal } from 'solid-js' +import fs from 'fs' +import webpPath from '../../../templates/images/background.webp' +import avifPath from '../../../templates/images/background.avif' +import noBackground from '../../../templates/images/no-background.webp' + +interface Props { + image?: boolean + color?: string +} + +let [imageLoaded, setImageLoaded] = createSignal(false) + +const checkBackground = () => { + if (!fs.existsSync(avifPath.src) && !fs.existsSync(webpPath.src)) { + setImageLoaded(true) + } else { + setImageLoaded(false) + } +} + +export default (props: Props) => { + checkBackground() + + return ( + <> + + + + + + + An image background + + + + + + An alternative background if found no image background + + + + + +
+ + + ) +} diff --git a/src/templates/components/Button/Button.sass b/src/templates/components/Button/Button.sass new file mode 100644 index 0000000..329ba1d --- /dev/null +++ b/src/templates/components/Button/Button.sass @@ -0,0 +1,223 @@ +@use '/src/styles/variables.sass' as vars +@use '/src/styles/fonts.sass' as fonts +@use 'sass:color' + +$bulmaPrimary: rgb(0, 235, 199) +$bulmaPrimaryText: rgb(0, 31, 26) +$bulmaLink: rgb(92, 111, 255) +$bulmaLinkText: rgb(245, 246, 255) +$bulmaInfo: rgb(128, 217, 255) +$bulmaInfoText: rgb(0, 36, 51) +$bulmaSuccess: rgb(91, 205, 154) +$bulmaSuccessText: rgb(10, 31, 21) +$bulmaWarning: rgb(255, 191, 41) +$bulmaWarningText: rgb(41, 29, 0) +$bulmaDanger: rgb(255, 128, 153) +$bulmaDangerText: rgb(26, 0, 5) +$bulmaLight: rgb(255, 255, 255) +$bulmaLightText: rgb(46, 51, 61) +$bulmaDark: rgb(57, 63, 76) +$bulmaDarkText: rgb(243, 244, 246) +$bulmaText: rgb(31, 34, 41) +$bulmaTextText: rgb(235, 236, 240) +$bulmaGhost: rgba(0,0,0,0) +$bulmaGhostText: rgb(66, 88, 255) + +$bootstrapTextLight: rgb(255, 255, 253) +$bootstrapTextDark: rgb(0, 0, 2) +$bootstrapTextLink: rgb(139, 185, 254) +$bootstrapPrimary: rgb(13, 110, 253) +$bootstrapSecondary: rgb(92, 99, 106) +$bootstrapSuccess: rgb(21, 115, 71) +$bootstrapDanger: rgb(187, 45, 59) +$bootstrapWarning: rgb(255, 202, 44) +$bootstrapInfo: rgb(49, 210, 242) +$bootstrapLight: rgb(211, 212, 213) +$bootstrapDark: rgb(33, 37, 41) + +.button + background-color: vars.$primaryColor + border: none + color: white + padding: 0.5rem 1.25rem + text-align: center + text-decoration: none + display: inline-block + font-size: 1rem + font-weight: 500 + cursor: pointer + transition: all 0.2s ease-out + + &:hover + background-color: color.adjust(vars.$primaryColor, $blackness: 20%) + + &:active + transform: scale(0.95) + +.bu-primary + @extend .button + font-family: fonts.$Inter + background-color: $bulmaPrimary + color: $bulmaPrimaryText + border: none + font-size: 1rem + border-radius: 0.375rem + font-weight: 500 + padding: 0.5rem 1.25rem + height: 2.5rem + + &:hover + background-color: color.adjust($bulmaPrimary, $lightness: 10%) + +.bu-link + @extend .bu-primary + background-color: $bulmaLink + color: $bulmaLinkText + + &:hover + background-color: color.adjust($bulmaLink, $lightness: 5%) + +.bu-info + @extend .bu-primary + background-color: $bulmaInfo + color: $bulmaInfoText + + &:hover + background-color: color.adjust($bulmaInfo, $lightness: 5%) + +.bu-success + @extend .bu-primary + background-color: $bulmaSuccess + color: $bulmaSuccessText + + &:hover + background-color: color.adjust($bulmaSuccess, $lightness: 5%) + +.bu-warning + @extend .bu-primary + background-color: $bulmaWarning + color: $bulmaWarningText + + &:hover + background-color: color.adjust($bulmaWarning, $lightness: 5%) + +.bu-danger + @extend .bu-primary + background-color: $bulmaDanger + color: $bulmaDangerText + + &:hover + background-color: color.adjust($bulmaDanger, $lightness: 5%) + +.bu-light + @extend .bu-primary + background-color: $bulmaLight + color: $bulmaLightText + + &:hover + background-color: color.adjust($bulmaLight, $lightness: 5%) + +.bu-dark + @extend .bu-primary + background-color: $bulmaDark + color: $bulmaDarkText + + &:hover + background-color: color.adjust($bulmaDark, $lightness: 5%) + +.bu-text + @extend .bu-primary + background-color: rgba(0,0,0,0) + color: $bulmaTextText + text-decoration: underline + + &:hover + background-color: hsl(221,14%,14%) + +.bu-ghost + @extend .bu-primary + background-color: $bulmaGhost + color: $bulmaGhostText + + &:hover + background-color: transparent + text-decoration: underline + +.bo-primary + @extend .button + font-family: 'Segoe UI', fonts.$Roboto + background-color: $bootstrapPrimary + color: $bootstrapTextLight + border: none + font-size: 1rem + border-radius: 0.375rem + font-weight: 400 + padding: 0.5rem 1.25rem + height: 2.5rem + margin: 0.25rem 0.125rem + + &:hover + background-color: color.adjust($bootstrapPrimary, $blackness: 10%) + +.bo-secondary + @extend .bo-primary + background-color: $bootstrapSecondary + + &:hover + background-color: color.adjust($bootstrapSecondary, $blackness: 10%) + +.bo-success + @extend .bo-primary + background-color: $bootstrapSuccess + + &:hover + background-color: color.adjust($bootstrapSuccess, $blackness: 10%) + +.bo-danger + @extend .bo-primary + background-color: $bootstrapDanger + + &:hover + background-color: color.adjust($bootstrapDanger, $blackness: 10%) + +.bo-warning + @extend .bo-primary + background-color: $bootstrapWarning + color: $bootstrapTextDark + + &:hover + background-color: color.adjust($bootstrapWarning, $lightness: 5%) + +.bo-info + @extend .bo-primary + background-color: $bootstrapInfo + color: $bootstrapTextDark + + &:hover + background-color: color.adjust($bootstrapInfo, $lightness: 5%) + +.bo-light + @extend .bo-primary + background-color: $bootstrapLight + color: $bootstrapTextDark + + &:hover + background-color: color.adjust($bootstrapLight, $blackness: 10%) + +.bo-dark + @extend .bo-primary + background-color: $bootstrapDark + // color: $bootstrapTextDark + + &:hover + background-color: color.adjust($bootstrapDark, $lightness: 10%) + +.bo-link + @extend .bo-primary + background-color: transparent + color: $bootstrapTextLink + text-decoration: underline + + &:hover + color: color.adjust($bootstrapTextLink, $lightness: 5%) + background-color: transparent diff --git a/src/templates/components/Button/Button.tsx b/src/templates/components/Button/Button.tsx new file mode 100644 index 0000000..61b7e7a --- /dev/null +++ b/src/templates/components/Button/Button.tsx @@ -0,0 +1,65 @@ +import './Button.sass' +import { Show, Switch, Match } from 'solid-js' + +interface Props { + label?: string + to?: string + onClick?: () => void + edges?: 'curved' | 'rounded' | 'flat' + design?: 'bu-primary' | 'bu-link' | 'bu-info' | 'bu-success' | 'bu-warning' | 'bu-danger' | 'bu-dark' | 'bu-light' | 'bu-text' | 'bu-ghost' | 'bo-primary' | 'bo-secondary' | 'bo-success' | 'bo-danger' | 'bo-warning' | 'bo-info' | 'bo-light' | 'bo-dark' | 'bo-link' +} + +const getBorderRadius = (edge: Props['edges']) => { + switch (edge) { + case 'curved': + return 'border-radius: 6px' + case 'rounded': + return 'border-radius: 32px' + case 'flat': + return 'border-radius: 0' + default: + return 'border-radius: 0' + } +} + +export default (props: Props) => { + const borderRadius = getBorderRadius(props.edges) + + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/src/templates/components/Image/Image.tsx b/src/templates/components/Image/Image.tsx new file mode 100644 index 0000000..bfb3b19 --- /dev/null +++ b/src/templates/components/Image/Image.tsx @@ -0,0 +1,36 @@ +import sharp from 'sharp' +import fs from 'fs' + +interface Props { + src: string + size?: number + alt?: string +} + +const convertImage = async (props: Props) => { + const avifOutputPath = `src/assets/optimized/${props.src.split('.').slice(0, -1).join('.')}.avif` + const webpOutputPath = `src/assets/optimized/${props.src.split('.').slice(0, -1).join('.')}.webp` + + if (!fs.existsSync(webpOutputPath) || !fs.existsSync(avifOutputPath)) { + const avifBuffer = await sharp(`src/assets/images/${props.src}`).avif({ quality: 60 }).resize(props.size).toBuffer() + await sharp(avifBuffer).toFile(avifOutputPath) + + const webpBuffer = await sharp(`src/assets/images/${props.src}`).webp({ quality: 75 }).resize(props.size).toBuffer() + await sharp(webpBuffer).toFile(webpOutputPath) + } +} + +export default (props: Props) => { + const imageSrc = `src/assets/optimized/${props.src.split('.').slice(0, -1).join('.')}.webp` + convertImage(props) + + return ( + <> + + + + {props.alt} + + + ) +} diff --git a/src/templates/components/Link/Link.tsx b/src/templates/components/Link/Link.tsx new file mode 100644 index 0000000..4ccf49f --- /dev/null +++ b/src/templates/components/Link/Link.tsx @@ -0,0 +1,14 @@ +interface Props { + to: string + children?: any +} + +export default (props: Props) => { + return ( + <> + + {props.children} + + + ) +} diff --git a/src/templates/components/Logo/Logo.tsx b/src/templates/components/Logo/Logo.tsx new file mode 100644 index 0000000..d293b1a --- /dev/null +++ b/src/templates/components/Logo/Logo.tsx @@ -0,0 +1,19 @@ +import webpPath from '../../../templates/images/logo.webp' +import avifPath from '../../../templates/images/logo.avif' + +interface Props { + size?: number + alt?: string +} + +export default (props: Props) => { + return ( + <> + + + + logo + + + ) +} diff --git a/src/templates/components/Optimizer/OptimizeBackground.tsx b/src/templates/components/Optimizer/OptimizeBackground.tsx new file mode 100644 index 0000000..2c004f5 --- /dev/null +++ b/src/templates/components/Optimizer/OptimizeBackground.tsx @@ -0,0 +1,17 @@ +import sharp from 'sharp' + +const convertBackground = async () => { + const inputSrc = 'src/assets/images/background.png' + const webpOutput = 'src/templates/images/background.webp' + const avifOutput = 'src/templates/images/background.avif' + + const avifBuffer = await sharp(inputSrc).avif({ quality: 60 }).resize(1920).toBuffer() + await sharp(avifBuffer).toFile(avifOutput) + + const webpBuffer = await sharp(inputSrc).webp({ quality: 75 }).resize(1920).toBuffer() + await sharp(webpBuffer).toFile(webpOutput) +} + +export default () => { + convertBackground() +} diff --git a/src/templates/components/Optimizer/OptimizeLogo.tsx b/src/templates/components/Optimizer/OptimizeLogo.tsx new file mode 100644 index 0000000..fb39b0d --- /dev/null +++ b/src/templates/components/Optimizer/OptimizeLogo.tsx @@ -0,0 +1,22 @@ +import sharp from 'sharp' + +interface Props { + size?: number + alt?: string +} + +const convertLogo = async (props: Props) => { + const inputSrc = 'src/assets/images/logo.png' + const webpImage = 'src/templates/images/logo.webp' + const avifImage = 'src/templates/images/logo.avif' + + const avifBuffer = await sharp(inputSrc).avif({ quality: 60 }).resize(props.size).toBuffer() + await sharp(avifBuffer).toFile(avifImage) + + const webpBuffer = await sharp(inputSrc).webp({ quality: 75 }).resize(props.size).toBuffer() + await sharp(webpBuffer).toFile(webpImage) +} + +export default (props: Props) => { + convertLogo(props) +} diff --git a/src/templates/components/Page/Page.sass b/src/templates/components/Page/Page.sass new file mode 100644 index 0000000..3d97ca8 --- /dev/null +++ b/src/templates/components/Page/Page.sass @@ -0,0 +1,15 @@ +.page + margin: 2rem + height: auto + +.column + @extend .page + display: flex + flex-direction: column + text-align: center + justify-content: center + align-items: center + +.row + @extend .column + flex-direction: row diff --git a/src/templates/components/Page/Page.tsx b/src/templates/components/Page/Page.tsx new file mode 100644 index 0000000..d16977f --- /dev/null +++ b/src/templates/components/Page/Page.tsx @@ -0,0 +1,20 @@ +import './Page.sass' +import { Show, Switch, Match } from 'solid-js' + +interface Props { + children?: any + alignment?: 'row' | 'column' +} + +export default (props: Props) => { + return ( + <> + +
{props.children}
+
+ +
{props.children}
+
+ + ) +} diff --git a/src/templates/images/no-background.webp b/src/templates/images/no-background.webp new file mode 100644 index 0000000000000000000000000000000000000000..87c7f4ce63c6eb5267b948de19bed31154a1fb93 GIT binary patch literal 11314 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 z zA85*okLzzS(6c%iUFqyUU_|$&W6!|LG&Psg3n(QK_jip_g;9qsMs{ei2B=-F(pG!c z;2mzN4u@kKS)Afd)u{T4Ka!yB&vyZcdfg0fZ-qZ6B6vs$V{&0a2{eQn<+X2RR*CUU zn`I2j260k+l;3G!v0i~mfWk>K5pt^!A;X#7^os155=OD+xR^y7btki0XnW6hq*7wP zrM?M~bH|a3qizhTxP>t06&yW0P;+#$>PF%`35@F^Y7P({aCb>oZ)#|zT*&g$+ZF*p zfmYOJ4!poJG3xi2v#e=3*%um9VPJw{{139e$~Ti4U;#JybA+Zt8!haL`$$ez