Skip to content

Commit 8820e61

Browse files
committed
Added Slider component and DialogTitle
1 parent 3ae3d11 commit 8820e61

26 files changed

+273
-58
lines changed

examples/example_pro/src/SimpleApp/App.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ function ProSample() {
159159
});
160160

161161
if (firebaseConfigLoading || !firebaseApp) {
162-
return <><CircularProgressCenter/></>;
162+
return <CircularProgressCenter/>;
163163
}
164164

165165
if (configError) {

packages/firecms_core/src/form/field_bindings/KeyValueFieldBinding.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ function MapKeyValueRow<T extends Record<string, any>>({
311311
}}/>;
312312
} else if (dataType === "boolean") {
313313
return <BooleanSwitchWithLabel value={entryValue}
314-
size={"medium"}
314+
size={"small"}
315315
position={"start"}
316316
disabled={disabled || !fieldKey}
317317
onValueChange={(newValue) => {
@@ -478,7 +478,7 @@ function ArrayKeyValueRow<T>({
478478
}}/>;
479479
} else if (dataType === "boolean") {
480480
return <BooleanSwitchWithLabel value={entryValue}
481-
size={"medium"}
481+
size={"small"}
482482
position={"start"}
483483
onValueChange={(v) => {
484484
setValue(v as T);

packages/ui/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,11 @@
6161
"@radix-ui/react-scroll-area": "^1.2.0",
6262
"@radix-ui/react-select": "^2.1.2",
6363
"@radix-ui/react-separator": "^1.1.0",
64+
"@radix-ui/react-slider": "^1.2.1",
6465
"@radix-ui/react-switch": "^1.1.1",
6566
"@radix-ui/react-tabs": "^1.1.1",
6667
"@radix-ui/react-tooltip": "^1.1.3",
68+
"@radix-ui/react-visually-hidden": "^1.1.0",
6769
"clsx": "^2.1.1",
6870
"cmdk": "^0.2.1",
6971
"date-fns": "^3.6.0",
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from "react";
2+
import * as DialogPrimitive from "@radix-ui/react-dialog";
3+
import * as VisuallyHidden from "@radix-ui/react-visually-hidden";
4+
import { Typography, TypographyProps, TypographyVariant } from "./Typography.tsx";
5+
6+
export type DialogContentProps = TypographyProps & {
7+
children: React.ReactNode,
8+
hidden?: boolean,
9+
className?: string,
10+
variant?: TypographyVariant
11+
};
12+
13+
export function DialogTitle({
14+
children,
15+
hidden,
16+
className,
17+
variant = "h4",
18+
...props
19+
}: DialogContentProps) {
20+
21+
const title = <DialogPrimitive.Title asChild>
22+
<Typography variant={variant}
23+
className={className}
24+
{...props}>
25+
{children}
26+
</Typography>
27+
</DialogPrimitive.Title>;
28+
29+
if (hidden) {
30+
return <VisuallyHidden.Root>{title}</VisuallyHidden.Root>
31+
}
32+
33+
return title;
34+
}

packages/ui/src/components/Slider.tsx

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import * as React from "react"
2+
import { cls } from "../util";
3+
import * as SliderPrimitive from "@radix-ui/react-slider";
4+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5+
6+
export interface SliderProps {
7+
className?: string;
8+
name?: string;
9+
disabled?: boolean;
10+
orientation?: React.AriaAttributes["aria-orientation"];
11+
dir?: "ltr" | "rtl";
12+
min?: number;
13+
max?: number;
14+
step?: number;
15+
minStepsBetweenThumbs?: number;
16+
value?: number[];
17+
defaultValue?: number[];
18+
19+
onValueChange?(value: number[]): void;
20+
21+
onValueCommit?(value: number[]): void;
22+
23+
inverted?: boolean;
24+
form?: string;
25+
}
26+
27+
const Slider = React.forwardRef<
28+
React.ElementRef<typeof SliderPrimitive.Root>,
29+
SliderProps
30+
>(({
31+
className,
32+
...props
33+
}, ref) => {
34+
const [hovered, setHovered] = React.useState(false);
35+
return (
36+
<TooltipPrimitive.Provider delayDuration={200}>
37+
<TooltipPrimitive.Root open={hovered}>
38+
<SliderPrimitive.Root
39+
ref={ref}
40+
onMouseEnter={() => setHovered(true)}
41+
onMouseLeave={() => setHovered(false)}
42+
className={cls(
43+
"relative flex w-full touch-none select-none items-center",
44+
className
45+
)}
46+
{...props}
47+
>
48+
<SliderPrimitive.Track
49+
className="relative h-2 w-full grow overflow-hidden rounded-full bg-slate-300 bg-opacity-40 dark:bg-gray-700 dark:bg-opacity-40">
50+
<SliderPrimitive.Range className={cls("absolute h-full",
51+
{
52+
"bg-primary": !props.disabled,
53+
"bg-slate-300 dark:bg-gray-700": props.disabled
54+
})}/>
55+
</SliderPrimitive.Track>
56+
<TooltipPrimitive.Trigger asChild>
57+
<SliderPrimitive.Thumb
58+
className={cls({
59+
"border-primary bg-primary hover:bg-primary-dark ring-offset-primary focus-visible:ring-2 focus-visible:ring-primary ": !props.disabled,
60+
"border-slate-300 bg-slate-300 dark:border-gray-700 dark:bg-gray-700": props.disabled
61+
}, "block h-6 w-6 rounded-full transition-colors focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50")}/>
62+
</TooltipPrimitive.Trigger>
63+
<TooltipPrimitive.Content side="top" sideOffset={5}
64+
className={cls(
65+
"TooltipContent",
66+
"max-w-lg leading-relaxed",
67+
"z-50 rounded px-3 py-2 text-xs leading-none bg-slate-700 dark:bg-slate-800 bg-opacity-90 font-medium text-slate-50 shadow-2xl select-none duration-400 ease-in transform opacity-100",
68+
)}>
69+
{props.value?.[0]}
70+
</TooltipPrimitive.Content>
71+
72+
</SliderPrimitive.Root>
73+
</TooltipPrimitive.Root>
74+
</TooltipPrimitive.Provider>
75+
);
76+
});
77+
78+
Slider.displayName = "Slider";
79+
80+
export { Slider }

packages/ui/src/components/Typography.tsx

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
import React, { ReactEventHandler } from "react";
22
import { cls } from "../util";
33

4-
export type TextProps<C extends React.ElementType> = {
4+
export type TypographyVariant = keyof typeof typographyVariants;
5+
export type TypographyProps<C extends React.ElementType = "span"> = {
56
align?: "center" | "inherit" | "justify" | "left" | "right";
67
children?: React.ReactNode;
78
className?: string;
89
component?: C;
910
gutterBottom?: boolean;
1011
noWrap?: boolean;
1112
paragraph?: boolean;
12-
variant?: keyof typeof defaultVariantMapping;
13+
variant?: TypographyVariant;
1314
variantMapping?: { [key: string]: string };
1415
color?: "inherit" | "initial" | "primary" | "secondary" | "disabled" | "error";
1516
onClick?: ReactEventHandler<HTMLElement>;
1617
style?: React.CSSProperties;
1718
} & React.ComponentPropsWithoutRef<C>;
1819

19-
const defaultVariantMapping = {
20+
const typographyVariants = {
2021
h1: "h1",
2122
h2: "h2",
2223
h3: "h3",
@@ -76,7 +77,7 @@ const variantToClasses = {
7677
button: "typography-button"
7778
};
7879

79-
export function Typography<C extends React.ElementType>(
80+
export function Typography<C extends React.ElementType = "span">(
8081
{
8182
align = "inherit",
8283
color = "primary",
@@ -87,15 +88,15 @@ export function Typography<C extends React.ElementType>(
8788
noWrap = false,
8889
paragraph = false,
8990
variant = "body1",
90-
variantMapping = defaultVariantMapping,
91+
variantMapping = typographyVariants,
9192
style,
9293
onClick,
9394
...other
94-
}: TextProps<C>
95+
}: TypographyProps<C>
9596
) {
9697
const Component =
9798
component ||
98-
(paragraph ? "p" : variantMapping[variant] || defaultVariantMapping[variant]) ||
99+
(paragraph ? "p" : variantMapping[variant] || typographyVariants[variant]) ||
99100
"span";
100101

101102
const classes = cls(

packages/ui/src/components/index.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export * from "./DateTimeField";
1515
export * from "./Dialog";
1616
export * from "./DialogActions";
1717
export * from "./DialogContent";
18+
export * from "./DialogTitle";
1819
export * from "./ExpandablePanel";
1920
export * from "./FileUpload";
2021
export * from "./IconButton";
@@ -31,6 +32,7 @@ export * from "./RadioGroup";
3132
export * from "./SearchBar";
3233
export * from "./Select";
3334
export * from "./Separator";
35+
export * from "./Slider";
3436
export * from "./Sheet";
3537
export * from "./TextareaAutosize";
3638
export * from "./TextField";

packages/ui/src/styles.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ export const fieldBackgroundMixin = "bg-opacity-50 bg-slate-200 dark:bg-gray-800
55
export const fieldBackgroundInvisibleMixin = "bg-opacity-0 bg-slate-100 dark:bg-gray-800 dark:bg-opacity-0";
66
export const fieldBackgroundDisabledMixin = "dark:bg-gray-800 bg-opacity-50 dark:bg-opacity-90";
77
export const fieldBackgroundHoverMixin = "hover:bg-opacity-70 dark:hover:bg-gray-700 dark:hover:bg-opacity-40";
8-
export const defaultBorderMixin = "border-gray-200 border-opacity-40 dark:border-gray-700 dark:border-opacity-70";
9-
export const paperMixin = "bg-white rounded-md dark:bg-gray-950 border border-gray-200 border-opacity-40 dark:border-gray-800 dark:border-opacity-80";
10-
export const cardMixin = "bg-white border border-gray-200 border-opacity-40 dark:border-transparent rounded-md dark:bg-gray-950 dark:border-gray-800 dark:border-opacity-50 m-1 -p-1";
8+
export const defaultBorderMixin = "border-gray-200 border-opacity-40 dark:border-gray-700 dark:border-opacity-50";
9+
export const paperMixin = "bg-white rounded-md dark:bg-gray-950 border border-gray-200 border-opacity-40 dark:border-gray-700 dark:border-opacity-50";
10+
export const cardMixin = "bg-white border border-gray-200 border-opacity-40 dark:border-transparent rounded-md dark:bg-gray-950 dark:border-gray-700 dark:border-opacity-50 m-1 -p-1";
1111
export const cardClickableMixin = "hover:bg-primary-bg dark:hover:bg-primary-bg hover:bg-opacity-20 dark:hover:bg-opacity-20 hover:ring-2 hover:ring-primary cursor-pointer";
1212
export const cardSelectedMixin = "bg-primary-bg dark:bg-primary-bg bg-opacity-30 dark:bg-opacity-10 ring-1 ring-primary ring-opacity-75";

website/blog/2023-05-28-why_react_cms.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ mobile, and IoT devices, effectively increasing your reach.
8888

8989
A React-based headless CMS allows content creators to customize their editorial
9090
workflows to suit their requirements better. Custom content types, taxonomies,
91-
and metadata can all be seamlessly managed and edited, ultimately fostering a
91+
and metadata can all be managed and edited, ultimately fostering a
9292
more efficient and tailored approach to content creation.
9393

9494
### 3. API-driven Content Delivery

website/docs/cloud/migrating_from_v2.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
id: migrating_from_v2
33
title: Migrating from FireCMS 2.0 to FireCMS Cloud
44
sidebar_label: Migrating from FireCMS 2.0 to FireCMS Cloud
5-
description: Migrate seamlessly to FireCMS 3.0, the latest innovation in headless CMS, by creating a new project on app.firecms.co. Benefit from centralized configuration management and hassle-free integration without having to reveal Firebase credentials. Initiate a fresh project setup with simple CLI commands and adapt your existing collections to the new format with ease. Tailored for developers, FireCMS 3.0 elevates content management to new flexibility and customization heights, while retaining the familiarity of previous versions.
5+
description: Migrate to FireCMS 3.0, the latest innovation in headless CMS, by creating a new project on app.firecms.co. Benefit from centralized configuration management and hassle-free integration without having to reveal Firebase credentials. Initiate a fresh project setup with simple CLI commands and adapt your existing collections to the new format with ease. Tailored for developers, FireCMS 3.0 brings content management to new flexibility and customization heights, while retaining the familiarity of previous versions.
66
---
77

88
:::important

website/docs/pro/migrating_from_v2_to_pro.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
id: migrating_from_v2_to_pro
33
title: Migrating from FireCMS 2.0 to FireCMS PRO
44
sidebar_label: Migrating from FireCMS 2.0 to FireCMS PRO
5-
description: Migrate seamlessly to FireCMS PRO, the self-hosted version of FireCMS.
5+
description: Migrate to FireCMS PRO, the self-hosted version of FireCMS.
66
---
77

88
FireCMS 3.0 is a major release that introduces a lot of changes. This page

website/docs/recipes/copy_entity.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
id: copy_entity
33
title: Copying an entity from one collection to another
44
sidebar_label: Copying from another collection
5-
description: Implement custom functionality to copy entities between collections in Firestore using FireCMS with this practical tutorial. Assuming you're equipped with a Firebase project and FireCMS instance, you'll learn how to introduce a copy button to your collection views, enabling the replication of data across different Firestore locations, a helpful feature in denormalized NoSQL databases. This guide walks you through declaring source and target collections, crafting a custom button component leveraging FireCMS hooks, and seamlessly integrating it as a custom action within your collection's framework. Complete with code snippets illustrating a simple product collection and the custom button logic, this tutorial equips you to handle common scenarios requiring data duplication, enhancing the data management capabilities of your CMS. Whether you're dealing with products, articles, or user data, mastering entity copying can streamline your workflow and maintain data consistency across your FireCMS application.
5+
description: Implement custom functionality to copy entities between collections in Firestore using FireCMS with this practical tutorial. Assuming you're equipped with a Firebase project and FireCMS instance, you'll learn how to introduce a copy button to your collection views, enabling the replication of data across different Firestore locations, a helpful feature in denormalized NoSQL databases. This guide walks you through declaring source and target collections, crafting a custom button component leveraging FireCMS hooks, and integrating it as a custom action within your collection's framework. Complete with code snippets illustrating a simple product collection and the custom button logic, this tutorial equips you to handle common scenarios requiring data duplication, enhancing the data management capabilities of your CMS. Whether you're dealing with products, articles, or user data, mastering entity copying can streamline your workflow and maintain data consistency across your FireCMS application.
66
---
77

88
![Product selection](/img/product_selection.webp)

website/samples/components/dialog/dialog_basic.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState } from "react";
2-
import { Button, Dialog, DialogActions, DialogContent, Typography } from "@firecms/ui";
2+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
33

44
export default function DialogBasicDemo() {
55
const [open, setOpen] = useState(false);
@@ -11,9 +11,9 @@ export default function DialogBasicDemo() {
1111
open={open}
1212
onOpenChange={setOpen}>
1313
<DialogContent className="p-8 flex flex-col space-y-2">
14-
<Typography variant={"h5"} gutterBottom>
14+
<DialogTitle variant={"h5"} gutterBottom>
1515
Your dialog
16-
</Typography>
16+
</DialogTitle>
1717
<Typography gutterBottom>
1818
Basic Dialog Content
1919
</Typography>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React, { useState } from "react";
2+
import { Slider } from "@firecms/ui";
3+
4+
export default function SliderBasicDemo() {
5+
const [value, setValue] = useState([50]);
6+
7+
return (
8+
<Slider
9+
value={value}
10+
onValueChange={setValue}
11+
min={0}
12+
max={100}
13+
step={1}
14+
/>
15+
);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from "react";
2+
import { Slider } from "@firecms/ui";
3+
4+
export default function SliderDisabledDemo() {
5+
return (
6+
<Slider
7+
value={[30]}
8+
min={0}
9+
max={100}
10+
disabled
11+
/>
12+
);
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React, { useState } from "react";
2+
import { Slider } from "@firecms/ui";
3+
4+
export default function SliderInvertedDemo() {
5+
const [value, setValue] = useState([70]);
6+
7+
return (
8+
<Slider
9+
value={value}
10+
onValueChange={setValue}
11+
min={0}
12+
max={100}
13+
inverted
14+
/>
15+
);
16+
}

website/src/docs_generation/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,4 @@ function camelToSlug(input: string): string {
4949
return slug.charAt(0) === "_" ? slug.slice(1) : slug;
5050
}
5151

52-
generateDocsForFile("../packages/ui/src/components/Menubar.tsx")
52+
generateDocsForFile("../packages/ui/src/components/Slider.tsx")

website/src/pages/pro.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ function ProPage() {
4141
could be easily customized to fit different needs.
4242
</p>
4343
</div>
44-
<HeroProButtons/>
4544
</Panel>
4645

4746
<PublicFacingApps/>

website/src/pages/ui.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ const UIPage: React.FC = () => {
1111
<Layout title="FireCMS UI, batteries included">
1212

1313
<Hero
14-
color={"secondary"}
1514
title={
1615
<>
1716
<span className="block lg:inline">FireCMS UI</span>
1817
</>}
1918
subtitle={
2019
<>
2120
<p>
22-
FireCMS includes a set of components based on <b>tailwind</b> and <b>RadixUI</b> that can be
21+
A battle-tested set of components based on <b>tailwind</b> and <b>RadixUI</b> that can be
2322
used in any React project.
2423
</p>
2524
</>}

website/src/partials/features/Features.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ import inlineEditingVideo from "@site/static/img/inline_table_editing.mp4";
1515

1616
import { useColorMode } from "@docusaurus/theme-common";
1717
import { TwoColumns } from "../general/TwoColumns";
18-
import { ContainerInnerPaddingMixin, CTACaret, CTAOutlinedButtonMixin, defaultBorderMixin } from "../styles";
18+
import {
19+
ContainerInnerPaddingMixin,
20+
CTACaret,
21+
CTAOutlinedButtonMixin,
22+
CTAOutlinedButtonWhiteMixin,
23+
defaultBorderMixin
24+
} from "../styles";
1925
import { BrowserFrame } from "../BrowserFrame";
2026
import clsx from "clsx";
2127
import { Panel } from "../general/Panel";
@@ -70,7 +76,7 @@ function Features() {
7076
</p>
7177

7278
<a
73-
className={CTAOutlinedButtonMixin + " w-fit"}
79+
className={CTAOutlinedButtonWhiteMixin + " w-fit"}
7480
href="https://demo.firecms.co"
7581
rel="noopener noreferrer"
7682
target="_blank"

0 commit comments

Comments
 (0)