Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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