A Pagination Table & Scroll List component suite for CRUD operation, which is based on MobX RESTful, React & Shadcn UI.
- Spinner
- Loading
- Badge Bar
- Badge Input
- Image Preview
- File Preview
- File Picker
- File Uploader
- Form Field
- Range Input
- Array Field
- REST Form
- REST Form Modal
- Pager
- REST Table
- Scroll Boundary
- Scroll List
- Searchable Input
- Editor
{
"registries": {
"@mobx-restful-shadcn": "https://mobx-restful-shadcn.idea2.app/r/{name}.json"
}
}npx shadcn-helper add @mobx-restful-shadcn/rest-tableReplace rest-table with any component name from the list above.
Set up i18n translation model for UI text:
import { TranslationModel } from "mobx-i18n";
import { IDType } from "mobx-restful";
export const i18n = new TranslationModel({
en_US: {
load_more: "Load more",
no_more: "No more",
create: "Create",
view: "View",
submit: "Submit",
cancel: "Cancel",
edit: "Edit",
delete: "Delete",
total_x_rows: ({ totalCount }: { totalCount: number }) =>
`Total ${totalCount} rows`,
sure_to_delete_x: ({ keys }: { keys: IDType[] }) =>
`Are you sure to delete ${keys.join(", ")}?`,
},
});Set up HTTP client and implement Model class:
import { githubClient, RepositoryModel } from "mobx-github";
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
githubClient.use(({ request }, next) => {
if (GITHUB_TOKEN)
request.headers = {
...request.headers,
Authorization: `Bearer ${GITHUB_TOKEN}`,
};
return next();
});
export const repositoryStore = new RepositoryModel("idea2app");import { computed } from "mobx";
import { observer } from "mobx-react";
import { Component } from "react";
import { BadgeBar } from "@/components/ui/badge-bar";
import { RestTable, Column } from "@/components/ui/rest-table";
import repositoryStore, { Repository } from "@/models/Repository";
import { i18n } from "@/models/Translation";
@observer
export class RepositoryTable extends Component {
@computed
get columns() {
return [
{
key: "full_name",
renderHead: "Repository Name",
renderBody: ({ html_url, full_name }) => (
<a target="_blank" href={html_url}>
{full_name}
</a>
),
required: true,
minLength: 3,
invalidMessage: "Input 3 characters at least",
},
{ key: "homepage", type: "url", renderHead: "Home Page" },
{ key: "language", renderHead: "Programming Language" },
{
key: "topics",
renderHead: "Topic",
renderBody: ({ topics }) => (
<BadgeBar
list={(topics || []).map((text) => ({
text,
link: `https://github.com/topics/${text}`,
}))}
/>
),
},
{ key: "stargazers_count", type: "number", renderHead: "Star Count" },
{ key: "description", renderHead: "Description", contentEditable: true },
];
}
render() {
return (
<RestTable
editable
deletable
columns={this.columns}
store={repositoryStore}
translator={i18n}
onCheck={console.log}
/>
);
}
}import { observer } from "mobx-react";
import { ScrollList } from "@/components/ui/scroll-list";
import repositoryStore from "@/models/Repository";
import { i18n } from "@/models/Translation";
export const ScrollListExample = () => (
<ScrollList
translator={i18n}
store={repositoryStore}
renderList={(allItems) => (
<ul className="grid grid-cols-1 md:grid-cols-2 gap-4">
{allItems.map(({ id, name, description }) => (
<li key={id} className="p-4 border rounded">
<h3>{name}</h3>
<p>{description}</p>
</li>
))}
</ul>
)}
/>
);import { FileModel, FileUploader } from "@/components/ui/file-uploader";
class MyFileModel extends FileModel {}
const store = new MyFileModel();
export const EditorPage = () => (
<FileUploader
store={store}
accept="image/*"
name="images"
multiple
required
onChange={console.log}
/>
);import { configure } from "mobx";
import { formToJSON } from "web-utility";
import { Editor, OriginalTools, ExtraTools } from "@/components/ui/editor";
configure({ enforceActions: "never" });
export const EditorPage = () => (
<form
onSubmit={(event) => {
event.preventDefault();
const { content } = formToJSON(event.currentTarget);
alert(content);
}}
>
<Editor
tools={[...OriginalTools, ...ExtraTools]}
name="content"
defaultValue="Hello <b>Edkit</b>!"
onChange={console.log}
/>
<button type="submit">Submit</button>
</form>
);This is a custom component registry built with Next.js and compatible with the shadcn CLI.
- Clone the repository
- Install dependencies:
pnpm install - Run development server:
pnpm dev - Build registry:
pnpm registry:build - Build project:
pnpm build
- The
registry.jsonfile defines all components and their files - Components are located in
registry/new-york/blocks/ - Each component has its implementation and example files
- The
shadcn buildcommand generates registry items inpublic/r/