Skip to content

Commit

Permalink
--wip-- [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
Fryuni committed Oct 1, 2024
1 parent 5ebff05 commit 354948d
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 82 deletions.
3 changes: 2 additions & 1 deletion examples/request-nanostores/astro.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { defineConfig } from 'astro/config';
import preact from '@astrojs/preact';
import requestNanostores from '@inox-tools/request-nanostores';
import portalGun from '@inox-tools/portal-gun';

import node from '@astrojs/node';

// https://astro.build/config
export default defineConfig({
// Enable many frameworks to support all different kinds of components.
integrations: [preact(), requestNanostores()],
integrations: [preact(), requestNanostores(), portalGun()],
compressHTML: false,
output: 'server',
adapter: node({
Expand Down
1 change: 1 addition & 0 deletions examples/request-nanostores/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@astrojs/node": "^8.3.4",
"@astrojs/preact": "^3.5.3",
"@inox-tools/request-nanostores": "workspace:^",
"@inox-tools/portal-gun": "workspace:^",
"@nanostores/preact": "^0.5.2",
"astro": "^4.15.9",
"nanostores": "^0.11.3",
Expand Down
12 changes: 11 additions & 1 deletion examples/request-nanostores/src/components/AddToCartForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,15 @@ export default function AddToCartForm({ item, children }: Props) {
addCartItem(item);
}

return <form onSubmit={addToCart}>{children}</form>;
return (
<>
<portal to="header">
<p>Adding to the header</p>
</portal>
<portal to="head">
<meta name="injector" content="preact element" />
</portal>
<form onSubmit={addToCart}>{children}</form>;
</>
);
}
140 changes: 71 additions & 69 deletions examples/request-nanostores/src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ const { title } = Astro.props;
<meta name="generator" content={Astro.generator} />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>{title}</title>
<link as="portal" rel="head" />
</head>
<body>
<header>
<portal name="header"></portal>
<nav>
<a href="/" class="nav-header"
><span style="color: var(--astro-blue)">Astro</span> storefront</a
Expand All @@ -30,83 +32,83 @@ const { title } = Astro.props;
<slot />
<CartFlyout client:load />
</body>
</html>

<style is:global>
:root {
--font-family: system-ui, sans-serif;
--font-size-base: clamp(1rem, 0.34vw + 0.91rem, 1.19rem);
--font-size-lg: clamp(1.2rem, 0.7vw + 1.2rem, 1.5rem);
--font-size-xl: clamp(2rem, 1.75vw + 1.35rem, 2.75rem);
<style is:global>
:root {
--font-family: system-ui, sans-serif;
--font-size-base: clamp(1rem, 0.34vw + 0.91rem, 1.19rem);
--font-size-lg: clamp(1.2rem, 0.7vw + 1.2rem, 1.5rem);
--font-size-xl: clamp(2rem, 1.75vw + 1.35rem, 2.75rem);

--color-text: hsl(12, 5%, 4%);
--color-bg: hsl(17, 20%, 97%);
--color-bg-2: hsl(17, 20%, 94%);
--color-bg-3: hsl(17, 20%, 88%);
--astro-blue: #4f39fa;
--astro-pink: #da62c4;
--color-text: hsl(12, 5%, 4%);
--color-bg: hsl(17, 20%, 97%);
--color-bg-2: hsl(17, 20%, 94%);
--color-bg-3: hsl(17, 20%, 88%);
--astro-blue: #4f39fa;
--astro-pink: #da62c4;

--content-max-width: 90ch;
--nav-height: clamp(2.44rem, 2.38vw + 1.85rem, 3.75rem);
}
--content-max-width: 90ch;
--nav-height: clamp(2.44rem, 2.38vw + 1.85rem, 3.75rem);
}

h1 {
font-size: var(--font-size-xl);
}
h1 {
font-size: var(--font-size-xl);
}

button {
border: none;
color: var(--astro-blue);
border: 2px solid var(--astro-blue);
transition:
color 0.2s,
background-color 0.2s;
background-color: transparent;
padding: 0.4rem 0.8rem;
border-radius: 0.4rem;
font-family: var(--font-family);
font-size: var(--font-size-base);
font-weight: bold;
cursor: pointer;
}
button {
border: none;
color: var(--astro-blue);
border: 2px solid var(--astro-blue);
transition:
color 0.2s,
background-color 0.2s;
background-color: transparent;
padding: 0.4rem 0.8rem;
border-radius: 0.4rem;
font-family: var(--font-family);
font-size: var(--font-size-base);
font-weight: bold;
cursor: pointer;
}

button:hover {
background-color: var(--astro-blue);
color: white;
}
</style>
button:hover {
background-color: var(--astro-blue);
color: white;
}
</style>

<style>
html {
font-family: var(--font-family);
font-size: var(--font-size-base);
color: var(--color-text);
background-color: var(--color-bg);
}
<style>
html {
font-family: var(--font-family);
font-size: var(--font-size-base);
color: var(--color-text);
background-color: var(--color-bg);
}

body {
margin: 0;
}
body {
margin: 0;
}

header {
background: var(--color-bg-2);
}
header {
background: var(--color-bg-2);
}

nav {
max-width: var(--content-max-width);
height: var(--nav-height);
margin: auto;
padding-inline: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
nav {
max-width: var(--content-max-width);
height: var(--nav-height);
margin: auto;
padding-inline: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}

.nav-header,
.nav-header:visited {
font-size: var(--font-size-base);
font-weight: bold;
color: inherit;
text-decoration: none;
}
</style>
.nav-header,
.nav-header:visited {
font-size: var(--font-size-base);
font-weight: bold;
color: inherit;
text-decoration: none;
}
</style>
</html>
14 changes: 12 additions & 2 deletions packages/portal-gun/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,14 @@
"dependencies": {
"@inox-tools/utils": "workspace:^",
"astro-integration-kit": "catalog:",
"debug": "catalog:"
"debug": "catalog:",
"rehype": "catalog:",
"unist-util-map": "catalog:",
"unist-util-visit": "catalog:"
},
"devDependencies": {
"@inox-tools/astro-tests": "workspace:",
"@types/hast": "catalog:",
"@types/node": "catalog:",
"@vitest/ui": "catalog:",
"jest-extended": "catalog:",
Expand All @@ -49,6 +53,12 @@
"vitest": "catalog:"
},
"peerDependencies": {
"astro": "catalog:lax"
"astro": "catalog:lax",
"preact": "*"
},
"peerDependenciesMeta": {
"preact": {
"optional": true
}
}
}
24 changes: 18 additions & 6 deletions packages/portal-gun/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import { defineIntegration } from 'astro-integration-kit';
import { createResolver, defineIntegration } from 'astro-integration-kit';
import { z } from 'astro/zod';
import { debug } from './internal/debug.js';

export default defineIntegration({
name: '@inox-tools/portal-gun',
optionsSchema: z.never().optional(),
setup() {
// TODO: Implement this
},
name: '@inox-tools/portal-gun',
optionsSchema: z.never().optional(),
setup() {
const { resolve } = createResolver(import.meta.url);

return {
hooks: {
'astro:config:setup': (params) => {
debug('Injecting middleware');
params.addMiddleware({
order: 'pre',
entrypoint: resolve('./runtime/middleware.js'),
});
},
},
};
},
});
63 changes: 63 additions & 0 deletions packages/portal-gun/src/runtime/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { MiddlewareHandler } from 'astro';
import { rehype } from 'rehype';
import type * as hast from 'hast';
import * as visitor from 'unist-util-visit';
import { debug } from '../internal/debug.js';

const processor = rehype();

export const onRequest: MiddlewareHandler = async (_, next) => {
const response = await next();
if (response.headers.get('content-type')?.includes('text/html') !== true) {
return response;
}

const body = await response.text();
const tree = processor.parse(body);

const portalContents = new Map<string, hast.ElementContent[]>();

visitor.visit(tree, 'element', (node, index, parent) => {
if (node.tagName !== 'portal') return visitor.CONTINUE;

const target = node.properties?.to;
if (typeof target !== 'string') return visitor.CONTINUE;

debug(`Sending ${node.children.length} children to portal ${target}`);

const children = portalContents.get(target) ?? [];
children.push(...node.children);
portalContents.set(target, children);

if (parent && index !== undefined) {
parent.children.splice(index, 1);

// Continue to the same index, which is now the following element
return [visitor.CONTINUE, index];
}
});

visitor.visit(tree, 'element', (node, index, parent) => {
if (!parent || index === undefined) return visitor.CONTINUE;
if (
!(node.tagName === 'portal' || (node.tagName === 'link' && node.properties?.as === 'portal'))
)
return visitor.CONTINUE;

let name = node.tagName === 'portal' ? node.properties?.name : node.properties?.rel;
if (Array.isArray(name)) {
name = name[0];
}
if (typeof name !== 'string') return visitor.CONTINUE;

const children = portalContents.get(name) ?? [];

debug(`Receiving ${children.length} children into portal ${name}`);

parent.children.splice(index, 1, ...children);
});

const newBody = processor.stringify(tree);

return new Response(newBody, response);
};
2 changes: 0 additions & 2 deletions packages/portal-gun/src/runtime/sample.ts

This file was deleted.

21 changes: 20 additions & 1 deletion packages/portal-gun/virtual.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,21 @@
declare module '@it-astro:portal-gun' {
type PortalAttrs = {
to?: string;
name?: string;
children?: any;
};

declare namespace JSX {
interface IntrinsicElements {
portal: PortalAttrs;
}
}

import 'preact';

declare module 'preact' {
export namespace JSX {
export interface IntrinsicElements {
portal: PortalAttrs;
}
}
}
Loading

0 comments on commit 354948d

Please sign in to comment.