commit d6c414f887ebaef6dd4612229a066597a1483d6f Author: MassiveBox Date: Mon Mar 17 17:43:53 2025 +0100 Rewrite diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..e816868 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +.husky +.vscode +node_modules +public +dist +.yarn \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..d38ad6e --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,23 @@ +module.exports = { + env: { + node: true, + es2022: true, + browser: true, + }, + extends: ["eslint:recommended", "plugin:astro/recommended"], + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + overrides: [ + { + files: ["*.astro"], + parser: "astro-eslint-parser", + parserOptions: { + parser: "@typescript-eslint/parser", + extraFileExtensions: [".astro"], + }, + rules: {}, + }, + ], +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ebc9a5a --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +# build output +dist/ +.output/ +dist.zip + +# dependencies +node_modules/ + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store + +# ignore .astro directory +.astro + +# ignore Jampack cache files +.jampack/ + +# yarn +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions +.pnp.* + +# blog +src/content/blog diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..d24fdfc --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx lint-staged diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.workspace.xml.~1614e1ad b/.idea/.workspace.xml.~1614e1ad new file mode 100644 index 0000000..24cdb92 --- /dev/null +++ b/.idea/.workspace.xml.~1614e1ad @@ -0,0 +1,125 @@ + + + + + + + + + + + { + "associatedIndex": 8 +} + + + + { + "keyToString": { + "JavaScript Debug.localhost:4321.executor": "Run", + "Node.js.Unnamed.executor": "Run", + "RunOnceActivity.ShowReadmeOnStart": "true", + "last_opened_file_path": "/home/massive/Dev/website/src/pages/contact", + "list.type.of.created.stylesheet": "CSS", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "npm.build.executor": "Run", + "npm.dev --host.executor": "Run", + "npm.dev.executor": "Run", + "settings.editor.selected.configurable": "watcher.settings", + "ts.external.directory.path": "/home/massive/Dev/website/node_modules/typescript/lib", + "vue.rearranger.settings.migration": "true" + } +} + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/Hr.astro b/src/components/Hr.astro new file mode 100644 index 0000000..d7e835b --- /dev/null +++ b/src/components/Hr.astro @@ -0,0 +1,12 @@ +--- +export interface Props { + noPadding?: boolean; + ariaHidden?: boolean; +} + +const { noPadding = false, ariaHidden = true } = Astro.props; +--- + +
+
+
diff --git a/src/components/LinkButton.astro b/src/components/LinkButton.astro new file mode 100644 index 0000000..4f38fd5 --- /dev/null +++ b/src/components/LinkButton.astro @@ -0,0 +1,33 @@ +--- +export interface Props { + href: string; + className?: string; + ariaLabel?: string; + title?: string; + disabled?: boolean; +} + +const { href, className, ariaLabel, title, disabled = false } = Astro.props; +--- + +{ + disabled ? ( + + + + ) : ( + + + + ) +} diff --git a/src/components/Matomo.astro b/src/components/Matomo.astro new file mode 100644 index 0000000..a8f7e7c --- /dev/null +++ b/src/components/Matomo.astro @@ -0,0 +1,12 @@ + + \ No newline at end of file diff --git a/src/components/Pagination.astro b/src/components/Pagination.astro new file mode 100644 index 0000000..1640670 --- /dev/null +++ b/src/components/Pagination.astro @@ -0,0 +1,55 @@ +--- +import LinkButton from "./LinkButton.astro"; +import { Icon } from 'astro-icon/components' + +export interface Props { + currentPage: number; + totalPages: number; + prevUrl: string; + nextUrl: string; +} + +const { currentPage, totalPages, prevUrl, nextUrl } = Astro.props; + +const prev = currentPage > 1 ? "" : "disabled"; +const next = currentPage < totalPages ? "" : "disabled"; +--- + +{ + totalPages > 1 && ( + + ) +} + + diff --git a/src/components/ShareLinks.astro b/src/components/ShareLinks.astro new file mode 100644 index 0000000..f7ba195 --- /dev/null +++ b/src/components/ShareLinks.astro @@ -0,0 +1,65 @@ +--- +import LinkButton from "./LinkButton.astro"; +import { Icon } from "astro-icon/components"; + + +const URL = Astro.url; + +const shareLinks = [ + { + name: "WhatsApp", + href: "https://wa.me/?text=", + icon: "simple-icons:whatsapp", + linkTitle: `Share this post via WhatsApp`, + }, + { + name: "Facebook", + href: "https://www.facebook.com/sharer.php?u=", + icon: "simple-icons:facebook", + linkTitle: `Share this post on Facebook`, + }, + { + name: "Twitter/X", + href: "https://twitter.com/intent/tweet?url=", + icon: "simple-icons:x", + linkTitle: `Tweet this post`, + }, + { + name: "Telegram", + href: "https://t.me/share/url?url=", + icon: "simple-icons:telegram", + linkTitle: `Share this post via Telegram`, + }, + { + name: "Pinterest", + href: "https://pinterest.com/pin/create/button/?url=", + icon: "simple-icons:pinterest", + linkTitle: `Share this post on Pinterest`, + }, + { + name: "Mail", + href: "mailto:?subject=See%20this%20post&body=", + icon: "fa6-solid:envelope", + linkTitle: `Share this post via email`, + }, +] as const; +--- + +
+ Share this post on: +
+ { + shareLinks.map(social => ( + + + + )) + } +
+
+ + diff --git a/src/components/Socials.astro b/src/components/Socials.astro new file mode 100755 index 0000000..c8a79c8 --- /dev/null +++ b/src/components/Socials.astro @@ -0,0 +1,41 @@ +--- +import { SOCIALS } from "@config"; +import { Icon } from "astro-icon/components"; +--- + + + + + { + SOCIALS.map(social => ( + + )) + } + + +
+ + + +
+ + diff --git a/src/components/Tag.astro b/src/components/Tag.astro new file mode 100644 index 0000000..e114ad5 --- /dev/null +++ b/src/components/Tag.astro @@ -0,0 +1,24 @@ +--- +export interface Props { + tag: string; +} + +const { tag } = Astro.props; +--- + + + + #{tag} + + + \ No newline at end of file diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..5e69128 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,51 @@ +import type { GiteaProfile, Site, SocialObjects } from "./types"; + +export const SITE: Site = { + website: "https://massive.box/", // replace this with your deployed domain + author: "MassiveBox", + desc: "MassiveBox is a free time developer and FOSS enthusiast. This is his website.", + title: "MassiveBox", + ogImage: "/og.webp", + lightAndDarkMode: true, + postPerPage: 3, + scheduledPostMargin: 15 * 60 * 1000, // 15 minutes + issoLocation: "https://isso.massive.box/", // empty to disable comments +}; + +export const LOCALE = { + lang: "en", // html lang code. Set this empty and default will be "en" + langTag: ["en-EN"], // BCP 47 Language Tags. Set this empty [] to use the environment default +} as const; + +export const SOCIALS: SocialObjects = [ + { + icon: "fa6-solid:envelope", + href: "/email", + name: "E-Mail" + }, + { + icon: "simple-icons:matrix", + href: "https://matrix.to/#/@massivebox:massivebox.net", + name: "Matrix", + }, + { + icon: "simple-icons:telegram", + href: "https://t.me/massivebox", + name: "Telegram", + }, + { + icon: "simple-icons:forgejo", + href: "https://git.massive.box/massivebox", + name: "Forgejo (Git hosting)", + }, + { + icon: "simple-icons:bluesky", + href: "https://bsky.app/profile/massive.box", + name: "Bluesky", + }, + { + icon: "fa6-solid:key", + href: "https://keyoxide.org/box@massive.box", + name: "Keyoxide", + } +]; \ No newline at end of file diff --git a/src/content/config.ts b/src/content/config.ts new file mode 100644 index 0000000..19a7056 --- /dev/null +++ b/src/content/config.ts @@ -0,0 +1,21 @@ +import { SITE } from "@config"; +import { defineCollection, z } from "astro:content"; + +const blog = defineCollection({ + type: "content", + schema: ({ image }) => + z.object({ + author: z.string().default(SITE.author), + pubDatetime: z.date(), + modDatetime: z.date().optional().nullable(), + title: z.string(), + featured: z.boolean().optional(), + draft: z.boolean().optional(), + tags: z.array(z.string()).default(["others"]), + ogImage: image().optional(), + description: z.string(), + canonicalURL: z.string().optional(), + }), +}); + +export const collections = { blog }; diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..acef35f --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro new file mode 100644 index 0000000..a52c82e --- /dev/null +++ b/src/layouts/Layout.astro @@ -0,0 +1,130 @@ +--- +import { LOCALE, SITE } from "@config"; +import "../../custom.scss"; +import Matomo from "../components/Matomo.astro"; + +const googleSiteVerification = import.meta.env.PUBLIC_GOOGLE_SITE_VERIFICATION; + +export interface Props { + pageTitle?: string; + title?: string; + author?: string; + description?: string; + ogImage?: string; + canonicalURL?: string; + pubDatetime?: Date; + modDatetime?: Date | null; +} + +const { + pageTitle = "Home", + title = pageTitle + " - " +SITE.title, + author = SITE.author, + description = SITE.desc, + ogImage = SITE.ogImage, + canonicalURL = new URL(Astro.url.pathname, Astro.site).href, + pubDatetime, + modDatetime, +} = Astro.props; + +const socialImageURL = new URL( + ogImage ?? SITE.ogImage ?? "og.png", + Astro.url.origin +).href; +--- + + + + + + + + + + + + {title} + + + + + + + + + + + + + { + pubDatetime && ( + + ) + } + { + modDatetime && ( + + ) + } + + + + + + + + + + + + + + + + + + { + // If PUBLIC_GOOGLE_SITE_VERIFICATION is set in the environment variable, + // include google-site-verification tag in the heading + // Learn more: https://support.google.com/webmasters/answer/9008080#meta_tag_verification&zippy=%2Chtml-tag + googleSiteVerification && ( + + ) + } + + + + + + + + + + + + + + diff --git a/src/layouts/Main.astro b/src/layouts/Main.astro new file mode 100644 index 0000000..b111701 --- /dev/null +++ b/src/layouts/Main.astro @@ -0,0 +1,40 @@ +--- +import { Heading } from "react-bulma-components" + +interface StringTitleProp { + pageTitle?: string; + pageDesc?: string; + fullWidth?: boolean; +} + +interface ArrayTitleProp { + pageTitle?: [string, string]; + titleTransition: string; + pageDesc?: string; + fullWidth?: boolean; +} + +export type Props = StringTitleProp | ArrayTitleProp; + +const { props } = Astro; +let maxWidth = props.fullWidth ? "84rem" : "" ; + +--- + +
+ { + "titleTransition" in props ? ( + + { props.pageTitle?.[0] } + + { props.pageTitle?.[1] } + + + ) : ( + { props.pageTitle } + ) + } +

{ props.pageDesc }

+ +
+ diff --git a/src/layouts/PageLayout.astro b/src/layouts/PageLayout.astro new file mode 100644 index 0000000..d33186b --- /dev/null +++ b/src/layouts/PageLayout.astro @@ -0,0 +1,29 @@ +--- +import { SITE } from "@config"; +import Breadcrumbs from "@components/Breadcrumbs.astro"; +import Footer from "@components/Footer.astro"; +import Header from "@components/Header.astro"; +import Layout from "./Layout.astro"; + +export interface Props { + frontmatter: { + title: string; + description?: string; + }; +} + +const { frontmatter } = Astro.props; +--- + + +
+
+
+

{frontmatter.title}

+
+ +
+
+
+