Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
36 changes: 19 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,25 @@ A **Pagination Table** & **Scroll List** component suite for [CRUD operation][1]

## Components

1. [Badge Bar](https://mobx-restful-shadcn.idea2.app/)
2. [Badge Input](https://mobx-restful-shadcn.idea2.app/)
3. [Image Preview](https://mobx-restful-shadcn.idea2.app/)
4. [File Preview](https://mobx-restful-shadcn.idea2.app/)
5. [File Picker](https://mobx-restful-shadcn.idea2.app/)
6. [File Uploader](https://mobx-restful-shadcn.idea2.app/)
7. [Form Field](https://mobx-restful-shadcn.idea2.app/)
8. [Range Input](https://mobx-restful-shadcn.idea2.app/)
9. [Array Field](https://mobx-restful-shadcn.idea2.app/)
10. [REST Form](https://mobx-restful-shadcn.idea2.app/)
11. [REST Form Modal](https://mobx-restful-shadcn.idea2.app/)
12. [Pager](https://mobx-restful-shadcn.idea2.app/)
13. [REST Table](https://mobx-restful-shadcn.idea2.app/)
14. [Scroll Boundary](https://mobx-restful-shadcn.idea2.app/)
15. [Scroll List](https://mobx-restful-shadcn.idea2.app/)
16. [Searchable Input](https://mobx-restful-shadcn.idea2.app/)
17. [Editor](https://mobx-restful-shadcn.idea2.app/)
1. [Spinner](https://mobx-restful-shadcn.idea2.app/r/spinner.json)
2. [Loading](https://mobx-restful-shadcn.idea2.app/r/loading.json)
3. [Badge Bar](https://mobx-restful-shadcn.idea2.app/r/badge-bar.json)
4. [Badge Input](https://mobx-restful-shadcn.idea2.app/r/badge-input.json)
5. [Image Preview](https://mobx-restful-shadcn.idea2.app/r/image-preview.json)
6. [File Preview](https://mobx-restful-shadcn.idea2.app/r/file-preview.json)
7. [File Picker](https://mobx-restful-shadcn.idea2.app/r/file-picker.json)
8. [File Uploader](https://mobx-restful-shadcn.idea2.app/r/file-uploader.json)
9. [Form Field](https://mobx-restful-shadcn.idea2.app/r/form-field.json)
10. [Range Input](https://mobx-restful-shadcn.idea2.app/r/range-input.json)
11. [Array Field](https://mobx-restful-shadcn.idea2.app/r/array-field.json)
12. [REST Form](https://mobx-restful-shadcn.idea2.app/r/rest-form.json)
13. [REST Form Modal](https://mobx-restful-shadcn.idea2.app/r/rest-form-modal.json)
14. [Pager](https://mobx-restful-shadcn.idea2.app/r/pager.json)
15. [REST Table](https://mobx-restful-shadcn.idea2.app/r/rest-table.json)
16. [Scroll Boundary](https://mobx-restful-shadcn.idea2.app/r/scroll-boundary.json)
17. [Scroll List](https://mobx-restful-shadcn.idea2.app/r/scroll-list.json)
18. [Searchable Input](https://mobx-restful-shadcn.idea2.app/r/searchable-input.json)
19. [Editor](https://mobx-restful-shadcn.idea2.app/r/editor.json)

## Installation

Expand Down
16 changes: 16 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import { FilePickerExample } from "@/registry/new-york/blocks/file-picker/exampl
import { FilePreviewExample } from "@/registry/new-york/blocks/file-preview/example";
import { FormFieldExample } from "@/registry/new-york/blocks/form-field/example";
import { ImagePreviewExample } from "@/registry/new-york/blocks/image-preview/example";
import { LoadingExample } from "@/registry/new-york/blocks/loading/example";
import { PagerExample } from "@/registry/new-york/blocks/pager/example";
import { RangeInputExample } from "@/registry/new-york/blocks/range-input/example";
import { RestTableExample } from "@/registry/new-york/blocks/rest-table/example";
import { ScrollBoundaryExample } from "@/registry/new-york/blocks/scroll-boundary/example";
import { ScrollListExample } from "@/registry/new-york/blocks/scroll-list/example";
import { SpinnerExample } from "@/registry/new-york/blocks/spinner/example";

export default function Home() {
return (
Expand All @@ -25,6 +27,20 @@ export default function Home() {
</p>
</header>
<main className="flex flex-col flex-1 gap-8">
<ComponentCard
name="spinner"
description="A loading spinner component with customizable size."
>
<SpinnerExample />
</ComponentCard>

<ComponentCard
name="loading"
description="A full-screen loading overlay component with spinner and customizable message."
>
<LoadingExample />
</ComponentCard>

<ComponentCard
name="badge-bar"
description="A component for displaying a list of badges with optional click and delete handlers."
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mobx-restful-shadcn",
"version": "1.6.0",
"version": "1.7.0",
"private": true,
"scripts": {
"prepare": "husky",
Expand Down
42 changes: 33 additions & 9 deletions registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,33 @@
"name": "mobx-restful-shadcn",
"homepage": "https://mobx-restful-shadcn.idea2.app",
"items": [
{
"name": "spinner",
"type": "registry:component",
"title": "Spinner",
"description": "A loading spinner component with customizable size.",
"files": [
{
"type": "registry:component",
"path": "registry/new-york/blocks/spinner/index.tsx",
"target": "components/ui/mobx-restful-shadcn/spinner/index.tsx"
}
]
},
{
"name": "loading",
"type": "registry:component",
"title": "Loading",
"description": "A full-screen loading overlay component with spinner and customizable message.",
"registryDependencies": ["@mobx-restful-shadcn/spinner"],
"files": [
{
"type": "registry:component",
"path": "registry/new-york/blocks/loading/index.tsx",
"target": "components/ui/mobx-restful-shadcn/loading/index.tsx"
}
]
},
{
"name": "badge-bar",
"type": "registry:component",
Expand Down Expand Up @@ -38,13 +65,8 @@
"type": "registry:component",
"title": "Image Preview",
"description": "An image preview component with modal viewing and download functionality.",
"registryDependencies": ["dialog"],
"dependencies": [
"lucide-react",
"mobx",
"mobx-react",
"mobx-react-helper"
],
"registryDependencies": ["dialog", "@mobx-restful-shadcn/spinner"],
"dependencies": ["mobx", "mobx-react", "mobx-react-helper"],
"files": [
{
"type": "registry:component",
Expand Down Expand Up @@ -266,7 +288,8 @@
"@mobx-restful-shadcn/badge-bar",
"@mobx-restful-shadcn/badge-input",
"@mobx-restful-shadcn/rest-form-modal",
"@mobx-restful-shadcn/scroll-list"
"@mobx-restful-shadcn/scroll-list",
"@mobx-restful-shadcn/spinner"
],
"dependencies": [
"lodash.debounce",
Expand Down Expand Up @@ -298,7 +321,8 @@
"@mobx-restful-shadcn/file-preview",
"@mobx-restful-shadcn/pager",
"@mobx-restful-shadcn/rest-form",
"@mobx-restful-shadcn/rest-form-modal"
"@mobx-restful-shadcn/rest-form-modal",
"@mobx-restful-shadcn/spinner"
],
"dependencies": [
"lodash.debounce",
Expand Down
4 changes: 2 additions & 2 deletions registry/new-york/blocks/image-preview/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import { Loader2 } from "lucide-react";
import { observable } from "mobx";
import { observer } from "mobx-react";
import { ObservedComponent, reaction } from "mobx-react-helper";
Expand All @@ -13,6 +12,7 @@ import {
DialogTitle,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
import { Spinner } from "../spinner";

export interface ImagePreviewProps extends ImgHTMLAttributes<HTMLImageElement> {
src: string;
Expand Down Expand Up @@ -77,7 +77,7 @@ export class ImagePreview extends ObservedComponent<ImagePreviewProps> {
{...props}
>
{downloading ? (
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
<Spinner className="text-muted-foreground" />
) : (
loadedPath && (
<img
Expand Down
24 changes: 24 additions & 0 deletions registry/new-york/blocks/loading/example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use client";

import { useState } from "react";

import { Button } from "@/components/ui/button";
import { Loading } from "./index";

export function LoadingExample() {
const [isLoading, setIsLoading] = useState(false);

return (
<div className="flex flex-col gap-4 items-center p-8">
<Button onClick={() => setIsLoading(!isLoading)}>
{isLoading ? "Hide Loading" : "Show Loading"}
</Button>

<p className="text-sm text-muted-foreground">
Click the button to toggle the full-screen loading overlay
</p>

{isLoading && <Loading>Please wait...</Loading>}
</div>
);
}
28 changes: 28 additions & 0 deletions registry/new-york/blocks/loading/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { FC, HTMLAttributes } from "react";

import { cn } from "@/lib/utils";
import { Spinner } from "../spinner";

export type LoadingProps = HTMLAttributes<HTMLDivElement>;

export const Loading: FC<LoadingProps> = ({
className,
children = "Loading...",
...props
}) => (
<div
className={cn(
"fixed inset-0 z-50 flex h-full w-full items-center justify-center bg-black/25",
className,
)}
{...props}
>
<div className="flex items-center gap-3">
<Spinner className="text-primary" />

{children && <span className="text-white">{children}</span>}
</div>
</div>
);

Loading.displayName = "Loading";
3 changes: 2 additions & 1 deletion registry/new-york/blocks/rest-table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { FilePreview } from "../file-preview";
import { Pager } from "../pager";
import { Field, RestForm, RestFormProps } from "../rest-form";
import { RestFormModal } from "../rest-form-modal";
import { Spinner } from "../spinner";

export interface Column<T extends DataObject>
extends Omit<Field<T>, "renderLabel"> {
Expand Down Expand Up @@ -301,7 +302,7 @@ export class RestTable<
<TableRow>
<TableCell className="text-center p-3" colSpan={columns.length}>
<div className="flex justify-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary" />
<Spinner />
</div>
</TableCell>
</TableRow>
Expand Down
3 changes: 2 additions & 1 deletion registry/new-york/blocks/searchable-input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { TextInputType } from "../badge-input";
import { RestFormProps } from "../rest-form";
import { RestFormModal } from "../rest-form-modal";
import { ScrollList, ScrollListProps } from "../scroll-list";
import { Spinner } from "../spinner";

export type OptionData = Record<"label" | "value", string>;

Expand Down Expand Up @@ -112,7 +113,7 @@ export class SearchableInput<
) : (
this.observedProps.store.downloading > 0 && (
<div className="text-center my-3">
<div className="inline-block h-4 w-4 animate-spin rounded-full border-2 border-solid border-current border-r-transparent" />
<Spinner size="sm" />
</div>
)
);
Expand Down
26 changes: 26 additions & 0 deletions registry/new-york/blocks/spinner/example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Spinner } from "./index";

export const SpinnerExample = () => (
<div className="flex flex-col gap-8 items-center p-8">
<div className="flex gap-4 items-center">
<Spinner size="sm" />
<span className="text-sm">Small Spinner</span>
</div>
<div className="flex gap-4 items-center">
<Spinner size="md" />
<span className="text-sm">Medium Spinner (Default)</span>
</div>
<div className="flex gap-4 items-center">
<Spinner size="lg" />
<span className="text-sm">Large Spinner</span>
</div>
<div className="flex gap-4 items-center">
<Spinner className="text-primary" />
<span className="text-sm">Custom Color (Primary)</span>
</div>
<div className="flex gap-4 items-center">
<Spinner className="text-destructive" size="lg" />
<span className="text-sm">Custom Color (Destructive)</span>
</div>
</div>
);
32 changes: 32 additions & 0 deletions registry/new-york/blocks/spinner/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { FC, HTMLAttributes } from "react";

import { cn } from "@/lib/utils";

export interface SpinnerProps extends HTMLAttributes<HTMLDivElement> {
size?: "sm" | "md" | "lg";
}

const SizeClass: Record<Required<SpinnerProps>["size"], string> = {
sm: "h-4 w-4 border-2",
md: "h-8 w-8 border-2",
lg: "h-12 w-12 border-4",
};

export const Spinner: FC<SpinnerProps> = ({
className,
size = "md",
...props
}) => (
<div
className={cn(
"inline-block animate-spin rounded-full border-solid border-current border-r-transparent",
SizeClass[size],
className,
)}
role="status"
aria-label="Loading"
{...props}
/>
);

Spinner.displayName = "Spinner";