fix(ui): add asChild support to Button and update theme styles
This commit is contained in:
parent
6a0fcf5343
commit
a96222cc28
186
src/App.css
186
src/App.css
@ -1,186 +0,0 @@
|
|||||||
.counter {
|
|
||||||
font-size: 16px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
color: var(--accent);
|
|
||||||
background: var(--accent-bg);
|
|
||||||
border: 2px solid transparent;
|
|
||||||
transition: border-color 0.3s;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: var(--accent-border);
|
|
||||||
}
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 2px solid var(--accent);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.hero {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.base,
|
|
||||||
.framework,
|
|
||||||
.vite {
|
|
||||||
inset-inline: 0;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.base {
|
|
||||||
width: 170px;
|
|
||||||
position: relative;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.framework,
|
|
||||||
.vite {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.framework {
|
|
||||||
z-index: 1;
|
|
||||||
top: 34px;
|
|
||||||
height: 28px;
|
|
||||||
transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg)
|
|
||||||
scale(1.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vite {
|
|
||||||
z-index: 0;
|
|
||||||
top: 107px;
|
|
||||||
height: 26px;
|
|
||||||
width: auto;
|
|
||||||
transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg)
|
|
||||||
scale(0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#center {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 25px;
|
|
||||||
place-content: center;
|
|
||||||
place-items: center;
|
|
||||||
flex-grow: 1;
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
padding: 32px 20px 24px;
|
|
||||||
gap: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#next-steps {
|
|
||||||
display: flex;
|
|
||||||
border-top: 1px solid var(--border);
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
flex: 1 1 0;
|
|
||||||
padding: 32px;
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
padding: 24px 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
flex-direction: column;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#docs {
|
|
||||||
border-right: 1px solid var(--border);
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
border-right: none;
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#next-steps ul {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
margin: 32px 0 0;
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--text-h);
|
|
||||||
font-size: 16px;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: var(--social-bg);
|
|
||||||
display: flex;
|
|
||||||
padding: 6px 12px;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: box-shadow 0.3s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
box-shadow: var(--shadow);
|
|
||||||
}
|
|
||||||
.button-icon {
|
|
||||||
height: 18px;
|
|
||||||
width: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
margin-top: 20px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
li {
|
|
||||||
flex: 1 1 calc(50% - 8px);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
width: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#spacer {
|
|
||||||
height: 88px;
|
|
||||||
border-top: 1px solid var(--border);
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ticks {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&::before,
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: -4.5px;
|
|
||||||
border: 5px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
left: 0;
|
|
||||||
border-left-color: var(--border);
|
|
||||||
}
|
|
||||||
&::after {
|
|
||||||
right: 0;
|
|
||||||
border-right-color: var(--border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
27
src/App.tsx
27
src/App.tsx
@ -1,4 +1,3 @@
|
|||||||
import './App.css'
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Navigate, createBrowserRouter, useParams } from "react-router";
|
import { Navigate, createBrowserRouter, useParams } from "react-router";
|
||||||
import { RouterProvider } from "react-router/dom";
|
import { RouterProvider } from "react-router/dom";
|
||||||
@ -46,6 +45,11 @@ import SettingsAccessibilityPage from "@/page/settings/accessibility";
|
|||||||
import SettingsSecurityPage from "@/page/settings/security";
|
import SettingsSecurityPage from "@/page/settings/security";
|
||||||
import SettingsTokensPage from "@/page/settings/tokens";
|
import SettingsTokensPage from "@/page/settings/tokens";
|
||||||
import SettingsSshKeysPage from "@/page/settings/ssh-keys";
|
import SettingsSshKeysPage from "@/page/settings/ssh-keys";
|
||||||
|
import LandingLayout from "@/page/landing/layout";
|
||||||
|
import LandingHome from "@/page/landing/home";
|
||||||
|
import FeaturesPage from "@/page/landing/features";
|
||||||
|
import WorkflowPage from "@/page/landing/workflow";
|
||||||
|
import PricingPage from "@/page/landing/pricing";
|
||||||
|
|
||||||
function WorkspaceCompatRedirect() {
|
function WorkspaceCompatRedirect() {
|
||||||
const { projectName = "" } = useParams();
|
const { projectName = "" } = useParams();
|
||||||
@ -65,8 +69,25 @@ function App() {
|
|||||||
element: <RootLayout />,
|
element: <RootLayout />,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "/",
|
element: <LandingLayout />,
|
||||||
element: <Navigate replace to="/me" />,
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <LandingHome />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "features",
|
||||||
|
element: <FeaturesPage />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "workflow",
|
||||||
|
element: <WorkflowPage />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "pricing",
|
||||||
|
element: <PricingPage />,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/workspace/:projectName/*",
|
path: "/workspace/:projectName/*",
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
|
import React from "react"
|
||||||
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
"group/button inline-flex shrink-0 items-center justify-center rounded-xl border border-transparent bg-clip-padding text-[13px] font-semibold whitespace-nowrap transition-all outline-none select-none focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:scale-[0.97] disabled:pointer-events-none disabled:opacity-40 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 shadow-sm",
|
"group/button inline-flex shrink-0 items-center justify-center rounded-xl border border-transparent bg-clip-padding text-[13px] font-semibold whitespace-nowrap transition-[background-color,border-color,color,box-shadow,transform] outline-none select-none focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:scale-[0.97] disabled:pointer-events-none disabled:opacity-40 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 shadow-sm",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
@ -42,14 +43,30 @@ function Button({
|
|||||||
className,
|
className,
|
||||||
variant = "default",
|
variant = "default",
|
||||||
size = "default",
|
size = "default",
|
||||||
|
asChild,
|
||||||
|
children,
|
||||||
|
render,
|
||||||
...props
|
...props
|
||||||
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
|
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants> & { asChild?: boolean }) {
|
||||||
|
const classes = cn(buttonVariants({ variant, size, className }))
|
||||||
|
|
||||||
|
let finalRender = render
|
||||||
|
let finalChildren = children
|
||||||
|
|
||||||
|
if (asChild && !finalRender) {
|
||||||
|
finalRender = React.Children.only(children) as React.ReactElement
|
||||||
|
finalChildren = undefined
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonPrimitive
|
<ButtonPrimitive
|
||||||
data-slot="button"
|
data-slot="button"
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
render={finalRender}
|
||||||
|
className={classes}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
>
|
||||||
|
{finalChildren}
|
||||||
|
</ButtonPrimitive>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
@plugin "@tailwindcss/typography";
|
||||||
@import "tw-animate-css";
|
@import "tw-animate-css";
|
||||||
@import "shadcn/tailwind.css";
|
@import "shadcn/tailwind.css";
|
||||||
@import "@fontsource-variable/space-grotesk";
|
@import "@fontsource-variable/space-grotesk";
|
||||||
@ -29,6 +30,12 @@
|
|||||||
--color-input: var(--input);
|
--color-input: var(--input);
|
||||||
--color-border: var(--border);
|
--color-border: var(--border);
|
||||||
--color-destructive: var(--destructive);
|
--color-destructive: var(--destructive);
|
||||||
|
--color-success: var(--success);
|
||||||
|
--color-success-foreground: var(--success-foreground);
|
||||||
|
--color-warning: var(--warning);
|
||||||
|
--color-warning-foreground: var(--warning-foreground);
|
||||||
|
--color-info: var(--info);
|
||||||
|
--color-info-foreground: var(--info-foreground);
|
||||||
--color-accent-foreground: var(--accent-foreground);
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
--color-accent: var(--accent);
|
--color-accent: var(--accent);
|
||||||
--color-muted-foreground: var(--muted-foreground);
|
--color-muted-foreground: var(--muted-foreground);
|
||||||
@ -68,6 +75,12 @@
|
|||||||
--accent: #f5f5f5;
|
--accent: #f5f5f5;
|
||||||
--accent-foreground: #111111;
|
--accent-foreground: #111111;
|
||||||
--destructive: #ef4444;
|
--destructive: #ef4444;
|
||||||
|
--success: #16a34a;
|
||||||
|
--success-foreground: #ffffff;
|
||||||
|
--warning: #d97706;
|
||||||
|
--warning-foreground: #ffffff;
|
||||||
|
--info: #2563eb;
|
||||||
|
--info-foreground: #ffffff;
|
||||||
--border: #e8e8e8;
|
--border: #e8e8e8;
|
||||||
--input: #e8e8e8;
|
--input: #e8e8e8;
|
||||||
--ring: #111111;
|
--ring: #111111;
|
||||||
@ -103,6 +116,12 @@
|
|||||||
--accent: #1f2128;
|
--accent: #1f2128;
|
||||||
--accent-foreground: #ececf1;
|
--accent-foreground: #ececf1;
|
||||||
--destructive: #EF4444;
|
--destructive: #EF4444;
|
||||||
|
--success: #22c55e;
|
||||||
|
--success-foreground: #052e16;
|
||||||
|
--warning: #f59e0b;
|
||||||
|
--warning-foreground: #451a03;
|
||||||
|
--info: #60a5fa;
|
||||||
|
--info-foreground: #082f49;
|
||||||
--border: rgba(255, 255, 255, 0.08);
|
--border: rgba(255, 255, 255, 0.08);
|
||||||
--input: rgba(255, 255, 255, 0.08);
|
--input: rgba(255, 255, 255, 0.08);
|
||||||
--ring: #5E6AD2;
|
--ring: #5E6AD2;
|
||||||
@ -120,12 +139,29 @@
|
|||||||
* {
|
* {
|
||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
}
|
}
|
||||||
|
html {
|
||||||
|
@apply font-sans;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground antialiased;
|
@apply bg-background text-foreground antialiased;
|
||||||
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
|
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
|
||||||
}
|
}
|
||||||
html {
|
button,
|
||||||
@apply font-sans;
|
a,
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
touch-action: manipulation;
|
||||||
|
}
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
p,
|
||||||
|
li {
|
||||||
|
text-wrap: pretty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -348,6 +348,11 @@ export function applyTheme(preset: ThemePreset) {
|
|||||||
root.style.setProperty("--chart-4", preset.isDark ? "#6e7681" : "#374151");
|
root.style.setProperty("--chart-4", preset.isDark ? "#6e7681" : "#374151");
|
||||||
root.style.setProperty("--chart-5", preset.isDark ? "#4b5563" : "#1f2937");
|
root.style.setProperty("--chart-5", preset.isDark ? "#4b5563" : "#1f2937");
|
||||||
|
|
||||||
|
root.style.setProperty("color-scheme", preset.isDark ? "dark" : "light");
|
||||||
|
|
||||||
|
const themeColorMeta = document.querySelector<HTMLMetaElement>('meta[name="theme-color"]');
|
||||||
|
themeColorMeta?.setAttribute("content", c.background);
|
||||||
|
|
||||||
// Toggle dark class for any tailwind dark: variants still in use
|
// Toggle dark class for any tailwind dark: variants still in use
|
||||||
if (preset.isDark) {
|
if (preset.isDark) {
|
||||||
root.classList.add("dark");
|
root.classList.add("dark");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user