diff --git a/astro.config.mjs b/astro.config.mjs
index 1196e5f..27848bf 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -6,7 +6,7 @@ import tailwind from "@astrojs/tailwind";
// https://astro.build/config
export default defineConfig({
site: "https://athenaos.org/",
- output: "static",
+ output: "hybrid",
integrations: [
starlight({
title: "Athena OS",
diff --git a/src/actions/index.ts b/src/actions/index.ts
new file mode 100644
index 0000000..5e91d11
--- /dev/null
+++ b/src/actions/index.ts
@@ -0,0 +1,67 @@
+import { defineAction } from "astro:actions";
+import { z } from "astro:schema";
+
+let bearerToken = import.meta.env.STRAPI_WRITE_TOKEN;
+
+const getDownloadCounts = async () => {
+ try {
+ const response = await fetch(
+ `https://cms.athenaos.org/api/download-counts-list`,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${bearerToken}`,
+ },
+ }
+ );
+ const result = await response.json();
+ return result;
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ }
+};
+
+const increaseDownloadCount = async (id: string) => {
+ let data = [
+ { id: "7", download_type: "docker" },
+ { id: "1", download_type: "iso" },
+ { id: "5", download_type: "virtualbox" },
+ { id: "3", download_type: "vmware" },
+ { id: "9", download_type: "wsl" },
+ ];
+
+ try {
+ let countId = data.find((item) => item.download_type === id)?.id;
+
+ const response = await fetch(
+ `https://cms.athenaos.org/api/download-count/${countId}/increment`,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${bearerToken}`,
+ },
+ }
+ );
+ const result = await response.json();
+ return result;
+ } catch (error) {
+ console.error("Error increasing download count:", error);
+ }
+};
+
+export const server = {
+ getDownloadCount: defineAction({
+ handler: async () => {
+ return await getDownloadCounts();
+ },
+ }),
+ increaseCount: defineAction({
+ input: z.object({
+ id: z.string(),
+ }),
+ handler: async (input) => {
+ return await increaseDownloadCount(input.id);
+ },
+ }),
+};
diff --git a/src/components/DownloadCards.jsx b/src/components/DownloadCards.jsx
deleted file mode 100755
index 474ae90..0000000
--- a/src/components/DownloadCards.jsx
+++ /dev/null
@@ -1,201 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { data } from 'src/javascript/downloadsData';
-
-const DownloadCards = () => {
- const [activeModal, setActiveModal] = useState(null);
- const [downloadItemsData, setDownloadItemsData] = useState(data)
- const [flippedCards, setFlippedCards] = useState({});
- const [activeHashes, setActiveHashes] = useState({});
- const [downloadEnabled, setDownloadEnabled] = useState(true)
-
- useEffect(() => {
- const initialHashes = {};
- data.forEach((_, index) => {
- initialHashes[index] = 'MD5';
- });
- setActiveHashes(initialHashes);
-
- const getDownloadCounts = async () => {
- try {
- const response = await fetch(
- `https://cms.athenaos.org/api/download-counts-list`,
- );
- const result = await response.json();
- const updatedData = [...downloadItemsData]; // Create a copy to avoid mutating the original state
- result.forEach((entry) => {
- const matchingItem = updatedData.find(
- (item) => item.title === entry.download_type // Match based on title
- );
- if (matchingItem) {
- matchingItem.downloadsCount = entry.download_count; // Update downloadsCount
- }
- });
- // Update the state with the new data
- setDownloadItemsData(updatedData);
- } catch (error) {
- console.error("Error fetching data:", error);
- return { data: [] };
- }
- }
- getDownloadCounts()
- }, []);
-
- const openModal = (index) => setActiveModal(index);
- const closeModal = () => {
- setActiveModal(null);
- setFlippedCards(prev => ({ ...prev, [activeModal]: false }));
- };
- const flipCard = (index) => setFlippedCards(prev => ({ ...prev, [index]: !prev[index] }));
- const changeHash = (index, hashType) => setActiveHashes(prev => ({ ...prev, [index]: hashType }));
- const downloadItem = () => {
-
- const downloadURL = downloadItemsData[activeModal]["downloadURL"];
-
- if (downloadURL.startsWith("https://cms.athenaos.org/")) {
- // Use fetch to get the file
- fetch(downloadURL)
- .then((response) => {
- if (!response.ok) {
- throw new Error("Network response was not ok");
- }
- return response.blob(); // Get the response as a Blob
- })
- .then((blob) => {
- const url = window.URL.createObjectURL(blob); // Create a URL for the Blob
- const a = document.createElement("a"); // Create a temporary anchor element
- a.style.display = "none"; // Hide the anchor
- a.href = url; // Set the href to the Blob URL
- a.download = downloadURL.split("/").pop(); // Set the download attribute with the file name
- document.body.appendChild(a); // Append the anchor to the document
- a.click(); // Programmatically click the anchor to trigger the download
- window.URL.revokeObjectURL(url); // Release the Blob URL
- document.body.removeChild(a); // Remove the anchor from the document
- // increment download counter
- setDownloadItemsData((prevData) => {
- return prevData.map((item, index) => {
- if (index === activeModal) {
- // Increment the downloadsCount for the active modal
- return { ...item, downloadsCount: (item.downloadsCount || 0) + 1 };
- }
- return item; // Return the item unchanged if it's not active
- });
- });
- })
- .catch((error) => {
- console.error("Error downloading the file:", error); // Handle errors
- });
- } else {
- // Open the link in a new tab
- window.open(downloadURL, "_blank");
- }
- setDownloadEnabled(false)
- setTimeout(() => {
- setDownloadEnabled(true);
- }, 10000);
- };
-
- return (
-
-
Download Links:
-
- {downloadItemsData.map((item, index) => (
-
- openModal(index)}
- className="cursor-pointer transform transition-transform duration-300 hover:scale-125 downloadButtonImage"
- >
-
-
- {activeModal === index && (
-
-
flipCard(index)}
- >
- {/* Front of the card */}
-
-
-
-
-
-
-
{item.title}
-
{item.description}
-
- Flip card for download
-
-
-
-
-
-
-
-
- {/* Back of the card */}
-
-
-
- {Object.keys(item.hashes).map((hashType) => (
- { e.stopPropagation(); changeHash(index, hashType); }}
- style={{ marginTop: "0" }}
- >
- {hashType}
-
- ))}
-
-
-
{activeHashes[index]}
-
{item.hashes[activeHashes[index]]}
-
-
-
- {item.enableDownloadCounter &&
-
Total downloads:{item.downloadsCount}
}
-
{
- e.stopPropagation(); // Prevent card flip
- // Perform the download action here
- downloadItem()
- }}
- >
- Download
-
-
-
-
-
-
- )}
-
- ))}
- {activeModal !== null && (
-
- )}
-
-
- );
-};
-
-export default DownloadCards;
\ No newline at end of file
diff --git a/src/components/DownloadTabs.astro b/src/components/DownloadTabs.astro
new file mode 100644
index 0000000..dcadcc4
--- /dev/null
+++ b/src/components/DownloadTabs.astro
@@ -0,0 +1,160 @@
+---
+import Tabs from "./tabs/Tabs.astro";
+import { TabItem } from "@astrojs/starlight/components";
+import { data } from "src/javascript/downloadsData";
+---
+
+
+
+ {
+ data.map((platform) => (
+
+
+
+
+
+
+
+ {platform.description}
+
+ {Object.keys(platform.hashes).map((hashType) => (
+
+ {/* @ts-expect-error */}
+ {platform.hashes[hashType]}
+
+ ))}
+
+
+
+ Download
+
+
+
+
+
+
+
+ ))
+ }
+
+
+
+
+
+
diff --git a/src/components/filter-builder.astro b/src/components/filter-builder.astro
index 1f1d7a0..e43107e 100644
--- a/src/components/filter-builder.astro
+++ b/src/components/filter-builder.astro
@@ -26,7 +26,6 @@ function capitalizeText(text: string): string {
Filter {value} Status
{s[value].length > 0 &&
s[value].map((i: string) => {
- console.log(i);
return {capitalizeText(i)} ;
})}
diff --git a/src/components/tabs/Tabs.astro b/src/components/tabs/Tabs.astro
new file mode 100644
index 0000000..ad3312a
--- /dev/null
+++ b/src/components/tabs/Tabs.astro
@@ -0,0 +1,262 @@
+---
+import { processPanels } from './rehype-tabs';
+
+interface Props {
+ syncKey?: string;
+}
+
+const { syncKey } = Astro.props;
+const panelHtml = await Astro.slots.render('default');
+const { html, panels } = processPanels(panelHtml);
+
+/**
+ * Synced tabs are persisted across page using `localStorage`. The script used to restore the
+ * active tab for a given sync key has a few requirements:
+ *
+ * - The script should only be included when at least one set of synced tabs is present on the page.
+ * - The script should be inlined to avoid a flash of invalid active tab.
+ * - The script should only be included once per page.
+ *
+ * To do so, we keep track of whether the script has been rendered using a variable stored using
+ * `Astro.locals` which will be reset for each new page. The value is tracked using an untyped
+ * symbol on purpose to avoid Starlight users to get autocomplete for it and avoid potential
+ * clashes with user-defined variables.
+ *
+ * The restore script defines a custom element `starlight-tabs-restore` that will be included in
+ * each set of synced tabs to restore the active tab based on the persisted value using the
+ * `connectedCallback` lifecycle method. To ensure this callback can access all tabs and panels for
+ * the current set of tabs, the script should be rendered before the tabs themselves.
+ */
+const isSynced = syncKey !== undefined;
+const didRenderSyncedTabsRestoreScriptSymbol = Symbol.for('starlight:did-render-synced-tabs-restore-script');
+// @ts-expect-error - See above
+const shouldRenderSyncedTabsRestoreScript = isSynced && Astro.locals[didRenderSyncedTabsRestoreScriptSymbol] !== true;
+
+if (isSynced) {
+ // @ts-expect-error - See above
+ Astro.locals[didRenderSyncedTabsRestoreScriptSymbol] = true
+}
+---
+
+{/* Inlined to avoid a flash of invalid active tab. */}
+{shouldRenderSyncedTabsRestoreScript && }
+
+
+ {
+ panels && (
+
+
+ {panels.map(({ label, panelId, tabId }, idx) => (
+
+
+ {label}
+
+
+ ))}
+
+
+ )
+ }
+
+ {isSynced && }
+
+
+
+
+
diff --git a/src/components/tabs/rehype-tabs.ts b/src/components/tabs/rehype-tabs.ts
new file mode 100644
index 0000000..35f34c5
--- /dev/null
+++ b/src/components/tabs/rehype-tabs.ts
@@ -0,0 +1,112 @@
+import type { Element } from "hast";
+import { select } from "hast-util-select";
+import { rehype } from "rehype";
+import { CONTINUE, SKIP, visit } from "unist-util-visit";
+
+interface Panel {
+ panelId: string;
+ tabId: string;
+ label: string;
+}
+
+declare module "vfile" {
+ interface DataMap {
+ panels: Panel[];
+ }
+}
+
+export const TabItemTagname = "starlight-tab-item";
+
+// https://github.com/adobe/react-spectrum/blob/99ca82e87ba2d7fdd54f5b49326fd242320b4b51/packages/%40react-aria/focus/src/FocusScope.tsx#L256-L275
+const focusableElementSelectors = [
+ "input:not([disabled]):not([type=hidden])",
+ "select:not([disabled])",
+ "textarea:not([disabled])",
+ "button:not([disabled])",
+ "a[href]",
+ "area[href]",
+ "summary",
+ "iframe",
+ "object",
+ "embed",
+ "audio[controls]",
+ "video[controls]",
+ "[contenteditable]",
+ "[tabindex]:not([disabled])",
+]
+ .map((selector) => `${selector}:not([hidden]):not([tabindex="-1"])`)
+ .join(",");
+
+let count = 0;
+const getIDs = () => {
+ const id = count++;
+ return { panelId: "tab-panel-" + id, tabId: "tab-" + id };
+};
+
+/**
+ * Rehype processor to extract tab panel data and turn each
+ * `` into a `` with the necessary
+ * attributes.
+ */
+const tabsProcessor = rehype()
+ .data("settings", { fragment: true })
+ .use(function tabs() {
+ return (tree: Element, file) => {
+ file.data.panels = [];
+ let isFirst = true;
+ visit(tree, "element", (node) => {
+ if (node.tagName !== TabItemTagname || !node.properties) {
+ return CONTINUE;
+ }
+
+ const { dataLabel } = node.properties;
+ const ids = getIDs();
+ const panel: Panel = {
+ ...ids,
+ label: String(dataLabel),
+ };
+ file.data.panels?.push(panel);
+
+ // Remove `
` props
+ delete node.properties.dataLabel;
+ // Turn into `` with required attributes
+ node.tagName = "div";
+ node.properties.id = ids.panelId;
+ node.properties["aria-labelledby"] = ids.tabId;
+ node.properties.role = "tabpanel";
+
+ const focusableChild = select(focusableElementSelectors, node);
+ // If the panel does not contain any focusable elements, include it in
+ // the tab sequence of the page.
+ if (!focusableChild) {
+ node.properties.tabindex = 0;
+ }
+
+ // Hide all panels except the first
+ // TODO: make initially visible tab configurable
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ node.properties.hidden = true;
+ }
+
+ // Skip over the tab panel’s children.
+ return SKIP;
+ });
+ };
+ });
+
+/**
+ * Process tab panel items to extract data for the tab links and format
+ * each tab panel correctly.
+ * @param html Inner HTML passed to the `
` component.
+ */
+export const processPanels = (html: string) => {
+ const file = tabsProcessor.processSync({ value: html });
+ return {
+ /** Data for each tab panel. */
+ panels: file.data.panels,
+ /** Processed HTML for the tab panels. */
+ html: file.toString(),
+ };
+};
diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx
index 654a1bf..838c6a4 100644
--- a/src/content/docs/index.mdx
+++ b/src/content/docs/index.mdx
@@ -26,17 +26,11 @@ import { Card, CardGrid } from "@astrojs/starlight/components";
import ScriptWorkaround from "/src/components/ScriptWorkaround.astro";
import TimelineComponent from "/src/components/TimelineComponent.astro";
import StatusComponent from "/src/components/StatusComponent.astro";
-import DownloadCards from "/src/components/DownloadCards.jsx";
+import DownloadTabs from "/src/components/DownloadTabs.astro";
-{/*
-Uncomment when to show Timeline
-*/}
-{/*
-Uncomment when to publish and show DownloadCards again
-
-*/}
+
@@ -50,7 +44,7 @@ Uncomment when to publish and show DownloadCards again
**Optimized resource consumption** by retrieving the tools you need only
- when you use them. Configured to load the **bare minimum** for its purpose.
+ when you use them. Configured to load the **bare minimum** for its purpose.
**No useless services** or **modules** consuming your resources.
@@ -59,4 +53,4 @@ Uncomment when to publish and show DownloadCards again
-
\ No newline at end of file
+
diff --git a/src/javascript/downloadsData.js b/src/javascript/downloadsData.js
index 9dd5def..f2f2ce8 100644
--- a/src/javascript/downloadsData.js
+++ b/src/javascript/downloadsData.js
@@ -1,89 +1,94 @@
export const data = [
- {
- title: "ISO Image",
- description:
- "Get the full capabilities of your hardware! Achieve unparalleled performance and seamless integration with your hardware, ensuring a smooth and efficient computing experience.",
- image: "/src/assets/iso.svg",
- hashes: {
- MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
- SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
- SHA256:
- "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
- SHA512:
- "abs118c0267216830b4214dcd2a2d2a3891a97dab6cf2aa5cd398262c0343d89a6beea759b9052a5cd37edccfdab855174a4ef0f56100177548d7c6f91bc0ab414d",
- },
- downloadURL: "https://cms.athenaos.org/api/downloads/11",
- enableDownloadCounter: true,
- downloadsCount: null,
+ {
+ id: "iso",
+ title: "ISO Image",
+ description:
+ "Get the full capabilities of your hardware! Achieve unparalleled performance and seamless integration with your hardware, ensuring a smooth and efficient computing experience.",
+ image: "/src/assets/iso.svg",
+ hashes: {
+ MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
+ SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
+ SHA256:
+ "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
+ SHA512:
+ "abs118c0267216830b4214dcd2a2d2a3891a97dab6cf2aa5cd398262c0343d89a6beea759b9052a5cd37edccfdab855174a4ef0f56100177548d7c6f91bc0ab414d",
},
- {
- title: "VMware Image",
- description:
- "Experience effortlessly! Ensure optimal performance and seamless integration. Take advantage of full feature set without modifying your primary system, providing a robust and efficient solution for your virtualization needs.",
- image: "/src/assets/vmware.svg",
- hashes: {
- MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
- SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
- SHA256:
- "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
- SHA512:
- "kFJrYlvyVlnqBMGpjRFNWskHzr1Bdv9VTOrqV9HogAspOWpCAzRDEsPiOMMJ1qle",
- },
- downloadURL: "https://cms.athenaos.org/api/downloads/14",
- enableDownloadCounter: true,
- downloadsCount: null,
+ downloadURL: "https://cms.athenaos.org/api/downloads/11",
+ enableDownloadCounter: true,
+ downloadsCount: null,
+ },
+ {
+ id: "vmware",
+ title: "VMware Image",
+ description:
+ "Experience effortlessly! Ensure optimal performance and seamless integration. Take advantage of full feature set without modifying your primary system, providing a robust and efficient solution for your virtualization needs.",
+ image: "/src/assets/vmware.svg",
+ hashes: {
+ MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
+ SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
+ SHA256:
+ "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
+ SHA512:
+ "kFJrYlvyVlnqBMGpjRFNWskHzr1Bdv9VTOrqV9HogAspOWpCAzRDEsPiOMMJ1qle",
},
- {
- title: "VirtualBox Image",
- description:
- "Run seamlessly! Designed for smooth performance and full compatibility. Enjoy all the features without altering your main system, providing a flexible and efficient virtualization solution.",
- image: "/src/assets/vbox.svg",
- hashes: {
- MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
- SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
- SHA256:
- "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
- SHA512:
- "kFJrYlvyVlnqBMGpjRFNWskHzr1Bdv9VTOrqV9HogAspOWpCAzRDEsPiOMMJ1qle",
- },
- downloadURL: "https://cms.athenaos.org/api/downloads/16",
- enableDownloadCounter: true,
- downloadsCount: null,
+ downloadURL: "https://cms.athenaos.org/api/downloads/14",
+ enableDownloadCounter: true,
+ downloadsCount: null,
+ },
+ {
+ id: "virtualbox",
+ title: "VirtualBox Image",
+ description:
+ "Run seamlessly! Designed for smooth performance and full compatibility. Enjoy all the features without altering your main system, providing a flexible and efficient virtualization solution.",
+ image: "/src/assets/vbox.svg",
+ hashes: {
+ MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
+ SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
+ SHA256:
+ "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
+ SHA512:
+ "kFJrYlvyVlnqBMGpjRFNWskHzr1Bdv9VTOrqV9HogAspOWpCAzRDEsPiOMMJ1qle",
},
- {
- title: "Docker Images",
- description:
- "Ideal for containerized environments! Ensure lightweight and efficient performance. Utilize the full potential across various platforms without the need for complex setups, providing a scalable and consistent solution for your development and deployment needs.",
- image: "/src/assets/docker.svg",
- hashes: {
- MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
- SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
- SHA256:
- "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
- SHA512:
- "kFJrYlvyVlnqBMGpjRFNWskHzr1Bdv9VTOrqV9HogAspOWpCAzRDEsPiOMMJ1qle",
- },
- downloadURL: "https://hub.docker.com/u/athenaos",
- enableDownloadCounter: false,
- downloadsCount: null,
+ downloadURL: "https://cms.athenaos.org/api/downloads/16",
+ enableDownloadCounter: true,
+ downloadsCount: null,
+ },
+ {
+ id: "docker",
+ title: "Docker Images",
+ description:
+ "Ideal for containerized environments! Ensure lightweight and efficient performance. Utilize the full potential across various platforms without the need for complex setups, providing a scalable and consistent solution for your development and deployment needs.",
+ image: "/src/assets/docker.svg",
+ hashes: {
+ MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
+ SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
+ SHA256:
+ "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
+ SHA512:
+ "kFJrYlvyVlnqBMGpjRFNWskHzr1Bdv9VTOrqV9HogAspOWpCAzRDEsPiOMMJ1qle",
},
- {
- title: "WSL Image",
- description:
- "Integrate seamlessly into your Windows environment! Enjoy the full power directly from Windows, offering a smooth and efficient Linux experience. Enhance your productivity with the flexibility and compatibility alongside your native Windows applications.",
- image: "/src/assets/wsl.svg",
- hashes: {
- MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
- SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
- SHA256:
- "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
- SHA512:
- "kFJrYlvyVlnqBMGpjRFNWskHzr1Bdv9VTOrqV9HogAspOWpCAzRDEsPiOMMJ1qle",
- },
- downloadURL:
- "https://www.microsoft.com/store/productId/9N1M7Q4F1KQF?ocid=pdpshare",
- enableDownloadCounter: false,
- downloadsCount: null,
+ downloadURL: "https://hub.docker.com/u/athenaos",
+ enableDownloadCounter: false,
+ downloadsCount: null,
+ },
+ {
+ id: "wsl",
+ title: "WSL Image",
+ description:
+ "Integrate seamlessly into your Windows environment! Enjoy the full power directly from Windows, offering a smooth and efficient Linux experience. Enhance your productivity with the flexibility and compatibility alongside your native Windows applications.",
+ image: "/src/assets/wsl.svg",
+ hashes: {
+ MD5: "7HFEJeGYbuXwkfMGy3yXAJhARt08gyzxCOgtDAJKiDpHNhnX2VA9LQ7O99a36734",
+ SHA1: "hg9qMB4356v24ERAn7Bx5dZoHuHNsQ57ibxlG0OH1JJUcBWbojA4aRNEuAFUvMmi",
+ SHA256:
+ "5eb9dc96cccbdfe7610d3cbced1bd6ee89b5acdfc83ffee1f06e6d02b058390c",
+ SHA512:
+ "kFJrYlvyVlnqBMGpjRFNWskHzr1Bdv9VTOrqV9HogAspOWpCAzRDEsPiOMMJ1qle",
},
- // ... other items (you can repeat this structure for multiple installers)
- ];
\ No newline at end of file
+ downloadURL:
+ "https://www.microsoft.com/store/productId/9N1M7Q4F1KQF?ocid=pdpshare",
+ enableDownloadCounter: false,
+ downloadsCount: null,
+ },
+ // ... other items (you can repeat this structure for multiple installers)
+];
diff --git a/src/pages/builder/_[page]/index.astro b/src/pages/builder/_[page]/index.astro
deleted file mode 100644
index 34607a2..0000000
--- a/src/pages/builder/_[page]/index.astro
+++ /dev/null
@@ -1,43 +0,0 @@
----
-import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
-import BuilderTable from "@components/builder-table.astro";
-
-export async function getStaticPaths() {
- const itemsPerPage = 100;
- let currentPage = 1;
- const response = await fetch(
- `${import.meta.env.STRAPI_URL}/api/builders?pagination[page]=${currentPage}&pagination[pageSize]=${itemsPerPage}&sort[1]=package_name:asc`,
- {
- headers: {
- Authorization: `Bearer ${import.meta.env.STRAPI_READONLY_TOKEN}`,
- "Content-Type": "application/json",
- },
- }
- );
- const apiResponse = await response.json();
-
- let totalPages = apiResponse.meta.pagination.pageCount;
- let params = Array.from({
- length: +totalPages,
- }).map((_, page) => {
- return { params: { page: page + 1 } };
- });
-
- return params;
-}
-
-let { page } = Astro.params;
----
-
-
-
-
-
-
diff --git a/src/pages/builder/index.astro b/src/pages/builder/index.astro
index cc8758a..dcf894c 100755
--- a/src/pages/builder/index.astro
+++ b/src/pages/builder/index.astro
@@ -7,7 +7,7 @@ import BuilderTable from "@components/builder-table.astro";
frontmatter={{ title: "Builder", tableOfContents: false }}
hasSidebar={false}
>
-
+
diff --git a/src/pages/packages/index.astro b/src/pages/packages/index.astro
index a6ef4bf..b1fef82 100644
--- a/src/pages/packages/index.astro
+++ b/src/pages/packages/index.astro
@@ -7,7 +7,7 @@ import PackageTable from "@components/package-table.astro";
frontmatter={{ title: "Packages", tableOfContents: false }}
hasSidebar={false}
>
-
+