Skip to content

Commit

Permalink
improving astro docs
Browse files Browse the repository at this point in the history
  • Loading branch information
AlfieJones committed Jun 10, 2024
1 parent b4c329d commit 3fffb65
Show file tree
Hide file tree
Showing 14 changed files with 790 additions and 18 deletions.
7 changes: 6 additions & 1 deletion apps/marketing-astro/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@ export default defineConfig({
// output: "hybrid",
adapter: vercel({
imageService: true,
})
}),
markdown: {
shikiConfig: {
theme: ''
}
}
});
1 change: 1 addition & 0 deletions apps/marketing-astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"dependencies": {
"@astrojs/check": "^0.7.0",
"@astrojs/markdoc": "^0.11.0",
"@astrojs/react": "^3.4.0",
"@astrojs/tailwind": "^5.1.0",
"@astrojs/vercel": "^7.6.0",
Expand Down
58 changes: 58 additions & 0 deletions apps/marketing-astro/src/components/docs/content.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
import type { RenderableTreeNodes } from "@markdoc/markdoc";
import Markdoc from "@markdoc/markdoc";
import DocsElement, { type Component, type Element } from "./element.astro";
import { HTMLString, isHTMLString } from "astro/runtime/server/index.js";
interface Props {
node: RenderableTreeNodes;
components?: Record<string, Component>;
}
const { node, components } = Astro.props;
function renderer(node: RenderableTreeNodes): Element[] {
if (isHTMLString(node)) {
return [{ type: "text", content: node as HTMLString }];
} else if (typeof node === "string" || typeof node === "number") {
return [{ type: "text", content: String(node) }];
} else if (
node === null ||
typeof node !== "object" ||
!Markdoc.Tag.isTag(node)
) {
return [{ type: "text", content: "" }];
}
const children = node.children.flatMap((child) => {
return renderer(child);
});
if (node.name in (components || {}))
return [
{
type: "component",
Component: components![node.name],
props: node.attributes,
children,
},
];
return [
{
type: "component",
Component: node.name,
props: node.attributes,
children,
},
];
}
const elements: Element[] = renderer(node);
---

{
elements.map((element) => {
return <DocsElement {element} />;
})
}
38 changes: 38 additions & 0 deletions apps/marketing-astro/src/components/docs/element.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
import type { HTMLString } from "astro/runtime/server/index.js";
export type Component = (props: Record<string, any>) => any;
export type Element = ({
children?: Element[];
type: "component" | "text";
} & (
| {
type: "component";
Component: Component | string;
props?: Record<string, any>;
}
| {
type: "text";
content: HTMLString | string;
}
));
interface Props {
element: Element;
}
const { element } = Astro.props;
---

{
element.type === "component" ? (
<element.Component {...element.props}>
{element.children?.map((child) => (
<Astro.self element={child} />
))}
</element.Component>
) : (
element.content
)
}
15 changes: 15 additions & 0 deletions apps/marketing-astro/src/components/schema/callout.markdoc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { component } from "@astrojs/markdoc/config";

const Callout = {
render: component("./src/components/callout.astro"),
children: ["paragraph", "tag", "list"],
attributes: {
type: {
type: String,
default: "note",
matches: ["check", "error", "note", "warning"],
},
},
};

export default Callout;
86 changes: 86 additions & 0 deletions apps/marketing-astro/src/components/schema/fence.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
import { Code } from "astro:components";
import Button from "../button.astro";
import ClipboardDocumentCheckIcon from "@heroicons/react/24/solid/ClipboardDocumentCheckIcon";
import ClipboardDocumentIcon from "@heroicons/react/24/solid/ClipboardDocumentIcon";
interface Props {
code: string;
lang: any;
title: string;
}
const { code, lang, title } = Astro.props;
---

<div class="flex flex-col rounded-lg overflow-hidden mt-4">
<div
class="flex items-center py-0.5 justify-between w-full text-sm text-on-surface bg-surface-container-high"
>
<div class="flex gap-1 ml-2 w-12">
{
Array.from({ length: 3 }).map((_, i) => (
<div class="bg-on-surface-variant/20 w-3 rounded-full h-3" />
))
}
</div>
<span>{title}</span>
<div class="w-12 flex items-end justify-center">
<!-- @ts-ignore -->
<Button
data-clipboard-text={code}
size="icon"
variant="ghost"
aria-label="Copy code"
data-coppied="false"
class="relative group !w-8 !h-8 mr-1 flex items-center justify-center text-on-surface-variant hover:text-on-surface"
>
<ClipboardDocumentIcon
className="w-6 h-6 group-data-[coppied='true']:hidden"
/>

<ClipboardDocumentCheckIcon
className="w-6 h-6 text-green-500 group-data-[coppied='false']:hidden"
/>
</Button>
</div>
</div>
<Code
themes={{
light: "light-plus",
dark: "dark-plus",
}}
class="px-4 pt-4 pb-10"
{code}
{lang}
/>
</div>

<script>
const btns = document.querySelectorAll("[data-clipboard-text]");

btns.forEach((btn) => {
btn.addEventListener("click", async (e) => {
const text = btn.getAttribute("data-clipboard-text")!;
await navigator.clipboard.writeText(text);
btn.setAttribute("data-coppied", "true");
setTimeout(() => {
btn.setAttribute("data-coppied", "false");
}, 3000);
});
});
</script>

<style is:global>
.astro-code {
background-color: rgba(var(--color-surface-container-low) / 1) !important;
}
.dark .astro-code,
.dark .astro-code span {
color: var(--shiki-dark) !important;
/* Optional, if you also want font styles */
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
</style>
18 changes: 18 additions & 0 deletions apps/marketing-astro/src/components/schema/fence.markdoc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Node } from "@markdoc/markdoc";
import { Markdoc } from "@astrojs/markdoc/config";

const FenceComponent = {
attributes: {},
transform: (node: Node) => {
const lang = node.attributes.language.split(".").at(-1);
const code = node.attributes.content;
const title =
node.attributes.language === "bash"
? "Terminal"
: node.attributes.language;

return new Markdoc.Tag("fence", { lang, code, title }, []);
},
};

export default FenceComponent;
39 changes: 39 additions & 0 deletions apps/marketing-astro/src/components/schema/heading.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
import type { HTMLAttributes } from "astro/types";
interface Props extends HTMLAttributes<"h1"> {
level: number;
}
const { level, id, ...rest } = Astro.props;
const Component = `h${level}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
---

<Component class="scroll-mt-20" {id} {...rest}>
<a
href={`#${id}`}
class="group text-inherit no-underline hover:text-inherit not-prose"
>
<div
class="absolute -ml-7 mt-1 hidden w-10 opacity-0 transition group-hover:opacity-100 md:block lg:z-10 xl:-ml-9"
>
<div
class="group/anchor block h-5 w-5 rounded-lg ring-1 ring-inset bg-surface-container-high ring-outline hover:bg-surface-container-highest"
>
<svg
viewBox="0 0 20 20"
fill="none"
stroke-linecap="round"
aria-hidden="true"
class="h-5 w-5 stroke-on-surface-variant transition group-hover/anchor:stroke-on-surface"
>
<path
d="m6.5 11.5-.964-.964a3.535 3.535 0 1 1 5-5l.964.964m2 2 .964.964a3.536 3.536 0 0 1-5 5L8.5 13.5m0-5 3 3"
></path>
</svg>
</div>
</div>
<slot />
</a>
</Component>
30 changes: 30 additions & 0 deletions apps/marketing-astro/src/components/schema/heading.markdoc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Markdoc, { type Config, type Node } from "@markdoc/markdoc";

function generateID(children: any, attributes: any) {
if (attributes.id && typeof attributes.id === "string") {
return attributes.id;
}
return children
.filter((child: any) => typeof child === "string")
.join(" ")
.replace(/[?]/g, "")
.replace(/\s+/g, "-")
.toLowerCase();
}

const Heading = {
...Markdoc.nodes.heading,
transform(node: Node, config: Config) {
const base = Markdoc.nodes.heading.transform?.(node, config) as any;
base.attributes.id = generateID(base.children, base.attributes);

if (base.name === "h1") {
return base;
}

base.attributes.level = base.name.replace("h", "");
return base;
},
};

export default Heading;
21 changes: 21 additions & 0 deletions apps/marketing-astro/src/components/schema/tab.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
import { Tabs as TabRoot, TabsList, TabsTrigger } from "@pixeleye/ui/src/tabs";
interface Props {
labeledByID: string;
id: string;
initial?: boolean;
}
const { labeledByID, id, initial } = Astro.props;
---

<div
role="tabpanel"
id={id}
aria-labelledby={labeledByID}
hidden={!initial}
class="mt-2 ring-offset-surface focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
>
<slot />
</div>
Loading

0 comments on commit 3fffb65

Please sign in to comment.