Skip to content

Commit

Permalink
feat: make Layout setting cumulative
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The `Layout` setting cannot be overriden anymore because it's now cumulative, see:
 - https://vike.dev/Layout#multiple-layouts
 - https://vike.dev/Layout#nested-layouts
  • Loading branch information
Blankeos committed Jun 18, 2024
1 parent 8affcc5 commit 33eadc7
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 10 deletions.
1 change: 1 addition & 0 deletions vike-solid/+config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const config = {
},
Layout: {
env: { server: true, client: true },
cumulative: true,
},
title: {
env: { server: true, client: true },
Expand Down
48 changes: 41 additions & 7 deletions vike-solid/renderer/getPageElement.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { PageContext } from "vike/types";
import { PageContextProvider } from "./PageContextProvider.js";
import { usePageContext } from "../hooks/usePageContext.js";
import type { JSX } from "solid-js";
import type { JSX, FlowComponent, FlowProps, ParentComponent } from "solid-js";
import { createComponent, createComputed, createEffect, createMemo, For } from "solid-js";
import { Dynamic } from "solid-js/web";
import type { Store } from "solid-js/store";
import { createStore, reconcile, unwrap, type Store } from "solid-js/store";

export function getPageElement(pageContext: Store<PageContext>): JSX.Element {
const page = (
Expand All @@ -18,11 +19,27 @@ export function getPageElement(pageContext: Store<PageContext>): JSX.Element {

function Layout(props: { children: JSX.Element }) {
const pageContext = usePageContext();
return (
<Dynamic component={pageContext.config.Layout ?? Passthrough}>
{props.children}
</Dynamic>
);

const [layouts, setLayouts] = createStore<FlowComponent[]>([]);

createComputed(() => {
setLayouts(reconcile(pageContext.config.Layout!));
})
const renderLayouts = (i: number = 0) => {
let item: FlowComponent = layouts[i];

if (!item) return props.children;

if (typeof item !== "function") item = Passthrough;

return createComponent(item, {
get children(): JSX.Element {
return renderLayouts(i + 1);
},
});
};

return renderLayouts();
}

function Page() {
Expand All @@ -37,3 +54,20 @@ function Page() {
function Passthrough(props: { children: JSX.Element }) {
return <>{props.children}</>;
}

/**
* Utility for tracking non-primitive values inside a store. (e.g. Arrays, Objects, Functions).
*
* Otherwise, your createMemo or createEffect won't run even if it actually changed.
*
* Reference: https://github.com/solidjs/solid/discussions/829#discussioncomment-2102335
*/
function deepTrack(store: any) {
for (const k in store) {
const value = store[k];
if (typeof value === "object") {
deepTrack(value);
}
}
}

7 changes: 5 additions & 2 deletions vike-solid/renderer/onRenderClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { hydrate, render } from "solid-js/web";
import { getHeadSetting } from "./getHeadSetting.js";
import type { OnRenderClientAsync, PageContextClient } from "vike/types";
import { getPageElement } from "./getPageElement.js";
import { createStore, reconcile } from "solid-js/store";
import { createStore, produce, reconcile } from "solid-js/store";

const [pageContextStore, setPageContext] = createStore<PageContextClient>(
{} as PageContextClient
Expand All @@ -17,6 +17,9 @@ let rendered = false;
const onRenderClient: OnRenderClientAsync = async (
pageContext
): ReturnType<OnRenderClientAsync> => {
// Reverse the layouts.
pageContext.config.Layout = pageContext.config.Layout?.toReversed() ?? [];

if (!rendered) {
// Dispose to prevent duplicate pages when navigating.
if (dispose) dispose();
Expand All @@ -35,7 +38,7 @@ const onRenderClient: OnRenderClientAsync = async (
} else {
// Client-side navigation

setPageContext(reconcile(pageContext));
setPageContext(pageContext);

const title = getHeadSetting("title", pageContext) || "";
const lang = getHeadSetting("lang", pageContext) || "en";
Expand Down
3 changes: 3 additions & 0 deletions vike-solid/renderer/onRenderHtml.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ checkVikeVersion();
const onRenderHtml: OnRenderHtmlAsync = async (
pageContext
): ReturnType<OnRenderHtmlAsync> => {
// Reverse the layouts.
pageContext.config.Layout = pageContext.config.Layout?.toReversed() ?? [];

const title = getHeadSetting("title", pageContext);
const favicon = getHeadSetting("favicon", pageContext);
const lang = getHeadSetting("lang", pageContext) || "en";
Expand Down
5 changes: 4 additions & 1 deletion vike-solid/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
export type { Component } from "solid-js";

import type { JSX } from "solid-js";
import type { Component, JSX } from "solid-js";

type Page = () => JSX.Element;

declare global {
namespace Vike {
interface ConfigResolved {
Layout?: Array<Component>;
}
interface PageContext {
// Page is undefined in onRenderHtml() when setting the `ssr` config flag to `false`
Page?: Page;
Expand Down

0 comments on commit 33eadc7

Please sign in to comment.