Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"devDependencies": {
"@changesets/cli": "^2.29.4",
"@nothing-but/node-resolve-ts": "^1.0.1",
"@solidjs/start": "^1.1.4",
"@solidjs/web": "2.0.0-beta.10",
"@types/jsdom": "^21.1.7",
"@types/node": "^22.15.31",
"@typescript-eslint/eslint-plugin": "^8.34.0",
Expand All @@ -52,9 +52,8 @@
"remark-gfm": "^4.0.1",
"solid-js": "2.0.0-beta.10",
"typescript": "^5.8.3",
"vinxi": "^0.5.7",
"vite": "^6.3.5",
"vite-plugin-solid": "^2.11.6",
"vite-plugin-solid": "3.0.0-next.5",
"vitest": "^2.1.9"
},
"packageManager": "pnpm@10.33.2",
Expand Down
4,221 changes: 351 additions & 3,870 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
"tailwindcss": "3.3.3",
"tailwindcss-dir": "^4.0.0",
"vite": "^8.0.8",
"vite-plugin-solid": "^2.11.12"
"vite-plugin-solid": "3.0.0-next.5"
},
"dependencies": {
"@solidjs/web": "2.0.0-beta.10",
"@solid-primitives/clipboard": "workspace:^",
"@solid-primitives/event-bus": "workspace:^",
"@solid-primitives/event-listener": "workspace:^",
Expand All @@ -39,8 +40,8 @@
"@solid-primitives/scroll": "workspace:^",
"@solid-primitives/tween": "workspace:^",
"@solid-primitives/utils": "workspace:^",
"@tanstack/solid-router": "^1.168.16",
"@tanstack/solid-start": "^1.167.28",
"@tanstack/solid-router": "^2.0.0-beta.17",
"@tanstack/solid-start": "^2.0.0-beta.17",
"clsx": "^2.0.0",
"fuse.js": "^7.0.0",
"rehype-sanitize": "^6.0.0",
Expand Down
2 changes: 1 addition & 1 deletion site/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isServer } from "solid-js/web";
import { isServer } from "@solidjs/web";
import type { PackageData, PackageListItem } from "./types.js";

const GEN_DIR = "_generated";
Expand Down
2 changes: 1 addition & 1 deletion site/src/client.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { debounce } from "@solid-primitives/scheduled";
import { hydrate } from "solid-js/web";
import { hydrate } from "@solidjs/web";
import { hydrateStart, StartClient } from "@tanstack/solid-start/client";

// Primitives/Table.tsx produces a lot of hydration warnings in development mode.
Expand Down
37 changes: 2 additions & 35 deletions site/src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,4 @@
// TEMP: stubbed during Solid 2 migration.
import { type Component } from "solid-js";

const Footer: Component = () => {
return (
<footer class="mt-10 bg-[#F3F5F7] dark:bg-slate-800/50">
<div class="prose mx-auto max-w-[864px] p-4 py-8 leading-7">
<p class="text-center">
This site is built with{" "}
<a class="text-link" href="https://www.solidjs.com" target="_blank">
SolidJS
</a>
,{" "}
<a
class="text-link"
href="https://tanstack.com/start/latest/docs/framework/solid/overview"
target="_blank"
>
TanStack Start for Solid
</a>
, and best of all ...{" "}
<span class="whitespace-nowrap">
<a
class="text-link"
href="https://github.com/solidjs-community/solid-primitives"
target="_blank"
>
Solid Primitives
</a>
</span>
!
</p>
</div>
</footer>
);
};

const Footer: Component = () => null;
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mocked this for now. Can revert after

export default Footer;
273 changes: 8 additions & 265 deletions site/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,271 +1,14 @@
import {
type Accessor,
type Component,
createEffect,
createMemo,
createSignal,
untrack,
onCleanup,
} from "solid-js";
import { makeEventListener } from "@solid-primitives/event-listener";
import { isMobile, isSafari } from "@solid-primitives/platform";
import { createScrollPosition } from "@solid-primitives/scroll";
import { defer } from "@solid-primitives/utils";
import Dismiss from "solid-dismiss";
import { pageWidthClass } from "~/constants.js";
import Hamburger from "../Icons/Hamburger.js";
import SearchBtn from "../Search/SearchBtn.js";
import NavMenu from "./NavMenu.js";
import ThemeBtn from "./ThemeBtn.js";
import clsx from "clsx";
import { createTween } from "@solid-primitives/tween";
import SearchModal from "../Search/SearchModal.js";
import { Link, useLocation } from "@tanstack/solid-router";
// TEMP: stubbed during Solid 2 migration to bypass workspace packages that
// still use Solid 1 APIs (onMount, solid-js/web, etc.). Re-enable once those
// packages have been migrated.
import { type Accessor, type Component } from "solid-js";

export const [isScrollEnabled, setScrollEnabled] = createSignal(false);

const [signalOverridingShadow, setSignalOverridingShadow] = createSignal<Accessor<boolean>>();
const isOverridingShadow = () => signalOverridingShadow()?.() ?? false;

export function overrideShadow(signal: Accessor<boolean>) {
setSignalOverridingShadow(() => signal);
onCleanup(() => setSignalOverridingShadow(p => (p === signal ? undefined : p)));
}

const OPEN_NAV_DURATION = 500;
export const HEADER_HEIGHT = 60;
export const PRIMITIVE_PAGE_PADDING_TOP = 140;

const Header: Component = () => {
const windowScroll = createScrollPosition(() => window);
const [isSearchOpen, setIsSearchOpen] = createSignal(false);
const [isNavOpen, setIsNavOpen] = createSignal(false);
const [from, setFrom] = createSignal(0);
const easeInOutCubic = (x: number): number => {
return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
};
const tweenedValue = createTween(from, { ease: easeInOutCubic, duration: OPEN_NAV_DURATION });
const location = useLocation();
let gradientOverflowLeftBG!: HTMLDivElement;
let gradientOverflowRightBG!: HTMLDivElement;
let menuButtonSearch!: HTMLButtonElement;
let menuButtonNavMenu!: HTMLButtonElement;
let headerOpaqueBg!: HTMLDivElement;
let headerSolidBg!: HTMLDivElement;
let headerOpaqueBgContainer!: HTMLDivElement;
let headerBottomGradientBorder!: HTMLDivElement;
let headerShadow!: HTMLDivElement;
let navMenu!: HTMLDivElement;
let navMenuHeight = 0;

// Issue is that when safari scroll 'rubberbands' at top of page there's a big white background that temporary covers header.
// It's caused by header elements, one containing blur in backdrop-filter and other containing solid white background.
if (isSafari && !isMobile) {
const checkScroll = () => {
if (!isNavOpen() && !isSearchOpen()) {
if (window.scrollY > 2) {
headerOpaqueBg.style.display = "";
headerSolidBg.style.display = "";
} else {
headerOpaqueBg.style.display = "none";
headerSolidBg.style.display = "none";
}
}
};

createEffect(() => {
if (isScrollEnabled()) {
untrack(checkScroll);
makeEventListener(window, "scroll", checkScroll, { passive: true });
}
});
}

createEffect(
defer(tweenedValue, tweenedValue => {
navMenu.style.transform = `translateY(${-navMenuHeight + tweenedValue}px)`;
headerBottomGradientBorder.style.transform = `translateY(${tweenedValue}px)`;
headerShadow.style.transform = `translateY(${tweenedValue}px)`;
headerOpaqueBg.style.transform = `translateY(${-navMenuHeight + tweenedValue}px)`;
gradientOverflowLeftBG.style.transform = `translateY(${-navMenuHeight + tweenedValue}px)`;
gradientOverflowRightBG.style.transform = `translateY(${-navMenuHeight + tweenedValue}px)`;
}),
);

createEffect(
defer(isNavOpen, isNavOpen => {
if (isNavOpen) {
navMenuHeight = navMenu.clientHeight;

headerOpaqueBg.style.height = `${navMenuHeight + HEADER_HEIGHT}px`;
gradientOverflowLeftBG.style.height = `${navMenuHeight + 220}px`;
gradientOverflowRightBG.style.height = `${navMenuHeight + 220}px`;
gradientOverflowLeftBG.style.setProperty(
"--header-gradient-overflow-start",
`${navMenuHeight + 60}px`,
);
gradientOverflowRightBG.style.setProperty(
"--header-gradient-overflow-start",
`${navMenuHeight + 60}px`,
);
headerOpaqueBgContainer.style.height = `${navMenuHeight + HEADER_HEIGHT}px`;
headerOpaqueBg.style.transform = `translateY(${-navMenuHeight}px)`;
gradientOverflowLeftBG.style.transform = `translateY(${-navMenuHeight}px)`;
gradientOverflowRightBG.style.transform = `translateY(${-navMenuHeight}px)`;
headerOpaqueBg.style.top = "-1px";
headerOpaqueBgContainer.style.top = "1px";

requestAnimationFrame(() => {
setFrom(navMenuHeight);
});
return;
}
setFrom(0);
}),
);

createEffect(
defer(
createMemo(() => location().hash),
() => setIsNavOpen(false),
),
);

return (
<>
<header
class="fixed left-0 right-0 top-0 z-10 h-[60px]"
classList={{
"md:z-[1001]": isSearchOpen(),
}}
>
<div class="relative h-full">
<div
class={`${pageWidthClass} mx-auto flex h-full w-full items-center justify-between gap-2 px-4 sm:px-8`}
>
<div
class={`${pageWidthClass} box-shadow-[var(--header-box-shadow)] -z-1 absolute bottom-0 left-0 right-0 top-0 mx-auto w-full opacity-0 transition-opacity duration-200`}
classList={{
// show the shadow when scrolled down or when the nav menu is open,
// but not when the search modal is open or when the table-sub-nav is shown
"opacity-100":
isNavOpen() ||
(!isSearchOpen() &&
!isOverridingShadow() &&
windowScroll.y > PRIMITIVE_PAGE_PADDING_TOP + 50),
}}
ref={headerShadow}
>
<div
class="box-shadow-[var(--header-big-box-shadow)] -z-1 duration-250 h-full opacity-0 transition-opacity"
classList={{ "opacity-100": isNavOpen() }}
/>
</div>
<Link to="/">
<img
class="hidden h-[28px] sm:block sm:h-[40px] dark:hidden"
src="/img/solid-primitives-logo.svg"
alt=""
/>
<img
class="hidden h-[28px] sm:h-[40px] dark:sm:block"
src="/img/solid-primitives-dark-logo.svg"
alt=""
/>
<img
class="h-[28px] sm:hidden sm:h-[40px] dark:hidden"
src="/img/solid-primitives-stacked-logo.svg"
alt=""
/>
<img
class="hidden h-[28px] sm:!hidden sm:h-[40px] dark:block"
src="/img/solid-primitives-stacked-dark-logo.svg"
alt=""
/>
</Link>
<nav>
<ul class="flex items-center gap-3">
<li class="transition" classList={{ "opacity-0": isSearchOpen() }}>
<SearchBtn ref={menuButtonSearch} />
</li>
<li>
<ThemeBtn />
</li>
<li>
<Hamburger active={isNavOpen()} ref={menuButtonNavMenu} />
</li>
</ul>
</nav>
</div>
<SearchModal
menuButton={menuButtonSearch}
open={isSearchOpen()}
setOpen={setIsSearchOpen}
/>
</div>
{/* fixes weird shimmering top dark shadow blur during openNavMenu animation in Chrome */}
{/* Still shows up in Safari, no fix */}
<div
class="-z-1 pointer-events-none absolute inset-0 overflow-clip"
ref={headerOpaqueBgContainer}
>
<div
class="absolute inset-0 translate-y-[calc(-100%+60px)] bg-white/50 backdrop-blur-md dark:bg-[#293843]/70"
ref={headerOpaqueBg}
/>
</div>
<div
class="bg-page-main-bg z-1 absolute left-0 right-0 top-0 h-[1px]"
ref={headerSolidBg}
/>
<div
class={`${pageWidthClass} background-[var(--header-border-bottom)] duration-250 mx-auto h-[2px] opacity-0 transition-opacity`}
classList={{ "opacity-100": isOverridingShadow() && !isSearchOpen() }}
ref={headerBottomGradientBorder}
/>
<div class={`${pageWidthClass} relative top-[-2px] mx-auto overflow-clip`}>
<Dismiss
menuButton={menuButtonNavMenu}
open={isNavOpen}
setOpen={setIsNavOpen}
class="-translate-y-full"
animation={{
onEnter: (_, done) => {
setTimeout(done, OPEN_NAV_DURATION);
},
onExit: (_, done) => {
setTimeout(done, OPEN_NAV_DURATION);
},
}}
ref={navMenu}
>
<NavMenu onClose={() => setIsNavOpen(false)} />
</Dismiss>
</div>
</header>
<div class="-z-1 pointer-events-none fixed left-0 right-0 top-0 hidden transition md:flex">
{untrack(() => {
const Gradient = (props: { class?: string; ref: HTMLDivElement }) => (
<div
class={clsx(
props.class,
"h-[220px] flex-grow bg-[linear-gradient(to_bottom,var(--page-main-bg)_var(--header-gradient-overflow-start),transparent)]",
)}
style={{ "--header-gradient-overflow-start": "60px" }}
ref={props.ref}
/>
);
return (
<>
<Gradient class="-order-1" ref={gradientOverflowLeftBG} />
<div class={`${pageWidthClass} w-full flex-shrink-0 flex-grow`} />
<Gradient ref={gradientOverflowRightBG} />
</>
);
})}
</div>
</>
);
};
export const isScrollEnabled: Accessor<boolean> = () => true;
export const setScrollEnabled = (_v: boolean): void => {};
export function overrideShadow(_signal: Accessor<boolean>): void {}

const Header: Component = () => null;
export default Header;
Loading