Compare commits

...

3 Commits

Author SHA1 Message Date
Trisha Lim
e098cbb2b0 type fix 2025-03-28 12:52:15 +07:00
Trisha Lim
a5cb5c0b01 homepage lint fixes 2025-03-28 12:32:55 +07:00
Trisha Lim
f29fdedfa4 fix missing icon 2025-03-28 12:29:11 +07:00
18 changed files with 81 additions and 58 deletions

View File

@@ -0,0 +1,5 @@
---
"jazz-inspector": patch
---
fix missing icon

View File

@@ -2,6 +2,7 @@ import { clsx } from "clsx";
import Link from "next/link";
import { forwardRef } from "react";
import { Icon } from "./Icon";
import type { IconName } from "./Icon";
import { Spinner } from "./Spinner";
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
@@ -9,7 +10,7 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
size?: "sm" | "md" | "lg";
href?: string;
newTab?: boolean;
icon?: string;
icon?: IconName;
loading?: boolean;
loadingText?: string;
children?: React.ReactNode;

View File

@@ -113,6 +113,8 @@ const strokeWidths = {
"9xl": 1,
};
export type IconName = keyof typeof icons;
export function Icon({
name,
icon,
@@ -120,7 +122,7 @@ export function Icon({
className,
...svgProps
}: {
name?: string;
name?: IconName;
icon?: LucideIcon;
size?: keyof typeof sizes;
className?: string;

View File

@@ -1,6 +1,6 @@
import clsx from "clsx";
import { Card } from "../atoms/Card";
import { Icon } from "../atoms/Icon";
import { Icon, IconName } from "../atoms/Icon";
import { Prose } from "./Prose";
export function FeatureCard({
@@ -11,7 +11,7 @@ export function FeatureCard({
className,
}: {
label: React.ReactNode;
icon?: string;
icon?: IconName;
explanation?: React.ReactNode;
children?: React.ReactNode;
className?: string;

View File

@@ -13,12 +13,13 @@ import { usePathname } from "next/navigation";
import { ComponentType, ReactNode, useEffect, useState } from "react";
import { isActive } from "../../utils/nav";
import { Icon } from "../atoms/Icon";
import type { IconName } from "../atoms/Icon";
import { BreadCrumb } from "../molecules/Breadcrumb";
import { SocialLinks, SocialLinksProps } from "./SocialLinks";
type NavItemProps = {
href: string;
icon?: string;
icon?: IconName;
title: string;
firstOnRight?: boolean;
newTab?: boolean;
@@ -38,7 +39,7 @@ type NavProps = {
export type NavSection = {
name: string;
content: ReactNode;
icon: string;
icon: IconName;
};
function NavItem({
@@ -134,7 +135,11 @@ export function MobileNav({
sections,
themeToggle: ThemeToggle,
}: NavProps) {
const primarySection = {
const primarySection: {
name: string;
icon: IconName;
content: ReactNode;
} = {
name: "Menu",
icon: "menu",
content: (
@@ -254,7 +259,7 @@ export function MobileNav({
onClick={() => toggle(section.name)}
key={section.name}
>
<Icon name={section.icon} size="xs" />
{section.icon && <Icon name={section.icon} size="xs" />}
{section.name}
</button>
),

View File

@@ -227,7 +227,7 @@ const FileUploadIllustration = () => (
</div>
<div className=" w-[12rem] h-2 rounded-full overflow-hidden bg-stone-200 mt-3">
<div className="w-3/4 h-full bg-green-500"/>
<div className="w-3/4 h-full bg-green-500" />
</div>
<div className="w-[12rem] flex justify-between text-xs mt-1.5">
<p>Uploading...</p>
@@ -379,7 +379,8 @@ const reactExamples: Example[] = [
{
name: "File upload",
slug: "filestream",
description: "Upload different types of files, and show upload progress, file size, and type.",
description:
"Upload different types of files, and show upload progress, file size, and type.",
tech: [tech.react],
features: [features.fileUpload],
demoUrl: "https://file-upload-demo.jazz.tools",

View File

@@ -7,8 +7,7 @@ import { Fragment } from "react";
const title = "Status";
export const revalidate = 300
export const revalidate = 300;
export const metadata: Metadata = {
title,
@@ -40,7 +39,6 @@ interface DataRow {
p99Latency: number;
}
const query = async () => {
const res = await fetch("https://gcmp.grafana.net/api/ds/query", {
method: "POST",
@@ -99,9 +97,9 @@ const query = async () => {
}
const responseData = await res.json();
const byProbe: Record<string, DataRow> = {};
for (const frame of responseData.results.up.frames) {
const probe = startCase(frame.schema.fields[1].labels.probe);
byProbe[probe] = {
@@ -115,7 +113,6 @@ const query = async () => {
byProbe[probe].latencyOverTime = frame.data.values;
}
for (const frame of responseData.results.avg_latency.frames) {
const probe = startCase(frame.schema.fields[1].labels.probe);
byProbe[probe].avgLatency = frame.data.values[1];
@@ -123,7 +120,7 @@ const query = async () => {
for (const frame of responseData.results.p99_latency.frames) {
const probe = startCase(frame.schema.fields[1].labels.probe);
byProbe[probe].p99Latency = frame.data.values[1];
byProbe[probe].p99Latency = frame.data.values[1];
}
const byRegion = Object.entries(byProbe).reduce<

View File

@@ -1,7 +1,7 @@
"use client";
import { track } from "@vercel/analytics";
import { Button } from "gcmp-design-system/src/app/components/atoms/Button";
import { track } from '@vercel/analytics';
export function FakeGetStartedButton({ tier }: { tier: "starter" | "indie" }) {
return (

View File

@@ -60,7 +60,11 @@ export default function LatencyChart({ data }: Props) {
<figure className="flex items-stretch w-full gap-px justify-end">
<Tooltip>
<TooltipTrigger asChild>
<div className={cn("rounded-md grow hover:opacity-50 dark:bg-gray-900 bg-gray-200")} />
<div
className={cn(
"rounded-md grow hover:opacity-50 dark:bg-gray-900 bg-gray-200",
)}
/>
</TooltipTrigger>
<TooltipContent>
<p>

View File

@@ -88,7 +88,7 @@ export function Pricing() {
</ul>
</div>
<FakeGetStartedButton tier="starter"/>
<FakeGetStartedButton tier="starter" />
<p className="text-sm">No credit card required. Takes 20s.</p>
</div>
@@ -122,22 +122,18 @@ export function Pricing() {
</ListItem>
<ListItem icon={LucideDatabase}>
<span className="tabular-nums">100</span> GB storage incl.{" "}
<span className="text-sm">
(then $0.02 per GB)
</span>
<span className="text-sm">(then $0.02 per GB)</span>
</ListItem>
<ListItem icon={LucideCloudDownload}>
<span className="tabular-nums">20</span> GB egress/mo incl.{" "}
<span className="text-sm">
(then $0.1 per GB)
</span>
<span className="text-sm">(then $0.1 per GB)</span>
</ListItem>
<hr className="my-2 border-stone-200 dark:border-stone-800" />
<ListItem icon={LucideChevronsUp}>High-priority sync</ListItem>
</ul>
</div>
<FakeGetStartedButton tier="indie"/>
<FakeGetStartedButton tier="indie" />
<p className="text-sm">
One month free trial. Unlimited projects. Takes 1min.
@@ -169,12 +165,8 @@ export function Pricing() {
<ListItem icon={LucideUsers}>
Custom monthly active users
</ListItem>
<ListItem icon={LucideDatabase}>
Custom storage
</ListItem>
<ListItem icon={LucideCloudDownload}>
Custom egress/mo
</ListItem>
<ListItem icon={LucideDatabase}>Custom storage</ListItem>
<ListItem icon={LucideCloudDownload}>Custom egress/mo</ListItem>
<hr className="my-2 border-stone-200 dark:border-stone-800" />
<ListItem icon={LucideHandshake}>
Rapid integration & premium onboarding

View File

@@ -4,6 +4,8 @@ import { TableOfContents } from "@/components/docs/TableOfContents";
import { JazzNav } from "@/components/nav";
import { useTocItems } from "@/lib/TocContext";
import { clsx } from "clsx";
import type { IconName } from "gcmp-design-system/src/app/components/atoms/Icon";
import type { NavSection } from "gcmp-design-system/src/app/components/organisms/Nav";
export default function DocsLayout({
children,
@@ -14,11 +16,11 @@ export default function DocsLayout({
children: React.ReactNode;
nav?: React.ReactNode;
navName?: string;
navIcon?: string;
navIcon?: IconName;
}) {
const { tocItems } = useTocItems();
const navSections = [
const navSections: NavSection[] = [
{
name: navName || "Docs",
content: nav,

View File

@@ -9,8 +9,7 @@ import CollaborationPublic from "./CollaborationPublic.mdx";
const data = [
{
title: "Private",
description:
"By default, CoValues are visible only to you.",
description: "By default, CoValues are visible only to you.",
codeSample: CollaborationPrivate,
},
{
@@ -20,8 +19,7 @@ const data = [
},
{
title: "By Invitation",
description:
"Create links that allow anyone to join.",
description: "Create links that allow anyone to join.",
codeSample: CollaborationInvite,
},
];
@@ -34,7 +32,8 @@ export function CollaborationFeaturesSection() {
title="Making secure collaboration the default"
slogan={
<>
Every CoValue belongs to a <code>Group</code>, where you can assign roles to users to control access &mdash; all from the client.
Every CoValue belongs to a <code>Group</code>, where you can assign
roles to users to control access &mdash; all from the client.
</>
}
></SectionHeader>

View File

@@ -1,13 +1,19 @@
import CreateJazzApp from "@/components/home/CreateJazzApp.mdx";
import { H1 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { Icon } from "gcmp-design-system/src/app/components/atoms/Icon";
import { CopyButton } from "gcmp-design-system/src/app/components/molecules/CodeGroup";
import {
Icon,
type IconName,
} from "gcmp-design-system/src/app/components/atoms/Icon";
import { Kicker } from "gcmp-design-system/src/app/components/atoms/Kicker";
import { CopyButton } from "gcmp-design-system/src/app/components/molecules/CodeGroup";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
import Link from "next/link";
const features = [
const features: Array<{
title: string;
icon: IconName;
}> = [
{
title: "Instant updates",
icon: "instant",
@@ -53,7 +59,8 @@ export function HeroSection() {
<Prose size="lg" className="text-pretty max-w-2xl dark:text-stone-200">
<p>
Jazz gives you data without needing a database plus auth, permissions, files and multiplayer without needing a backend.
Jazz gives you data without needing a database plus auth,
permissions, files and multiplayer without needing a backend.
</p>
<p>
Do everything right from the frontend and ship better apps, faster.

View File

@@ -1,8 +1,8 @@
import { clsx } from "clsx";
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { H2 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { Kicker } from "gcmp-design-system/src/app/components/atoms/Kicker";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import CodeStepAction from "./CodeStepAction.mdx";
import CodeStepCloud from "./CodeStepCloud.mdx";
import CodeStepRender from "./CodeStepRender.mdx";
@@ -80,16 +80,16 @@ export function HowJazzWorksSection() {
return (
<div className="grid gap-8">
<div className="grid gap-3">
<Kicker>
How it works
</Kicker>
<Kicker>How it works</Kicker>
<H2>Build entire apps using only client-side code</H2>
</div>
<GappedGrid>
<Step
step={1}
description={"Describe your apps state with CoValues (\"collaborative values\"), your new cloud-synced building blocks."}
description={
'Describe your apps state with CoValues ("collaborative values"), your new cloud-synced building blocks.'
}
>
<Code fileName="schema.ts">
<CodeStepSchema />

View File

@@ -1,9 +1,14 @@
import type { IconName } from "gcmp-design-system/src/app/components/atoms/Icon";
import { FeatureCard } from "gcmp-design-system/src/app/components/molecules/FeatureCard";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
export function LocalFirstFeaturesSection() {
const features = [
const features: Array<{
title: string;
icon: IconName;
description: React.ReactNode;
}> = [
{
title: "Offline-first",
icon: "offline",
@@ -52,7 +57,8 @@ export function LocalFirstFeaturesSection() {
slogan={
<>
<p>
With cloud-synced local state, your data is kept on-device, and synced whenever possible.
With cloud-synced local state, your data is kept on-device, and
synced whenever possible.
</p>
</>
}

View File

@@ -68,9 +68,9 @@ export default function ProblemStatementSection() {
<strong>With users &amp; permissions built-in.</strong>
</p>
<p>
With completely <strong>app-independent infra,</strong> you get to focus on{" "}
<strong>building the app your users want.</strong> You'll notice
that <strong>90% of the work is now the UI.</strong>
With completely <strong>app-independent infra,</strong> you get to
focus on <strong>building the app your users want.</strong> You'll
notice that <strong>90% of the work is now the UI.</strong>
</p>
</Prose>
</div>

View File

@@ -14,9 +14,9 @@ export const products = [
},
{
name: "Hend",
description: "Learn languages naturally with interesting, compelling content tailored just for you.",
description:
"Learn languages naturally with interesting, compelling content tailored just for you.",
url: "https://hendapp.com",
imageUrl: "/hend.png",
}
},
];

View File

@@ -1,10 +1,12 @@
import { classNames } from "../utils.js";
import { ChevronDownIcon } from "./icons/chevron-down-icon.js";
import { DeleteIcon } from "./icons/delete-icon.js";
import { LinkIcon } from "./icons/link-icon.js";
const icons = {
chevronDown: ChevronDownIcon,
delete: DeleteIcon,
link: LinkIcon,
};
// copied from tailwind line height https://tailwindcss.com/docs/font-size
@@ -48,7 +50,7 @@ export function Icon({
className,
...svgProps
}: {
name?: string;
name?: keyof typeof icons;
size?: keyof typeof sizes;
className?: string;
} & React.SVGProps<SVGSVGElement>) {