Compare commits
143 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bd72301b01 | |||
| cc839cdd1f | |||
| c9e5c2ef7f | |||
| e8f5264cf8 | |||
| df7f773f3d | |||
| af925d56d1 | |||
| baec55029d | |||
| ea2868e58e | |||
| 691f380dff | |||
| ac8afec964 | |||
| 5fe5521a7c | |||
| 15403bc67e | |||
| c186f37c98 | |||
| 1bc2a50e2c | |||
| 453f792a7a | |||
| 3f6fd48eee | |||
| d7c6c79f38 | |||
| f068552774 | |||
| 6d7372ede1 | |||
| 1487219a1c | |||
| 6e7e834c2d | |||
| 80a8f7e94c | |||
| fae7467b64 | |||
| 4e7789c1f6 | |||
| 6694b934e6 | |||
| 4d341081e3 | |||
| df562449fb | |||
| 4063362699 | |||
| 94d65df533 | |||
| 8f66c6b564 | |||
| 4a19a3c906 | |||
| 0be398ade9 | |||
| 50d23e5378 | |||
| d0341020e6 | |||
| 4170ecdc76 | |||
| e2b0076b53 | |||
| e2b0497b07 | |||
| df3b309542 | |||
| 6c35a502fe | |||
| a629f8c088 | |||
| fd4e01dcfa | |||
| e9c08abd55 | |||
| 3e263aa882 | |||
| 9add9aba97 | |||
| 0311ae43f1 | |||
| 79c5fb9a94 | |||
| abe1ba58de | |||
| e6c3747153 | |||
| d15b16ecab | |||
| fe03c42fa1 | |||
| 25a918d146 | |||
| 87918ac5b4 | |||
| a30cec4810 | |||
| 1b0653c97a | |||
| 710395f3a2 | |||
| e7e58e854a | |||
| d13a14facc | |||
| cef7235c4b | |||
| fcff1a1d36 | |||
| c7ba9e1508 | |||
| 1d8dc4b9d8 | |||
| ea5e0fb096 | |||
| 26f64d043d | |||
| a078c3dcd2 | |||
| 5a50390e3f | |||
| 894d85d059 | |||
| 0ef41d27e7 | |||
| 4200164712 | |||
| 6d4c6980d5 | |||
| f3f36a7146 | |||
| 8de209bff7 | |||
| e9d01be74d | |||
| 66ac2e67ae | |||
| 7ed88f39c1 | |||
| 32d18bfd41 | |||
| a1b32c1ceb | |||
| 9e683b32ba | |||
| b7c947805d | |||
| a76fdfa774 | |||
| ac605eb71f | |||
| 5b343b6181 | |||
| 05562dcf90 | |||
| 0a60388258 | |||
| d794225cb7 | |||
| ec2ed200f5 | |||
| 2f7703ec8e | |||
| 25cbe1146f | |||
| 3db9b6248e | |||
| b1b5eda15b | |||
| e3e13a095f | |||
| 86f921d098 | |||
| eefda8d6e2 | |||
| 2e4ce7bcee | |||
| 5a4c4f498d | |||
| ec30a9adbd | |||
| a6954c4156 | |||
| b887a2f503 | |||
| edc2bc741e | |||
| a1a02dc0db | |||
| cd1dc8b469 | |||
| 459ac5ed45 | |||
| 9c4bb22e87 | |||
| 7fa5459381 | |||
| b77b8fa9d7 | |||
| c6c4a4d6a1 | |||
| e96b1dbab0 | |||
| 1b55d27645 | |||
| bdc246a8a4 | |||
| 5064bfe4e4 | |||
| 36ddbff557 | |||
| 043b42c895 | |||
| c8330b8106 | |||
| 7f20346423 | |||
| 85b3fd7269 | |||
| 649204ceac | |||
| c7a1376872 | |||
| 3323592211 | |||
| fb570a372d | |||
| 184d3a9c49 | |||
| 849eff5715 | |||
| b400f3ee6d | |||
| dedede0be0 | |||
| e96a23c8a3 | |||
| 7efd6c97e4 | |||
| 43e5e4fb26 | |||
| 39da69cf81 | |||
| 8743a6c6b6 | |||
| c635c951d6 | |||
| cb05342a4a | |||
| 59ef7bc6b6 | |||
| cfd19415ea | |||
| 39ca892b4e | |||
| fc2dad8b39 | |||
| d9bbd2e45f | |||
| 75bc039b4b | |||
| e79bd0fa4c | |||
| 65c5af4f63 | |||
| f58c8a7d99 | |||
| 9da06aaa50 | |||
| 508f11e968 | |||
| 2812f61f4f | |||
| 0ee0e95678 | |||
| e940ec06ac |
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
|
||||
"changelog": false,
|
||||
"changelog": [
|
||||
"@changesets/changelog-github",
|
||||
{ "repo": "nextui-org/nextui" }
|
||||
],
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.now/*
|
||||
.next/*
|
||||
*.css
|
||||
.changeset
|
||||
dist
|
||||
esm/*
|
||||
public/*
|
||||
|
||||
@@ -21,6 +21,16 @@ body:
|
||||
- NextUI's [Discussions tab](https://github.com/nextui-org/nextui/discussions)
|
||||
|
||||
The more information you fill in, the better the community can help you.
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: NextUI Version
|
||||
description: |
|
||||
Please provide the version of NextUI you are using.
|
||||
You can find the version number in the package.json file.
|
||||
placeholder: ex. 2.0.10
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
name: "Install"
|
||||
description: "Sets up Node.js and runs install"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 8
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Setup Git User
|
||||
shell: bash
|
||||
run: |
|
||||
git config --global user.email "jrgarciadev@gmail.com"
|
||||
git config --global user.name "Junior Garcia"
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: pnpm install
|
||||
@@ -0,0 +1,72 @@
|
||||
name: QA
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/common-actions/install
|
||||
|
||||
- name: Build packages
|
||||
run: pnpm build
|
||||
|
||||
tests:
|
||||
name: Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/common-actions/install
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
|
||||
eslint:
|
||||
name: ESLint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/common-actions/install
|
||||
|
||||
- name: Run ESLint
|
||||
run: pnpm lint
|
||||
|
||||
types:
|
||||
name: TypeScript
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/common-actions/install
|
||||
|
||||
- name: Run typecheck
|
||||
run: pnpm typecheck
|
||||
|
||||
prettier:
|
||||
name: Prettier
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/common-actions/install
|
||||
|
||||
- name: Run prettier
|
||||
run: pnpm format:check
|
||||
@@ -1,128 +0,0 @@
|
||||
name: CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore: ['**/README.md']
|
||||
pull_request:
|
||||
branches: [main]
|
||||
types: [opened, synchronize]
|
||||
paths-ignore: ['**/README.md']
|
||||
|
||||
jobs:
|
||||
avoid_reduncy:
|
||||
runs-on: ubuntu-20.04
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
steps:
|
||||
- name: Cancel Previous Redundant Builds
|
||||
uses: styfle/cancel-workflow-action@0.9.1
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: '16'
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: '16'
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ github.workspace }}/.next/cache
|
||||
# Generate a new cache whenever packages or source files change.
|
||||
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
|
||||
# If source files changed but packages didn't, rebuild from a prior cache.
|
||||
restore-keys: |
|
||||
${{ runner.os }}-nextjs-${{ hashFiles('**/yarn.lock') }}-
|
||||
- name: Build
|
||||
run: yarn build
|
||||
|
||||
tests:
|
||||
needs: [lint, build]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: '16'
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Test
|
||||
run: yarn coverage:update
|
||||
- uses: codecov/codecov-action@v2
|
||||
with:
|
||||
directory: './packages/react'
|
||||
|
||||
publish:
|
||||
needs: [build, tests]
|
||||
runs-on: ubuntu-20.04
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: '16'
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Pre puiblish NextUI package
|
||||
run: yarn pre-publish:nextui
|
||||
- uses: JS-DevTools/npm-publish@v1
|
||||
with:
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
package: './packages/react/lib/package.json'
|
||||
- name: Show published version
|
||||
if: steps.publish.outputs.type != 'none'
|
||||
run: |
|
||||
echo "Version changed: ${{ steps.publish.outputs.old-version }} => ${{ steps.publish.outputs.version }}"
|
||||
- name: Tag new version
|
||||
if: steps.publish.outputs.type != 'none'
|
||||
uses: Klemensas/action-autotag@stable
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
tag_prefix: "v"
|
||||
package_root: "./packages/react"
|
||||
|
||||
update_algolia_index:
|
||||
needs: [publish]
|
||||
runs-on: ubuntu-20.04
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: '16'
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- name: Upload docs on Algolia
|
||||
run: yarn build:docs-meta
|
||||
env:
|
||||
ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }}
|
||||
ALGOLIA_ADMIN_API_KEY: ${{ secrets.ALGOLIA_ADMIN_API_KEY }}
|
||||
ALGOLIA_SEARCH_API_KEY: ${{ secrets.ALGOLIA_SEARCH_API_KEY }}
|
||||
@@ -1,17 +1,52 @@
|
||||
name: Tagged Release
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
paths:
|
||||
- ".changeset/**"
|
||||
- "packages/**"
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
tagged-release:
|
||||
name: Tagged Release
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/common-actions/install
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Tests
|
||||
run: pnpm test
|
||||
|
||||
- name: Create Release Pull Request or Publish to NPM
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
repo_token: "${{ github.token }}"
|
||||
prerelease: false
|
||||
publish: pnpm release
|
||||
title: "ci(changesets): :package: version packages"
|
||||
commit: "ci(changesets): version packages"
|
||||
setupGitUser: false
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create @dev release
|
||||
if: steps.changesets.outputs.published != 'true'
|
||||
run: |
|
||||
git checkout main
|
||||
pnpm version:dev
|
||||
pnpm release:dev
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -20,6 +20,7 @@ coverage
|
||||
dist/
|
||||
storybook-static
|
||||
/packages/storybook/public/tailwind.css
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
|
||||
+2
-2
@@ -13,12 +13,12 @@ const removeIgnoredFiles = async (files) => {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
"**/*.{cjs,mjs,js,ts,jsx,tsx}": async (files) => {
|
||||
"**/*.{js,ts,jsx,tsx}": async (files) => {
|
||||
const filesToLint = await removeIgnoredFiles(files);
|
||||
|
||||
return [`eslint -c .eslintrc.json --max-warnings=0 --fix ${filesToLint}`];
|
||||
},
|
||||
"**/*.{css,json,md}": async (files) => {
|
||||
"**/*.css": async (files) => {
|
||||
const filesToLint = await removeIgnoredFiles(files);
|
||||
|
||||
return [`prettier --config .prettierrc.json --ignore-path --write ${filesToLint}`];
|
||||
|
||||
@@ -2,6 +2,7 @@ dist
|
||||
node_modules
|
||||
plop
|
||||
coverage
|
||||
.changeset
|
||||
.next
|
||||
build
|
||||
scripts
|
||||
|
||||
@@ -11,7 +11,6 @@ import {MDXContent} from "@/components/mdx-content";
|
||||
import {siteConfig} from "@/config/site";
|
||||
import {Route} from "@/libs/docs/page";
|
||||
import {ChevronRightLinearIcon} from "@/components/icons";
|
||||
import {__PROD__} from "@/utils";
|
||||
|
||||
interface BlogPostProps {
|
||||
params: {
|
||||
@@ -79,7 +78,7 @@ export async function generateStaticParams(): Promise<BlogPostProps["params"][]>
|
||||
export default async function DocPage({params}: BlogPostProps) {
|
||||
const {post} = await getBlogPostFromParams({params});
|
||||
|
||||
if (!post || __PROD__) {
|
||||
if (!post) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,10 @@ import {allBlogPosts} from "contentlayer/generated";
|
||||
import {compareDesc} from "date-fns";
|
||||
|
||||
import {BlogPostList} from "@/components/blog-post";
|
||||
import {__PROD__} from "@/utils";
|
||||
|
||||
export default function Blog() {
|
||||
const posts = allBlogPosts.sort((a, b) => compareDesc(new Date(a.date), new Date(b.date)));
|
||||
|
||||
if (__PROD__) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full lg:px-16 mt-12">
|
||||
<div className="text-center">
|
||||
|
||||
@@ -16,7 +16,7 @@ import {useState} from "react";
|
||||
|
||||
export default function Page() {
|
||||
const {isOpen, onOpen, onOpenChange} = useDisclosure();
|
||||
const [modalPlacement, setModalPlacement] = useState<ModalProps["placement"]>("auto");
|
||||
const [modalPlacement, setModalPlacement] = useState("auto");
|
||||
|
||||
return (
|
||||
<div className="flex px-10 min-h-[80vh] justify-center items-center flex-col gap-4">
|
||||
@@ -36,7 +36,11 @@ export default function Page() {
|
||||
<Radio value="top-center">top-center</Radio>
|
||||
<Radio value="bottom-center">bottom-center</Radio>
|
||||
</RadioGroup>
|
||||
<Modal isOpen={isOpen} placement={modalPlacement} onOpenChange={onOpenChange}>
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
placement={modalPlacement as ModalProps["placement"]}
|
||||
onOpenChange={onOpenChange}
|
||||
>
|
||||
<ModalContent>
|
||||
{(onClose) => (
|
||||
<>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
NavbarMenu,
|
||||
NavbarMenuItem,
|
||||
NavbarMenuToggle,
|
||||
Avatar,
|
||||
Button,
|
||||
Link as NextUiLink,
|
||||
LinkProps,
|
||||
} from "@nextui-org/react";
|
||||
@@ -79,16 +79,13 @@ export default function Page() {
|
||||
</NavbarContent>
|
||||
|
||||
<NavbarContent justify="end">
|
||||
<NavbarItem className="hidden lg:flex">
|
||||
<Link href="#">Login</Link>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<Avatar
|
||||
isBordered
|
||||
as="button"
|
||||
className="transition-transform"
|
||||
color="warning"
|
||||
name="Jane Lee"
|
||||
size="sm"
|
||||
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
|
||||
/>
|
||||
<Button as={Link} color="warning" href="#" variant="flat">
|
||||
Sign Up
|
||||
</Button>
|
||||
</NavbarItem>
|
||||
</NavbarContent>
|
||||
|
||||
|
||||
@@ -51,22 +51,19 @@ export default function Page() {
|
||||
</Link>
|
||||
</NavbarItem>
|
||||
</NavbarContent>
|
||||
<NavbarContent justify="end">
|
||||
<NavbarContent as="div" justify="end">
|
||||
<Dropdown placement="bottom-end">
|
||||
<NavbarItem>
|
||||
<DropdownTrigger>
|
||||
<Avatar
|
||||
isBordered
|
||||
as={Link}
|
||||
className="transition-transform"
|
||||
color="secondary"
|
||||
href="#"
|
||||
name="Jason Hughes"
|
||||
size="sm"
|
||||
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
</NavbarItem>
|
||||
<DropdownTrigger>
|
||||
<Avatar
|
||||
isBordered
|
||||
as="button"
|
||||
className="transition-transform"
|
||||
color="secondary"
|
||||
name="Jason Hughes"
|
||||
size="sm"
|
||||
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu aria-label="Profile Actions" variant="flat">
|
||||
<DropdownItem key="profile" className="h-14 gap-2">
|
||||
<p className="font-semibold">Signed in as</p>
|
||||
|
||||
@@ -56,12 +56,13 @@ export default function Page() {
|
||||
</NavbarItem>
|
||||
</NavbarContent>
|
||||
</NavbarContent>
|
||||
<NavbarContent className="items-center" justify="end">
|
||||
<NavbarContent as="div" className="items-center" justify="end">
|
||||
<Input
|
||||
classNames={{
|
||||
base: "max-w-full sm:max-w-[10rem] h-10",
|
||||
input: "text-small",
|
||||
inputWrapper: "font-normal text-default-500 bg-default-400/20 dark:bg-default-500/20",
|
||||
inputWrapper:
|
||||
"h-full font-normal text-default-500 bg-default-400/20 dark:bg-default-500/20",
|
||||
}}
|
||||
placeholder="Type to search..."
|
||||
startContent={<SearchLinearIcon size={18} />}
|
||||
@@ -72,10 +73,9 @@ export default function Page() {
|
||||
<DropdownTrigger>
|
||||
<Avatar
|
||||
isBordered
|
||||
as={Link}
|
||||
as="button"
|
||||
className="transition-transform"
|
||||
color="secondary"
|
||||
href="#"
|
||||
name="Jason Hughes"
|
||||
size="sm"
|
||||
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
|
||||
|
||||
@@ -179,9 +179,9 @@ const MyButton2 = extendVariants(Button, {
|
||||
});
|
||||
|
||||
export default function NextUIPerf() {
|
||||
const [textA, setTextA] = useState<string | undefined>("");
|
||||
const [textB, setTextB] = useState<string | undefined>("");
|
||||
const [textC, setTextC] = useState<string | undefined>("");
|
||||
const [textA, setTextA] = useState<string>("");
|
||||
const [textB, setTextB] = useState<string>("");
|
||||
const [textC, setTextC] = useState<string>("");
|
||||
|
||||
return (
|
||||
<div className="w-full p-24 gap-4 flex flex-col">
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/* eslint-disable no-console */
|
||||
"use client";
|
||||
|
||||
import {Select, SelectItem} from "@nextui-org/react";
|
||||
import {useEffect, useState} from "react";
|
||||
import {useInfiniteScroll} from "@nextui-org/use-infinite-scroll";
|
||||
|
||||
type Pokemon = {
|
||||
name: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
type UsePokemonListProps = {
|
||||
/** Delay to wait before fetching more items */
|
||||
fetchDelay?: number;
|
||||
};
|
||||
|
||||
function usePokemonList({fetchDelay = 0}: UsePokemonListProps = {}) {
|
||||
const [items, setItems] = useState<Pokemon[]>([]);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [offset, setOffset] = useState(0);
|
||||
const limit = 10; // Number of items per page, adjust as necessary
|
||||
|
||||
const loadPokemon = async (currentOffset: number) => {
|
||||
const controller = new AbortController();
|
||||
const {signal} = controller;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
if (offset > 0) {
|
||||
// Delay to simulate network latency
|
||||
await new Promise((resolve) => setTimeout(resolve, fetchDelay));
|
||||
}
|
||||
|
||||
let res = await fetch(
|
||||
`https://pokeapi.co/api/v2/pokemon?offset=${currentOffset}&limit=${limit}`,
|
||||
{signal},
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
|
||||
let json = await res.json();
|
||||
|
||||
setHasMore(json.next !== null);
|
||||
// Append new results to existing ones
|
||||
setItems((prevItems) => [...prevItems, ...json.results]);
|
||||
} catch (error) {
|
||||
// @ts-ignore
|
||||
if (error.name === "AbortError") {
|
||||
console.log("Fetch aborted");
|
||||
} else {
|
||||
console.error("There was an error with the fetch operation:", error);
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadPokemon(offset);
|
||||
}, []);
|
||||
|
||||
const onLoadMore = () => {
|
||||
const newOffset = offset + limit;
|
||||
|
||||
setOffset(newOffset);
|
||||
loadPokemon(newOffset);
|
||||
};
|
||||
|
||||
return {
|
||||
items,
|
||||
hasMore,
|
||||
isLoading,
|
||||
onLoadMore,
|
||||
};
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const {items, hasMore, isLoading, onLoadMore} = usePokemonList({fetchDelay: 1500});
|
||||
|
||||
const [, scrollerRef] = useInfiniteScroll({
|
||||
hasMore,
|
||||
isEnabled: isOpen,
|
||||
shouldUseLoader: false, // We don't want to show the loader at the bottom of the list
|
||||
onLoadMore,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-6">
|
||||
<Select
|
||||
className="max-w-xs"
|
||||
isLoading={isLoading}
|
||||
items={items}
|
||||
label="Pick a Pokemon"
|
||||
placeholder="Select a Pokemon"
|
||||
scrollRef={scrollerRef}
|
||||
selectionMode="single"
|
||||
onOpenChange={setIsOpen}
|
||||
>
|
||||
{(item) => (
|
||||
<SelectItem key={item.name} className="capitalize">
|
||||
{item.name}
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -105,7 +105,7 @@ const users = [
|
||||
email: "kristen.cooper@example.com",
|
||||
},
|
||||
{
|
||||
key: 6,
|
||||
id: 6,
|
||||
name: "Brian Kim",
|
||||
role: "P. Manager",
|
||||
team: "Management",
|
||||
|
||||
@@ -105,7 +105,7 @@ const users = [
|
||||
email: "kristen.cooper@example.com",
|
||||
},
|
||||
{
|
||||
key: 6,
|
||||
id: 6,
|
||||
name: "Brian Kim",
|
||||
role: "P. Manager",
|
||||
team: "Management",
|
||||
@@ -271,8 +271,6 @@ export default function Page() {
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
|
||||
const pages = Math.ceil(users.length / rowsPerPage);
|
||||
|
||||
const hasSearchFilter = Boolean(filterValue);
|
||||
|
||||
const headerColumns = useMemo(() => {
|
||||
@@ -298,6 +296,8 @@ export default function Page() {
|
||||
return filteredUsers;
|
||||
}, [users, filterValue, statusFilter]);
|
||||
|
||||
const pages = Math.ceil(filteredItems.length / rowsPerPage);
|
||||
|
||||
const items = useMemo(() => {
|
||||
const start = (page - 1) * rowsPerPage;
|
||||
const end = start + rowsPerPage;
|
||||
@@ -390,6 +390,11 @@ export default function Page() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onClear = useCallback(() => {
|
||||
setFilterValue("");
|
||||
setPage(1);
|
||||
}, []);
|
||||
|
||||
const topContent = useMemo(() => {
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
@@ -400,7 +405,7 @@ export default function Page() {
|
||||
placeholder="Search by name..."
|
||||
startContent={<SearchIcon />}
|
||||
value={filterValue}
|
||||
onClear={() => setFilterValue("")}
|
||||
onClear={() => onClear()}
|
||||
onValueChange={onSearchChange}
|
||||
/>
|
||||
<div className="flex gap-3">
|
||||
@@ -483,23 +488,22 @@ export default function Page() {
|
||||
<span className="w-[30%] text-small text-default-400">
|
||||
{selectedKeys === "all"
|
||||
? "All items selected"
|
||||
: `${selectedKeys.size} of ${items.length} selected`}
|
||||
: `${selectedKeys.size} of ${filteredItems.length} selected`}
|
||||
</span>
|
||||
<Pagination
|
||||
isCompact
|
||||
showControls
|
||||
showShadow
|
||||
color="primary"
|
||||
isDisabled={hasSearchFilter}
|
||||
page={page}
|
||||
total={pages}
|
||||
onChange={setPage}
|
||||
/>
|
||||
<div className="hidden sm:flex w-[30%] justify-end gap-2">
|
||||
<Button isDisabled={hasSearchFilter} size="sm" variant="flat" onPress={onPreviousPage}>
|
||||
<Button isDisabled={pages === 1} size="sm" variant="flat" onPress={onPreviousPage}>
|
||||
Previous
|
||||
</Button>
|
||||
<Button isDisabled={hasSearchFilter} size="sm" variant="flat" onPress={onNextPage}>
|
||||
<Button isDisabled={pages === 1} size="sm" variant="flat" onPress={onNextPage}>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import Rss from "rss";
|
||||
import {allBlogPosts} from "contentlayer/generated";
|
||||
|
||||
import {siteConfig} from "@/config/site";
|
||||
import {allCoreContent} from "@/libs/contentlayer";
|
||||
|
||||
export async function GET() {
|
||||
const feed = new Rss({
|
||||
title: siteConfig.name,
|
||||
description: siteConfig.description,
|
||||
feed_url: `${siteConfig.siteUrl}/feed.xml`,
|
||||
site_url: siteConfig.siteUrl,
|
||||
webMaster: `${siteConfig.author} <${siteConfig.email}>`,
|
||||
managingEditor: `${siteConfig.author} <${siteConfig.email}>`,
|
||||
language: "en-US",
|
||||
});
|
||||
|
||||
allCoreContent(allBlogPosts).forEach((post) => {
|
||||
const author = post.author ? post.author : siteConfig.author;
|
||||
|
||||
feed.item({
|
||||
title: post.title,
|
||||
description: post.description ?? "",
|
||||
url: `${siteConfig.siteUrl}/blog/${post.slug}`,
|
||||
guid: `${siteConfig.siteUrl}/blog/${post.slug}`,
|
||||
date: post.date,
|
||||
author: `${author} <${siteConfig.email}>`,
|
||||
categories: post.tags ?? [],
|
||||
});
|
||||
});
|
||||
|
||||
return new Response(feed.xml(), {
|
||||
headers: {
|
||||
"Content-Type": "application/xml",
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import {Button, Image, Link} from "@nextui-org/react";
|
||||
|
||||
import {Blockquote} from "@/components/docs/components/blockquote";
|
||||
|
||||
export default function FigmaPage() {
|
||||
return (
|
||||
<>
|
||||
<main className="relative container mx-auto max-w-7xl z-10 px-6 min-h-[calc(100vh_-_64px_-_108px)] mb-12 flex-grow">
|
||||
<section className="w-full flex flex-col items-center lg:px-16 mt-12 gap-6">
|
||||
<div className="text-center max-w-xl">
|
||||
<h1 className="mb-2 font-bold text-4xl">NextUI Figma Kit</h1>
|
||||
<h5 className="text-default-500 text-lg">
|
||||
A Figma file that contains the basis of the NextUI design system to help you design
|
||||
your applications.
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
<iframe
|
||||
className="aspect-video w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
|
||||
height="600"
|
||||
src="https://embed.figma.com/file/1267584376234254760/hf_embed?community_viewer=true&embed_host=nextui"
|
||||
title="NextUI Figma Kit"
|
||||
width="800"
|
||||
/>
|
||||
<div className="text-center max-w-2xl m-auto">
|
||||
<Button className="max-w-fit" color="default" variant="bordered">
|
||||
<Link
|
||||
isExternal
|
||||
showAnchorIcon
|
||||
className="text-current"
|
||||
href="https://www.figma.com/community/file/1267584376234254760"
|
||||
>
|
||||
Open in Figma
|
||||
</Link>
|
||||
</Button>
|
||||
<Blockquote color="warning">
|
||||
This file is still in development and will be continuously updated.
|
||||
</Blockquote>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="fixed hidden dark:md:block dark:opacity-70 -bottom-[40%] -left-[20%] z-0"
|
||||
>
|
||||
<Image removeWrapper alt="docs left background" src="/gradients/docs-left.png" />
|
||||
</div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="fixed hidden dark:md:block dark:opacity-70 -top-[80%] -right-[60%] 2xl:-top-[60%] 2xl:-right-[45%] z-0 rotate-12"
|
||||
>
|
||||
<Image removeWrapper alt="docs right background" src="/gradients/docs-right.png" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export const metadata: Metadata = {
|
||||
],
|
||||
icons: {
|
||||
icon: "/favicon.ico",
|
||||
shortcut: "/favicon-16x16.png",
|
||||
shortcut: "/favicon-32x32.png",
|
||||
apple: "/apple-touch-icon.png",
|
||||
},
|
||||
manifest: "/manifest.json",
|
||||
@@ -64,7 +64,7 @@ export default function RootLayout({children}: {children: React.ReactNode}) {
|
||||
<body className={clsx("min-h-screen bg-background font-sans antialiased", fontSans.variable)}>
|
||||
<Providers themeProps={{attribute: "class", defaultTheme: "dark"}}>
|
||||
<div className="relative flex flex-col" id="app-container">
|
||||
<Navbar routes={manifest.routes} />
|
||||
<Navbar mobileRoutes={manifest.mobileRoutes} routes={manifest.routes} />
|
||||
{children}
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Spacer} from "@nextui-org/react";
|
||||
import {Spacer} from "@nextui-org/spacer";
|
||||
|
||||
import {Hero} from "@/components/marketing/hero";
|
||||
import {FeaturesGrid} from "@/components/marketing/features-grid";
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import React, {useCallback, useEffect} from "react";
|
||||
import Script from "next/script";
|
||||
|
||||
import carbonOptimize from "./carbon-optimize";
|
||||
|
||||
import {loadScript} from "@/utils/scripts";
|
||||
import {useIsMounted} from "@/hooks/use-is-mounted";
|
||||
import {__PROD__} from "@/utils";
|
||||
|
||||
const EA_PROVIDER_RATIO = 0.85;
|
||||
|
||||
export const CarbonAd: React.FC<unknown> = () => {
|
||||
const carbonRef = React.useRef(null);
|
||||
const [showEthicalAds, setShowEthicalAds] = React.useState(false);
|
||||
|
||||
const isMounted = useIsMounted();
|
||||
|
||||
const loadEthicalAds = useCallback(() => {
|
||||
return new Promise((resolve) => {
|
||||
const script = document.createElement("script");
|
||||
|
||||
script.src = "https://media.ethicalads.io/media/client/ethicalads.min.js";
|
||||
script.async = true;
|
||||
script.onload = () => {
|
||||
// @ts-ignore
|
||||
resolve(window.ethicalads);
|
||||
};
|
||||
|
||||
script.onerror = () => {
|
||||
resolve(null);
|
||||
};
|
||||
|
||||
document.body.appendChild(script);
|
||||
|
||||
return () => {
|
||||
document.body.removeChild(script);
|
||||
};
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const shouldShowEthicalAds = Math.random() < EA_PROVIDER_RATIO;
|
||||
|
||||
let loadCarbon: any = null;
|
||||
|
||||
const loadCarbonAds = () => {
|
||||
setShowEthicalAds(false);
|
||||
// The isolation logic of carbonads is flawed.
|
||||
// Once the script starts loading, it will asynchronous resolve, with no way to stop it.
|
||||
// This leads to duplication of the ad. To solve the issue, we debounce the load action.
|
||||
loadCarbon =
|
||||
isMounted &&
|
||||
setTimeout(() => {
|
||||
const script = loadScript(
|
||||
"https://cdn.carbonads.com/carbon.js?serve=CESIC53Y&placement=nextuiorg",
|
||||
carbonRef.current,
|
||||
);
|
||||
|
||||
script.id = "_carbonads_js";
|
||||
carbonOptimize.init();
|
||||
});
|
||||
};
|
||||
|
||||
const loadAdProvider = async () => {
|
||||
if (shouldShowEthicalAds) {
|
||||
try {
|
||||
const ethicalads = await loadEthicalAds();
|
||||
|
||||
if (!ethicalads) {
|
||||
loadCarbonAds();
|
||||
|
||||
return;
|
||||
}
|
||||
// @ts-ignore
|
||||
ethicalads.wait.then((placements) => {
|
||||
if (!placements.length) {
|
||||
loadCarbonAds();
|
||||
} else {
|
||||
setShowEthicalAds(true);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
loadCarbonAds();
|
||||
}
|
||||
} else {
|
||||
loadCarbonAds();
|
||||
}
|
||||
};
|
||||
|
||||
loadAdProvider();
|
||||
|
||||
return () => {
|
||||
loadCarbon && clearTimeout(loadCarbon);
|
||||
};
|
||||
}, [isMounted]);
|
||||
|
||||
if (!__PROD__) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<>
|
||||
<Script async src="https://media.ethicalads.io/media/client/ethicalads.min.js" />
|
||||
<div
|
||||
className="ea-container horizontal"
|
||||
data-ea-campaign-types="paid|publisher-house|community"
|
||||
data-ea-publisher="nextuiorg"
|
||||
data-ea-type="image"
|
||||
style={{display: showEthicalAds ? "block" : "none"}}
|
||||
/>
|
||||
</>
|
||||
<div className="carbon-ad-container" style={{display: showEthicalAds ? "none" : "block"}}>
|
||||
<span ref={carbonRef} id="carbon-ad" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
export default {
|
||||
isRefreshAble: function () {
|
||||
return !(
|
||||
typeof document.addEventListener === "undefined" || this.browserSupport().hidden === undefined
|
||||
);
|
||||
},
|
||||
browserSupport: function () {
|
||||
let hidden;
|
||||
let visibilityChange;
|
||||
|
||||
if (typeof document.hidden !== "undefined") {
|
||||
// Opera 12.10 and Firefox 18 and later support
|
||||
hidden = "hidden";
|
||||
visibilityChange = "visibilitychange";
|
||||
} else if (typeof document.msHidden !== "undefined") {
|
||||
hidden = "msHidden";
|
||||
visibilityChange = "msvisibilitychange";
|
||||
} else if (typeof document.webkitHidden !== "undefined") {
|
||||
hidden = "webkitHidden";
|
||||
visibilityChange = "webkitvisibilitychange";
|
||||
}
|
||||
|
||||
return {
|
||||
hidden: hidden,
|
||||
visibilityChange: visibilityChange,
|
||||
};
|
||||
},
|
||||
handleVisibilityChange: function () {
|
||||
const isElementInViewport = function (el) {
|
||||
let element = document.querySelector(el);
|
||||
let bounding = element.getBoundingClientRect();
|
||||
let isVisible;
|
||||
|
||||
if (
|
||||
bounding.top >= 0 &&
|
||||
bounding.left >= 0 &&
|
||||
bounding.right <= window.innerWidth &&
|
||||
bounding.bottom <= window.innerHeight
|
||||
) {
|
||||
isVisible = true;
|
||||
} else {
|
||||
isVisible = false;
|
||||
}
|
||||
|
||||
return isVisible;
|
||||
};
|
||||
|
||||
if (!document.hidden) {
|
||||
if (typeof _carbonads !== "undefined" && isElementInViewport("#carbonads")) {
|
||||
// eslint-disable-next-line no-undef
|
||||
_carbonads.refresh();
|
||||
}
|
||||
}
|
||||
},
|
||||
init: function () {
|
||||
if (this.isRefreshAble()) {
|
||||
document.addEventListener(
|
||||
this.browserSupport().visibilityChange,
|
||||
this.handleVisibilityChange,
|
||||
false,
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./carbon-ad";
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import {BlogPost} from "contentlayer/generated";
|
||||
import {Card, CardFooter, CardBody, CardHeader, Link, Avatar} from "@nextui-org/react";
|
||||
import {Card, CardFooter, CardBody, CardHeader, Link, Avatar, Image} from "@nextui-org/react";
|
||||
import Balancer from "react-wrap-balancer";
|
||||
import {format, parseISO} from "date-fns";
|
||||
import NextLink from "next/link";
|
||||
@@ -15,7 +15,7 @@ const BlogPostCard = (post: BlogPost) => {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isMounted && (
|
||||
<motion.div
|
||||
<motion.article
|
||||
animate={{opacity: 1, y: 0}}
|
||||
exit={{opacity: 0, y: 5}}
|
||||
initial={{opacity: 0, y: 5}}
|
||||
@@ -24,7 +24,7 @@ const BlogPostCard = (post: BlogPost) => {
|
||||
<Card
|
||||
isBlurred
|
||||
as={NextLink}
|
||||
className="p-2 border-transparent text-start bg-white/5 dark:bg-default-400/10 backdrop-blur-lg backdrop-saturate-[1.8]"
|
||||
className="p-2 h-full border-transparent text-start bg-white/5 dark:bg-default-400/10 backdrop-blur-lg backdrop-saturate-[1.8]"
|
||||
href={post.url}
|
||||
isPressable={!!post.url}
|
||||
>
|
||||
@@ -39,10 +39,9 @@ const BlogPostCard = (post: BlogPost) => {
|
||||
<Balancer>{post.title}</Balancer>
|
||||
</Link>
|
||||
</CardHeader>
|
||||
<CardBody className="px-3 pt-0 pb-1">
|
||||
<p className="font-normal text-default-600">
|
||||
<Balancer>{post.description}</Balancer>
|
||||
</p>
|
||||
<CardBody className="pt-0 px-2 pb-1">
|
||||
<Image className="mb-4" src={post.image} />
|
||||
<p className="font-normal w-full text-default-600">{post.description}</p>
|
||||
</CardBody>
|
||||
<CardFooter className="flex justify-between items-center">
|
||||
<time className="block text-small text-default-500" dateTime={post.date}>
|
||||
@@ -51,7 +50,7 @@ const BlogPostCard = (post: BlogPost) => {
|
||||
<Avatar size="sm" src={post.author?.avatar} />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</motion.div>
|
||||
</motion.article>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
@@ -59,7 +58,7 @@ const BlogPostCard = (post: BlogPost) => {
|
||||
|
||||
export const BlogPostList = ({posts}: {posts: BlogPost[]}) => {
|
||||
return (
|
||||
<div className="mt-10 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div className="mt-10 grid gap-4 grid-cols-[repeat(auto-fill,minmax(300px,1fr))]">
|
||||
{posts.map((post, idx) => (
|
||||
<BlogPostCard key={idx} {...post} />
|
||||
))}
|
||||
|
||||
@@ -5,11 +5,14 @@ import {useInView} from "framer-motion";
|
||||
import {useRef, FC, useEffect, useState, useCallback} from "react";
|
||||
import {Button, cn, Spinner, Tooltip} from "@nextui-org/react";
|
||||
|
||||
import {PlayBoldIcon, PauseBoldIcon} from "@/components/icons";
|
||||
import {RotateLeftLinearIcon} from "@/components/icons";
|
||||
|
||||
interface VideoInViewProps {
|
||||
src: string;
|
||||
playMode?: "auto" | "manual";
|
||||
autoPlay?: boolean;
|
||||
poster?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
controls?: boolean;
|
||||
@@ -20,18 +23,25 @@ export const VideoInView: FC<VideoInViewProps> = ({
|
||||
src,
|
||||
width,
|
||||
height,
|
||||
poster,
|
||||
autoPlay = true,
|
||||
playMode = "manual",
|
||||
controls = false,
|
||||
className,
|
||||
}) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
|
||||
const isVisible = useInView(videoRef);
|
||||
|
||||
// play video when it is visible
|
||||
// play video when it is visible and playMode is auto
|
||||
useEffect(() => {
|
||||
if (playMode !== "auto") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
videoRef.current?.play();
|
||||
} else {
|
||||
@@ -39,19 +49,53 @@ export const VideoInView: FC<VideoInViewProps> = ({
|
||||
}
|
||||
}, [isVisible]);
|
||||
|
||||
const handleCanPlayThrough = useCallback(() => {
|
||||
const handleCanPlay = useCallback(() => {
|
||||
setIsLoading(false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const videoEl = videoRef.current;
|
||||
|
||||
if (videoEl) {
|
||||
if (videoEl.readyState > 3) {
|
||||
// HAVE_FUTURE_DATA: enough data to start playing
|
||||
handleCanPlay();
|
||||
} else {
|
||||
videoEl.addEventListener("canplaythrough", handleCanPlay);
|
||||
}
|
||||
|
||||
// Cleanup the event listener
|
||||
return () => {
|
||||
videoEl.removeEventListener("canplaythrough", handleCanPlay);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onRestart = useCallback(() => {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.currentTime = 0;
|
||||
videoRef.current.play();
|
||||
setIsPlaying(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onTogglePlay = useCallback(() => {
|
||||
if (videoRef.current) {
|
||||
if (!isPlaying) {
|
||||
videoRef.current.play();
|
||||
} else {
|
||||
videoRef.current.pause();
|
||||
}
|
||||
|
||||
setIsPlaying((v) => !v);
|
||||
}
|
||||
}, [isPlaying]);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div
|
||||
className="relative data-[playing=true]:after:opacity-0 data-[playing=true]:after:z-[-1] after:content-[''] after:absolute after:inset-0 after:bg-black/30 after:z-20 after:transition-opacity"
|
||||
data-playing={isPlaying}
|
||||
>
|
||||
{isLoading && (
|
||||
<Spinner
|
||||
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
|
||||
@@ -59,6 +103,22 @@ export const VideoInView: FC<VideoInViewProps> = ({
|
||||
size="lg"
|
||||
/>
|
||||
)}
|
||||
<Tooltip content={isPlaying ? "Pause" : "Play"} delay={1000}>
|
||||
<Button
|
||||
isIconOnly
|
||||
className="absolute z-50 right-12 top-3 border-1 border-transparent bg-transparent before:bg-white/10 before:content-[''] before:block before:z-[-1] before:absolute before:inset-0 before:backdrop-blur-md before:backdrop-saturate-100 before:rounded-lg"
|
||||
size="sm"
|
||||
variant="bordered"
|
||||
onPress={onTogglePlay}
|
||||
>
|
||||
{isPlaying ? (
|
||||
<PauseBoldIcon className="text-white" size={16} />
|
||||
) : (
|
||||
<PlayBoldIcon className="text-white" size={16} />
|
||||
)}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content="Restart" delay={1000}>
|
||||
<Button
|
||||
isIconOnly
|
||||
@@ -67,24 +127,24 @@ export const VideoInView: FC<VideoInViewProps> = ({
|
||||
variant="bordered"
|
||||
onPress={onRestart}
|
||||
>
|
||||
<RotateLeftLinearIcon size={16} />
|
||||
<RotateLeftLinearIcon className="text-white" size={16} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<video
|
||||
ref={videoRef}
|
||||
loop
|
||||
muted
|
||||
autoPlay={autoPlay}
|
||||
autoPlay={autoPlay && playMode === "auto"}
|
||||
className={cn(
|
||||
"w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg",
|
||||
className,
|
||||
)}
|
||||
controls={controls}
|
||||
height={height}
|
||||
poster={poster}
|
||||
src={src}
|
||||
width={width}
|
||||
onCanPlayThrough={handleCanPlayThrough}
|
||||
onPlaying={() => setIsLoading(false)}
|
||||
onCanPlay={handleCanPlay}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -11,7 +11,7 @@ import {usePathname, useRouter} from "next/navigation";
|
||||
import MultiRef from "react-multi-ref";
|
||||
import {clsx} from "@nextui-org/shared-utils";
|
||||
import scrollIntoView from "scroll-into-view-if-needed";
|
||||
import {isAppleDevice} from "@react-aria/utils";
|
||||
import {isAppleDevice, isWebKit} from "@react-aria/utils";
|
||||
import {create} from "zustand";
|
||||
import {intersectionBy, isEmpty} from "lodash";
|
||||
import {writeStorage, useLocalStorage} from "@rehooks/local-storage";
|
||||
@@ -194,8 +194,6 @@ export const Cmdk: FC<{}> = () => {
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
|
||||
return () => document.removeEventListener("keydown", onKeyDown);
|
||||
}, [isOpen]);
|
||||
|
||||
const onItemSelect = useCallback(
|
||||
@@ -366,14 +364,14 @@ export const Cmdk: FC<{}> = () => {
|
||||
placement="top-center"
|
||||
scrollBehavior="inside"
|
||||
size="xl"
|
||||
onClose={onClose}
|
||||
onClose={() => onClose()}
|
||||
>
|
||||
<ModalContent>
|
||||
<Command className={slots.base()} label="Quick search command" shouldFilter={false}>
|
||||
<div className={slots.header()}>
|
||||
<SearchLinearIcon className={slots.searchIcon()} strokeWidth={2} />
|
||||
<Command.Input
|
||||
autoFocus
|
||||
autoFocus={!isWebKit()}
|
||||
className={slots.input()}
|
||||
placeholder="Search documentation"
|
||||
value={query}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import {FC} from "react";
|
||||
import {tv, VariantProps} from "tailwind-variants";
|
||||
|
||||
const blockquoteStyles = tv({
|
||||
base: "border pl-4 bg-default-50 my-6 py-3 rounded-xl [&>p]:m-0",
|
||||
base: "border px-4 bg-default-50 my-6 py-3 rounded-xl [&>p]:m-0",
|
||||
variants: {
|
||||
color: {
|
||||
default: "border-default-200 dark:border-default-100 bg-default-200/20",
|
||||
|
||||
@@ -33,9 +33,11 @@ interface CodeDemoProps extends UseCodeDemoProps, WindowResizerProps {
|
||||
enableResize?: boolean;
|
||||
showTabs?: boolean;
|
||||
showPreview?: boolean;
|
||||
hideWindowActions?: boolean;
|
||||
showOpenInCodeSandbox?: boolean;
|
||||
isPreviewCentered?: boolean;
|
||||
resizeEnabled?: boolean;
|
||||
typescriptStrict?: boolean;
|
||||
displayMode?: "always" | "visible";
|
||||
isGradientBox?: boolean;
|
||||
gradientColor?: GradientBoxProps["color"];
|
||||
@@ -52,8 +54,11 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
|
||||
showPreview = true,
|
||||
asIframe = false,
|
||||
resizeEnabled = true,
|
||||
hideWindowActions = false,
|
||||
showSandpackPreview = false,
|
||||
isPreviewCentered = false,
|
||||
// when false .js files will be used
|
||||
typescriptStrict = false,
|
||||
showOpenInCodeSandbox,
|
||||
isGradientBox = false,
|
||||
defaultExpanded = false,
|
||||
@@ -96,6 +101,7 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
|
||||
|
||||
const content = asIframe ? (
|
||||
<WindowResizer
|
||||
hideWindowActions={hideWindowActions}
|
||||
iframeHeight={previewHeight}
|
||||
iframeInitialWidth={iframeInitialWidth}
|
||||
iframeSrc={iframeSrc}
|
||||
@@ -121,6 +127,7 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
|
||||
isGradientBox,
|
||||
gradientColor,
|
||||
previewHeight,
|
||||
hideWindowActions,
|
||||
asIframe,
|
||||
showPreview,
|
||||
isInView,
|
||||
@@ -138,6 +145,7 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
|
||||
showEditor={showEditor}
|
||||
showOpenInCodeSandbox={showOpenInCodeSandbox || showPreview}
|
||||
showPreview={showSandpackPreview}
|
||||
typescriptStrict={typescriptStrict}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ const resizer = tv({
|
||||
|
||||
export interface WindowResizerProps {
|
||||
resizeEnabled?: boolean;
|
||||
hideWindowActions?: boolean;
|
||||
iframeHeight?: string | number;
|
||||
iframeMinWidth?: number;
|
||||
iframeSrc?: string;
|
||||
@@ -70,6 +71,7 @@ const WindowResizer: React.FC<WindowResizerProps> = (props) => {
|
||||
iframeSrc,
|
||||
iframeTitle,
|
||||
resizeEnabled,
|
||||
hideWindowActions = false,
|
||||
iframeHeight: height = "420px",
|
||||
iframeInitialWidth,
|
||||
iframeMinWidth: minWidth = MIN_WIDTH,
|
||||
@@ -120,7 +122,7 @@ const WindowResizer: React.FC<WindowResizerProps> = (props) => {
|
||||
width: isMobile ? "100%" : browserWidth,
|
||||
}}
|
||||
>
|
||||
<WindowActions className="bg-default-100 dark:bg-default-50" />
|
||||
{!hideWindowActions && <WindowActions className="bg-default-100 dark:bg-default-50" />}
|
||||
<motion.iframe ref={iframeRef} className={iframe()} src={iframeSrc} title={iframeTitle} />
|
||||
</motion.div>
|
||||
{resizeEnabled && (
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import {Button, ButtonProps, Link} from "@nextui-org/react";
|
||||
import {Button, ButtonProps, Code, Link, Tooltip} from "@nextui-org/react";
|
||||
import {ReactNode} from "react";
|
||||
import Balancer from "react-wrap-balancer";
|
||||
|
||||
import {GithubIcon, NpmIcon, AdobeIcon, StorybookIcon} from "@/components/icons";
|
||||
import {GithubIcon, NpmIcon, AdobeIcon, StorybookIcon, NextJsIcon} from "@/components/icons";
|
||||
import {COMPONENT_PATH, COMPONENT_THEME_PATH} from "@/libs/github/constants";
|
||||
|
||||
export interface ComponentLinksProps {
|
||||
component: string;
|
||||
styles?: string;
|
||||
storybook?: string;
|
||||
rscCompatible?: boolean;
|
||||
reactAriaHook?: string;
|
||||
}
|
||||
|
||||
@@ -14,27 +17,40 @@ const ButtonLink = ({
|
||||
children,
|
||||
href,
|
||||
startContent,
|
||||
tooltip,
|
||||
...props
|
||||
}: ButtonProps & {
|
||||
href: string;
|
||||
}) => (
|
||||
<Button
|
||||
isExternal
|
||||
as={Link}
|
||||
className="!text-small py-4 bg-default-100 dark:bg-default-50 text-default-700"
|
||||
href={href}
|
||||
size="sm"
|
||||
startContent={startContent}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
tooltip?: string | ReactNode;
|
||||
}) => {
|
||||
const button = (
|
||||
<Button
|
||||
isExternal
|
||||
as={Link}
|
||||
className="!text-small py-4 bg-default-100 dark:bg-default-50 text-default-700"
|
||||
href={href}
|
||||
size="sm"
|
||||
startContent={startContent}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
|
||||
return tooltip ? (
|
||||
<Tooltip className="max-w-[230px]" content={tooltip}>
|
||||
{button}
|
||||
</Tooltip>
|
||||
) : (
|
||||
button
|
||||
);
|
||||
};
|
||||
|
||||
export const ComponentLinks = ({
|
||||
component,
|
||||
storybook,
|
||||
styles,
|
||||
rscCompatible,
|
||||
reactAriaHook,
|
||||
}: ComponentLinksProps) => {
|
||||
if (!component) {
|
||||
@@ -44,7 +60,7 @@ export const ComponentLinks = ({
|
||||
return (
|
||||
<div className="flex flex-wrap gap-3 mt-6">
|
||||
<ButtonLink
|
||||
href={`https://storiesv2.nextui.org/?path=/story/components-${storybook || component}`}
|
||||
href={`https://storybook.nextui.org/?path=/story/components-${storybook || component}`}
|
||||
startContent={<StorybookIcon className="text-lg text-[#ff4785]" />}
|
||||
>
|
||||
Storybook
|
||||
@@ -63,6 +79,26 @@ export const ComponentLinks = ({
|
||||
React Aria
|
||||
</ButtonLink>
|
||||
)}
|
||||
{rscCompatible && (
|
||||
<ButtonLink
|
||||
href="https://nextjs.org/docs/getting-started/react-essentials#server-components"
|
||||
startContent={<NextJsIcon size={18} />}
|
||||
tooltip={
|
||||
<p>
|
||||
<Balancer>
|
||||
This component doesn't use the
|
||||
<Code className="font-normal bg-transparent px-0 py-0 text-code-mdx">
|
||||
`use client;`
|
||||
</Code>
|
||||
directive making it compatible with RSC.
|
||||
</Balancer>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
Server component
|
||||
</ButtonLink>
|
||||
)}
|
||||
|
||||
<ButtonLink href={`${COMPONENT_PATH}/${component}`} startContent={<GithubIcon size={20} />}>
|
||||
Source
|
||||
</ButtonLink>
|
||||
|
||||
@@ -14,3 +14,5 @@ export * from "./info";
|
||||
export * from "./document-code";
|
||||
export * from "./hash";
|
||||
export * from "./more-square";
|
||||
export * from "./play";
|
||||
export * from "./pause";
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import {IconSvgProps} from "@/types";
|
||||
|
||||
export const PauseBoldIcon = ({size = 24, width, height, ...props}: IconSvgProps) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M10.65 19.11V4.89C10.65 3.54 10.08 3 8.64 3H5.01C3.57 3 3 3.54 3 4.89V19.11C3 20.46 3.57 21 5.01 21H8.64C10.08 21 10.65 20.46 10.65 19.11Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M21 19.11V4.89C21 3.54 20.43 3 18.99 3H15.36C13.93 3 13.35 3.54 13.35 4.89V19.11C13.35 20.46 13.92 21 15.36 21H18.99C20.43 21 21 20.46 21 19.11Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,19 @@
|
||||
import {IconSvgProps} from "@/types";
|
||||
|
||||
export const PlayBoldIcon = ({size = 24, width, height, ...props}: IconSvgProps) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M4 11.9999V8.43989C4 4.01989 7.13 2.2099 10.96 4.4199L14.05 6.1999L17.14 7.9799C20.97 10.1899 20.97 13.8099 17.14 16.0199L14.05 17.7999L10.96 19.5799C7.13 21.7899 4 19.9799 4 15.5599V11.9999Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@@ -7,6 +7,7 @@ import NextImage from "next/image";
|
||||
import {ThemeSwitch} from "./theme-switch";
|
||||
|
||||
import {Sandpack} from "@/components/sandpack";
|
||||
import {CarbonAd} from "@/components/ads/carbon-ad";
|
||||
import * as DocsComponents from "@/components/docs/components";
|
||||
import * as BlogComponents from "@/components/blog/components";
|
||||
import {Codeblock} from "@/components/docs/components";
|
||||
@@ -195,7 +196,7 @@ export const MDXComponents = {
|
||||
thead: Thead,
|
||||
tr: Trow,
|
||||
td: Tcol,
|
||||
// CarbonAd,
|
||||
CarbonAd,
|
||||
code: Code,
|
||||
ul: List,
|
||||
a: (props: React.HTMLAttributes<HTMLAnchorElement>) => <Link {...props} />,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import {useRef, useState, FC, ReactNode} from "react";
|
||||
import {useRef, useState, FC, ReactNode, Key} from "react";
|
||||
import {
|
||||
link,
|
||||
Navbar as NextUINavbar,
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
DropdownMenu,
|
||||
DropdownItem,
|
||||
DropdownTrigger,
|
||||
Chip,
|
||||
} from "@nextui-org/react";
|
||||
import {dataFocusVisibleClasses} from "@nextui-org/theme";
|
||||
import {ChevronDownIcon, LinkIcon} from "@nextui-org/shared-icons";
|
||||
@@ -29,6 +30,7 @@ import {useEffect} from "react";
|
||||
import {usePress} from "@react-aria/interactions";
|
||||
import {useFocusRing} from "@react-aria/focus";
|
||||
|
||||
import {currentVersion} from "@/utils/version";
|
||||
import {siteConfig} from "@/config/site";
|
||||
import {Route} from "@/libs/docs/page";
|
||||
import {LargeLogo, SmallLogo, ThemeSwitch} from "@/components";
|
||||
@@ -42,16 +44,16 @@ import {
|
||||
import {useIsMounted} from "@/hooks/use-is-mounted";
|
||||
import {DocsSidebar} from "@/components/docs/sidebar";
|
||||
import {useCmdkStore} from "@/components/cmdk";
|
||||
import {__PROD__} from "@/utils";
|
||||
|
||||
export interface NavbarProps {
|
||||
routes: Route[];
|
||||
mobileRoutes?: Route[];
|
||||
tag?: string;
|
||||
slug?: string;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], slug, tag}) => {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState<boolean | undefined>(false);
|
||||
const [commandKey, setCommandKey] = useState<"ctrl" | "command">("command");
|
||||
|
||||
@@ -60,7 +62,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
|
||||
const pathname = usePathname();
|
||||
|
||||
const cmkdStore = useCmdkStore();
|
||||
const cmdkStore = useCmdkStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (isMenuOpen) {
|
||||
@@ -73,7 +75,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
}, []);
|
||||
|
||||
const {pressProps} = usePress({
|
||||
onPress: () => cmkdStore.onOpen(),
|
||||
onPress: () => cmdkStore.onOpen(),
|
||||
});
|
||||
const {focusProps, isFocusVisible} = useFocusRing();
|
||||
|
||||
@@ -99,7 +101,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
strokeWidth={2}
|
||||
/>
|
||||
}
|
||||
onPress={() => cmkdStore.onOpen()}
|
||||
onPress={() => cmdkStore.onOpen()}
|
||||
>
|
||||
Quick Search...
|
||||
</Button>
|
||||
@@ -109,10 +111,15 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const navLinkClasses = clsx(
|
||||
link({color: "foreground"}),
|
||||
"data-[active=true]:text-primary data-[active=true]:font-medium",
|
||||
);
|
||||
const navLinkClasses = clsx(link({color: "foreground"}), "data-[active=true]:text-primary");
|
||||
|
||||
const handleVersionChange = (key: Key) => {
|
||||
if (key === "v1") {
|
||||
const newWindow = window.open("https://v1.nextui.org", "_blank", "noopener,noreferrer");
|
||||
|
||||
if (newWindow) newWindow.opener = null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<NextUINavbar
|
||||
@@ -148,7 +155,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
size="sm"
|
||||
variant="flat"
|
||||
>
|
||||
v2.0.0
|
||||
v{currentVersion}
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
</motion.div>
|
||||
@@ -158,8 +165,9 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
aria-label="NextUI versions"
|
||||
defaultSelectedKeys={["v2"]}
|
||||
selectionMode="single"
|
||||
onAction={handleVersionChange}
|
||||
>
|
||||
<DropdownItem key="v2">v2.0.0</DropdownItem>
|
||||
<DropdownItem key="v2">v{currentVersion}</DropdownItem>
|
||||
<DropdownItem key="v1" endContent={<LinkIcon />}>
|
||||
v1.0.0
|
||||
</DropdownItem>
|
||||
@@ -169,7 +177,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
<div className="w-[74px]" />
|
||||
)}
|
||||
</NavbarBrand>
|
||||
<ul className="hidden lg:flex gap-4 justify-start">
|
||||
<ul className="hidden lg:flex gap-4 justify-start items-center">
|
||||
<NavbarItem>
|
||||
<NextLink
|
||||
className={navLinkClasses}
|
||||
@@ -190,18 +198,16 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
Components
|
||||
</NextLink>
|
||||
</NavbarItem>
|
||||
{!__PROD__ && (
|
||||
<NavbarItem>
|
||||
<NextLink
|
||||
className={navLinkClasses}
|
||||
color="foreground"
|
||||
data-active={includes(pathname, "blog")}
|
||||
href="/blog"
|
||||
>
|
||||
Blog
|
||||
</NextLink>
|
||||
</NavbarItem>
|
||||
)}
|
||||
<NavbarItem>
|
||||
<NextLink
|
||||
className={navLinkClasses}
|
||||
color="foreground"
|
||||
data-active={includes(pathname, "blog")}
|
||||
href="/blog"
|
||||
>
|
||||
Blog
|
||||
</NextLink>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<NextLink
|
||||
className={navLinkClasses}
|
||||
@@ -212,6 +218,20 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
Figma
|
||||
</NextLink>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<Chip
|
||||
as={NextLink}
|
||||
className="hover:bg-default-100 border-default-200/80 dark:border-default-100/80 transition-colors cursor-pointer"
|
||||
color="secondary"
|
||||
href="/blog/v2.1.0"
|
||||
variant="dot"
|
||||
>
|
||||
New components v2.1.0
|
||||
<span aria-label="party emoji" role="img">
|
||||
🎉
|
||||
</span>
|
||||
</Chip>
|
||||
</NavbarItem>
|
||||
</ul>
|
||||
</NavbarContent>
|
||||
|
||||
@@ -243,7 +263,12 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
<SearchLinearIcon className="mt-px text-default-600 dark:text-default-500" size={20} />
|
||||
</button>
|
||||
</NavbarItem>
|
||||
<NavbarMenuToggle aria-label={isMenuOpen ? "Close menu" : "Open menu"} className="ml-2" />
|
||||
<NavbarItem className="w-10 h-full">
|
||||
<NavbarMenuToggle
|
||||
aria-label={isMenuOpen ? "Close menu" : "Open menu"}
|
||||
className="w-full h-full pt-1"
|
||||
/>
|
||||
</NavbarItem>
|
||||
</NavbarContent>
|
||||
|
||||
<NavbarContent className="hidden sm:flex basis-1/5 sm:basis-full" justify="end">
|
||||
@@ -273,15 +298,15 @@ export const Navbar: FC<NavbarProps> = ({children, routes, slug, tag}) => {
|
||||
>
|
||||
Sponsor
|
||||
</Button>
|
||||
</NavbarItem>{" "}
|
||||
</NavbarItem>
|
||||
<NavbarMenuToggle
|
||||
aria-label={isMenuOpen ? "Close menu" : "Open menu"}
|
||||
className="hidden sm:flex lg:hidden"
|
||||
className="hidden sm:flex lg:hidden ml-4"
|
||||
/>
|
||||
</NavbarContent>
|
||||
|
||||
<NavbarMenu>
|
||||
<DocsSidebar className="mt-4" routes={routes} slug={slug} tag={tag} />
|
||||
<DocsSidebar className="mt-4" routes={[...mobileRoutes, ...routes]} slug={slug} tag={tag} />
|
||||
{children}
|
||||
</NavbarMenu>
|
||||
</NextUINavbar>
|
||||
|
||||
@@ -26,6 +26,7 @@ export const Sandpack: FC<SandpackProps> = ({
|
||||
files: filesProp,
|
||||
template,
|
||||
highlightedLines,
|
||||
typescriptStrict = false,
|
||||
showPreview = false,
|
||||
showEditor = true,
|
||||
defaultExpanded = false,
|
||||
@@ -41,6 +42,7 @@ export const Sandpack: FC<SandpackProps> = ({
|
||||
useSandpack({
|
||||
files: filesProp,
|
||||
template,
|
||||
typescriptStrict,
|
||||
highlightedLines,
|
||||
});
|
||||
|
||||
|
||||
@@ -30,8 +30,7 @@ export const nextuiTheme: SandpackTheme = {
|
||||
},
|
||||
font: {
|
||||
body: "Inter var",
|
||||
mono:
|
||||
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
||||
mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
||||
size: "14px",
|
||||
lineHeight: "1.5rem",
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@ import {useLocalStorage} from "@/hooks/use-local-storage";
|
||||
|
||||
export interface UseSandpackProps {
|
||||
files?: SandpackFiles;
|
||||
typescriptStrict?: boolean;
|
||||
template?: SandpackPredefinedTemplate;
|
||||
highlightedLines?: HighlightedLines;
|
||||
}
|
||||
@@ -19,6 +20,7 @@ const importAllReact = 'import * as React from "react";';
|
||||
|
||||
export const useSandpack = ({
|
||||
files = {},
|
||||
typescriptStrict = false,
|
||||
template = "vite-react",
|
||||
highlightedLines,
|
||||
}: UseSandpackProps) => {
|
||||
@@ -57,6 +59,9 @@ export const useSandpack = ({
|
||||
if (key.includes("App") && !key.includes(mimeType)) {
|
||||
return acc;
|
||||
}
|
||||
if (typescriptStrict && key.includes("js")) {
|
||||
return acc;
|
||||
}
|
||||
// @ts-ignore
|
||||
acc[key] = files[key];
|
||||
|
||||
@@ -65,7 +70,7 @@ export const useSandpack = ({
|
||||
|
||||
let dependencies = {
|
||||
"framer-motion": "10.12.16",
|
||||
"@nextui-org/react": "dev-v2",
|
||||
"@nextui-org/react": "latest",
|
||||
};
|
||||
|
||||
// sort files by dependency
|
||||
@@ -76,6 +81,11 @@ export const useSandpack = ({
|
||||
const aName = getFileName(a);
|
||||
const bName = getFileName(b);
|
||||
|
||||
// if bName includes "App" should be first
|
||||
if (bName.includes("App")) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (aFile?.includes(bName)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -164,8 +164,7 @@
|
||||
"key": "chip",
|
||||
"title": "Chip",
|
||||
"keywords": "chip, tag, label, small actionable entity",
|
||||
"path": "/docs/components/chip.mdx",
|
||||
"newPost": true
|
||||
"path": "/docs/components/chip.mdx"
|
||||
},
|
||||
{
|
||||
"key": "circular-progress",
|
||||
@@ -183,8 +182,7 @@
|
||||
"key": "divider",
|
||||
"title": "Divider",
|
||||
"keywords": "divider, boundary, separator, section divider",
|
||||
"path": "/docs/components/divider.mdx",
|
||||
"newPost": true
|
||||
"path": "/docs/components/divider.mdx"
|
||||
},
|
||||
{
|
||||
"key": "dropdown",
|
||||
@@ -208,8 +206,7 @@
|
||||
"key": "kbd",
|
||||
"title": "Kbd",
|
||||
"keywords": "keyboard input, shortcut, keys, user input display",
|
||||
"path": "/docs/components/kbd.mdx",
|
||||
"newPost": true
|
||||
"path": "/docs/components/kbd.mdx"
|
||||
},
|
||||
{
|
||||
"key": "link",
|
||||
@@ -217,6 +214,13 @@
|
||||
"keywords": "link, navigation, href, web page connection",
|
||||
"path": "/docs/components/link.mdx"
|
||||
},
|
||||
{
|
||||
"key": "listbox",
|
||||
"title": "Listbox",
|
||||
"keywords": "listbox, selection, option list, multiple choice",
|
||||
"path": "/docs/components/listbox.mdx",
|
||||
"newPost": true
|
||||
},
|
||||
{
|
||||
"key": "modal",
|
||||
"title": "Modal",
|
||||
@@ -253,18 +257,30 @@
|
||||
"keywords": "radio group, selection set, option selection, exclusive choices",
|
||||
"path": "/docs/components/radio-group.mdx"
|
||||
},
|
||||
{
|
||||
"key": "select",
|
||||
"title": "Select",
|
||||
"keywords": "select, selection, option list, multiple choice",
|
||||
"path": "/docs/components/select.mdx",
|
||||
"newPost": true
|
||||
},
|
||||
{
|
||||
"key": "skeleton",
|
||||
"title": "Skeleton",
|
||||
"keywords": "skeleton, loading state, placeholder, content preview",
|
||||
"path": "/docs/components/skeleton.mdx",
|
||||
"newPost": true
|
||||
"path": "/docs/components/skeleton.mdx"
|
||||
},
|
||||
{
|
||||
"key": "snippet",
|
||||
"title": "Snippet",
|
||||
"keywords": "snippet, code block, programming, code example",
|
||||
"path": "/docs/components/snippet.mdx",
|
||||
"path": "/docs/components/snippet.mdx"
|
||||
},
|
||||
{
|
||||
"key": "scroll-shadow",
|
||||
"title": "Scroll Shadow",
|
||||
"keywords": "scroll shadow, scroll indicator, scroll bar, scroll position",
|
||||
"path": "/docs/components/scroll-shadow.mdx",
|
||||
"newPost": true
|
||||
},
|
||||
{
|
||||
@@ -295,8 +311,7 @@
|
||||
"key": "tabs",
|
||||
"title": "Tabs",
|
||||
"keywords": "tabs, section navigation, categorized content, tabbed interface",
|
||||
"path": "/docs/components/tabs.mdx",
|
||||
"newPost": true
|
||||
"path": "/docs/components/tabs.mdx"
|
||||
},
|
||||
{
|
||||
"key": "textarea",
|
||||
@@ -318,5 +333,39 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mobileRoutes": [
|
||||
{
|
||||
"key": "getting-started",
|
||||
"title": "Getting Started",
|
||||
"defaultOpen": true,
|
||||
"keywords": "getting started, main routes, blog, docs, components, nextui",
|
||||
"routes": [
|
||||
{
|
||||
"key": "docs",
|
||||
"title": "Documentation",
|
||||
"keywords": "documentation, guide, nextui",
|
||||
"path": "/docs/guide/introduction.mdx"
|
||||
},
|
||||
{
|
||||
"key": "components",
|
||||
"title": "Components",
|
||||
"keywords": "components, nextui",
|
||||
"path": "/docs/components/avatar"
|
||||
},
|
||||
{
|
||||
"key": "blog",
|
||||
"title": "Blog",
|
||||
"keywords": "blog, nextui, news, updates",
|
||||
"path": "/blog"
|
||||
},
|
||||
{
|
||||
"key": "figma",
|
||||
"title": "Figma",
|
||||
"keywords": "figma, nextui, design, ui kit",
|
||||
"path": "/figma"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+1912
-1159
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,9 @@ export const siteConfig = {
|
||||
name: "NextUI - Beautiful, fast and modern React UI Library",
|
||||
description: "Make beautiful websites regardless of your design experience.",
|
||||
ogImage: "https://nextui.org/twitter-cards/nextui.jpeg",
|
||||
author: "Junior Garcia",
|
||||
email: "jrgarciadev@gmail.com",
|
||||
siteUrl: "https://nextui.org",
|
||||
creator: "@getnextui",
|
||||
openGraph: {
|
||||
type: "website",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
title: "Introducing NextUI Version 2"
|
||||
description: "Discover NextUI v2. TailwindCSS integration, enhanced theming, improved animations, and more."
|
||||
date: "2023-07-29"
|
||||
title: "Introducing NextUI Version 2.0"
|
||||
description: "Discover NextUI v2.0 TailwindCSS integration, enhanced theming, improved animations, and more."
|
||||
date: "2023-07-31"
|
||||
image: "/blog/nextuiv2.jpg"
|
||||
tags: ["nextui", "tailwindcss", "react", "nextjs", "react-server-components"]
|
||||
author:
|
||||
name: "Junior Garcia"
|
||||
username: "@jrgarciadev"
|
||||
@@ -24,18 +25,18 @@ towards achieving that.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Transition to TailwindCSS](#transition-to-tailwindcss) - Our shift to TailwindCSS.
|
||||
- [Transition to TailwindCSS](#transition-from-stitches-to-tailwindcss) - Our shift to TailwindCSS.
|
||||
- [TailwindCSS Plugin](#tailwindcss-plugin) - Introducing theme customization plugin.
|
||||
- [React Server Components](#react-server-components) - Enhanced performance with React Server Components.
|
||||
- [Custom Themes, Layouts, Colors](#custom-themes-layouts-colors) - New customizability options.
|
||||
- [React Server Components](#react-server-components-support) - Enhanced performance with React Server Components.
|
||||
- [Custom Themes, Layouts, Colors](#custom-themes-layouts-and-colors) - New customizability options.
|
||||
- [Enhanced Documentation](#enhanced-documentation) - A better navigation experience.
|
||||
- [New Templates & Guides](#new-templates-guides) - Easier app creation process.
|
||||
- [New Templates & Guides](#new-templates-and-guides) - Easier app creation process.
|
||||
- [Custom Variants](#custom-variants) - Customization of components' variants.
|
||||
- [Enhanced Styling Model](#enhanced-styling-model) - Effortless component styling.
|
||||
- [Tailwind Variants](#tailwind-variants) - Our new library for better TailwindCSS handling.
|
||||
- [Revamped Components](#revamped-components) - Rewritten components with react-aria hooks.
|
||||
- [Optimized Animations](#optimized-animations) - Smoother app animations.
|
||||
- [Individual Packages](#individual-packages) - Install only what you need.
|
||||
- [Individual Packages](#individual-packages-support) - Install only what you need.
|
||||
- [Dark Mode Support](#dark-mode-support) - Easier implementation of dark mode.
|
||||
- [New Components](#new-components) - Six new components added.
|
||||
- [Figma Community File](#figma-community-file) - Streamlining design-to-development process.
|
||||
@@ -85,8 +86,8 @@ Thanks to the switch to TailwindCSS, **NextUI v2.0** now supports React Server C
|
||||
improves performance and allows you to use it with the latest versions of [React](https://reactjs.org/) and
|
||||
[Next.js](https://nextjs.org/).
|
||||
|
||||
NextUI components already inclue the `use client;` directive so you can import them
|
||||
server components.
|
||||
NextUI components already include the `use client;` directive so you can import them directly
|
||||
in your React Server Components (RSC).
|
||||
|
||||
```jsx
|
||||
// app/page.tsx
|
||||
@@ -144,7 +145,8 @@ links at the top of each component documentation, such as the component storyboo
|
||||
the source code and styles source code.
|
||||
|
||||
<VideoInView
|
||||
src="https://nextui-public-resources.s3.amazonaws.com/new-docs.mp4"
|
||||
src="https://d2u8k2ocievbld.cloudfront.net/new-docs.mp4"
|
||||
poster="https://d2u8k2ocievbld.cloudfront.net/new-docs-poster.png"
|
||||
width={700}
|
||||
height={350}
|
||||
/>
|
||||
@@ -167,21 +169,23 @@ installation guides, are introduced to aid your app creation process.
|
||||
We've added a new function, `extendVariants`, that allows you to customize any NextUI components's variants.
|
||||
|
||||
<VideoInView
|
||||
src="https://nextui-public-resources.s3.amazonaws.com/custom-variants.mp4"
|
||||
src="https://d2u8k2ocievbld.cloudfront.net/custom-variants.mp4"
|
||||
poster="https://d2u8k2ocievbld.cloudfront.net/custom-variants-poster.png"
|
||||
width={700}
|
||||
height={350}
|
||||
/>
|
||||
|
||||
You can create or override the component `variants`, `defaultVariants` and `componentVariants`.
|
||||
You can create or override the component `variants`, `defaultVariants` and `compoundVariants`.
|
||||
|
||||
> Check out the [Custom Variants](/docs/customization/variants) documentation for more information.
|
||||
> Check out the [Custom Variants](/docs/customization/custom-variants) documentation for more information.
|
||||
|
||||
### Enhanced Styling Model
|
||||
|
||||
With the new slots model, you can style every part of your components effortlessly.
|
||||
|
||||
<VideoInView
|
||||
src="https://nextui-public-resources.s3.amazonaws.com/override-styles.mp4"
|
||||
src="https://d2u8k2ocievbld.cloudfront.net/override-styles.mp4"
|
||||
poster="https://d2u8k2ocievbld.cloudfront.net/override-styles-poster.png"
|
||||
width={700}
|
||||
height={350}
|
||||
/>
|
||||
@@ -206,7 +210,8 @@ Thanks to [framer-motion](https://www.framer.com/motion/), we've significantly i
|
||||
app feel more fluid and smooth.
|
||||
|
||||
<VideoInView
|
||||
src="https://nextui-public-resources.s3.amazonaws.com/dropdown-animation.mp4"
|
||||
src="https://d2u8k2ocievbld.cloudfront.net/dropdown-animation.mp4"
|
||||
poster="https://d2u8k2ocievbld.cloudfront.net/dropdown-animation-poster.png"
|
||||
width={700}
|
||||
height={350}
|
||||
/>
|
||||
@@ -251,7 +256,8 @@ ReactDOM.createRoot(document.getElementById("root")).render(
|
||||
```
|
||||
|
||||
<VideoInView
|
||||
src="https://nextui-public-resources.s3.amazonaws.com/dark-mode.mp4"
|
||||
src="https://d2u8k2ocievbld.cloudfront.net/dark-mode.mp4"
|
||||
poster="https://d2u8k2ocievbld.cloudfront.net/dark-mode-poster.png"
|
||||
width={700}
|
||||
height={350}
|
||||
/>
|
||||
@@ -280,7 +286,7 @@ file helps streamline the process of transforming design ideas into functioning
|
||||
</Blockquote>
|
||||
|
||||
<iframe
|
||||
height="450"
|
||||
height="600"
|
||||
width="800"
|
||||
src="https://embed.figma.com/file/1267584376234254760/hf_embed?community_viewer=true&embed_host=nextui"
|
||||
className="aspect-video w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
|
||||
@@ -289,7 +295,12 @@ file helps streamline the process of transforming design ideas into functioning
|
||||
<Spacer y={10} />
|
||||
|
||||
<Button color="default" variant="bordered">
|
||||
<Link isExternal className="text-current" href="https://www.figma.com/community/file/1267584376234254760">
|
||||
<Link
|
||||
isExternal
|
||||
showAnchorIcon
|
||||
className="text-current"
|
||||
href="https://www.figma.com/community/file/1267584376234254760"
|
||||
>
|
||||
Open in Figma
|
||||
</Link>
|
||||
</Button>
|
||||
@@ -299,3 +310,16 @@ file helps streamline the process of transforming design ideas into functioning
|
||||
To start using **NextUI v2.0**, head over to our [installation guide](/docs/guide/installation).
|
||||
|
||||
We can't wait to see the amazing things you'll build with **NextUI v2.0**!
|
||||
|
||||
---
|
||||
|
||||
## Community
|
||||
|
||||
We're excited to see the community adopt NextUI, raise issues, and provide feedback.
|
||||
Whether it's a feature request, bug report, or a project to showcase, please get involved!
|
||||
|
||||
<Community />
|
||||
|
||||
## Contributing
|
||||
|
||||
PR's on NextUI are always welcome, please see our [contribution guidelines](https://github.com/nextui-org/nextui/blob/main/CONTRIBUTING.MD) to learn how you can contribute to this project.
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
---
|
||||
title: "New components v2.1.0 🎉"
|
||||
description: "NextUI v2.1.0 is here with new components, Select, Listbox and ScrollShadow."
|
||||
date: "2023-08-21"
|
||||
image: "/blog/v2.1.0.jpg"
|
||||
tags: ["nextui", "select", "listbox", "scroll-shadow", "multi-select"]
|
||||
author:
|
||||
name: "Junior Garcia"
|
||||
username: "@jrgarciadev"
|
||||
link: "https://twitter.com/jrgarciadev"
|
||||
avatar: "/avatars/junior-garcia.jpeg"
|
||||
---
|
||||
|
||||
import {selectContent} from "@/content/components/select";
|
||||
import {listboxContent} from "@/content/components/listbox";
|
||||
import {scrollShadowContent} from "@/content/components/scroll-shadow";
|
||||
|
||||
|
||||
<img
|
||||
src="/blog/v2.1.0.jpg"
|
||||
width={700}
|
||||
height={350}
|
||||
alt="NextUI v2"
|
||||
className="w-full border border-transparent dark:border-default-200/50 object-fit rounded-xl shadow-lg"
|
||||
/>
|
||||
|
||||
We are thrilled to announce the latest update to NextUI, version **2.1.0**! This release introduces some game-changing
|
||||
additions that many of you have eagerly been waiting for.
|
||||
|
||||
First on the list is the highly-anticipated **Select** component. Fully customizable and beautifully designed, supports both single and
|
||||
multi-select modes and is accessible out of the box.
|
||||
|
||||
But that's not all. We're also rolling out two more incredible components **Listbox** and **ScrollShadow**. The new
|
||||
**Listbox** allows you to make list manipulations more efficient and visually appealing. Meanwhile, the
|
||||
**ScrollShadow** component adds an elegant shadow effect to scrollable areas, enhancing the UI aesthetics while
|
||||
also improving usability.
|
||||
|
||||
## Select
|
||||
|
||||
Creating a select component that is both accessible and customizable is a challenging task. We've spent a lot of time
|
||||
researching and testing different approaches to come up with a solution that works for everyone. The result is a
|
||||
component that is easy to use, fully accessible, and highly customizable.
|
||||
|
||||
The new **Select** component includes:
|
||||
|
||||
- Support for selecting a single option.
|
||||
- Support for selecting multiple options.
|
||||
- Support for disabled options.
|
||||
- Support for sections.
|
||||
- Labeling support for accessibility.
|
||||
- Exposed to assistive technology as a button with a listbox popup using ARIA (combined with [Listbox](/docs/components/listbox)).
|
||||
- Support for description and error message help text linked to the input via ARIA.
|
||||
- Support for mouse, touch, and keyboard interactions.
|
||||
- Tab stop focus management.
|
||||
- Asynchronous options loading.
|
||||
- Keyboard support for opening the listbox using the arrow keys, including automatically focusing the first or last item accordingly.
|
||||
- Typeahead to allow selecting options by typing text, even without opening the listbox.
|
||||
- Browser autofill integration via a hidden native `<select>` element.
|
||||
- Support for mobile form navigation via software keyboard.
|
||||
- Mobile screen reader listbox dismissal support.
|
||||
- And much more...
|
||||
|
||||
### Single Select
|
||||
|
||||
The single select component is used to select a single option from a list of options. It is a combination of a button
|
||||
and a listbox. The button displays the currently selected option and the listbox displays the available options.
|
||||
|
||||
<CodeDemo title="Usage" files={selectContent.usage} />
|
||||
|
||||
### Multiple Select
|
||||
|
||||
The multiple select component can be used to select multiple options from a list of options.
|
||||
|
||||
You only need to pass the `selectionMode="multiple"` prop to the `Select` component.
|
||||
|
||||
<CodeDemo title="Multiple Selection" files={selectContent.multiple} />
|
||||
|
||||
### Multiple Variants
|
||||
|
||||
The select component comes with multiple variants.
|
||||
|
||||
<CodeDemo title="Variants" files={selectContent.variants} />
|
||||
|
||||
|
||||
### Chips Support
|
||||
|
||||
The select component is flexible and allows you to render any component as an option and as a selected option.
|
||||
|
||||
<CodeDemo title="Multiple Selection with Chips" files={selectContent.multipleWithChips} />
|
||||
|
||||
|
||||
### Customizable
|
||||
|
||||
The select component is highly customizable, you can customize the selected option, the options, the listbox,
|
||||
the popover and the scrollable area.
|
||||
|
||||
<CodeDemo title="Custom Styles" files={selectContent.customStyles} />
|
||||
|
||||
|
||||
Go to the [Select](/docs/components/select) component page to learn more about sizes, colors, and more.
|
||||
|
||||
|
||||
## Listbox
|
||||
|
||||
The listbox component allows you to make list manipulations more efficient and visually appealing.
|
||||
|
||||
The new **Listbox** component includes:
|
||||
|
||||
- Support for single, multiple, or no selection.
|
||||
- Exposed to assistive technology as a `listbox` using ARIA.
|
||||
- Support for disabled items.
|
||||
- Support for sections.
|
||||
- Labeling support for accessibility.
|
||||
- Support for mouse, touch, and keyboard interactions.
|
||||
- Tab stop focus management.
|
||||
- Keyboard navigation support including arrow keys, home/end, page up/down, select all, and clear.
|
||||
- Automatic scrolling support during keyboard navigation.
|
||||
- Typeahead to allow focusing options by typing text.
|
||||
|
||||
|
||||
### Usage
|
||||
|
||||
<CodeDemo title="Usage" files={listboxContent.usage} />
|
||||
|
||||
### Custom Styles
|
||||
|
||||
The Listbox components offers multiple customization options.
|
||||
|
||||
<CodeDemo title="Custom Styles" files={listboxContent.customStyles} />
|
||||
|
||||
> **Note**: In the above example, we've utilized the [Boxicons](https://boxicons.com/) icons collection.
|
||||
|
||||
Go to the [Listbox](/docs/components/listbox) component page to learn more about it.
|
||||
|
||||
|
||||
## ScrollShadow
|
||||
|
||||
The ScrollShadow component gives a nice shadow effect to scrollable areas. These shadows are handled by using
|
||||
the CSS `mask-image` property, which makes the shadows adapt to the background color.
|
||||
|
||||
### Usage
|
||||
|
||||
<CodeDemo title="Usage" files={scrollShadowContent.usage} />
|
||||
|
||||
You can hide the scrollbars, customize the shadows size, change the orientation, and more.
|
||||
|
||||
Go to the [ScrollShadow](/docs/components/scroll-shadow) component page to learn more about it.
|
||||
|
||||
|
||||
<Spacer y={6}/>
|
||||
|
||||
We hope you enjoy these new components and the new features. We're excited to see what you build with them!
|
||||
|
||||
Thanks for reading and happy coding! 🚀
|
||||
|
||||
---
|
||||
|
||||
## Community
|
||||
|
||||
We're excited to see the community adopt NextUI, raise issues, and provide feedback.
|
||||
Whether it's a feature request, bug report, or a project to showcase, please get involved!
|
||||
|
||||
<Community />
|
||||
|
||||
## Contributing
|
||||
|
||||
PR's on NextUI are always welcome, please see our [contribution guidelines](https://github.com/nextui-org/nextui/blob/main/CONTRIBUTING.MD) to learn how you can contribute to this project.
|
||||
@@ -140,7 +140,7 @@ const ShuffleIcon = `export const ShuffleIcon = ({size = 24, width, height, ...p
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const App = `import {Card, CardFooter, Image, Button, Progress} from "@nextui-org/react";
|
||||
const App = `import {Card, CardBody, Image, Button, Progress} from "@nextui-org/react";
|
||||
import {HeartIcon} from "./HeartIcon";
|
||||
import {PauseCircleIcon} from "./PauseCircleIcon";
|
||||
import {NextIcon} from "./NextIcon";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const App = `import {Card, CardHeader, CardBody, Avatar, Button} from "@nextui-org/react";
|
||||
const App = `import {Card, CardHeader, CardBody, CardFooter, Avatar, Button} from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
const [isFollowed, setIsFollowed] = React.useState(false);
|
||||
|
||||
@@ -6,7 +6,7 @@ export const CustomCheckbox = ({ user, statusColor, value }) => {
|
||||
aria-label={user.name}
|
||||
classNames={{
|
||||
base: cn(
|
||||
"inline-flex max-w-md w-full bg-content1",
|
||||
"inline-flex max-w-md w-full bg-content1 m-0",
|
||||
"hover:bg-content2 items-center justify-start",
|
||||
"cursor-pointer rounded-lg gap-2 p-4 border-2 border-transparent",
|
||||
"data-[selected=true]:border-primary"
|
||||
|
||||
@@ -49,6 +49,7 @@ export default function App() {
|
||||
"data-[hover=true]:text-foreground",
|
||||
"data-[hover=true]:bg-default-100",
|
||||
"dark:data-[hover=true]:bg-default-50",
|
||||
"data-[selectable=true]:focus:bg-default-50",
|
||||
"data-[pressed=true]:opacity-70",
|
||||
"data-[focus-visible=true]:ring-default-500",
|
||||
],
|
||||
|
||||
@@ -138,6 +138,7 @@ export default function App() {
|
||||
<DropdownItem
|
||||
key="edit"
|
||||
shortcut="⌘⇧E"
|
||||
showDivider
|
||||
description="Allows you to edit the file"
|
||||
startContent={<EditDocumentIcon className={iconClasses} />}
|
||||
>
|
||||
@@ -145,7 +146,6 @@ export default function App() {
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
key="delete"
|
||||
showDivider
|
||||
className="text-danger"
|
||||
color="danger"
|
||||
shortcut="⌘⇧D"
|
||||
|
||||
@@ -142,7 +142,6 @@ export default function App() {
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
key="delete"
|
||||
showDivider
|
||||
className="text-danger"
|
||||
color="danger"
|
||||
shortcut="⌘⇧D"
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function App() {
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
aria-label="Single selection actions"
|
||||
aria-label="Multiple selection example"
|
||||
variant="flat"
|
||||
closeOnSelect={false}
|
||||
disallowEmptySelection
|
||||
|
||||
@@ -14,7 +14,7 @@ export default function App() {
|
||||
<DropdownItem key="new" shortcut="⌘N">New file</DropdownItem>
|
||||
<DropdownItem key="copy" shortcut="⌘C">Copy link</DropdownItem>
|
||||
<DropdownItem key="edit" shortcut="⌘⇧E">Edit file</DropdownItem>
|
||||
<DropdownItem key="delete" showDivider shortcut="⌘⇧D" className="text-danger" color="danger">
|
||||
<DropdownItem key="delete" shortcut="⌘⇧D" className="text-danger" color="danger">
|
||||
Delete file
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function App() {
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
aria-label="Single selection actions"
|
||||
aria-label="Single selection example"
|
||||
variant="flat"
|
||||
disallowEmptySelection
|
||||
selectionMode="single"
|
||||
|
||||
@@ -6,7 +6,7 @@ import sizes from "./sizes";
|
||||
import colors from "./colors";
|
||||
import variants from "./variants";
|
||||
import radius from "./radius";
|
||||
import labelPositions from "./label-positions";
|
||||
import labelPlacements from "./label-placements";
|
||||
import description from "./description";
|
||||
import password from "./password";
|
||||
import clearButton from "./clear-button";
|
||||
@@ -26,7 +26,7 @@ export const inputContent = {
|
||||
colors,
|
||||
variants,
|
||||
radius,
|
||||
labelPositions,
|
||||
labelPlacements,
|
||||
description,
|
||||
password,
|
||||
clearButton,
|
||||
|
||||
+9
-9
@@ -1,7 +1,7 @@
|
||||
const App = `import {Input} from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
const positions = [
|
||||
const placements = [
|
||||
"inside",
|
||||
"outside",
|
||||
"outside-left",
|
||||
@@ -12,13 +12,13 @@ export default function App() {
|
||||
<div className="flex flex-col gap-2">
|
||||
<h3 className="text-default-500 text-small">Without placeholder</h3>
|
||||
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
|
||||
{positions.map((position) => (
|
||||
{placements.map((placement) => (
|
||||
<Input
|
||||
key={position}
|
||||
key={placement}
|
||||
type="email"
|
||||
label="Email"
|
||||
labelPlacement={position}
|
||||
description={position}
|
||||
labelPlacement={placement}
|
||||
description={placement}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -26,14 +26,14 @@ export default function App() {
|
||||
<div className="flex flex-col gap-2">
|
||||
<h3 className="text-default-500 text-small">With placeholder</h3>
|
||||
<div className="flex w-full flex-wrap items-end md:flex-nowrap mb-6 md:mb-0 gap-4">
|
||||
{positions.map((position) => (
|
||||
{placements.map((placement) => (
|
||||
<Input
|
||||
key={position}
|
||||
key={placement}
|
||||
type="email"
|
||||
label="Email"
|
||||
labelPlacement={position}
|
||||
labelPlacement={placement}
|
||||
placeholder="Enter your email"
|
||||
description={position}
|
||||
description={placement}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
const MailFilledIcon = `export const MailFilledIcon = (props) => (
|
||||
const MailIcon = `export const MailIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
@@ -17,7 +17,7 @@ const MailFilledIcon = `export const MailFilledIcon = (props) => (
|
||||
);`;
|
||||
|
||||
const App = `import {Input} from "@nextui-org/react";
|
||||
import {MailFilledIcon} from './MailFilledIcon';
|
||||
import {MailIcon} from './MailIcon';
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
@@ -29,7 +29,7 @@ export default function App() {
|
||||
placeholder="you@example.com"
|
||||
labelPlacement="outside"
|
||||
startContent={
|
||||
<MailFilledIcon className="text-2xl text-default-400 pointer-events-none flex-shrink-0" />
|
||||
<MailIcon className="text-2xl text-default-400 pointer-events-none flex-shrink-0" />
|
||||
}
|
||||
/>
|
||||
<Input
|
||||
@@ -62,7 +62,7 @@ export default function App() {
|
||||
placeholder="you@example.com"
|
||||
labelPlacement="outside"
|
||||
endContent={
|
||||
<MailFilledIcon className="text-2xl text-default-400 pointer-events-none flex-shrink-0" />
|
||||
<MailIcon className="text-2xl text-default-400 pointer-events-none flex-shrink-0" />
|
||||
}
|
||||
/>
|
||||
<Input
|
||||
@@ -94,7 +94,7 @@ export default function App() {
|
||||
placeholder="nextui"
|
||||
labelPlacement="outside"
|
||||
startContent={
|
||||
<MailFilledIcon className="text-xl text-default-400 pointer-events-none flex-shrink-0" />
|
||||
<MailIcon className="text-xl text-default-400 pointer-events-none flex-shrink-0" />
|
||||
}
|
||||
endContent={
|
||||
<div className="pointer-events-none flex items-center">
|
||||
@@ -152,7 +152,7 @@ export default function App() {
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/MailFilledIcon.jsx": MailFilledIcon,
|
||||
"/MailIcon.jsx": MailIcon,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const App = `import {Input} from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
|
||||
const variants = ["flat", "bordered", "underlined", "faded"];
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
const BugIcon = `export const BugIcon = (props) => (
|
||||
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M16.895,6.519l2.813-2.812l-1.414-1.414l-2.846,2.846c-0.233-0.166-0.473-0.321-0.723-0.454 c-1.723-0.91-3.726-0.911-5.45,0c-0.25,0.132-0.488,0.287-0.722,0.453L5.707,2.293L4.293,3.707l2.813,2.812 C6.53,7.242,6.08,8.079,5.756,9H2v2h2.307C4.242,11.495,4.2,11.997,4.2,12.5c0,0.507,0.042,1.013,0.107,1.511H2v2h2.753 c0.013,0.039,0.021,0.08,0.034,0.118c0.188,0.555,0.421,1.093,0.695,1.6c0.044,0.081,0.095,0.155,0.141,0.234l-2.33,2.33 l1.414,1.414l2.11-2.111c0.235,0.254,0.478,0.498,0.736,0.716c0.418,0.354,0.867,0.657,1.332,0.903 c0.479,0.253,0.982,0.449,1.496,0.58C10.911,21.931,11.455,22,12,22s1.089-0.069,1.618-0.204c0.514-0.131,1.017-0.327,1.496-0.58 c0.465-0.246,0.914-0.55,1.333-0.904c0.258-0.218,0.5-0.462,0.734-0.716l2.111,2.111l1.414-1.414l-2.33-2.33 c0.047-0.08,0.098-0.155,0.142-0.236c0.273-0.505,0.507-1.043,0.694-1.599c0.013-0.039,0.021-0.079,0.034-0.118H22v-2h-2.308 c0.065-0.499,0.107-1.004,0.107-1.511c0-0.503-0.042-1.005-0.106-1.5H22V9h-3.756C17.92,8.079,17.47,7.242,16.895,6.519z M8.681,7.748c0.445-0.558,0.96-0.993,1.528-1.294c1.141-0.603,2.442-0.602,3.581,0c0.569,0.301,1.084,0.736,1.53,1.295 c0.299,0.373,0.54,0.8,0.753,1.251H7.927C8.141,8.549,8.381,8.121,8.681,7.748z M17.8,12.5c0,0.522-0.042,1.044-0.126,1.553 c-0.079,0.49-0.199,0.973-0.355,1.436c-0.151,0.449-0.34,0.882-0.559,1.288c-0.217,0.399-0.463,0.772-0.733,1.11 c-0.267,0.333-0.56,0.636-0.869,0.898c-0.31,0.261-0.639,0.484-0.979,0.664s-0.695,0.317-1.057,0.41 c-0.04,0.01-0.082,0.014-0.122,0.023V14h-2v5.881c-0.04-0.009-0.082-0.013-0.122-0.023c-0.361-0.093-0.717-0.23-1.057-0.41 s-0.669-0.403-0.978-0.664c-0.311-0.263-0.604-0.565-0.871-0.899c-0.27-0.337-0.516-0.71-0.731-1.108 c-0.22-0.407-0.408-0.84-0.56-1.289c-0.156-0.463-0.276-0.946-0.356-1.438C6.242,13.544,6.2,13.022,6.2,12.5 c0-0.505,0.041-1.009,0.119-1.5h11.361C17.759,11.491,17.8,11.995,17.8,12.5z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
`;
|
||||
|
||||
const PullRequestIcon = `export const PullRequestIcon = (props) => (
|
||||
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M19.01 15.163V7.997C19.005 6.391 17.933 4 15 4V2l-4 3 4 3V6c1.829 0 2.001 1.539 2.01 2v7.163c-1.44.434-2.5 1.757-2.5 3.337 0 1.93 1.57 3.5 3.5 3.5s3.5-1.57 3.5-3.5c0-1.58-1.06-2.903-2.5-3.337zm-1 4.837c-.827 0-1.5-.673-1.5-1.5s.673-1.5 1.5-1.5 1.5.673 1.5 1.5-.673 1.5-1.5 1.5zM9.5 5.5C9.5 3.57 7.93 2 6 2S2.5 3.57 2.5 5.5c0 1.58 1.06 2.903 2.5 3.337v6.326c-1.44.434-2.5 1.757-2.5 3.337C2.5 20.43 4.07 22 6 22s3.5-1.57 3.5-3.5c0-1.58-1.06-2.903-2.5-3.337V8.837C8.44 8.403 9.5 7.08 9.5 5.5zm-5 0C4.5 4.673 5.173 4 6 4s1.5.673 1.5 1.5S6.827 7 6 7s-1.5-.673-1.5-1.5zm3 13c0 .827-.673 1.5-1.5 1.5s-1.5-.673-1.5-1.5S5.173 17 6 17s1.5.673 1.5 1.5z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const ChatIcon = `export const ChatIcon = (props) => (
|
||||
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M5 18v3.766l1.515-.909L11.277 18H16c1.103 0 2-.897 2-2V8c0-1.103-.897-2-2-2H4c-1.103 0-2 .897-2 2v8c0 1.103.897 2 2 2h1zM4 8h12v8h-5.277L7 18.234V16H4V8z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M20 2H8c-1.103 0-2 .897-2 2h12c1.103 0 2 .897 2 2v8c1.103 0 2-.897 2-2V4c0-1.103-.897-2-2-2z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const PlayCircleIcon = `export const PlayCircleIcon = (props) => (
|
||||
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10 10-4.486 10-10S17.514 2 12 2zm0 18c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path d="m9 17 8-5-8-5z" fill="currentColor" />
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const LayoutIcon = `export const LayoutIcon = (props) => (
|
||||
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M19 3H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2h14c1.103 0 2-.897 2-2V5c0-1.103-.897-2-2-2zm0 2 .001 4H5V5h14zM5 11h8v8H5v-8zm10 8v-8h4.001l.001 8H15z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const TagIcon = `export const TagIcon = (props) => (
|
||||
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M11.707 2.293A.997.997 0 0 0 11 2H6a.997.997 0 0 0-.707.293l-3 3A.996.996 0 0 0 2 6v5c0 .266.105.52.293.707l10 10a.997.997 0 0 0 1.414 0l8-8a.999.999 0 0 0 0-1.414l-10-10zM13 19.586l-9-9V6.414L6.414 4h4.172l9 9L13 19.586z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<circle cx="8.353" cy="8.353" fill="currentColor" r="1.647" />
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const UsersIcon = `export const UsersIcon = (props) => (
|
||||
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M16.604 11.048a5.67 5.67 0 0 0 .751-3.44c-.179-1.784-1.175-3.361-2.803-4.44l-1.105 1.666c1.119.742 1.8 1.799 1.918 2.974a3.693 3.693 0 0 1-1.072 2.986l-1.192 1.192 1.618.475C18.951 13.701 19 17.957 19 18h2c0-1.789-.956-5.285-4.396-6.952z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M9.5 12c2.206 0 4-1.794 4-4s-1.794-4-4-4-4 1.794-4 4 1.794 4 4 4zm0-6c1.103 0 2 .897 2 2s-.897 2-2 2-2-.897-2-2 .897-2 2-2zm1.5 7H8c-3.309 0-6 2.691-6 6v1h2v-1c0-2.206 1.794-4 4-4h3c2.206 0 4 1.794 4 4v1h2v-1c0-3.309-2.691-6-6-6z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const WatchersIcon = `export const WatchersIcons = (props) => (
|
||||
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="m21.977 13.783-2-9A1.002 1.002 0 0 0 19 4h-3v2h2.198l.961 4.326A4.467 4.467 0 0 0 17.5 10c-1.953 0-3.603 1.258-4.224 3h-2.553c-.621-1.742-2.271-3-4.224-3-.587 0-1.145.121-1.659.326L5.802 6H8V4H5a1 1 0 0 0-.976.783l-2 9 .047.011A4.552 4.552 0 0 0 2 14.5C2 16.981 4.019 19 6.5 19c2.31 0 4.197-1.756 4.449-4h2.102c.252 2.244 2.139 4 4.449 4 2.481 0 4.5-2.019 4.5-4.5 0-.242-.034-.475-.071-.706l.048-.011zM6.5 17C5.122 17 4 15.878 4 14.5S5.122 12 6.5 12 9 13.122 9 14.5 7.878 17 6.5 17zm11 0c-1.379 0-2.5-1.122-2.5-2.5s1.121-2.5 2.5-2.5 2.5 1.122 2.5 2.5-1.121 2.5-2.5 2.5z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const BookIcon = `export const BookIcon = (props) => (
|
||||
<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M6 22h15v-2H6.012C5.55 19.988 5 19.805 5 19s.55-.988 1.012-1H21V4c0-1.103-.897-2-2-2H6c-1.206 0-3 .799-3 3v14c0 2.201 1.794 3 3 3zM5 8V5c0-.805.55-.988 1-1h13v12H5V8z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path d="M8 6h9v2H8z" fill="currentColor" />
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const ChevronRightIcon = `export const ChevronRightIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path d="m9 18 6-6-6-6" />
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const IconWrapper = `import {cn} from "@nextui-org/react";
|
||||
|
||||
const IconWrapper = ({children, className}) => (
|
||||
<div className={cn(className, "flex items-center rounded-small justify-center w-7 h-7")}>
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const ItemCounter = `const ItemCounter = ({number}) => (
|
||||
<div className="flex items-center gap-1 text-default-400">
|
||||
<span className="text-small">{number}</span>
|
||||
<ChevronRightIcon className="text-xl" />
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem} from "@nextui-org/react";
|
||||
import {IconWrapper} from "./IconWrapper";
|
||||
import {ItemCounter} from "./ItemCounter";
|
||||
import {BugIcon} from "./BugIcon";
|
||||
import {PullRequestIcon} from "./PullRequestIcon";
|
||||
import {ChatIcon} from "./ChatIcon";
|
||||
import {PlayCircleIcon} from "./PlayCircleIcon";
|
||||
import {LayoutIcon} from "./LayoutIcon";
|
||||
import {TagIcon} from "./TagIcon";
|
||||
import {UsersIcon} from "./UsersIcon";
|
||||
import {WatchersIcon} from "./WatchersIcon";
|
||||
import {BookIcon} from "./BookIcon";
|
||||
import {ChevronRightIcon} from "./ChevronRightIcon";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Listbox
|
||||
aria-label="User Menu"
|
||||
onAction={(key) => alert(key)}
|
||||
className="p-0 gap-0 divide-y divide-default-300/50 dark:divide-default-100/80 bg-content1 max-w-[300px] overflow-visible shadow-small rounded-medium"
|
||||
itemClasses={{
|
||||
base: "px-3 first:rounded-t-medium last:rounded-b-medium rounded-none gap-3 h-12 data-[hover=true]:bg-default-100/80",
|
||||
}}
|
||||
>
|
||||
<ListboxItem
|
||||
key="issues"
|
||||
endContent={<ItemCounter number={13} />}
|
||||
startContent={
|
||||
<IconWrapper className="bg-success/10 text-success">
|
||||
<BugIcon className="text-lg " />
|
||||
</IconWrapper>
|
||||
}
|
||||
>
|
||||
Issues
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="pull_requests"
|
||||
endContent={<ItemCounter number={6} />}
|
||||
startContent={
|
||||
<IconWrapper className="bg-primary/10 text-primary">
|
||||
<PullRequestIcon className="text-lg " />
|
||||
</IconWrapper>
|
||||
}
|
||||
>
|
||||
Pull Requests
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="discussions"
|
||||
endContent={<ItemCounter number={293} />}
|
||||
startContent={
|
||||
<IconWrapper className="bg-secondary/10 text-secondary">
|
||||
<ChatIcon className="text-lg " />
|
||||
</IconWrapper>
|
||||
}
|
||||
>
|
||||
Discussions
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="actions"
|
||||
endContent={<ItemCounter number={2} />}
|
||||
startContent={
|
||||
<IconWrapper className="bg-warning/10 text-warning">
|
||||
<PlayCircleIcon className="text-lg " />
|
||||
</IconWrapper>
|
||||
}
|
||||
>
|
||||
Actions
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="projects"
|
||||
endContent={<ItemCounter number={4} />}
|
||||
startContent={
|
||||
<IconWrapper className="bg-default/50 text-foreground">
|
||||
<LayoutIcon className="text-lg " />
|
||||
</IconWrapper>
|
||||
}
|
||||
>
|
||||
Projects
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="releases"
|
||||
className="group h-auto py-3"
|
||||
endContent={<ItemCounter number={399} />}
|
||||
startContent={
|
||||
<IconWrapper className="bg-primary/10 text-primary">
|
||||
<TagIcon className="text-lg" />
|
||||
</IconWrapper>
|
||||
}
|
||||
textValue="Releases"
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
<span>Releases</span>
|
||||
<div className="px-2 py-1 rounded-small bg-default-100 group-data-[hover=true]:bg-default-200">
|
||||
<span className="text-tiny text-default-600">@nextui-org/react@2.0.10</span>
|
||||
<div className="flex gap-2 text-tiny">
|
||||
<span className="text-default-500">49 minutes ago</span>
|
||||
<span className="text-success">Latest</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="contributors"
|
||||
endContent={<ItemCounter number={79} />}
|
||||
startContent={
|
||||
<IconWrapper className="bg-warning/10 text-warning">
|
||||
<UsersIcon />
|
||||
</IconWrapper>
|
||||
}
|
||||
>
|
||||
Contributors
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="watchers"
|
||||
endContent={<ItemCounter number={82} />}
|
||||
startContent={
|
||||
<IconWrapper className="bg-default/50 text-foreground">
|
||||
<WatchersIcons />
|
||||
</IconWrapper>
|
||||
}
|
||||
>
|
||||
Watchers
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="license"
|
||||
endContent={<span className="text-small text-default-400">MIT</span>}
|
||||
startContent={
|
||||
<IconWrapper className="bg-danger/10 text-danger dark:text-danger-500">
|
||||
<BookIcon />
|
||||
</IconWrapper>
|
||||
}
|
||||
>
|
||||
License
|
||||
</ListboxItem>
|
||||
</Listbox>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/IconWrapper.jsx": IconWrapper,
|
||||
"/ItemCounter.jsx": ItemCounter,
|
||||
"/BugIcon.jsx": BugIcon,
|
||||
"/PullRequestIcon.jsx": PullRequestIcon,
|
||||
"/ChatIcon.jsx": ChatIcon,
|
||||
"/PlayCircleIcon.jsx": PlayCircleIcon,
|
||||
"/LayoutIcon.jsx": LayoutIcon,
|
||||
"/TagIcon.jsx": TagIcon,
|
||||
"/UsersIcon.jsx": UsersIcon,
|
||||
"/WatchersIcons.jsx": WatchersIcon,
|
||||
"/BookIcon.jsx": BookIcon,
|
||||
"/ChevronRightIcon.jsx": ChevronRightIcon,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,169 @@
|
||||
const AddNoteIcon = `export const AddNoteIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M7.37 22h9.25a4.87 4.87 0 0 0 4.87-4.87V8.37a4.87 4.87 0 0 0-4.87-4.87H7.37A4.87 4.87 0 0 0 2.5 8.37v8.75c0 2.7 2.18 4.88 4.87 4.88Z"
|
||||
fill="currentColor"
|
||||
opacity={0.4}
|
||||
/>
|
||||
<path
|
||||
d="M8.29 6.29c-.42 0-.75-.34-.75-.75V2.75a.749.749 0 1 1 1.5 0v2.78c0 .42-.33.76-.75.76ZM15.71 6.29c-.42 0-.75-.34-.75-.75V2.75a.749.749 0 1 1 1.5 0v2.78c0 .42-.33.76-.75.76ZM12 14.75h-1.69V13c0-.41-.34-.75-.75-.75s-.75.34-.75.75v1.75H7c-.41 0-.75.34-.75.75s.34.75.75.75h1.81V18c0 .41.34.75.75.75s.75-.34.75-.75v-1.75H12c.41 0 .75-.34.75-.75s-.34-.75-.75-.75Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const CopyDocumentIcon = `export const CopyDocumentIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M15.5 13.15h-2.17c-1.78 0-3.23-1.44-3.23-3.23V7.75c0-.41-.33-.75-.75-.75H6.18C3.87 7 2 8.5 2 11.18v6.64C2 20.5 3.87 22 6.18 22h5.89c2.31 0 4.18-1.5 4.18-4.18V13.9c0-.42-.34-.75-.75-.75Z"
|
||||
fill="currentColor"
|
||||
opacity={0.4}
|
||||
/>
|
||||
<path
|
||||
d="M17.82 2H11.93C9.67 2 7.84 3.44 7.76 6.01c.06 0 .11-.01.17-.01h5.89C16.13 6 18 7.5 18 10.18V16.83c0 .06-.01.11-.01.16 2.23-.07 4.01-1.55 4.01-4.16V6.18C22 3.5 20.13 2 17.82 2Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M11.98 7.15c-.31-.31-.84-.1-.84.33v2.62c0 1.1.93 2 2.07 2 .71.01 1.7.01 2.55.01.43 0 .65-.5.35-.8-1.09-1.09-3.03-3.04-4.13-4.16Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const EditDocumentIcon = `export const EditDocumentIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M15.48 3H7.52C4.07 3 2 5.06 2 8.52v7.95C2 19.94 4.07 22 7.52 22h7.95c3.46 0 5.52-2.06 5.52-5.52V8.52C21 5.06 18.93 3 15.48 3Z"
|
||||
fill="currentColor"
|
||||
opacity={0.4}
|
||||
/>
|
||||
<path
|
||||
d="M21.02 2.98c-1.79-1.8-3.54-1.84-5.38 0L14.51 4.1c-.1.1-.13.24-.09.37.7 2.45 2.66 4.41 5.11 5.11.03.01.08.01.11.01.1 0 .2-.04.27-.11l1.11-1.12c.91-.91 1.36-1.78 1.36-2.67 0-.9-.45-1.79-1.36-2.71ZM17.86 10.42c-.27-.13-.53-.26-.77-.41-.2-.12-.4-.25-.59-.39-.16-.1-.34-.25-.52-.4-.02-.01-.08-.06-.16-.14-.31-.25-.64-.59-.95-.96-.02-.02-.08-.08-.13-.17-.1-.11-.25-.3-.38-.51-.11-.14-.24-.34-.36-.55-.15-.25-.28-.5-.4-.76-.13-.28-.23-.54-.32-.79L7.9 10.72c-.35.35-.69 1.01-.76 1.5l-.43 2.98c-.09.63.08 1.22.47 1.61.33.33.78.5 1.28.5.11 0 .22-.01.33-.02l2.97-.42c.49-.07 1.15-.4 1.5-.76l5.38-5.38c-.25-.08-.5-.19-.78-.31Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const DeleteDocumentIcon = `export const DeleteDocumentIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M21.07 5.23c-1.61-.16-3.22-.28-4.84-.37v-.01l-.22-1.3c-.15-.92-.37-2.3-2.71-2.3h-2.62c-2.33 0-2.55 1.32-2.71 2.29l-.21 1.28c-.93.06-1.86.12-2.79.21l-2.04.2c-.42.04-.72.41-.68.82.04.41.4.71.82.67l2.04-.2c5.24-.52 10.52-.32 15.82.21h.08c.38 0 .71-.29.75-.68a.766.766 0 0 0-.69-.82Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M19.23 8.14c-.24-.25-.57-.39-.91-.39H5.68c-.34 0-.68.14-.91.39-.23.25-.36.59-.34.94l.62 10.26c.11 1.52.25 3.42 3.74 3.42h6.42c3.49 0 3.63-1.89 3.74-3.42l.62-10.25c.02-.36-.11-.7-.34-.95Z"
|
||||
fill="currentColor"
|
||||
opacity={0.399}
|
||||
/>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M9.58 17a.75.75 0 0 1 .75-.75h3.33a.75.75 0 0 1 0 1.5h-3.33a.75.75 0 0 1-.75-.75ZM8.75 13a.75.75 0 0 1 .75-.75h5a.75.75 0 0 1 0 1.5h-5a.75.75 0 0 1-.75-.75Z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem, cn} from "@nextui-org/react";
|
||||
import {ListboxWrapper} from "./ListboxWrapper";
|
||||
import {AddNoteIcon} from "./AddNoteIcon.jsx";
|
||||
import {CopyDocumentIcon} from "./CopyDocumentIcon.jsx";
|
||||
import {EditDocumentIcon} from "./EditDocumentIcon.jsx";
|
||||
import {DeleteDocumentIcon} from "./DeleteDocumentIcon.jsx";
|
||||
|
||||
export default function App() {
|
||||
const iconClasses = "text-xl text-default-500 pointer-events-none flex-shrink-0";
|
||||
|
||||
return (
|
||||
<ListboxWrapper>
|
||||
<Listbox variant="flat" aria-label="Listbox menu with descriptions">
|
||||
<ListboxItem
|
||||
key="new"
|
||||
description="Create a new file"
|
||||
startContent={<AddNoteIcon className={iconClasses} />}
|
||||
>
|
||||
New file
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="copy"
|
||||
description="Copy the file link"
|
||||
startContent={<CopyDocumentIcon className={iconClasses} />}
|
||||
>
|
||||
Copy link
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="edit"
|
||||
showDivider
|
||||
description="Allows you to edit the file"
|
||||
startContent={<EditDocumentIcon className={iconClasses} />}
|
||||
>
|
||||
Edit file
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="delete"
|
||||
className="text-danger"
|
||||
color="danger"
|
||||
description="Permanently delete the file"
|
||||
startContent={<DeleteDocumentIcon className={cn(iconClasses, "text-danger")} />}
|
||||
>
|
||||
Delete file
|
||||
</ListboxItem>
|
||||
</Listbox>
|
||||
</ListboxWrapper>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/ListboxWrapper.jsx": ListboxWrapper,
|
||||
"/AddNoteIcon.jsx": AddNoteIcon,
|
||||
"/CopyDocumentIcon.jsx": CopyDocumentIcon,
|
||||
"/EditDocumentIcon.jsx": EditDocumentIcon,
|
||||
"/DeleteDocumentIcon.jsx": DeleteDocumentIcon,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem} from "@nextui-org/react";
|
||||
import {ListboxWrapper} from "./ListboxWrapper";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ListboxWrapper>
|
||||
<Listbox
|
||||
aria-label="Example with disabled actions"
|
||||
disabledKeys={["edit", "delete"]}
|
||||
onAction={(key) => alert(key)}
|
||||
>
|
||||
<ListboxItem key="new">New file</ListboxItem>
|
||||
<ListboxItem key="copy">Copy link</ListboxItem>
|
||||
<ListboxItem key="edit">Edit file</ListboxItem>
|
||||
<ListboxItem key="delete" className="text-danger" color="danger">
|
||||
Delete file
|
||||
</ListboxItem>
|
||||
</Listbox>
|
||||
</ListboxWrapper>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/ListboxWrapper.jsx": ListboxWrapper,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem} from "@nextui-org/react";
|
||||
import {ListboxWrapper} from "./ListboxWrapper";
|
||||
|
||||
export default function App() {
|
||||
const items = [
|
||||
{
|
||||
key: "new",
|
||||
label: "New file",
|
||||
},
|
||||
{
|
||||
key: "copy",
|
||||
label: "Copy link",
|
||||
},
|
||||
{
|
||||
key: "edit",
|
||||
label: "Edit file",
|
||||
},
|
||||
{
|
||||
key: "delete",
|
||||
label: "Delete file",
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ListboxWrapper>
|
||||
<Listbox
|
||||
items={items}
|
||||
aria-label="Dynamic Actions"
|
||||
onAction={(key) => alert(key)}
|
||||
>
|
||||
{(item) => (
|
||||
<ListboxItem
|
||||
key={item.key}
|
||||
color={item.key === "delete" ? "danger" : "default"}
|
||||
className={item.key === "delete" ? "text-danger" : ""}
|
||||
>
|
||||
{item.label}
|
||||
</ListboxItem>
|
||||
)}
|
||||
</Listbox>
|
||||
</ListboxWrapper>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/ListboxWrapper.jsx": ListboxWrapper,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,165 @@
|
||||
const AddNoteIcon = `export const AddNoteIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M7.37 22h9.25a4.87 4.87 0 0 0 4.87-4.87V8.37a4.87 4.87 0 0 0-4.87-4.87H7.37A4.87 4.87 0 0 0 2.5 8.37v8.75c0 2.7 2.18 4.88 4.87 4.88Z"
|
||||
fill="currentColor"
|
||||
opacity={0.4}
|
||||
/>
|
||||
<path
|
||||
d="M8.29 6.29c-.42 0-.75-.34-.75-.75V2.75a.749.749 0 1 1 1.5 0v2.78c0 .42-.33.76-.75.76ZM15.71 6.29c-.42 0-.75-.34-.75-.75V2.75a.749.749 0 1 1 1.5 0v2.78c0 .42-.33.76-.75.76ZM12 14.75h-1.69V13c0-.41-.34-.75-.75-.75s-.75.34-.75.75v1.75H7c-.41 0-.75.34-.75.75s.34.75.75.75h1.81V18c0 .41.34.75.75.75s.75-.34.75-.75v-1.75H12c.41 0 .75-.34.75-.75s-.34-.75-.75-.75Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const CopyDocumentIcon = `export const CopyDocumentIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M15.5 13.15h-2.17c-1.78 0-3.23-1.44-3.23-3.23V7.75c0-.41-.33-.75-.75-.75H6.18C3.87 7 2 8.5 2 11.18v6.64C2 20.5 3.87 22 6.18 22h5.89c2.31 0 4.18-1.5 4.18-4.18V13.9c0-.42-.34-.75-.75-.75Z"
|
||||
fill="currentColor"
|
||||
opacity={0.4}
|
||||
/>
|
||||
<path
|
||||
d="M17.82 2H11.93C9.67 2 7.84 3.44 7.76 6.01c.06 0 .11-.01.17-.01h5.89C16.13 6 18 7.5 18 10.18V16.83c0 .06-.01.11-.01.16 2.23-.07 4.01-1.55 4.01-4.16V6.18C22 3.5 20.13 2 17.82 2Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M11.98 7.15c-.31-.31-.84-.1-.84.33v2.62c0 1.1.93 2 2.07 2 .71.01 1.7.01 2.55.01.43 0 .65-.5.35-.8-1.09-1.09-3.03-3.04-4.13-4.16Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const EditDocumentIcon = `export const EditDocumentIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M15.48 3H7.52C4.07 3 2 5.06 2 8.52v7.95C2 19.94 4.07 22 7.52 22h7.95c3.46 0 5.52-2.06 5.52-5.52V8.52C21 5.06 18.93 3 15.48 3Z"
|
||||
fill="currentColor"
|
||||
opacity={0.4}
|
||||
/>
|
||||
<path
|
||||
d="M21.02 2.98c-1.79-1.8-3.54-1.84-5.38 0L14.51 4.1c-.1.1-.13.24-.09.37.7 2.45 2.66 4.41 5.11 5.11.03.01.08.01.11.01.1 0 .2-.04.27-.11l1.11-1.12c.91-.91 1.36-1.78 1.36-2.67 0-.9-.45-1.79-1.36-2.71ZM17.86 10.42c-.27-.13-.53-.26-.77-.41-.2-.12-.4-.25-.59-.39-.16-.1-.34-.25-.52-.4-.02-.01-.08-.06-.16-.14-.31-.25-.64-.59-.95-.96-.02-.02-.08-.08-.13-.17-.1-.11-.25-.3-.38-.51-.11-.14-.24-.34-.36-.55-.15-.25-.28-.5-.4-.76-.13-.28-.23-.54-.32-.79L7.9 10.72c-.35.35-.69 1.01-.76 1.5l-.43 2.98c-.09.63.08 1.22.47 1.61.33.33.78.5 1.28.5.11 0 .22-.01.33-.02l2.97-.42c.49-.07 1.15-.4 1.5-.76l5.38-5.38c-.25-.08-.5-.19-.78-.31Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const DeleteDocumentIcon = `export const DeleteDocumentIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M21.07 5.23c-1.61-.16-3.22-.28-4.84-.37v-.01l-.22-1.3c-.15-.92-.37-2.3-2.71-2.3h-2.62c-2.33 0-2.55 1.32-2.71 2.29l-.21 1.28c-.93.06-1.86.12-2.79.21l-2.04.2c-.42.04-.72.41-.68.82.04.41.4.71.82.67l2.04-.2c5.24-.52 10.52-.32 15.82.21h.08c.38 0 .71-.29.75-.68a.766.766 0 0 0-.69-.82Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M19.23 8.14c-.24-.25-.57-.39-.91-.39H5.68c-.34 0-.68.14-.91.39-.23.25-.36.59-.34.94l.62 10.26c.11 1.52.25 3.42 3.74 3.42h6.42c3.49 0 3.63-1.89 3.74-3.42l.62-10.25c.02-.36-.11-.7-.34-.95Z"
|
||||
fill="currentColor"
|
||||
opacity={0.399}
|
||||
/>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M9.58 17a.75.75 0 0 1 .75-.75h3.33a.75.75 0 0 1 0 1.5h-3.33a.75.75 0 0 1-.75-.75ZM8.75 13a.75.75 0 0 1 .75-.75h5a.75.75 0 0 1 0 1.5h-5a.75.75 0 0 1-.75-.75Z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem, cn} from "@nextui-org/react";
|
||||
import {ListboxWrapper} from "./ListboxWrapper";
|
||||
import {AddNoteIcon} from "./AddNoteIcon.jsx";
|
||||
import {CopyDocumentIcon} from "./CopyDocumentIcon.jsx";
|
||||
import {EditDocumentIcon} from "./EditDocumentIcon.jsx";
|
||||
import {DeleteDocumentIcon} from "./DeleteDocumentIcon.jsx";
|
||||
|
||||
export default function App() {
|
||||
const iconClasses = "text-xl text-default-500 pointer-events-none flex-shrink-0";
|
||||
|
||||
return (
|
||||
<ListboxWrapper>
|
||||
<Listbox variant="faded" aria-label="Listbox menu with icons">
|
||||
<ListboxItem
|
||||
key="new"
|
||||
startContent={<AddNoteIcon className={iconClasses} />}
|
||||
>
|
||||
New file
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="copy"
|
||||
startContent={<CopyDocumentIcon className={iconClasses} />}
|
||||
>
|
||||
Copy link
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="edit"
|
||||
showDivider
|
||||
startContent={<EditDocumentIcon className={iconClasses} />}
|
||||
>
|
||||
Edit file
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="delete"
|
||||
className="text-danger"
|
||||
color="danger"
|
||||
startContent={<DeleteDocumentIcon className={cn(iconClasses, "text-danger")} />}
|
||||
>
|
||||
Delete file
|
||||
</ListboxItem>
|
||||
</Listbox>
|
||||
</ListboxWrapper>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/ListboxWrapper.jsx": ListboxWrapper,
|
||||
"/AddNoteIcon.jsx": AddNoteIcon,
|
||||
"/CopyDocumentIcon.jsx": CopyDocumentIcon,
|
||||
"/EditDocumentIcon.jsx": EditDocumentIcon,
|
||||
"/DeleteDocumentIcon.jsx": DeleteDocumentIcon,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import usage from "./usage";
|
||||
import dynamic from "./dynamic";
|
||||
import disabledKeys from "./disabled-keys";
|
||||
import variants from "./variants";
|
||||
import singleSelection from "./single-selection";
|
||||
import multipleSelection from "./multiple-selection";
|
||||
import icons from "./icons";
|
||||
import description from "./description";
|
||||
import sections from "./sections";
|
||||
import customStyles from "./custom-styles";
|
||||
|
||||
export const listboxContent = {
|
||||
usage,
|
||||
dynamic,
|
||||
disabledKeys,
|
||||
variants,
|
||||
singleSelection,
|
||||
multipleSelection,
|
||||
icons,
|
||||
description,
|
||||
sections,
|
||||
customStyles,
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
<div className="w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem} from "@nextui-org/react";
|
||||
import {ListboxWrapper} from "./ListboxWrapper";
|
||||
|
||||
export default function App() {
|
||||
const [selectedKeys, setSelectedKeys] = React.useState(new Set(["text"]));
|
||||
|
||||
const selectedValue = React.useMemo(
|
||||
() => Array.from(selectedKeys).join(", "),
|
||||
[selectedKeys]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<ListboxWrapper>
|
||||
<Listbox
|
||||
aria-label="Multiple selection example"
|
||||
variant="flat"
|
||||
disallowEmptySelection
|
||||
selectionMode="multiple"
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
>
|
||||
<ListboxItem key="text">Text</ListboxItem>
|
||||
<ListboxItem key="number">Number</ListboxItem>
|
||||
<ListboxItem key="date">Date</ListboxItem>
|
||||
<ListboxItem key="single_date">Single Date</ListboxItem>
|
||||
<ListboxItem key="iteration">Iteration</ListboxItem>
|
||||
</Listbox>
|
||||
</ListboxWrapper>
|
||||
<p className="text-small text-default-500">Selected value: {selectedValue}</p>
|
||||
</div>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/ListboxWrapper.jsx": ListboxWrapper,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,172 @@
|
||||
const AddNoteIcon = `export const AddNoteIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M7.37 22h9.25a4.87 4.87 0 0 0 4.87-4.87V8.37a4.87 4.87 0 0 0-4.87-4.87H7.37A4.87 4.87 0 0 0 2.5 8.37v8.75c0 2.7 2.18 4.88 4.87 4.88Z"
|
||||
fill="currentColor"
|
||||
opacity={0.4}
|
||||
/>
|
||||
<path
|
||||
d="M8.29 6.29c-.42 0-.75-.34-.75-.75V2.75a.749.749 0 1 1 1.5 0v2.78c0 .42-.33.76-.75.76ZM15.71 6.29c-.42 0-.75-.34-.75-.75V2.75a.749.749 0 1 1 1.5 0v2.78c0 .42-.33.76-.75.76ZM12 14.75h-1.69V13c0-.41-.34-.75-.75-.75s-.75.34-.75.75v1.75H7c-.41 0-.75.34-.75.75s.34.75.75.75h1.81V18c0 .41.34.75.75.75s.75-.34.75-.75v-1.75H12c.41 0 .75-.34.75-.75s-.34-.75-.75-.75Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const CopyDocumentIcon = `export const CopyDocumentIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M15.5 13.15h-2.17c-1.78 0-3.23-1.44-3.23-3.23V7.75c0-.41-.33-.75-.75-.75H6.18C3.87 7 2 8.5 2 11.18v6.64C2 20.5 3.87 22 6.18 22h5.89c2.31 0 4.18-1.5 4.18-4.18V13.9c0-.42-.34-.75-.75-.75Z"
|
||||
fill="currentColor"
|
||||
opacity={0.4}
|
||||
/>
|
||||
<path
|
||||
d="M17.82 2H11.93C9.67 2 7.84 3.44 7.76 6.01c.06 0 .11-.01.17-.01h5.89C16.13 6 18 7.5 18 10.18V16.83c0 .06-.01.11-.01.16 2.23-.07 4.01-1.55 4.01-4.16V6.18C22 3.5 20.13 2 17.82 2Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M11.98 7.15c-.31-.31-.84-.1-.84.33v2.62c0 1.1.93 2 2.07 2 .71.01 1.7.01 2.55.01.43 0 .65-.5.35-.8-1.09-1.09-3.03-3.04-4.13-4.16Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const EditDocumentIcon = `export const EditDocumentIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M15.48 3H7.52C4.07 3 2 5.06 2 8.52v7.95C2 19.94 4.07 22 7.52 22h7.95c3.46 0 5.52-2.06 5.52-5.52V8.52C21 5.06 18.93 3 15.48 3Z"
|
||||
fill="currentColor"
|
||||
opacity={0.4}
|
||||
/>
|
||||
<path
|
||||
d="M21.02 2.98c-1.79-1.8-3.54-1.84-5.38 0L14.51 4.1c-.1.1-.13.24-.09.37.7 2.45 2.66 4.41 5.11 5.11.03.01.08.01.11.01.1 0 .2-.04.27-.11l1.11-1.12c.91-.91 1.36-1.78 1.36-2.67 0-.9-.45-1.79-1.36-2.71ZM17.86 10.42c-.27-.13-.53-.26-.77-.41-.2-.12-.4-.25-.59-.39-.16-.1-.34-.25-.52-.4-.02-.01-.08-.06-.16-.14-.31-.25-.64-.59-.95-.96-.02-.02-.08-.08-.13-.17-.1-.11-.25-.3-.38-.51-.11-.14-.24-.34-.36-.55-.15-.25-.28-.5-.4-.76-.13-.28-.23-.54-.32-.79L7.9 10.72c-.35.35-.69 1.01-.76 1.5l-.43 2.98c-.09.63.08 1.22.47 1.61.33.33.78.5 1.28.5.11 0 .22-.01.33-.02l2.97-.42c.49-.07 1.15-.4 1.5-.76l5.38-5.38c-.25-.08-.5-.19-.78-.31Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const DeleteDocumentIcon = `export const DeleteDocumentIcon = (props) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M21.07 5.23c-1.61-.16-3.22-.28-4.84-.37v-.01l-.22-1.3c-.15-.92-.37-2.3-2.71-2.3h-2.62c-2.33 0-2.55 1.32-2.71 2.29l-.21 1.28c-.93.06-1.86.12-2.79.21l-2.04.2c-.42.04-.72.41-.68.82.04.41.4.71.82.67l2.04-.2c5.24-.52 10.52-.32 15.82.21h.08c.38 0 .71-.29.75-.68a.766.766 0 0 0-.69-.82Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M19.23 8.14c-.24-.25-.57-.39-.91-.39H5.68c-.34 0-.68.14-.91.39-.23.25-.36.59-.34.94l.62 10.26c.11 1.52.25 3.42 3.74 3.42h6.42c3.49 0 3.63-1.89 3.74-3.42l.62-10.25c.02-.36-.11-.7-.34-.95Z"
|
||||
fill="currentColor"
|
||||
opacity={0.399}
|
||||
/>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M9.58 17a.75.75 0 0 1 .75-.75h3.33a.75.75 0 0 1 0 1.5h-3.33a.75.75 0 0 1-.75-.75ZM8.75 13a.75.75 0 0 1 .75-.75h5a.75.75 0 0 1 0 1.5h-5a.75.75 0 0 1-.75-.75Z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem, ListboxSection, cn} from "@nextui-org/react";
|
||||
import {ListboxWrapper} from "./ListboxWrapper";
|
||||
import {AddNoteIcon} from "./AddNoteIcon.jsx";
|
||||
import {CopyDocumentIcon} from "./CopyDocumentIcon.jsx";
|
||||
import {EditDocumentIcon} from "./EditDocumentIcon.jsx";
|
||||
import {DeleteDocumentIcon} from "./DeleteDocumentIcon.jsx";
|
||||
|
||||
export default function App() {
|
||||
const iconClasses = "text-xl text-default-500 pointer-events-none flex-shrink-0";
|
||||
|
||||
return (
|
||||
<ListboxWrapper>
|
||||
<Listbox variant="flat" aria-label="Listbox menu with sections">
|
||||
<ListboxSection title="Actions" showDivider>
|
||||
<ListboxItem
|
||||
key="new"
|
||||
description="Create a new file"
|
||||
startContent={<AddNoteIcon className={iconClasses} />}
|
||||
>
|
||||
New file
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="copy"
|
||||
description="Copy the file link"
|
||||
startContent={<CopyDocumentIcon className={iconClasses} />}
|
||||
>
|
||||
Copy link
|
||||
</ListboxItem>
|
||||
<ListboxItem
|
||||
key="edit"
|
||||
description="Allows you to edit the file"
|
||||
startContent={<EditDocumentIcon className={iconClasses} />}
|
||||
>
|
||||
Edit file
|
||||
</ListboxItem>
|
||||
</ListboxSection>
|
||||
<ListboxSection title="Danger zone">
|
||||
<ListboxItem
|
||||
key="delete"
|
||||
className="text-danger"
|
||||
color="danger"
|
||||
description="Permanently delete the file"
|
||||
startContent={<DeleteDocumentIcon className={cn(iconClasses, "text-danger")} />}
|
||||
>
|
||||
Delete file
|
||||
</ListboxItem>
|
||||
</ListboxSection>
|
||||
</Listbox>
|
||||
</ListboxWrapper>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/ListboxWrapper.jsx": ListboxWrapper,
|
||||
"/AddNoteIcon.jsx": AddNoteIcon,
|
||||
"/CopyDocumentIcon.jsx": CopyDocumentIcon,
|
||||
"/EditDocumentIcon.jsx": EditDocumentIcon,
|
||||
"/DeleteDocumentIcon.jsx": DeleteDocumentIcon,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
<div className="w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem} from "@nextui-org/react";
|
||||
import {ListboxWrapper} from "./ListboxWrapper";
|
||||
|
||||
export default function App() {
|
||||
const [selectedKeys, setSelectedKeys] = React.useState(new Set(["text"]));
|
||||
|
||||
const selectedValue = React.useMemo(
|
||||
() => Array.from(selectedKeys).join(", "),
|
||||
[selectedKeys]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<ListboxWrapper>
|
||||
<Listbox
|
||||
aria-label="Single selection example"
|
||||
variant="flat"
|
||||
disallowEmptySelection
|
||||
selectionMode="single"
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
>
|
||||
<ListboxItem key="text">Text</ListboxItem>
|
||||
<ListboxItem key="number">Number</ListboxItem>
|
||||
<ListboxItem key="date">Date</ListboxItem>
|
||||
<ListboxItem key="single_date">Single Date</ListboxItem>
|
||||
<ListboxItem key="iteration">Iteration</ListboxItem>
|
||||
</Listbox>
|
||||
</ListboxWrapper>
|
||||
<p className="text-small text-default-500">Selected value: {selectedValue}</p>
|
||||
</div>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/ListboxWrapper.jsx": ListboxWrapper,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem} from "@nextui-org/react";
|
||||
import {ListboxWrapper} from "./ListboxWrapper";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ListboxWrapper>
|
||||
<Listbox
|
||||
aria-label="Actions"
|
||||
onAction={(key) => alert(key)}
|
||||
>
|
||||
<ListboxItem key="new">New file</ListboxItem>
|
||||
<ListboxItem key="copy">Copy link</ListboxItem>
|
||||
<ListboxItem key="edit">Edit file</ListboxItem>
|
||||
<ListboxItem key="delete" className="text-danger" color="danger">
|
||||
Delete file
|
||||
</ListboxItem>
|
||||
</Listbox>
|
||||
</ListboxWrapper>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/ListboxWrapper.jsx": ListboxWrapper,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {Listbox, ListboxItem, RadioGroup, Radio} from "@nextui-org/react";
|
||||
import {ListboxWrapper} from "./ListboxWrapper";
|
||||
|
||||
export default function App() {
|
||||
const [selectedVariant, setSelectedVariant] = React.useState("solid")
|
||||
const [selectedColor, setSelectedColor] = React.useState("default")
|
||||
|
||||
const variants = ["solid", "bordered", "light", "flat", "faded", "shadow"];
|
||||
const colors = ["default", "primary", "secondary", "success", "warning", "danger"];
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<ListboxWrapper>
|
||||
<Listbox
|
||||
aria-label="Listbox Variants"
|
||||
color={selectedColor}
|
||||
variant={selectedVariant}
|
||||
>
|
||||
<ListboxItem key="new">New file</ListboxItem>
|
||||
<ListboxItem key="copy">Copy link</ListboxItem>
|
||||
<ListboxItem key="edit">Edit file</ListboxItem>
|
||||
<ListboxItem key="delete" className="text-danger" color="danger">
|
||||
Delete file
|
||||
</ListboxItem>
|
||||
</Listbox>
|
||||
</ListboxWrapper>
|
||||
<div className="flex flex-col gap-2">
|
||||
<RadioGroup
|
||||
label="Select listbox item variant"
|
||||
orientation="horizontal"
|
||||
color={selectedVariant}
|
||||
defaultValue="solid"
|
||||
onValueChange={setSelectedVariant}
|
||||
>
|
||||
{variants.map((variant) => (
|
||||
<Radio key={variant} value={variant} className="capitalize">
|
||||
{variant}
|
||||
</Radio>
|
||||
))}
|
||||
</RadioGroup>
|
||||
<RadioGroup
|
||||
label="Select listbox item color"
|
||||
orientation="horizontal"
|
||||
color={selectedColor}
|
||||
defaultValue="default"
|
||||
onValueChange={setSelectedColor}
|
||||
>
|
||||
{colors.map((color) => (
|
||||
<Radio key={color} value={color} className="capitalize">
|
||||
{color}
|
||||
</Radio>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/ListboxWrapper.jsx": ListboxWrapper,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -16,6 +16,7 @@ export default function App() {
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{backdrops.map((b) => (
|
||||
<Button
|
||||
key={b}
|
||||
variant="flat"
|
||||
color="warning"
|
||||
onPress={() => handleOpen(b)}
|
||||
@@ -50,7 +51,7 @@ export default function App() {
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onClick={onClose}>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function App() {
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onClick={onClose}>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
|
||||
@@ -55,7 +55,7 @@ export default function App() {
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onClick={onClose}>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
|
||||
@@ -44,7 +44,7 @@ export default function App() {
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="foreground" variant="light" onClick={onClose}>
|
||||
<Button color="foreground" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button className="bg-[#6f4ef2] shadow-lg shadow-indigo-500/20" onPress={onClose}>
|
||||
|
||||
@@ -40,7 +40,7 @@ const LockIcon = `export const LockIcon = (props) => (
|
||||
);`;
|
||||
|
||||
const App = `import {Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button, useDisclosure, Checkbox, Input, Link} from "@nextui-org/react";
|
||||
import {MailFilledIcon} from './MailIcon.jsx';
|
||||
import {MailIcon} from './MailIcon.jsx';
|
||||
import {LockIcon} from './LockIcon.jsx';
|
||||
|
||||
export default function App() {
|
||||
@@ -91,7 +91,7 @@ export default function App() {
|
||||
</div>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="flat" onClick={onClose}>
|
||||
<Button color="danger" variant="flat" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function App() {
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onClick={onClose}>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
|
||||
@@ -104,7 +104,7 @@ export default function App() {
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onClick={onClose}>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
|
||||
@@ -42,7 +42,7 @@ export default function App() {
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onClick={onClose}>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
|
||||
@@ -16,7 +16,7 @@ export default function App() {
|
||||
<>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{sizes.map((size) => (
|
||||
<Button onPress={() => handleOpen(size)}>Open {size}</Button>
|
||||
<Button key={size} onPress={() => handleOpen(size)}>Open {size}</Button>
|
||||
))}
|
||||
</div>
|
||||
<Modal
|
||||
@@ -46,7 +46,7 @@ export default function App() {
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onClick={onClose}>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function App() {
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onClick={onClose}>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
|
||||
@@ -19,6 +19,7 @@ export default function App() {
|
||||
<AcmeLogo />
|
||||
<p className="font-bold text-inherit">ACME</p>
|
||||
</NavbarBrand>
|
||||
|
||||
<NavbarContent className="hidden sm:flex gap-4" justify="center">
|
||||
<NavbarItem>
|
||||
<Link color="foreground" href="#">
|
||||
@@ -36,22 +37,20 @@ export default function App() {
|
||||
</Link>
|
||||
</NavbarItem>
|
||||
</NavbarContent>
|
||||
<NavbarContent justify="end">
|
||||
|
||||
<NavbarContent as="div" justify="end">
|
||||
<Dropdown placement="bottom-end">
|
||||
<NavbarItem>
|
||||
<DropdownTrigger>
|
||||
<Avatar
|
||||
isBordered
|
||||
as={Link}
|
||||
href="#"
|
||||
className="transition-transform"
|
||||
color="secondary"
|
||||
name="Jason Hughes"
|
||||
size="sm"
|
||||
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
</NavbarItem>
|
||||
<DropdownTrigger>
|
||||
<Avatar
|
||||
isBordered
|
||||
as="button"
|
||||
className="transition-transform"
|
||||
color="secondary"
|
||||
name="Jason Hughes"
|
||||
size="sm"
|
||||
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu aria-label="Profile Actions" variant="flat">
|
||||
<DropdownItem key="profile" className="h-14 gap-2">
|
||||
<p className="font-semibold">Signed in as</p>
|
||||
|
||||
@@ -74,33 +74,32 @@ export default function App() {
|
||||
</NavbarItem>
|
||||
</NavbarContent>
|
||||
</NavbarContent>
|
||||
<NavbarContent className="items-center" justify="end">
|
||||
|
||||
<NavbarContent as="div" className="items-center" justify="end">
|
||||
<Input
|
||||
classNames={{
|
||||
base: "max-w-full sm:max-w-[10rem] h-10",
|
||||
mainWrapper: "h-full",
|
||||
input: "text-small",
|
||||
inputWrapper: "font-normal text-default-500 bg-default-400/20 dark:bg-default-500/20",
|
||||
inputWrapper: "h-full font-normal text-default-500 bg-default-400/20 dark:bg-default-500/20",
|
||||
}}
|
||||
placeholder="Type to search..."
|
||||
size="sm"
|
||||
startContent={<SearchLinearIcon size={18} />}
|
||||
startContent={<SearchIcon size={18} />}
|
||||
type="search"
|
||||
/>
|
||||
<Dropdown placement="bottom-end">
|
||||
<NavbarItem>
|
||||
<DropdownTrigger>
|
||||
<Avatar
|
||||
isBordered
|
||||
as={Link}
|
||||
href="#"
|
||||
className="transition-transform"
|
||||
color="secondary"
|
||||
name="Jason Hughes"
|
||||
size="sm"
|
||||
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
</NavbarItem>
|
||||
<DropdownTrigger>
|
||||
<Avatar
|
||||
isBordered
|
||||
as="button"
|
||||
className="transition-transform"
|
||||
color="secondary"
|
||||
name="Jason Hughes"
|
||||
size="sm"
|
||||
src="https://i.pravatar.cc/150?u=a042581f4e29026704d"
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu aria-label="Profile Actions" variant="flat">
|
||||
<DropdownItem key="profile" className="h-14 gap-2">
|
||||
<p className="font-semibold">Signed in as</p>
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function App() {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
{colors.map((color) => (
|
||||
<Pagination total={10} initialPage={1} color={color} />
|
||||
<Pagination key={color} total={10} initialPage={1} color={color} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ export default function App() {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
<p className="text-default-500">Selected Page: {currentPage}</p>
|
||||
<p className="text-small text-default-500">Selected Page: {currentPage}</p>
|
||||
<Pagination
|
||||
total={10}
|
||||
color="secondary"
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function App() {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
{radius.map((r) => (
|
||||
<Pagination total={10} initialPage={1} radius={r} />
|
||||
<Pagination key={r} total={10} initialPage={1} radius={r} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function App() {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
{sizes.map((size) => (
|
||||
<Pagination total={10} initialPage={1} size={size} />
|
||||
<Pagination key={size} total={10} initialPage={1} size={size} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function App() {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-4 items-center">
|
||||
{variants.map((variant) => (
|
||||
<Pagination total={10} initialPage={1} variant={variant} />
|
||||
<Pagination key={variant} total={10} initialPage={1} variant={variant} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ export const CustomRadio = (props) => {
|
||||
{...otherProps}
|
||||
classNames={{
|
||||
base: cn(
|
||||
"inline-flex bg-content1 hover:bg-content2 items-center justify-between",
|
||||
"inline-flex m-0 bg-content1 hover:bg-content2 items-center justify-between",
|
||||
"flex-row-reverse max-w-[300px] cursor-pointer rounded-lg gap-4 p-4 border-2 border-transparent",
|
||||
"data-[selected=true]:border-primary"
|
||||
),
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
const Content = `export const Content = () => (
|
||||
<div>
|
||||
<p>
|
||||
Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco deserunt aute id consequat veniam incididunt duis in sint irure nisi. Mollit officia cillum Lorem ullamco minim nostrud elit officia tempor esse quis.
|
||||
</p>
|
||||
<p>
|
||||
Sunt ad dolore quis aute consequat. Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
|
||||
</p>
|
||||
<p>
|
||||
Est velit labore esse esse cupidatat. Velit id elit consequat minim. Mollit enim excepteur ea laboris adipisicing aliqua proident occaecat do do adipisicing adipisicing ut fugiat. Consequat pariatur ullamco aute sunt esse. Irure excepteur eu non eiusmod. Commodo commodo et ad ipsum elit esse pariatur sit adipisicing sunt excepteur enim.
|
||||
</p>
|
||||
<p>
|
||||
Incididunt duis commodo mollit esse veniam non exercitation dolore occaecat ea nostrud laboris. Adipisicing occaecat fugiat fugiat irure fugiat in magna non consectetur proident fugiat. Commodo magna et aliqua elit sint cupidatat. Sint aute ullamco enim cillum anim ex. Est eiusmod commodo occaecat consequat laboris est do duis. Enim incididunt non culpa velit quis aute in elit magna ullamco in consequat ex proident.
|
||||
</p>
|
||||
<p>
|
||||
Dolore incididunt mollit fugiat pariatur cupidatat ipsum laborum cillum. Commodo consequat velit cupidatat duis ex nisi non aliquip ad ea pariatur do culpa. Eiusmod proident adipisicing tempor tempor qui pariatur voluptate dolor do ea commodo. Veniam voluptate cupidatat ex nisi do ullamco in quis elit.
|
||||
</p>
|
||||
<p>
|
||||
Cillum proident veniam cupidatat pariatur laborum tempor cupidatat anim eiusmod id nostrud pariatur tempor reprehenderit. Do esse ullamco laboris sunt proident est ea exercitation cupidatat. Do Lorem eiusmod aliqua culpa ullamco consectetur veniam voluptate cillum. Dolor consequat cillum tempor laboris mollit laborum reprehenderit reprehenderit veniam aliqua deserunt cupidatat consequat id.
|
||||
</p>
|
||||
<p>
|
||||
Est id tempor excepteur enim labore sint aliquip consequat duis minim tempor proident. Dolor incididunt aliquip minim elit ea. Exercitation non officia eu id.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum ipsum consequat incididunt do aliquip pariatur nostrud. Qui ut sint culpa labore Lorem. Magna deserunt aliquip aute duis consectetur magna amet anim. Magna fugiat est nostrud veniam. Officia duis ea sunt aliqua.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum minim officia aute anim minim aute aliquip aute non in non. Ipsum aliquip proident ut dolore eiusmod ad fugiat fugiat ut ex. Ea velit Lorem ut et commodo nulla voluptate veniam ea et aliqua esse id. Pariatur dolor et adipisicing ea mollit. Ipsum non irure proident ipsum dolore aliquip adipisicing laborum irure dolor nostrud occaecat exercitation.
|
||||
</p>
|
||||
<p>
|
||||
Culpa qui reprehenderit nostrud aliqua reprehenderit et ullamco proident nisi commodo non ut. Ipsum quis irure nisi sint do qui velit nisi. Sunt voluptate eu reprehenderit tempor consequat eiusmod Lorem irure velit duis Lorem laboris ipsum cupidatat. Pariatur excepteur tempor veniam cillum et nulla ipsum veniam ad ipsum ad aute. Est officia duis pariatur ad eiusmod id voluptate.
|
||||
</p>
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {ScrollShadow} from "@nextui-org/react";
|
||||
import {Content} from "./Content";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ScrollShadow size={100} className="w-[300px] h-[400px]">
|
||||
<Content />
|
||||
</ScrollShadow>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/Content.jsx": Content,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
const Content = `export const Content = () => (
|
||||
<div>
|
||||
<p>
|
||||
Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco deserunt aute id consequat veniam incididunt duis in sint irure nisi. Mollit officia cillum Lorem ullamco minim nostrud elit officia tempor esse quis.
|
||||
</p>
|
||||
<p>
|
||||
Sunt ad dolore quis aute consequat. Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
|
||||
</p>
|
||||
<p>
|
||||
Est velit labore esse esse cupidatat. Velit id elit consequat minim. Mollit enim excepteur ea laboris adipisicing aliqua proident occaecat do do adipisicing adipisicing ut fugiat. Consequat pariatur ullamco aute sunt esse. Irure excepteur eu non eiusmod. Commodo commodo et ad ipsum elit esse pariatur sit adipisicing sunt excepteur enim.
|
||||
</p>
|
||||
<p>
|
||||
Incididunt duis commodo mollit esse veniam non exercitation dolore occaecat ea nostrud laboris. Adipisicing occaecat fugiat fugiat irure fugiat in magna non consectetur proident fugiat. Commodo magna et aliqua elit sint cupidatat. Sint aute ullamco enim cillum anim ex. Est eiusmod commodo occaecat consequat laboris est do duis. Enim incididunt non culpa velit quis aute in elit magna ullamco in consequat ex proident.
|
||||
</p>
|
||||
<p>
|
||||
Dolore incididunt mollit fugiat pariatur cupidatat ipsum laborum cillum. Commodo consequat velit cupidatat duis ex nisi non aliquip ad ea pariatur do culpa. Eiusmod proident adipisicing tempor tempor qui pariatur voluptate dolor do ea commodo. Veniam voluptate cupidatat ex nisi do ullamco in quis elit.
|
||||
</p>
|
||||
<p>
|
||||
Cillum proident veniam cupidatat pariatur laborum tempor cupidatat anim eiusmod id nostrud pariatur tempor reprehenderit. Do esse ullamco laboris sunt proident est ea exercitation cupidatat. Do Lorem eiusmod aliqua culpa ullamco consectetur veniam voluptate cillum. Dolor consequat cillum tempor laboris mollit laborum reprehenderit reprehenderit veniam aliqua deserunt cupidatat consequat id.
|
||||
</p>
|
||||
<p>
|
||||
Est id tempor excepteur enim labore sint aliquip consequat duis minim tempor proident. Dolor incididunt aliquip minim elit ea. Exercitation non officia eu id.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum ipsum consequat incididunt do aliquip pariatur nostrud. Qui ut sint culpa labore Lorem. Magna deserunt aliquip aute duis consectetur magna amet anim. Magna fugiat est nostrud veniam. Officia duis ea sunt aliqua.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum minim officia aute anim minim aute aliquip aute non in non. Ipsum aliquip proident ut dolore eiusmod ad fugiat fugiat ut ex. Ea velit Lorem ut et commodo nulla voluptate veniam ea et aliqua esse id. Pariatur dolor et adipisicing ea mollit. Ipsum non irure proident ipsum dolore aliquip adipisicing laborum irure dolor nostrud occaecat exercitation.
|
||||
</p>
|
||||
<p>
|
||||
Culpa qui reprehenderit nostrud aliqua reprehenderit et ullamco proident nisi commodo non ut. Ipsum quis irure nisi sint do qui velit nisi. Sunt voluptate eu reprehenderit tempor consequat eiusmod Lorem irure velit duis Lorem laboris ipsum cupidatat. Pariatur excepteur tempor veniam cillum et nulla ipsum veniam ad ipsum ad aute. Est officia duis pariatur ad eiusmod id voluptate.
|
||||
</p>
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {ScrollShadow} from "@nextui-org/react";
|
||||
import {Content} from "./Content";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ScrollShadow hideScrollBar className="w-[300px] h-[400px]">
|
||||
<Content />
|
||||
</ScrollShadow>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/Content.jsx": Content,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
const Content = `export const Content = ({className}) => (
|
||||
<div className={className}>
|
||||
<p>
|
||||
Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco deserunt aute id consequat veniam incididunt duis in sint irure nisi. Mollit officia cillum Lorem ullamco minim nostrud elit officia tempor esse quis.
|
||||
</p>
|
||||
<p>
|
||||
Sunt ad dolore quis aute consequat. Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
|
||||
</p>
|
||||
<p>
|
||||
Est velit labore esse esse cupidatat. Velit id elit consequat minim. Mollit enim excepteur ea laboris adipisicing aliqua proident occaecat do do adipisicing adipisicing ut fugiat. Consequat pariatur ullamco aute sunt esse. Irure excepteur eu non eiusmod. Commodo commodo et ad ipsum elit esse pariatur sit adipisicing sunt excepteur enim.
|
||||
</p>
|
||||
<p>
|
||||
Incididunt duis commodo mollit esse veniam non exercitation dolore occaecat ea nostrud laboris. Adipisicing occaecat fugiat fugiat irure fugiat in magna non consectetur proident fugiat. Commodo magna et aliqua elit sint cupidatat. Sint aute ullamco enim cillum anim ex. Est eiusmod commodo occaecat consequat laboris est do duis. Enim incididunt non culpa velit quis aute in elit magna ullamco in consequat ex proident.
|
||||
</p>
|
||||
<p>
|
||||
Dolore incididunt mollit fugiat pariatur cupidatat ipsum laborum cillum. Commodo consequat velit cupidatat duis ex nisi non aliquip ad ea pariatur do culpa. Eiusmod proident adipisicing tempor tempor qui pariatur voluptate dolor do ea commodo. Veniam voluptate cupidatat ex nisi do ullamco in quis elit.
|
||||
</p>
|
||||
<p>
|
||||
Cillum proident veniam cupidatat pariatur laborum tempor cupidatat anim eiusmod id nostrud pariatur tempor reprehenderit. Do esse ullamco laboris sunt proident est ea exercitation cupidatat. Do Lorem eiusmod aliqua culpa ullamco consectetur veniam voluptate cillum. Dolor consequat cillum tempor laboris mollit laborum reprehenderit reprehenderit veniam aliqua deserunt cupidatat consequat id.
|
||||
</p>
|
||||
<p>
|
||||
Est id tempor excepteur enim labore sint aliquip consequat duis minim tempor proident. Dolor incididunt aliquip minim elit ea. Exercitation non officia eu id.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum ipsum consequat incididunt do aliquip pariatur nostrud. Qui ut sint culpa labore Lorem. Magna deserunt aliquip aute duis consectetur magna amet anim. Magna fugiat est nostrud veniam. Officia duis ea sunt aliqua.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum minim officia aute anim minim aute aliquip aute non in non. Ipsum aliquip proident ut dolore eiusmod ad fugiat fugiat ut ex. Ea velit Lorem ut et commodo nulla voluptate veniam ea et aliqua esse id. Pariatur dolor et adipisicing ea mollit. Ipsum non irure proident ipsum dolore aliquip adipisicing laborum irure dolor nostrud occaecat exercitation.
|
||||
</p>
|
||||
<p>
|
||||
Culpa qui reprehenderit nostrud aliqua reprehenderit et ullamco proident nisi commodo non ut. Ipsum quis irure nisi sint do qui velit nisi. Sunt voluptate eu reprehenderit tempor consequat eiusmod Lorem irure velit duis Lorem laboris ipsum cupidatat. Pariatur excepteur tempor veniam cillum et nulla ipsum veniam ad ipsum ad aute. Est officia duis pariatur ad eiusmod id voluptate.
|
||||
</p>
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {ScrollShadow} from "@nextui-org/react";
|
||||
import {Content} from "./Content";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ScrollShadow orientation="horizontal" className="max-w-[400px] max-h-[300px]">
|
||||
<Content className="w-[800px]" />
|
||||
</ScrollShadow>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/Content.jsx": Content,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import usage from "./usage";
|
||||
import hideScrollbar from "./hide-scrollbar";
|
||||
import customSize from "./custom-size";
|
||||
import horizontal from "./horizontal";
|
||||
import offset from "./offset";
|
||||
|
||||
export const scrollShadowContent = {
|
||||
usage,
|
||||
hideScrollbar,
|
||||
customSize,
|
||||
horizontal,
|
||||
offset,
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
const Content = `export const Content = ({className}) => (
|
||||
<div className={className}>
|
||||
<p>
|
||||
Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco deserunt aute id consequat veniam incididunt duis in sint irure nisi. Mollit officia cillum Lorem ullamco minim nostrud elit officia tempor esse quis.
|
||||
</p>
|
||||
<p>
|
||||
Sunt ad dolore quis aute consequat. Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
|
||||
</p>
|
||||
<p>
|
||||
Est velit labore esse esse cupidatat. Velit id elit consequat minim. Mollit enim excepteur ea laboris adipisicing aliqua proident occaecat do do adipisicing adipisicing ut fugiat. Consequat pariatur ullamco aute sunt esse. Irure excepteur eu non eiusmod. Commodo commodo et ad ipsum elit esse pariatur sit adipisicing sunt excepteur enim.
|
||||
</p>
|
||||
<p>
|
||||
Incididunt duis commodo mollit esse veniam non exercitation dolore occaecat ea nostrud laboris. Adipisicing occaecat fugiat fugiat irure fugiat in magna non consectetur proident fugiat. Commodo magna et aliqua elit sint cupidatat. Sint aute ullamco enim cillum anim ex. Est eiusmod commodo occaecat consequat laboris est do duis. Enim incididunt non culpa velit quis aute in elit magna ullamco in consequat ex proident.
|
||||
</p>
|
||||
<p>
|
||||
Dolore incididunt mollit fugiat pariatur cupidatat ipsum laborum cillum. Commodo consequat velit cupidatat duis ex nisi non aliquip ad ea pariatur do culpa. Eiusmod proident adipisicing tempor tempor qui pariatur voluptate dolor do ea commodo. Veniam voluptate cupidatat ex nisi do ullamco in quis elit.
|
||||
</p>
|
||||
<p>
|
||||
Cillum proident veniam cupidatat pariatur laborum tempor cupidatat anim eiusmod id nostrud pariatur tempor reprehenderit. Do esse ullamco laboris sunt proident est ea exercitation cupidatat. Do Lorem eiusmod aliqua culpa ullamco consectetur veniam voluptate cillum. Dolor consequat cillum tempor laboris mollit laborum reprehenderit reprehenderit veniam aliqua deserunt cupidatat consequat id.
|
||||
</p>
|
||||
<p>
|
||||
Est id tempor excepteur enim labore sint aliquip consequat duis minim tempor proident. Dolor incididunt aliquip minim elit ea. Exercitation non officia eu id.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum ipsum consequat incididunt do aliquip pariatur nostrud. Qui ut sint culpa labore Lorem. Magna deserunt aliquip aute duis consectetur magna amet anim. Magna fugiat est nostrud veniam. Officia duis ea sunt aliqua.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum minim officia aute anim minim aute aliquip aute non in non. Ipsum aliquip proident ut dolore eiusmod ad fugiat fugiat ut ex. Ea velit Lorem ut et commodo nulla voluptate veniam ea et aliqua esse id. Pariatur dolor et adipisicing ea mollit. Ipsum non irure proident ipsum dolore aliquip adipisicing laborum irure dolor nostrud occaecat exercitation.
|
||||
</p>
|
||||
<p>
|
||||
Culpa qui reprehenderit nostrud aliqua reprehenderit et ullamco proident nisi commodo non ut. Ipsum quis irure nisi sint do qui velit nisi. Sunt voluptate eu reprehenderit tempor consequat eiusmod Lorem irure velit duis Lorem laboris ipsum cupidatat. Pariatur excepteur tempor veniam cillum et nulla ipsum veniam ad ipsum ad aute. Est officia duis pariatur ad eiusmod id voluptate.
|
||||
</p>
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {ScrollShadow} from "@nextui-org/react";
|
||||
import {Content} from "./Content";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ScrollShadow
|
||||
hideScrollBar
|
||||
offset={100}
|
||||
orientation="horizontal"
|
||||
className="max-w-[400px] max-h-[300px]"
|
||||
>
|
||||
<Content className="w-[800px]" />
|
||||
</ScrollShadow>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/Content.jsx": Content,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
const Content = `export const Content = () => (
|
||||
<div>
|
||||
<p>
|
||||
Sit nulla est ex deserunt exercitation anim occaecat. Nostrud ullamco deserunt aute id consequat veniam incididunt duis in sint irure nisi. Mollit officia cillum Lorem ullamco minim nostrud elit officia tempor esse quis.
|
||||
</p>
|
||||
<p>
|
||||
Sunt ad dolore quis aute consequat. Magna exercitation reprehenderit magna aute tempor cupidatat consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et mollit incididunt nisi consectetur esse laborum eiusmod pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad veniam.
|
||||
</p>
|
||||
<p>
|
||||
Est velit labore esse esse cupidatat. Velit id elit consequat minim. Mollit enim excepteur ea laboris adipisicing aliqua proident occaecat do do adipisicing adipisicing ut fugiat. Consequat pariatur ullamco aute sunt esse. Irure excepteur eu non eiusmod. Commodo commodo et ad ipsum elit esse pariatur sit adipisicing sunt excepteur enim.
|
||||
</p>
|
||||
<p>
|
||||
Incididunt duis commodo mollit esse veniam non exercitation dolore occaecat ea nostrud laboris. Adipisicing occaecat fugiat fugiat irure fugiat in magna non consectetur proident fugiat. Commodo magna et aliqua elit sint cupidatat. Sint aute ullamco enim cillum anim ex. Est eiusmod commodo occaecat consequat laboris est do duis. Enim incididunt non culpa velit quis aute in elit magna ullamco in consequat ex proident.
|
||||
</p>
|
||||
<p>
|
||||
Dolore incididunt mollit fugiat pariatur cupidatat ipsum laborum cillum. Commodo consequat velit cupidatat duis ex nisi non aliquip ad ea pariatur do culpa. Eiusmod proident adipisicing tempor tempor qui pariatur voluptate dolor do ea commodo. Veniam voluptate cupidatat ex nisi do ullamco in quis elit.
|
||||
</p>
|
||||
<p>
|
||||
Cillum proident veniam cupidatat pariatur laborum tempor cupidatat anim eiusmod id nostrud pariatur tempor reprehenderit. Do esse ullamco laboris sunt proident est ea exercitation cupidatat. Do Lorem eiusmod aliqua culpa ullamco consectetur veniam voluptate cillum. Dolor consequat cillum tempor laboris mollit laborum reprehenderit reprehenderit veniam aliqua deserunt cupidatat consequat id.
|
||||
</p>
|
||||
<p>
|
||||
Est id tempor excepteur enim labore sint aliquip consequat duis minim tempor proident. Dolor incididunt aliquip minim elit ea. Exercitation non officia eu id.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum ipsum consequat incididunt do aliquip pariatur nostrud. Qui ut sint culpa labore Lorem. Magna deserunt aliquip aute duis consectetur magna amet anim. Magna fugiat est nostrud veniam. Officia duis ea sunt aliqua.
|
||||
</p>
|
||||
<p>
|
||||
Ipsum minim officia aute anim minim aute aliquip aute non in non. Ipsum aliquip proident ut dolore eiusmod ad fugiat fugiat ut ex. Ea velit Lorem ut et commodo nulla voluptate veniam ea et aliqua esse id. Pariatur dolor et adipisicing ea mollit. Ipsum non irure proident ipsum dolore aliquip adipisicing laborum irure dolor nostrud occaecat exercitation.
|
||||
</p>
|
||||
<p>
|
||||
Culpa qui reprehenderit nostrud aliqua reprehenderit et ullamco proident nisi commodo non ut. Ipsum quis irure nisi sint do qui velit nisi. Sunt voluptate eu reprehenderit tempor consequat eiusmod Lorem irure velit duis Lorem laboris ipsum cupidatat. Pariatur excepteur tempor veniam cillum et nulla ipsum veniam ad ipsum ad aute. Est officia duis pariatur ad eiusmod id voluptate.
|
||||
</p>
|
||||
</div>
|
||||
);`;
|
||||
|
||||
const App = `import {ScrollShadow} from "@nextui-org/react";
|
||||
import {Content} from "./Content";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ScrollShadow className="w-[300px] h-[400px]">
|
||||
<Content />
|
||||
</ScrollShadow>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/Content.jsx": Content,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,187 @@
|
||||
const usePokemonListTs = `export type Pokemon = {
|
||||
name: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type UsePokemonListProps = {
|
||||
/** Delay to wait before fetching more items */
|
||||
fetchDelay?: number;
|
||||
};
|
||||
|
||||
export function usePokemonList({fetchDelay = 0}: UsePokemonListProps = {}) {
|
||||
const [items, setItems] = React.useState<Pokemon[]>([]);
|
||||
const [hasMore, setHasMore] = React.useState(true);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [offset, setOffset] = React.useState(0);
|
||||
const limit = 10; // Number of items per page, adjust as necessary
|
||||
|
||||
const loadPokemon = async (currentOffset: number) => {
|
||||
const controller = new AbortController();
|
||||
const {signal} = controller;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
if (offset > 0) {
|
||||
// Delay to simulate network latency
|
||||
await new Promise((resolve) => setTimeout(resolve, fetchDelay));
|
||||
}
|
||||
|
||||
let res = await fetch(
|
||||
\`https://pokeapi.co/api/v2/pokemon?offset=\${currentOffset}&limit=\${limit}\`,
|
||||
{signal},
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
|
||||
let json = await res.json();
|
||||
|
||||
setHasMore(json.next !== null);
|
||||
// Append new results to existing ones
|
||||
setItems((prevItems) => [...prevItems, ...json.results]);
|
||||
} catch (error) {
|
||||
if (error.name === "AbortError") {
|
||||
console.log("Fetch aborted");
|
||||
} else {
|
||||
console.error("There was an error with the fetch operation:", error);
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
loadPokemon(offset);
|
||||
}, []);
|
||||
|
||||
const onLoadMore = () => {
|
||||
const newOffset = offset + limit;
|
||||
|
||||
setOffset(newOffset);
|
||||
loadPokemon(newOffset);
|
||||
};
|
||||
|
||||
return {
|
||||
items,
|
||||
hasMore,
|
||||
isLoading,
|
||||
onLoadMore,
|
||||
};
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
const usePokemonList = `export function usePokemonList({fetchDelay = 0} = {}) {
|
||||
const [items, setItems] = React.useState([]);
|
||||
const [hasMore, setHasMore] = React.useState(true);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [offset, setOffset] = React.useState(0);
|
||||
const limit = 10; // Number of items per page, adjust as necessary
|
||||
|
||||
const loadPokemon = async (currentOffset) => {
|
||||
const controller = new AbortController();
|
||||
const {signal} = controller;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
if (offset > 0) {
|
||||
// Delay to simulate network latency
|
||||
await new Promise((resolve) => setTimeout(resolve, fetchDelay));
|
||||
}
|
||||
|
||||
let res = await fetch(
|
||||
\`https://pokeapi.co/api/v2/pokemon?offset=\${currentOffset}&limit=\${limit}\`,
|
||||
{signal},
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
|
||||
let json = await res.json();
|
||||
|
||||
setHasMore(json.next !== null);
|
||||
// Append new results to existing ones
|
||||
setItems((prevItems) => [...prevItems, ...json.results]);
|
||||
} catch (error) {
|
||||
if (error.name === "AbortError") {
|
||||
console.log("Fetch aborted");
|
||||
} else {
|
||||
console.error("There was an error with the fetch operation:", error);
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
loadPokemon(offset);
|
||||
}, []);
|
||||
|
||||
const onLoadMore = () => {
|
||||
const newOffset = offset + limit;
|
||||
|
||||
setOffset(newOffset);
|
||||
loadPokemon(newOffset);
|
||||
};
|
||||
|
||||
return {
|
||||
items,
|
||||
hasMore,
|
||||
isLoading,
|
||||
onLoadMore,
|
||||
};
|
||||
};`;
|
||||
|
||||
const App = `import {Select, SelectItem} from "@nextui-org/react";
|
||||
import {useInfiniteScroll} from "@nextui-org/use-infinity-scroll";
|
||||
import {usePokemonList} from "./usePokemonList";
|
||||
|
||||
export default function App() {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const {items, hasMore, isLoading, onLoadMore} = usePokemonList({fetchDelay: 1500});
|
||||
|
||||
const [, scrollerRef] = useInfiniteScroll({
|
||||
hasMore,
|
||||
isEnabled: isOpen,
|
||||
shouldUseLoader: false, // We don't want to show the loader at the bottom of the list
|
||||
onLoadMore,
|
||||
});
|
||||
|
||||
return (
|
||||
<Select
|
||||
className="max-w-xs"
|
||||
isLoading={isLoading}
|
||||
items={items}
|
||||
label="Pick a Pokemon"
|
||||
placeholder="Select a Pokemon"
|
||||
scrollRef={scrollerRef}
|
||||
selectionMode="single"
|
||||
onOpenChange={setIsOpen}
|
||||
>
|
||||
{(item) => (
|
||||
<SelectItem key={item.name} className="capitalize">
|
||||
{item.name}
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/usePokemonList.js": usePokemonList,
|
||||
};
|
||||
|
||||
const reactTs = {
|
||||
"/App.tsx": App,
|
||||
"/usePokemonList.ts": usePokemonListTs,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
...reactTs,
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
const data = `export const animals = [
|
||||
{label: "Cat", value: "cat", description: "The second most popular pet in the world"},
|
||||
{label: "Dog", value: "dog", description: "The most popular pet in the world"},
|
||||
{label: "Elephant", value: "elephant", description: "The largest land animal"},
|
||||
{label: "Lion", value: "lion", description: "The king of the jungle"},
|
||||
{label: "Tiger", value: "tiger", description: "The largest cat species"},
|
||||
{label: "Giraffe", value: "giraffe", description: "The tallest land animal"},
|
||||
{
|
||||
label: "Dolphin",
|
||||
value: "dolphin",
|
||||
description: "A widely distributed and diverse group of aquatic mammals",
|
||||
},
|
||||
{label: "Penguin", value: "penguin", description: "A group of aquatic flightless birds"},
|
||||
{label: "Zebra", value: "zebra", description: "A several species of African equids"},
|
||||
{
|
||||
label: "Shark",
|
||||
value: "shark",
|
||||
description: "A group of elasmobranch fish characterized by a cartilaginous skeleton",
|
||||
},
|
||||
{
|
||||
label: "Whale",
|
||||
value: "whale",
|
||||
description: "Diverse group of fully aquatic placental marine mammals",
|
||||
},
|
||||
{label: "Otter", value: "otter", description: "A carnivorous mammal in the subfamily Lutrinae"},
|
||||
{label: "Crocodile", value: "crocodile", description: "A large semiaquatic reptile"},
|
||||
];`;
|
||||
|
||||
const App = `import {Select, SelectItem} from "@nextui-org/react";
|
||||
import {animals} from "./data";
|
||||
|
||||
export default function App() {
|
||||
const colors = [
|
||||
"default",
|
||||
"primary",
|
||||
"secondary",
|
||||
"success",
|
||||
"warning",
|
||||
"danger",
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="w-full flex flex-row flex-wrap gap-4">
|
||||
{colors.map((color) => (
|
||||
<Select
|
||||
key={color}
|
||||
color={color}
|
||||
label="Favorite Animal"
|
||||
placeholder="Select an animal"
|
||||
defaultSelectedKeys={["cat"]}
|
||||
className="max-w-xs"
|
||||
>
|
||||
{animals.map((animal) => (
|
||||
<SelectItem key={animal.value} value={animal.value}>
|
||||
{animal.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/data.js": data,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,238 @@
|
||||
const data = `export const users = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Tony Reichert",
|
||||
role: "CEO",
|
||||
team: "Management",
|
||||
status: "active",
|
||||
age: "29",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/1.png",
|
||||
email: "tony.reichert@example.com",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Zoey Lang",
|
||||
role: "Tech Lead",
|
||||
team: "Development",
|
||||
status: "paused",
|
||||
age: "25",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/1.png",
|
||||
email: "zoey.lang@example.com",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Jane Fisher",
|
||||
role: "Sr. Dev",
|
||||
team: "Development",
|
||||
status: "active",
|
||||
age: "22",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/2.png",
|
||||
email: "jane.fisher@example.com",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "William Howard",
|
||||
role: "C.M.",
|
||||
team: "Marketing",
|
||||
status: "vacation",
|
||||
age: "28",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/2.png",
|
||||
email: "william.howard@example.com",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Kristen Copper",
|
||||
role: "S. Manager",
|
||||
team: "Sales",
|
||||
status: "active",
|
||||
age: "24",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/3.png",
|
||||
email: "kristen.cooper@example.com",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Brian Kim",
|
||||
role: "P. Manager",
|
||||
team: "Management",
|
||||
age: "29",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/3.png",
|
||||
email: "brian.kim@example.com",
|
||||
status: "Active",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Michael Hunt",
|
||||
role: "Designer",
|
||||
team: "Design",
|
||||
status: "paused",
|
||||
age: "27",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/4.png",
|
||||
email: "michael.hunt@example.com",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Samantha Brooks",
|
||||
role: "HR Manager",
|
||||
team: "HR",
|
||||
status: "active",
|
||||
age: "31",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/4.png",
|
||||
email: "samantha.brooks@example.com",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Frank Harrison",
|
||||
role: "F. Manager",
|
||||
team: "Finance",
|
||||
status: "vacation",
|
||||
age: "33",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/5.png",
|
||||
email: "frank.harrison@example.com",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Emma Adams",
|
||||
role: "Ops Manager",
|
||||
team: "Operations",
|
||||
status: "active",
|
||||
age: "35",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/5.png",
|
||||
email: "emma.adams@example.com",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Brandon Stevens",
|
||||
role: "Jr. Dev",
|
||||
team: "Development",
|
||||
status: "active",
|
||||
age: "22",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/7.png",
|
||||
email: "brandon.stevens@example.com",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Megan Richards",
|
||||
role: "P. Manager",
|
||||
team: "Product",
|
||||
status: "paused",
|
||||
age: "28",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/7.png",
|
||||
email: "megan.richards@example.com",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: "Oliver Scott",
|
||||
role: "S. Manager",
|
||||
team: "Security",
|
||||
status: "active",
|
||||
age: "37",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/8.png",
|
||||
email: "oliver.scott@example.com",
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
name: "Grace Allen",
|
||||
role: "M. Specialist",
|
||||
team: "Marketing",
|
||||
status: "active",
|
||||
age: "30",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/8.png",
|
||||
email: "grace.allen@example.com",
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
name: "Noah Carter",
|
||||
role: "IT Specialist",
|
||||
team: "I. Technology",
|
||||
status: "paused",
|
||||
age: "31",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/9.png",
|
||||
email: "noah.carter@example.com",
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
name: "Ava Perez",
|
||||
role: "Manager",
|
||||
team: "Sales",
|
||||
status: "active",
|
||||
age: "29",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/9.png",
|
||||
email: "ava.perez@example.com",
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
name: "Liam Johnson",
|
||||
role: "Data Analyst",
|
||||
team: "Analysis",
|
||||
status: "active",
|
||||
age: "28",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/11.png",
|
||||
email: "liam.johnson@example.com",
|
||||
},
|
||||
{
|
||||
id: 18,
|
||||
name: "Sophia Taylor",
|
||||
role: "QA Analyst",
|
||||
team: "Testing",
|
||||
status: "active",
|
||||
age: "27",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/11.png",
|
||||
email: "sophia.taylor@example.com",
|
||||
},
|
||||
{
|
||||
id: 19,
|
||||
name: "Lucas Harris",
|
||||
role: "Administrator",
|
||||
team: "Information Technology",
|
||||
status: "paused",
|
||||
age: "32",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/12.png",
|
||||
email: "lucas.harris@example.com",
|
||||
},
|
||||
{
|
||||
id: 20,
|
||||
name: "Mia Robinson",
|
||||
role: "Coordinator",
|
||||
team: "Operations",
|
||||
status: "active",
|
||||
age: "26",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/12.png",
|
||||
email: "mia.robinson@example.com",
|
||||
},
|
||||
];`;
|
||||
|
||||
const App = `import {Select, SelectItem, Avatar} from "@nextui-org/react";
|
||||
import {users} from "./data";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Select
|
||||
items={users}
|
||||
label="Assigned to"
|
||||
placeholder="Select a user"
|
||||
labelPlacement="outside"
|
||||
className="max-w-xs"
|
||||
>
|
||||
{(user) => (
|
||||
<SelectItem key={user.id} textValue={user.name}>
|
||||
<div className="flex gap-2 items-center">
|
||||
<Avatar alt={user.name} className="flex-shrink-0" size="sm" src={user.avatar} />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-small">{user.name}</span>
|
||||
<span className="text-tiny text-default-400">{user.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/data.js": data,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -0,0 +1,320 @@
|
||||
const data = `export const users = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Tony Reichert",
|
||||
role: "CEO",
|
||||
team: "Management",
|
||||
status: "active",
|
||||
age: "29",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/1.png",
|
||||
email: "tony.reichert@example.com",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Zoey Lang",
|
||||
role: "Tech Lead",
|
||||
team: "Development",
|
||||
status: "paused",
|
||||
age: "25",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/1.png",
|
||||
email: "zoey.lang@example.com",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Jane Fisher",
|
||||
role: "Sr. Dev",
|
||||
team: "Development",
|
||||
status: "active",
|
||||
age: "22",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/2.png",
|
||||
email: "jane.fisher@example.com",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "William Howard",
|
||||
role: "C.M.",
|
||||
team: "Marketing",
|
||||
status: "vacation",
|
||||
age: "28",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/2.png",
|
||||
email: "william.howard@example.com",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Kristen Copper",
|
||||
role: "S. Manager",
|
||||
team: "Sales",
|
||||
status: "active",
|
||||
age: "24",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/3.png",
|
||||
email: "kristen.cooper@example.com",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Brian Kim",
|
||||
role: "P. Manager",
|
||||
team: "Management",
|
||||
age: "29",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/3.png",
|
||||
email: "brian.kim@example.com",
|
||||
status: "Active",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Michael Hunt",
|
||||
role: "Designer",
|
||||
team: "Design",
|
||||
status: "paused",
|
||||
age: "27",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/4.png",
|
||||
email: "michael.hunt@example.com",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Samantha Brooks",
|
||||
role: "HR Manager",
|
||||
team: "HR",
|
||||
status: "active",
|
||||
age: "31",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/4.png",
|
||||
email: "samantha.brooks@example.com",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Frank Harrison",
|
||||
role: "F. Manager",
|
||||
team: "Finance",
|
||||
status: "vacation",
|
||||
age: "33",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/5.png",
|
||||
email: "frank.harrison@example.com",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Emma Adams",
|
||||
role: "Ops Manager",
|
||||
team: "Operations",
|
||||
status: "active",
|
||||
age: "35",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/5.png",
|
||||
email: "emma.adams@example.com",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Brandon Stevens",
|
||||
role: "Jr. Dev",
|
||||
team: "Development",
|
||||
status: "active",
|
||||
age: "22",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/7.png",
|
||||
email: "brandon.stevens@example.com",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Megan Richards",
|
||||
role: "P. Manager",
|
||||
team: "Product",
|
||||
status: "paused",
|
||||
age: "28",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/7.png",
|
||||
email: "megan.richards@example.com",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: "Oliver Scott",
|
||||
role: "S. Manager",
|
||||
team: "Security",
|
||||
status: "active",
|
||||
age: "37",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/8.png",
|
||||
email: "oliver.scott@example.com",
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
name: "Grace Allen",
|
||||
role: "M. Specialist",
|
||||
team: "Marketing",
|
||||
status: "active",
|
||||
age: "30",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/8.png",
|
||||
email: "grace.allen@example.com",
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
name: "Noah Carter",
|
||||
role: "IT Specialist",
|
||||
team: "I. Technology",
|
||||
status: "paused",
|
||||
age: "31",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/9.png",
|
||||
email: "noah.carter@example.com",
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
name: "Ava Perez",
|
||||
role: "Manager",
|
||||
team: "Sales",
|
||||
status: "active",
|
||||
age: "29",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/9.png",
|
||||
email: "ava.perez@example.com",
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
name: "Liam Johnson",
|
||||
role: "Data Analyst",
|
||||
team: "Analysis",
|
||||
status: "active",
|
||||
age: "28",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/11.png",
|
||||
email: "liam.johnson@example.com",
|
||||
},
|
||||
{
|
||||
id: 18,
|
||||
name: "Sophia Taylor",
|
||||
role: "QA Analyst",
|
||||
team: "Testing",
|
||||
status: "active",
|
||||
age: "27",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/11.png",
|
||||
email: "sophia.taylor@example.com",
|
||||
},
|
||||
{
|
||||
id: 19,
|
||||
name: "Lucas Harris",
|
||||
role: "Administrator",
|
||||
team: "Information Technology",
|
||||
status: "paused",
|
||||
age: "32",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/male/12.png",
|
||||
email: "lucas.harris@example.com",
|
||||
},
|
||||
{
|
||||
id: 20,
|
||||
name: "Mia Robinson",
|
||||
role: "Coordinator",
|
||||
team: "Operations",
|
||||
status: "active",
|
||||
age: "26",
|
||||
avatar: "https://d2u8k2ocievbld.cloudfront.net/memojis/female/12.png",
|
||||
email: "mia.robinson@example.com",
|
||||
},
|
||||
];`;
|
||||
|
||||
const App = `import {Select, SelectItem, Avatar} from "@nextui-org/react";
|
||||
import {users} from "./data";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Select
|
||||
items={users}
|
||||
label="Assigned to"
|
||||
placeholder="Select a user"
|
||||
labelPlacement="outside"
|
||||
classNames={{
|
||||
base: "max-w-xs",
|
||||
trigger: "h-12",
|
||||
}}
|
||||
renderValue={(items) => {
|
||||
return items.map((item) => (
|
||||
<div key={item.key} className="flex items-center gap-2">
|
||||
<Avatar
|
||||
alt={item.data.name}
|
||||
className="flex-shrink-0"
|
||||
size="sm"
|
||||
src={item.data.avatar}
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<span>{item.data.name}</span>
|
||||
<span className="text-default-500 text-tiny">({item.data.email})</span>
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
}}
|
||||
>
|
||||
{(user) => (
|
||||
<SelectItem key={user.id} textValue={user.name}>
|
||||
<div className="flex gap-2 items-center">
|
||||
<Avatar alt={user.name} className="flex-shrink-0" size="sm" src={user.avatar} />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-small">{user.name}</span>
|
||||
<span className="text-tiny text-default-400">{user.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
);
|
||||
}`;
|
||||
|
||||
const AppTs = `import {Select, SelectItem, Avatar, SelectedItems} from "@nextui-org/react";
|
||||
import {users} from "./data";
|
||||
|
||||
type User = {
|
||||
id: number;
|
||||
name: string;
|
||||
role: string;
|
||||
team: string;
|
||||
status: string;
|
||||
age: string;
|
||||
avatar: string;
|
||||
email: string;
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Select
|
||||
items={users}
|
||||
label="Assigned to"
|
||||
placeholder="Select a user"
|
||||
labelPlacement="outside"
|
||||
classNames={{
|
||||
base: "max-w-xs",
|
||||
trigger: "h-12",
|
||||
}}
|
||||
renderValue={(items: SelectedItems<User>) => {
|
||||
return items.map((item) => (
|
||||
<div key={item.key} className="flex items-center gap-2">
|
||||
<Avatar
|
||||
alt={item.data.name}
|
||||
className="flex-shrink-0"
|
||||
size="sm"
|
||||
src={item.data.avatar}
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<span>{item.data.name}</span>
|
||||
<span className="text-default-500 text-tiny">({item.data.email})</span>
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
}}
|
||||
>
|
||||
{(user) => (
|
||||
<SelectItem key={user.id} textValue={user.name}>
|
||||
<div className="flex gap-2 items-center">
|
||||
<Avatar alt={user.name} className="flex-shrink-0" size="sm" src={user.avatar} />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-small">{user.name}</span>
|
||||
<span className="text-tiny text-default-400">{user.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
"/data.js": data,
|
||||
};
|
||||
|
||||
const reactTs = {
|
||||
"/App.tsx": AppTs,
|
||||
"/data.ts": data,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
...reactTs,
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
const App = `import {Select, SelectItem, SelectSection} from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
const headingClasses = "flex w-full sticky top-1 z-20 py-1.5 px-2 bg-default-100 shadow-small rounded-small";
|
||||
|
||||
return (
|
||||
<Select
|
||||
label="Favorite Animal"
|
||||
placeholder="Select an animal"
|
||||
className="max-w-xs"
|
||||
scrollShadowProps={{
|
||||
isEnabled: false,
|
||||
}}
|
||||
>
|
||||
<SelectSection
|
||||
title="Mammals"
|
||||
classNames={{
|
||||
heading: headingClasses,
|
||||
}}
|
||||
>
|
||||
<SelectItem key="Lion">Lion</SelectItem>
|
||||
<SelectItem key="Tiger">Tiger</SelectItem>
|
||||
<SelectItem key="Elephant">Elephant</SelectItem>
|
||||
<SelectItem key="Kangaroo">Kangaroo</SelectItem>
|
||||
<SelectItem key="Panda">Panda</SelectItem>
|
||||
<SelectItem key="Giraffe">Giraffe</SelectItem>
|
||||
<SelectItem key="Zebra">Zebra</SelectItem>
|
||||
<SelectItem key="Cheetah">Cheetah</SelectItem>
|
||||
</SelectSection>
|
||||
<SelectSection
|
||||
title="Birds"
|
||||
classNames={{
|
||||
heading: headingClasses,
|
||||
}}
|
||||
>
|
||||
<SelectItem key="Eagle">Eagle</SelectItem>
|
||||
<SelectItem key="Parrot">Parrot</SelectItem>
|
||||
<SelectItem key="Penguin">Penguin</SelectItem>
|
||||
<SelectItem key="Ostrich">Ostrich</SelectItem>
|
||||
<SelectItem key="Peacock">Peacock</SelectItem>
|
||||
<SelectItem key="Swan">Swan</SelectItem>
|
||||
<SelectItem key="Falcon">Falcon</SelectItem>
|
||||
<SelectItem key="Flamingo">Flamingo</SelectItem>
|
||||
</SelectSection>
|
||||
</Select>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user