feat: add compressO website

This commit is contained in:
niraj-khatiwada 2026-02-27 23:56:37 +05:45
parent ff16f7b842
commit 47d4b8786d
53 changed files with 7426 additions and 4 deletions

1
.gitignore vendored
View file

@ -13,6 +13,7 @@
/build
/out/
/dist/
/dist-tauri/
# misc
.DS_Store

1
CNAME Normal file
View file

@ -0,0 +1 @@
compresso.codeforreal.com

View file

@ -10,7 +10,7 @@
"type": "module",
"scripts": {
"vite:dev": "vite --port=3001",
"vite:build": "vite build",
"vite:build": "vite build --outDir ./dist-tauri",
"vite:preview": "vite preview",
"vite:start": "vite",
"tauri:dev": "tauri dev",

View file

@ -5,7 +5,7 @@
"identifier": "com.compresso.app",
"build": {
"beforeBuildCommand": "pnpm vite:build",
"frontendDist": "../dist",
"frontendDist": "../dist-tauri",
"devUrl": "http://localhost:3001"
},
"bundle": {

View file

@ -23,5 +23,5 @@
}
},
"include": ["**/*.ts", "**/*.tsx", "./dist/types/**/*.ts"],
"exclude": ["node_modules"]
"exclude": ["node_modules", "website"]
}

View file

@ -1,6 +1,6 @@
import { resolve } from 'path'
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
import { defineConfig } from 'vite'
import svgr from 'vite-plugin-svgr'

24
website/.gitignore vendored Normal file
View file

@ -0,0 +1,24 @@
# build output
dist/
# generated types
.astro/
# 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
# jetbrains setting folder
.idea/

4
website/.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode", "unifiedjs.vscode-mdx"],
"unwantedRecommendations": []
}

11
website/.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

1
website/CNAME Normal file
View file

@ -0,0 +1 @@
compresso.codeforreal.com

10
website/README.md Normal file
View file

@ -0,0 +1,10 @@
# Code For Real Website
Made with Astro 🗲
### Development:
```
pnpm install
pnpm dev
```

27
website/astro.config.mjs Normal file
View file

@ -0,0 +1,27 @@
// @ts-check
import { defineConfig } from "astro/config";
import mdx from "@astrojs/mdx";
import sitemap from "@astrojs/sitemap";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
base: "/",
site: "https://compresso.codeforreal.com",
integrations: [mdx(), sitemap()],
output: "static",
outDir: "../dist",
vite: {
plugins: [tailwindcss()],
build: {
rollupOptions: {
external: ["@resvg/resvg-js"],
},
},
},
markdown: {
shikiConfig: {
theme: 'catppuccin-mocha',
},
},
});

23
website/package.json Normal file
View file

@ -0,0 +1,23 @@
{
"name": "codeforreal",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^4.3.0",
"@astrojs/rss": "^4.0.12",
"@astrojs/sitemap": "^3.4.1",
"@resvg/resvg-js": "^2.6.2",
"@tailwindcss/vite": "^4.1.8",
"astro": "^5.9.1",
"astro-seo": "^0.8.4",
"sharp": "^0.34.2",
"tailwindcss": "^4.1.8"
},
"packageManager": "pnpm@10.0.0"
}

5247
website/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load diff

1
website/public/CNAME Normal file
View file

@ -0,0 +1 @@
compresso.codeforreal.com

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
website/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
website/src/assets/hero.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

BIN
website/src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
website/src/assets/og.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

View file

@ -0,0 +1,72 @@
---
import type { ImageMetadata } from "astro";
import { SITE_TITLE } from "../consts";
import FallbackImage from "../assets/placeholder.jpg";
import "../styles/global.css";
import PostHog from "./PostHog.astro";
interface Props {
title: string;
description: string;
image?: ImageMetadata;
}
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
const { title, description, image = FallbackImage } = Astro.props;
const { url, site, generator } = Astro;
---
<!-- Global Metadata -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="icon" type="image/svgxml" href="/favicon.ico" />
<link rel="sitemap" href="/sitemap-index.xml" />
<link
rel="alternate"
type="application/rssxml"
title={SITE_TITLE}
href={new URL("rss.xml", site)}
/>
<meta name="generator" content={generator} />
<!-- Font preloads -->
<link
rel="preload"
href="/fonts/atkinson-regular.woff"
as="font"
type="font/woff"
crossorigin
/>
<link
rel="preload"
href="/fonts/atkinson-bold.woff"
as="font"
type="font/woff"
crossorigin
/>
<!-- Canonical URL -->
<link rel="canonical" href={canonicalURL} />
<!-- Primary Meta Tags -->
<title>{title}</title>
<meta name="title" content={title} />
<meta name="description" content={description} />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:url" content={url} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={new URL(image.src, url)} />
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={url} />
<meta property="twitter:title" content={title} />
<meta property="twitter:description" content={description} />
<meta property="twitter:image" content={new URL(image.src, url)} />
<PostHog />

View file

@ -0,0 +1,17 @@
---
interface Props {
date: Date;
}
const { date } = Astro.props;
---
<time datetime={date.toISOString()} class="m-0!">
{
date.toLocaleDateString("en-us", {
year: "numeric",
month: "short",
day: "numeric",
})
}
</time>

View file

@ -0,0 +1,24 @@
---
import SocialLinks from "./SocialLinks.astro";
const today = new Date();
---
<footer>
&copy; {today.getFullYear()} Code For Real. All rights reserved.
<div>
<a href="mailto:hello@codeforreal.com" target="_blank"
>hello@codeforreal.com</a
>
</div>
<div class="flex justify-center">
<SocialLinks />
</div>
</footer>
<style>
footer {
padding: 2em 1em 2em 1em;
color: rgb(var(--gray));
text-align: center;
}
</style>

View file

@ -0,0 +1,71 @@
---
import { Image } from "astro:assets";
import LogoImage from "../assets/logo.png";
import SocialLinks from "./SocialLinks.astro";
---
<header>
<nav class="px-2 py-4">
<h2>
<a href="https://codeforreal.com">
<Image
src={LogoImage}
alt="codeforreal logo"
class="w-45 sm:w-65"
loading="eager"
/>
</a>
</h2>
<SocialLinks />
</nav>
</header>
<style>
header {
width: 960px;
margin: 0 auto;
padding: 10px 0;
}
h2 {
margin: 0;
font-size: 1em;
}
h2 a,
h2 a.active {
text-decoration: none;
}
nav {
display: flex;
align-items: center;
justify-content: space-between;
}
nav a {
color: var(--black);
text-decoration: none;
color: var(--white);
}
nav a.active {
text-decoration: none;
border-bottom-color: var(--accent);
}
.social-links,
.social-links a {
display: flex;
}
@media (max-width: 720px) {
.social-links {
display: none;
}
header {
width: unset;
margin: 0 unset;
padding: 0 1em;
}
}
@media screen and (min-width: 720px) and (max-width: 1000px) {
nav {
padding: 2rem;
}
}
</style>

View file

@ -0,0 +1,24 @@
---
import type { HTMLAttributes } from 'astro/types';
type Props = HTMLAttributes<'a'>;
const { href, class: className, ...props } = Astro.props;
const pathname = Astro.url.pathname.replace(import.meta.env.BASE_URL, '');
const subpath = pathname.match(/[^\/]+/g);
const isActive = href === pathname || href === '/' + (subpath?.[0] || '');
---
<a href={href} class:list={[className, { active: isActive }]} {...props}>
<slot />
</a>
<style>
a {
display: inline-block;
text-decoration: none;
}
a.active {
font-weight: bolder;
text-decoration: underline;
}
</style>

View file

@ -0,0 +1,58 @@
---
---
<script is:inline>
!(function (t, e) {
var o, n, p, r;
e.__SV ||
((window.posthog = e),
(e._i = []),
(e.init = function (i, s, a) {
function g(t, e) {
var o = e.split(".");
2 == o.length && ((t = t[o[0]]), (e = o[1])),
(t[e] = function () {
t.push([e].concat(Array.prototype.slice.call(arguments, 0)));
});
}
((p = t.createElement("script")).type = "text/javascript"),
(p.crossOrigin = "anonymous"),
(p.async = !0),
(p.src = s.api_host + "/static/array.js"),
(r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(
p,
r
);
var u = e;
for (
void 0 !== a ? (u = e[a] = []) : (a = "posthog"),
u.people = u.people || [],
u.toString = function (t) {
var e = "posthog";
return (
"posthog" !== a && (e += "." + a), t || (e += " (stub)"), e
);
},
u.people.toString = function () {
return u.toString(1) + ".people (stub)";
},
o =
"capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(
" "
),
n = 0;
n < o.length;
n++
)
g(u, o[n]);
e._i.push([i, s, a]);
}),
(e.__SV = 1));
})(document, window.posthog || []);
posthog.init("phc_6BTRvDFFc10XTkIVhIgeKa1gDUNrTtroBBcPbIREdrV", {
api_host: "https://us.i.posthog.com",
defaults: "2025-05-24",
person_profiles: "always",
});
</script>

View file

@ -0,0 +1,24 @@
---
import { Image } from "astro:assets";
import FallbackImage from "../assets/placeholder.jpg";
import type { Project } from "../types/project";
const { title, description, heroImage, url, starsUrl } = Astro.props as Project;
---
<div class="rounded-xl overflow-hidden">
<a href={url} target="_blank">
<Image
src={heroImage! ?? FallbackImage}
alt={title}
class="w-full h-[220px]! object-cover"
/>
</a>
<h4 class="text-white opacity-85 mt-2! my-0!">{title}</h4>
<p class="text-[var(--gray)] m-0! text-sm mt-2!">
{description}
</p>
<a href={url} target="_blank">
<img alt={`${title} stars`} src={starsUrl} loading="lazy" class="my-2" />
</a>
</div>

View file

@ -0,0 +1,107 @@
<div class="social-links flex items-center gap-[0.8rem]">
<a href="https://www.instagram.com/codeforreal" target="_blank">
<span class="sr-only">Follow on Instagram</span>
<svg
viewBox="0 0 20 20"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="#ffffff"
stroke="#ffffff"
width="20"
height="20"
astro-icon="social/instagram"
><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier">
<title>instagram [#ffffff]</title>
<desc>Created with Sketch.</desc>
<defs> </defs>
<g
id="Page-1"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g
id="Dribbble-Light-Preview"
transform="translate(-340.000000, -7439.000000)"
fill="#ffffff"
>
<g id="icons" transform="translate(56.000000, 160.000000)">
<path
d="M289.869652,7279.12273 C288.241769,7279.19618 286.830805,7279.5942 285.691486,7280.72871 C284.548187,7281.86918 284.155147,7283.28558 284.081514,7284.89653 C284.035742,7285.90201 283.768077,7293.49818 284.544207,7295.49028 C285.067597,7296.83422 286.098457,7297.86749 287.454694,7298.39256 C288.087538,7298.63872 288.809936,7298.80547 289.869652,7298.85411 C298.730467,7299.25511 302.015089,7299.03674 303.400182,7295.49028 C303.645956,7294.859 303.815113,7294.1374 303.86188,7293.08031 C304.26686,7284.19677 303.796207,7282.27117 302.251908,7280.72871 C301.027016,7279.50685 299.5862,7278.67508 289.869652,7279.12273 M289.951245,7297.06748 C288.981083,7297.0238 288.454707,7296.86201 288.103459,7296.72603 C287.219865,7296.3826 286.556174,7295.72155 286.214876,7294.84312 C285.623823,7293.32944 285.819846,7286.14023 285.872583,7284.97693 C285.924325,7283.83745 286.155174,7282.79624 286.959165,7281.99226 C287.954203,7280.99968 289.239792,7280.51332 297.993144,7280.90837 C299.135448,7280.95998 300.179243,7281.19026 300.985224,7281.99226 C301.980262,7282.98483 302.473801,7284.28014 302.071806,7292.99991 C302.028024,7293.96767 301.865833,7294.49274 301.729513,7294.84312 C300.829003,7297.15085 298.757333,7297.47145 289.951245,7297.06748 M298.089663,7283.68956 C298.089663,7284.34665 298.623998,7284.88065 299.283709,7284.88065 C299.943419,7284.88065 300.47875,7284.34665 300.47875,7283.68956 C300.47875,7283.03248 299.943419,7282.49847 299.283709,7282.49847 C298.623998,7282.49847 298.089663,7283.03248 298.089663,7283.68956 M288.862673,7288.98792 C288.862673,7291.80286 291.150266,7294.08479 293.972194,7294.08479 C296.794123,7294.08479 299.081716,7291.80286 299.081716,7288.98792 C299.081716,7286.17298 296.794123,7283.89205 293.972194,7283.89205 C291.150266,7283.89205 288.862673,7286.17298 288.862673,7288.98792 M290.655732,7288.98792 C290.655732,7287.16159 292.140329,7285.67967 293.972194,7285.67967 C295.80406,7285.67967 297.288657,7287.16159 297.288657,7288.98792 C297.288657,7290.81525 295.80406,7292.29716 293.972194,7292.29716 C292.140329,7292.29716 290.655732,7290.81525 290.655732,7288.98792"
id="instagram-[#ffffff]"
>
</path>
</g>
</g>
</g>
</g></svg
>
</a>
<a href="https://www.threads.com/@codeforreal" target="_blank">
<span class="sr-only">Follow on Threads</span>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
width="25"
height="25"
astro-icon="social/threads"
>
<path
fill="#e0e0e0"
d="M331.5 235.7c2.2 .9 4.2 1.9 6.3 2.8c29.2 14.1 50.6 35.2 61.8 61.4c15.7 36.5 17.2 95.8-30.3 143.2c-36.2 36.2-80.3 52.5-142.6 53h-.3c-70.2-.5-124.1-24.1-160.4-70.2c-32.3-41-48.9-98.1-49.5-169.6V256v-.2C17 184.3 33.6 127.2 65.9 86.2C102.2 40.1 156.2 16.5 226.4 16h.3c70.3 .5 124.9 24 162.3 69.9c18.4 22.7 32 50 40.6 81.7l-40.4 10.8c-7.1-25.8-17.8-47.8-32.2-65.4c-29.2-35.8-73-54.2-130.5-54.6c-57 .5-100.1 18.8-128.2 54.4C72.1 146.1 58.5 194.3 58 256c.5 61.7 14.1 109.9 40.3 143.3c28 35.6 71.2 53.9 128.2 54.4c51.4-.4 85.4-12.6 113.7-40.9c32.3-32.2 31.7-71.8 21.4-95.9c-6.1-14.2-17.1-26-31.9-34.9c-3.7 26.9-11.8 48.3-24.7 64.8c-17.1 21.8-41.4 33.6-72.7 35.3c-23.6 1.3-46.3-4.4-63.9-16c-20.8-13.8-33-34.8-34.3-59.3c-2.5-48.3 35.7-83 95.2-86.4c21.1-1.2 40.9-.3 59.2 2.8c-2.4-14.8-7.3-26.6-14.6-35.2c-10-11.7-25.6-17.7-46.2-17.8H227c-16.6 0-39 4.6-53.3 26.3l-34.4-23.6c19.2-29.1 50.3-45.1 87.8-45.1h.8c62.6 .4 99.9 39.5 103.7 107.7l-.2 .2zm-156 68.8c1.3 25.1 28.4 36.8 54.6 35.3c25.6-1.4 54.6-11.4 59.5-73.2c-13.2-2.9-27.8-4.4-43.4-4.4c-4.8 0-9.6 .1-14.4 .4c-42.9 2.4-57.2 23.2-56.2 41.8l-.1 .1z"
></path></svg
>
</a>
<a href="https://github.com/codeforreal1" target="_blank">
<span class="sr-only">Check out my GitHub</span>
<svg
viewBox="0 0 20 20"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="#000000"
width="20"
height="20"
astro-icon="social/threads"
><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier">
<title>github [#142]</title>
<desc>Created with Sketch.</desc>
<defs> </defs>
<g
id="Page-1"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g
id="Dribbble-Light-Preview"
transform="translate(-140.000000, -7559.000000)"
fill="#e6e6e6"
>
<g id="icons" transform="translate(56.000000, 160.000000)">
<path
d="M94,7399 C99.523,7399 104,7403.59 104,7409.253 C104,7413.782 101.138,7417.624 97.167,7418.981 C96.66,7419.082 96.48,7418.762 96.48,7418.489 C96.48,7418.151 96.492,7417.047 96.492,7415.675 C96.492,7414.719 96.172,7414.095 95.813,7413.777 C98.04,7413.523 100.38,7412.656 100.38,7408.718 C100.38,7407.598 99.992,7406.684 99.35,7405.966 C99.454,7405.707 99.797,7404.664 99.252,7403.252 C99.252,7403.252 98.414,7402.977 96.505,7404.303 C95.706,7404.076 94.85,7403.962 94,7403.958 C93.15,7403.962 92.295,7404.076 91.497,7404.303 C89.586,7402.977 88.746,7403.252 88.746,7403.252 C88.203,7404.664 88.546,7405.707 88.649,7405.966 C88.01,7406.684 87.619,7407.598 87.619,7408.718 C87.619,7412.646 89.954,7413.526 92.175,7413.785 C91.889,7414.041 91.63,7414.493 91.54,7415.156 C90.97,7415.418 89.522,7415.871 88.63,7414.304 C88.63,7414.304 88.101,7413.319 87.097,7413.247 C87.097,7413.247 86.122,7413.234 87.029,7413.87 C87.029,7413.87 87.684,7414.185 88.139,7415.37 C88.139,7415.37 88.726,7417.2 91.508,7416.58 C91.513,7417.437 91.522,7418.245 91.522,7418.489 C91.522,7418.76 91.338,7419.077 90.839,7418.982 C86.865,7417.627 84,7413.783 84,7409.253 C84,7403.59 88.478,7399 94,7399"
id="github-[#142]"
>
</path>
</g>
</g>
</g>
</g></svg
>
</a>
</div>
<style>
.social-links a:hover {
opacity: 0.8;
}
</style>

View file

@ -0,0 +1,23 @@
---
import { Image } from "astro:assets";
import type { BlogPost } from "../../types/blog";
import Date from "../Date.astro";
import FallbackImage from "../../assets/placeholder.jpg";
const { title, publishedDate, heroImage } = Astro.props as BlogPost;
---
<div>
<Image
width={720}
height={360}
src={heroImage! ?? FallbackImage}
alt={title}
class="w-full overflow-hidden"
fit="cover"
/>
<h4 class="text-white opacity-85 mt-2! my-0!">{title}</h4>
<p class="text-[var(--gray)] m-0! text-sm">
<Date date={publishedDate} />
</p>
</div>

3
website/src/consts.ts Normal file
View file

@ -0,0 +1,3 @@
export const SITE_TITLE = "CompressO";
export const SITE_DESCRIPTION =
"CompressO is a free and open-source video compression app available for Mac, Windows & Linux.";

View file

@ -0,0 +1,17 @@
import { glob } from 'astro/loaders'
import { defineCollection, z } from 'astro:content'
const blogs = defineCollection({
loader: glob({ base: './src/content/blogs', pattern: '**/*.{md,mdx}' }),
schema: ({ image }) =>
z.object({
title: z.string(),
description: z.string(),
publishedDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
heroImage: image().optional(),
}),
})
export const collections = { blogs }

View file

@ -0,0 +1,78 @@
---
import BaseHead from "../components/BaseHead.astro";
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
import OGImage from "../assets/og.jpg";
---
<!doctype html>
<html lang="en">
<head>
<BaseHead
title="404 - Page Not Found"
description="Oops! The page you are looking for does not exist."
image={OGImage}
/>
</head>
<body>
<Header />
<main
class="flex flex-col items-center justify-center text-center mt-20 px-4"
>
<h1 class="text-6xl md:text-7xl font-bold mb-4">
<span class="wave">😅</span> 404
</h1>
<p class="text-xl md:text-2xl mb-6">
Oops! The page you are looking for does not exist.
</p>
<p class="mb-6">
You can head back to <a href="/" class="text-blue-500 underline"
>Home</a
>
</p>
<br />
Or not...
<img
src="https://media.tenor.com/1UCD9Riiam8AAAAM/celebration.gif"
style="width: 300px;"
/>
</main>
<Footer />
</body>
</html>
<style>
.wave {
display: inline-block;
animation: wave-animation 7s infinite;
transform-origin: 70% 70%;
}
@keyframes wave-animation {
0% {
transform: rotate(0deg);
}
10% {
transform: rotate(14deg);
}
20% {
transform: rotate(-8deg);
}
30% {
transform: rotate(14deg);
}
40% {
transform: rotate(-4deg);
}
50% {
transform: rotate(10deg);
}
60% {
transform: rotate(0deg);
}
100% {
transform: rotate(0deg);
}
}
</style>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
export async function GET(context) {
const posts = await getCollection('blog');
return rss({
title: SITE_TITLE,
description: SITE_DESCRIPTION,
site: context.site,
items: posts.map((post) => ({
...post.data,
link: `/blog/${post.id}/`,
})),
});
}

View file

@ -0,0 +1,174 @@
@import "tailwindcss";
:root {
--accent: #7f4cfe;
--accent-dark: #5d2fd1;
--white: #fff;
--black: #000;
--gray: rgb(96, 115, 159);
--gray-light: rgb(229, 233, 240);
--gray-dark: rgb(34, 41, 57);
--gray-gradient: rgba(var(--gray-light), 50%), #fff;
--box-shadow: 0 2px 6px rgba(var(--gray), 25%),
0 8px 24px rgba(var(--gray), 33%), 0 16px 32px rgba(var(--gray), 33%);
}
@font-face {
font-family: "Atkinson";
src: url("/fonts/atkinson-regular.woff") format("woff");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Atkinson";
src: url("/fonts/atkinson-bold.woff") format("woff");
font-weight: 700;
font-style: normal;
font-display: swap;
}
body {
font-family: "Atkinson", sans-serif;
margin: 0;
padding: 0;
text-align: left;
word-wrap: break-word;
overflow-wrap: break-word;
font-size: 20px;
line-height: 1.7;
background-color: var(--black);
color: var(--white);
}
main {
width: 960px;
max-width: calc(100% - 0em);
margin: auto;
padding: 2rem 0.5rem;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0 0 0.5rem 0;
line-height: 1.2;
}
h1 {
font-size: 2em;
}
h2 {
font-size: 1.8em;
}
h3 {
font-size: 1.5em;
}
h4 {
font-size: 1.2em;
}
h5 {
font-size: 1em;
}
strong,
b {
font-weight: 700;
}
a {
color: var(--accent);
}
a:hover {
color: var(--accent);
}
p {
margin-bottom: 1em;
}
.prose p {
margin-bottom: 2em;
}
textarea {
width: 100%;
font-size: 16px;
}
input {
font-size: 16px;
}
table {
width: 100%;
}
img {
max-width: 100%;
height: auto;
border-radius: 8px;
}
code {
padding: 2px 5px;
background-color: rgb(var(--gray-light));
border-radius: 2px;
font-size: 0.9rem;
}
pre {
padding: 1.5em;
border-radius: 8px;
}
pre > code {
all: unset;
}
blockquote {
border-left: 4px solid var(--accent);
padding: 0 0 0 20px;
margin: 0px;
font-size: 1.333em;
}
hr {
border: none;
border-top: 1px solid rgb(var(--gray-light));
}
@media (max-width: 720px) {
body {
font-size: 18px;
}
}
@media (max-width: 720px) {
main {
padding: 1em;
}
}
@media screen and (min-width: 720px) and (max-width: 1000px) {
main {
padding: 2rem;
}
}
.sr-only {
border: 0;
padding: 0;
margin: 0;
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
/* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
clip: rect(1px 1px 1px 1px);
/* maybe deprecated but we need to support legacy browsers */
clip: rect(1px, 1px, 1px, 1px);
/* modern browsers, clip-path works inwards from each corner */
clip-path: inset(50%);
/* added line to stop words getting smushed together (as they go onto separate lines and some screen readers do not understand line feeds as a space */
white-space: nowrap;
}
.code {
font-size: 0.8rem;
margin-bottom: 2rem;
}
.giscus{
max-width: 768px;
margin: 0 auto;
padding: 0 1.2rem;
}
@media screen and (min-width: 768px){
.giscus{
padding: 0;
}
}

View file

@ -0,0 +1,7 @@
export type BlogPost = {
title: string;
description?: string;
publishedDate: Date;
updatedDate?: Date;
heroImage?: string;
};

View file

@ -0,0 +1,43 @@
import type { ImageMetadata } from "astro";
export type Project = {
title: string;
url: string;
slug: string;
description?: string;
heroImage?: ImageMetadata;
starsUrl?: string;
tags?: string[];
longDescription?: string;
features?: string[];
techStack?: string[];
installation?: string;
usage?: string;
screenshots?: ImageMetadata[];
demoUrl?: string;
documentationUrl?: string;
license?: string;
};
export type ProjectDetails = Omit<
Project,
"url" | "slug"
> & {
repositoryUrl: string;
githubStars?: string;
githubForks?: string;
contributors?: Array<{
name: string;
url: string;
avatar?: string;
}>;
roadmap?: Array<{
title: string;
status: "completed" | "in-progress" | "planned";
}>;
changelog?: Array<{
version: string;
date: string;
changes: string[];
}>;
};

View file

@ -0,0 +1,74 @@
export interface GitHubRelease {
tag_name: string;
html_url: string;
assets: Array<{
name: string;
browser_download_url: string;
}>;
}
const REPO_OWNER = "codeforreal1";
const REPO_NAME = "compressO";
/**
* Fetch the latest release from GitHub
* This runs at build time, so there's no runtime API call from the client
*/
export async function getLatestRelease(): Promise<GitHubRelease> {
const response = await fetch(
`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases/latest`
);
if (!response.ok) {
throw new Error(`GitHub API error: ${response.statusText}`);
}
return response.json();
}
/**
* Generate download URL for a specific asset
*/
export function getDownloadUrl(version: string, assetName: string): string {
return `https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/${version}/${assetName}`;
}
/**
* Download asset types
*/
export interface DownloadAssets {
version: string;
mac: {
aarch64: string;
x64: string;
};
linux: {
appImage: string;
deb: string;
};
windows: {
x64: string;
};
}
/**
* Get all download URLs for the current version
*/
export function getDownloadAssets(version: string): DownloadAssets {
const baseUrl = `https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/${version}`;
return {
version,
mac: {
aarch64: `${baseUrl}/CompressO_${version}_aarch64.dmg`,
x64: `${baseUrl}/CompressO_${version}_x64.dmg`,
},
linux: {
appImage: `${baseUrl}/CompressO_${version}_amd64.AppImage`,
deb: `${baseUrl}/CompressO_${version}_amd64.deb`,
},
windows: {
x64: `${baseUrl}/CompressO_${version}_x64.exe`,
},
};
}

13
website/tsconfig.json Normal file
View file

@ -0,0 +1,13 @@
{
"extends": "astro/tsconfigs/strict",
"include": [
".astro/types.d.ts",
"**/*"
],
"exclude": [
"dist"
],
"compilerOptions": {
"strictNullChecks": true
}
}