Compare commits

...

23 Commits

Author SHA1 Message Date
James Ritchie efd77109d9 Copy updates 2025-11-21 16:42:17 +00:00
James Ritchie 158392f352 Simplify the Deploy blank state on dev 2025-11-21 15:23:59 +00:00
James Ritchie 4d0647a7bb Adds props for Github connect button 2025-11-21 14:36:22 +00:00
James Ritchie c1f822a22f Tabs hover state improvement 2025-11-21 13:48:08 +00:00
James Ritchie 87ae16b964 Storybook layout update 2025-11-21 13:47:57 +00:00
James Ritchie 4a6159a3d5 Better tab layout 2025-11-21 13:37:12 +00:00
James Ritchie bf288519d8 Removed unneeded div 2025-11-21 13:36:58 +00:00
James Ritchie a8513011d4 Improves the tab transition animation 2025-11-21 12:09:33 +00:00
James Ritchie fff74e1719 ClientTabs now mirror the Tabs component 2025-11-21 12:09:03 +00:00
James Ritchie cd629524ae Update storybook tabs layout 2025-11-21 12:08:33 +00:00
James Ritchie 86a7f0911d Remove unused styles 2025-11-10 14:45:35 +00:00
James Ritchie dd55ef67aa Update storybook tabs 2025-11-10 14:45:26 +00:00
James Ritchie 05439c955a update the outlet 2025-11-05 14:59:22 -08:00
James Ritchie 15f0d7a937 storybook update for the new style variants 2025-11-05 14:59:08 -08:00
James Ritchie aaad5f1a36 Adds new style variants to the tabs 2025-11-05 14:58:46 -08:00
James Ritchie 8a7b74c75e Tidy exports 2025-11-02 16:06:03 +00:00
James Ritchie dff6abc1a2 Remove unused component 2025-11-02 16:05:44 +00:00
James Ritchie d9a0638f34 typed imports 2025-11-02 16:05:35 +00:00
James Ritchie 1bf2b55f68 Show the 3 deploy options in tabs instead 2025-11-02 16:04:24 +00:00
James Ritchie 414dd6d635 Add GitHub step to deployments page onboarding 2025-11-02 15:15:02 +00:00
James Ritchie 50c9836cdc Make the onboarding steps container wider 2025-11-02 15:14:26 +00:00
James Ritchie b2a3fb1490 Separate hint from function 2025-11-02 15:14:05 +00:00
James Ritchie 6f6df7e475 Export function 2025-11-02 15:13:43 +00:00
7 changed files with 625 additions and 225 deletions
+150 -132
View File
@@ -52,6 +52,15 @@ import {
} from "./SetupCommands";
import { StepContentContainer } from "./StepContentContainer";
import { V4Badge } from "./V4Badge";
import { GitHubConnectionPrompt } from "~/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route";
import SegmentedControl from "./primitives/SegmentedControl";
import { useState } from "react";
import {
ClientTabs,
ClientTabsContent,
ClientTabsList,
ClientTabsTrigger,
} from "./primitives/ClientTabs";
export function HasNoTasksDev() {
return (
@@ -93,62 +102,7 @@ export function HasNoTasksDev() {
}
export function HasNoTasksDeployed({ environment }: { environment: MinimumEnvironment }) {
return (
<PackageManagerProvider>
<div>
<div className="mb-6 flex items-center justify-between border-b">
<div className="mb-2 flex items-center gap-2">
<EnvironmentIcon environment={environment} className="-ml-1 size-8" />
<Header1>Deploy your tasks to {environmentFullTitle(environment)}</Header1>
</div>
<div className="flex items-center">
<SimpleTooltip
button={
<LinkButton
variant="small-menu-item"
LeadingIcon={BookOpenIcon}
leadingIconClassName="text-blue-500"
to={docsPath("deployment/overview")}
/>
}
content="Deploy docs"
/>
<SimpleTooltip
button={
<LinkButton
variant="small-menu-item"
LeadingIcon={QuestionMarkCircleIcon}
leadingIconClassName="text-blue-500"
to={docsPath("troubleshooting#deployment")}
/>
}
content="Troubleshooting docs"
/>
<AskAI />
</div>
</div>
<StepNumber stepNumber="1a" title="Run the CLI 'deploy' command" />
<StepContentContainer>
<Paragraph spacing>
This will deploy your tasks to the {environmentFullTitle(environment)} environment. Read
the <TextLink to={docsPath("deployment/overview")}>full guide</TextLink>.
</Paragraph>
<TriggerDeployStep environment={environment} />
</StepContentContainer>
<StepNumber stepNumber="1b" title="Or deploy using GitHub Actions" />
<StepContentContainer>
<Paragraph spacing>
Read the <TextLink to={docsPath("github-actions")}>GitHub Actions guide</TextLink> to
get started.
</Paragraph>
</StepContentContainer>
<StepNumber stepNumber="2" title="Waiting for tasks to deploy" displaySpinner />
<StepContentContainer>
<Paragraph>This page will automatically refresh when your tasks are deployed.</Paragraph>
</StepContentContainer>
</div>
</PackageManagerProvider>
);
return <DeploymentOnboardingSteps />;
}
export function SchedulesNoPossibleTaskPanel() {
@@ -266,45 +220,7 @@ export function TestHasNoTasks() {
}
export function DeploymentsNone() {
const organization = useOrganization();
const project = useProject();
const environment = useEnvironment();
return (
<InfoPanel
icon={ServerStackIcon}
iconClassName="text-deployments"
title="Deploy for the first time"
panelClassName="max-w-full"
>
<Paragraph spacing variant="small">
There are several ways to deploy your tasks. You can use the CLI or a Continuous Integration
service like GitHub Actions. Make sure you{" "}
<TextLink href={v3EnvironmentVariablesPath(organization, project, environment)}>
set your environment variables
</TextLink>{" "}
first.
</Paragraph>
<div className="flex gap-3">
<LinkButton
to={docsPath("v3/cli-deploy")}
variant="docs/medium"
LeadingIcon={BookOpenIcon}
className="inline-flex"
>
Deploy with the CLI
</LinkButton>
<LinkButton
to={docsPath("v3/github-actions")}
variant="docs/medium"
LeadingIcon={BookOpenIcon}
className="inline-flex"
>
Deploy with GitHub actions
</LinkButton>
</div>
</InfoPanel>
);
return <DeploymentOnboardingSteps />;
}
export function DeploymentsNoneDev() {
@@ -313,46 +229,52 @@ export function DeploymentsNoneDev() {
const environment = useEnvironment();
return (
<div className="space-y-8">
<InfoPanel
icon={ServerStackIcon}
iconClassName="text-deployments"
title="Deploying tasks"
panelClassName="max-w-full"
>
<Paragraph spacing variant="small">
<>
<div className="mb-6 flex items-center justify-between border-b">
<div className="mb-2 flex items-center gap-2">
<EnvironmentIcon environment={environment} className="-ml-1 size-8" />
<Header1>Deploy your tasks</Header1>
</div>
<div className="flex items-center">
<SimpleTooltip
button={
<LinkButton
variant="small-menu-item"
LeadingIcon={BookOpenIcon}
leadingIconClassName="text-blue-500"
to={docsPath("deployment/overview")}
/>
}
content="Deploy docs"
/>
<SimpleTooltip
button={
<LinkButton
variant="small-menu-item"
LeadingIcon={QuestionMarkCircleIcon}
leadingIconClassName="text-blue-500"
to={docsPath("troubleshooting#deployment")}
/>
}
content="Troubleshooting docs"
/>
<AskAI />
</div>
</div>
<StepNumber stepNumber="" title="Switch to a deployed environment" />
<StepContentContainer className="mb-4 flex flex-col gap-4">
<Paragraph>
This is the Development environment. When you're ready to deploy your tasks, switch to a
different environment.
</Paragraph>
<Paragraph spacing variant="small">
There are several ways to deploy your tasks. You can use the CLI or a Continuous
Integration service like GitHub Actions. Make sure you{" "}
<TextLink href={v3EnvironmentVariablesPath(organization, project, environment)}>
set your environment variables
</TextLink>{" "}
first.
</Paragraph>
<div className="flex gap-3">
<LinkButton
to={docsPath("v3/cli-deploy")}
variant="docs/medium"
LeadingIcon={BookOpenIcon}
className="inline-flex"
>
Deploy with the CLI
</LinkButton>
<LinkButton
to={docsPath("v3/github-actions")}
variant="docs/medium"
LeadingIcon={BookOpenIcon}
className="inline-flex"
>
Deploy with GitHub actions
</LinkButton>
</div>
</InfoPanel>
<SwitcherPanel />
</div>
<EnvironmentSelector
organization={organization}
project={project}
environment={environment}
className="w-fit border border-charcoal-600 bg-secondary hover:border-charcoal-550 hover:bg-charcoal-600"
/>
</StepContentContainer>
</>
);
}
@@ -670,3 +592,99 @@ export function BulkActionsNone() {
</div>
);
}
function DeploymentOnboardingSteps() {
const environment = useEnvironment();
const organization = useOrganization();
const project = useProject();
return (
<PackageManagerProvider>
<div className="mb-2 flex items-center justify-between border-b">
<div className="mb-2 flex items-center gap-2">
<EnvironmentIcon environment={environment} className="-ml-1 size-8" />
<Header1>Deploy your tasks to {environmentFullTitle(environment)}</Header1>
</div>
<div className="flex items-center">
<SimpleTooltip
button={
<LinkButton
variant="small-menu-item"
LeadingIcon={BookOpenIcon}
leadingIconClassName="text-blue-500"
to={docsPath("deployment/overview")}
/>
}
content="Deploy docs"
/>
<SimpleTooltip
button={
<LinkButton
variant="small-menu-item"
LeadingIcon={QuestionMarkCircleIcon}
leadingIconClassName="text-blue-500"
to={docsPath("troubleshooting#deployment")}
/>
}
content="Troubleshooting docs"
/>
<AskAI />
</div>
</div>
<ClientTabs defaultValue="github">
<ClientTabsList variant="segmented" className="mb-6">
<ClientTabsTrigger value={"github"} variant="segmented" layoutId="deploy-tabs">
GitHub
</ClientTabsTrigger>
<ClientTabsTrigger value={"cli"} variant="segmented" layoutId="deploy-tabs">
Manual
</ClientTabsTrigger>
<ClientTabsTrigger value={"github-actions"} variant="segmented" layoutId="deploy-tabs">
GitHub Actions
</ClientTabsTrigger>
</ClientTabsList>
<ClientTabsContent value={"github"}>
<StepNumber stepNumber="1" title="Connect your GitHub repository" />
<StepContentContainer>
<Paragraph spacing>
Deploy automatically with every push. Read the{" "}
<TextLink to={docsPath("github-integration")}>full guide</TextLink>.
</Paragraph>
<div className="w-fit">
<GitHubConnectionPrompt
gitHubAppInstallations={[]}
organizationSlug={organization.slug}
projectSlug={project.slug}
environmentSlug={environment.slug}
/>
</div>
</StepContentContainer>
</ClientTabsContent>
<ClientTabsContent value={"cli"}>
<StepNumber stepNumber="1" title="Run the CLI 'deploy' command" />
<StepContentContainer>
<Paragraph spacing>
This will deploy your tasks to the {environmentFullTitle(environment)} environment.
Read the <TextLink to={docsPath("deployment/overview")}>full guide</TextLink>.
</Paragraph>
<TriggerDeployStep environment={environment} />
</StepContentContainer>
</ClientTabsContent>
<ClientTabsContent value={"github-actions"}>
<StepNumber stepNumber="1" title="Deploy using GitHub Actions" />
<StepContentContainer>
<Paragraph spacing>
Read the <TextLink to={docsPath("github-actions")}>GitHub Actions guide</TextLink> to
get started.
</Paragraph>
</StepContentContainer>
</ClientTabsContent>
</ClientTabs>
<StepNumber stepNumber="2" title="Waiting for tasks to deploy" displaySpinner />
<StepContentContainer>
<Paragraph>This page will automatically refresh when your tasks are deployed.</Paragraph>
</StepContentContainer>
</PackageManagerProvider>
);
}
@@ -1,41 +1,185 @@
"use client";
import * as React from "react";
import * as TabsPrimitive from "@radix-ui/react-tabs";
import { cn } from "~/utils/cn";
import { motion } from "framer-motion";
import * as TabsPrimitive from "@radix-ui/react-tabs";
import * as React from "react";
import { cn } from "~/utils/cn";
import { type Variants } from "./Tabs";
type ClientTabsContextValue = {
value?: string;
};
const ClientTabsContext = React.createContext<ClientTabsContextValue | undefined>(undefined);
function useClientTabsContext() {
return React.useContext(ClientTabsContext);
}
const ClientTabs = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>
>((props, ref) => <TabsPrimitive.Root ref={ref} {...props} />);
>(({ onValueChange, value: valueProp, defaultValue, ...props }, ref) => {
const [value, setValue] = React.useState<string | undefined>(valueProp ?? defaultValue);
React.useEffect(() => {
if (valueProp !== undefined) {
setValue(valueProp);
}
}, [valueProp]);
const handleValueChange = React.useCallback(
(nextValue: string) => {
if (valueProp === undefined) {
setValue(nextValue);
}
onValueChange?.(nextValue);
},
[onValueChange, valueProp]
);
const controlledProps =
valueProp !== undefined
? { value: valueProp }
: defaultValue !== undefined
? { defaultValue }
: {};
const contextValue = React.useMemo<ClientTabsContextValue>(() => ({ value }), [value]);
return (
<ClientTabsContext.Provider value={contextValue}>
<TabsPrimitive.Root
ref={ref}
onValueChange={handleValueChange}
{...controlledProps}
{...props}
/>
</ClientTabsContext.Provider>
);
});
ClientTabs.displayName = TabsPrimitive.Root.displayName;
const ClientTabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn("inline-flex items-center justify-center transition duration-100", className)}
{...props}
/>
));
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> & {
variant?: Variants;
}
>(({ className, variant = "pipe-divider", ...props }, ref) => {
const variantClassName = (() => {
switch (variant) {
case "segmented":
return "relative flex h-10 w-full items-center rounded bg-charcoal-700/50 p-1";
case "underline":
return "flex gap-x-6 border-b border-grid-bright";
default:
return "inline-flex items-center justify-center transition duration-100";
}
})();
return <TabsPrimitive.List ref={ref} className={cn(variantClassName, className)} {...props} />;
});
ClientTabsList.displayName = TabsPrimitive.List.displayName;
const ClientTabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"ring-offset-background focus-visible:ring-ring inline-flex items-center justify-center whitespace-nowrap border-r border-charcoal-700 px-2 text-sm transition-all first:pl-0 last:border-none data-[state=active]:text-indigo-500 data-[state=inactive]:text-text-dimmed data-[state=inactive]:hover:text-text-bright focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
className
)}
{...props}
/>
));
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger> & {
variant?: Variants;
layoutId?: string;
}
>(({ className, variant = "pipe-divider", layoutId, children, ...props }, ref) => {
const context = useClientTabsContext();
const activeValue = context?.value;
const isActive = activeValue === props.value;
if (variant === "segmented") {
return (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"group relative flex h-full grow items-center justify-center focus-custom disabled:pointer-events-none disabled:opacity-50",
"flex-1 basis-0",
className
)}
{...props}
>
<div className="relative z-10 flex h-full w-full items-center justify-center px-3 py-[0.13rem]">
<span
className={cn(
"text-sm transition duration-200",
isActive
? "text-text-bright"
: "text-text-dimmed transition group-hover:text-text-bright"
)}
>
{children}
</span>
</div>
{isActive ? (
layoutId ? (
<motion.div
layoutId={layoutId}
transition={{ duration: 0.4, type: "spring" }}
className="absolute inset-0 rounded-[2px] border border-charcoal-500/50 bg-charcoal-600"
/>
) : (
<div className="absolute inset-0 rounded-[2px] border border-charcoal-500/50 bg-charcoal-600" />
)
) : null}
</TabsPrimitive.Trigger>
);
}
if (variant === "underline") {
return (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"group flex flex-col items-center pt-1 focus-custom disabled:pointer-events-none disabled:opacity-50",
className
)}
{...props}
>
<span
className={cn(
"text-sm transition duration-200",
isActive ? "text-text-bright" : "text-text-dimmed hover:text-text-bright"
)}
>
{children}
</span>
{layoutId ? (
isActive ? (
<motion.div
layoutId={layoutId}
transition={{ type: "spring", stiffness: 500, damping: 30 }}
className="mt-1 h-0.5 w-full bg-indigo-500"
/>
) : (
<div className="mt-1 h-0.5 w-full bg-charcoal-500 opacity-0 transition duration-200 group-hover:opacity-100" />
)
) : isActive ? (
<div className="mt-1 h-0.5 w-full bg-indigo-500" />
) : (
<div className="mt-1 h-0.5 w-full bg-charcoal-500 opacity-0 transition duration-200 group-hover:opacity-100" />
)}
</TabsPrimitive.Trigger>
);
}
return (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"ring-offset-background focus-visible:ring-ring inline-flex items-center justify-center whitespace-nowrap border-r border-charcoal-700 px-2 text-sm transition-all first:pl-0 last:border-none data-[state=active]:text-indigo-500 data-[state=inactive]:text-text-dimmed data-[state=inactive]:hover:text-text-bright focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
className
)}
{...props}
>
{children}
</TabsPrimitive.Trigger>
);
});
ClientTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
const ClientTabsContent = React.forwardRef<
@@ -61,39 +205,7 @@ export type TabsProps = {
currentValue: string;
className?: string;
layoutId: string;
variant?: Variants;
};
export function ClientTabsWithUnderline({ className, tabs, currentValue, layoutId }: TabsProps) {
return (
<TabsPrimitive.List
className={cn(`flex flex-row gap-x-6 border-b border-charcoal-700`, className)}
>
{tabs.map((tab, index) => {
const isActive = currentValue === tab.value;
return (
<TabsPrimitive.Trigger
key={tab.value}
value={tab.value}
className={cn(`group flex flex-col items-center`, className)}
>
<span
className={cn(
"text-sm transition duration-200",
isActive ? "text-indigo-500" : "text-charcoal-200"
)}
>
{tab.label}
</span>
{isActive ? (
<motion.div layoutId={layoutId} className="mt-1 h-0.5 w-full bg-indigo-500" />
) : (
<div className="mt-1 h-0.5 w-full bg-charcoal-500 opacity-0 transition duration-200 group-hover:opacity-100" />
)}
</TabsPrimitive.Trigger>
);
})}
</TabsPrimitive.List>
);
}
export { ClientTabs, ClientTabsList, ClientTabsTrigger, ClientTabsContent };
export { ClientTabs, ClientTabsContent, ClientTabsList, ClientTabsTrigger };
+111 -14
View File
@@ -1,10 +1,12 @@
import { NavLink } from "@remix-run/react";
import { motion } from "framer-motion";
import { ReactNode, useRef } from "react";
import { ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
import { type ReactNode, useRef } from "react";
import { type ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
import { cn } from "~/utils/cn";
import { ShortcutKey } from "./ShortcutKey";
export type Variants = "underline" | "pipe-divider" | "segmented";
export type TabsProps = {
tabs: {
label: string;
@@ -12,13 +14,14 @@ export type TabsProps = {
}[];
className?: string;
layoutId: string;
variant?: Variants;
};
export function Tabs({ tabs, className, layoutId }: TabsProps) {
export function Tabs({ tabs, className, layoutId, variant = "underline" }: TabsProps) {
return (
<TabContainer className={className}>
<TabContainer className={className} variant={variant}>
{tabs.map((tab, index) => (
<TabLink key={index} to={tab.to} layoutId={layoutId}>
<TabLink key={index} to={tab.to} layoutId={layoutId} variant={variant}>
{tab.label}
</TabLink>
))}
@@ -26,23 +29,107 @@ export function Tabs({ tabs, className, layoutId }: TabsProps) {
);
}
export function TabContainer({ children, className }: { children: ReactNode; className?: string }) {
return (
<div className={cn(`flex flex-row gap-x-6 border-b border-grid-bright`, className)}>
{children}
</div>
);
export function TabContainer({
children,
className,
variant = "underline",
}: {
children: ReactNode;
className?: string;
variant?: Variants;
}) {
if (variant === "segmented") {
return (
<div
className={cn("relative flex h-10 items-center rounded bg-charcoal-700/50 p-1", className)}
>
{children}
</div>
);
}
if (variant === "underline") {
return (
<div className={cn(`flex gap-x-6 border-b border-grid-bright`, className)}>{children}</div>
);
}
return <div className={cn(`flex`, className)}>{children}</div>;
}
export function TabLink({
to,
children,
layoutId,
variant = "underline",
}: {
to: string;
children: ReactNode;
layoutId: string;
variant?: Variants;
}) {
if (variant === "segmented") {
return (
<NavLink
to={to}
className="group relative flex h-full grow items-center justify-center focus-custom"
end
>
{({ isActive, isPending }) => {
const active = isActive || isPending;
return (
<>
<div className="relative z-10 flex h-full w-full items-center justify-center px-3 py-[0.13rem]">
<span
className={cn(
"text-sm transition duration-200",
active
? "text-text-bright"
: "text-text-dimmed transition group-hover:text-text-bright"
)}
>
{children}
</span>
</div>
{active && (
<motion.div
layoutId={layoutId}
transition={{ duration: 0.4, type: "spring" }}
className="absolute inset-0 rounded-[2px] border border-charcoal-500/50 bg-charcoal-600"
/>
)}
</>
);
}}
</NavLink>
);
}
if (variant === "pipe-divider") {
return (
<NavLink
to={to}
className="group flex flex-col items-center border-r border-charcoal-700 px-2 pt-1 focus-custom first:pl-0 last:border-none"
end
>
{({ isActive, isPending }) => {
const active = isActive || isPending;
return (
<span
className={cn(
"text-sm transition duration-200",
active ? "text-text-link" : "text-text-dimmed transition hover:text-text-bright"
)}
>
{children}
</span>
);
}}
</NavLink>
);
}
// underline variant (default)
return (
<NavLink to={to} className="group flex flex-col items-center pt-1 focus-custom" end>
{({ isActive, isPending }) => {
@@ -51,13 +138,19 @@ export function TabLink({
<span
className={cn(
"text-sm transition duration-200",
isActive || isPending ? "text-text-bright" : "text-text-bright"
isActive || isPending
? "text-text-bright"
: "text-text-dimmed hover:text-text-bright"
)}
>
{children}
</span>
{isActive || isPending ? (
<motion.div layoutId={layoutId} className="mt-1 h-0.5 w-full bg-indigo-500" />
<motion.div
layoutId={layoutId}
transition={{ type: "spring", stiffness: 500, damping: 30 }}
className="mt-1 h-0.5 w-full bg-indigo-500"
/>
) : (
<div className="mt-1 h-0.5 w-full bg-charcoal-500 opacity-0 transition duration-200 group-hover:opacity-100" />
)}
@@ -116,7 +209,11 @@ export function TabButton({
{shortcut && <ShortcutKey className={cn("")} shortcut={shortcut} variant={"small"} />}
</div>
{isActive ? (
<motion.div layoutId={layoutId} className="mt-1 h-0.5 w-full bg-indigo-500" />
<motion.div
layoutId={layoutId}
transition={{ type: "spring", stiffness: 500, damping: 30 }}
className="mt-1 h-0.5 w-full bg-indigo-500"
/>
) : (
<div className="mt-1 h-0.5 w-full bg-charcoal-500 opacity-0 transition duration-200 group-hover:opacity-100" />
)}
@@ -359,11 +359,11 @@ export default function Page() {
</div>
</div>
) : environment.type === "DEVELOPMENT" ? (
<MainCenteredContainer className="max-w-md">
<MainCenteredContainer className="max-w-prose">
<DeploymentsNoneDev />
</MainCenteredContainer>
) : (
<MainCenteredContainer className="max-w-md">
<MainCenteredContainer className="max-w-prose">
<DeploymentsNone />
</MainCenteredContainer>
)}
@@ -577,12 +577,17 @@ export default function Page() {
previewEnvironmentEnabled={isPreviewEnvironmentEnabled}
/>
) : (
<GitHubConnectionPrompt
gitHubAppInstallations={githubAppInstallations ?? []}
organizationSlug={organization.slug}
projectSlug={project.slug}
environmentSlug={environment.slug}
/>
<div className="flex flex-col gap-2">
<GitHubConnectionPrompt
gitHubAppInstallations={githubAppInstallations ?? []}
organizationSlug={organization.slug}
projectSlug={project.slug}
environmentSlug={environment.slug}
/>
<Hint>
Connect your GitHub repository to automatically deploy your changes.
</Hint>
</div>
)}
</div>
</div>
@@ -858,7 +863,7 @@ function ConnectGitHubRepoModal({
);
}
function GitHubConnectionPrompt({
export function GitHubConnectionPrompt({
gitHubAppInstallations,
organizationSlug,
projectSlug,
@@ -901,8 +906,6 @@ function GitHubConnectionPrompt({
</span>
</div>
)}
<Hint>Connect your GitHub repository to automatically deploy your changes.</Hint>
</InputGroup>
</Fieldset>
);
@@ -3,7 +3,7 @@ import { useParams } from "@remix-run/react";
export default function Story() {
const { tabNumber } = useParams();
return (
<div className="flex items-center justify-center py-8">
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">{tabNumber}</h1>
</div>
);
+180 -10
View File
@@ -1,18 +1,188 @@
import { Outlet } from "@remix-run/react";
import {
ClientTabs,
ClientTabsContent,
ClientTabsList,
ClientTabsTrigger,
} from "~/components/primitives/ClientTabs";
import { Header1 } from "~/components/primitives/Headers";
import { Paragraph } from "~/components/primitives/Paragraph";
import { Tabs } from "~/components/primitives/Tabs";
export default function Story() {
return (
<div className="w-96 p-8">
<Tabs
tabs={[
{ label: "My first tab", to: "1" },
{ label: "Second tab", to: "2" },
{ label: "Third tab", to: "3" },
]}
layoutId="my-tabs"
/>
<Outlet />
<div className="flex items-start justify-center gap-20 px-16 pt-20">
<div className="flex w-full max-w-2xl flex-col gap-4">
<div className="flex h-fit flex-col gap-2">
<div className="flex flex-col gap-2">
<Header1 spacing>{"<Tabs/>"} (updates the URL)</Header1>
<Paragraph>Variant="underline"</Paragraph>
</div>
<Tabs
tabs={[
{ label: "First tab", to: "1" },
{ label: "Second tab", to: "2" },
{ label: "Third tab", to: "3" },
]}
layoutId="my-tabs-1"
variant="underline"
/>
<Outlet />
</div>
<div className="flex h-fit flex-col gap-2">
<Paragraph>Variant="pipe-divider"</Paragraph>
<Tabs
tabs={[
{ label: "First tab", to: "1" },
{ label: "Second tab", to: "2" },
{ label: "Third tab", to: "3" },
]}
layoutId="my-tabs-2"
variant="pipe-divider"
/>
<Outlet />
</div>
<div className="flex h-fit flex-col gap-2">
<Paragraph>Variant="segmented"</Paragraph>
<Tabs
tabs={[
{ label: "First tab", to: "1" },
{ label: "Second tab", to: "2" },
{ label: "Third tab", to: "3" },
]}
layoutId="my-tabs-3"
variant="segmented"
/>
<Outlet />
</div>
</div>
<div className="flex w-full max-w-2xl flex-col gap-4">
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-2">
<Header1 spacing>{"<ClientTabs/>"}</Header1>
<Paragraph>Variant="underline"</Paragraph>
</div>
<ClientTabs defaultValue="tab-1">
<div className="flex items-center gap-4">
<ClientTabsList variant="underline">
<ClientTabsTrigger
value={"tab-1"}
variant="underline"
layoutId="client-tabs-underline"
>
First tab
</ClientTabsTrigger>
<ClientTabsTrigger
value={"tab-2"}
variant="underline"
layoutId="client-tabs-underline"
>
Second tab
</ClientTabsTrigger>
<ClientTabsTrigger
value={"tab-3"}
variant="underline"
layoutId="client-tabs-underline"
>
Third tab
</ClientTabsTrigger>
</ClientTabsList>
</div>
<ClientTabsContent value={"tab-1"}>
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">1</h1>
</div>
</ClientTabsContent>
<ClientTabsContent value={"tab-2"}>
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">2</h1>
</div>
</ClientTabsContent>
<ClientTabsContent value={"tab-3"}>
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">3</h1>
</div>
</ClientTabsContent>
</ClientTabs>
</div>
<div>
<Paragraph spacing>Variant="pipe-divider"</Paragraph>
<ClientTabs defaultValue="tab-1">
<div className="flex items-center gap-4">
<ClientTabsList variant="pipe-divider">
<ClientTabsTrigger value={"tab-1"} variant="pipe-divider">
First tab
</ClientTabsTrigger>
<ClientTabsTrigger value={"tab-2"} variant="pipe-divider">
Second tab
</ClientTabsTrigger>
<ClientTabsTrigger value={"tab-3"} variant="pipe-divider">
Third tab
</ClientTabsTrigger>
</ClientTabsList>
</div>
<ClientTabsContent value={"tab-1"}>
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">1</h1>
</div>
</ClientTabsContent>
<ClientTabsContent value={"tab-2"}>
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">2</h1>
</div>
</ClientTabsContent>
<ClientTabsContent value={"tab-3"}>
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">3</h1>
</div>
</ClientTabsContent>
</ClientTabs>
</div>
<div>
<Paragraph spacing>Variant="segmented"</Paragraph>
<ClientTabs defaultValue="tab-1">
<ClientTabsList variant="segmented">
<ClientTabsTrigger
value={"tab-1"}
variant="segmented"
layoutId="client-tabs-segmented"
>
First tab
</ClientTabsTrigger>
<ClientTabsTrigger
value={"tab-2"}
variant="segmented"
layoutId="client-tabs-segmented"
>
Second tab
</ClientTabsTrigger>
<ClientTabsTrigger
value={"tab-3"}
variant="segmented"
layoutId="client-tabs-segmented"
>
Third tab
</ClientTabsTrigger>
</ClientTabsList>
<ClientTabsContent value={"tab-1"}>
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">1</h1>
</div>
</ClientTabsContent>
<ClientTabsContent value={"tab-2"}>
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">2</h1>
</div>
</ClientTabsContent>
<ClientTabsContent value={"tab-3"}>
<div className="flex items-center justify-center rounded bg-charcoal-700/50 py-8">
<h1 className="text-5xl">3</h1>
</div>
</ClientTabsContent>
</ClientTabs>
</div>
</div>
</div>
);
}