├── static ├── .nojekyll └── img │ ├── favicon.ico │ ├── docusaurus.png │ ├── petstore-logo-dark.png │ ├── docusaurus-social-card.jpg │ ├── react.svg │ ├── x-logo.svg │ ├── email.svg │ ├── tailwind.svg │ ├── linkedin.svg │ ├── github.svg │ └── logo.svg ├── postcss.config.js ├── .npmrc ├── .yarnrc.yml ├── docs ├── tutorial-extras │ ├── _category_.json │ ├── img │ │ ├── localeDropdown.png │ │ └── docsVersionDropdown.png │ ├── manage-docs-versions.md │ └── translate-your-site.md ├── tutorial-basics │ ├── _category_.json │ ├── deploy-your-site.md │ ├── create-a-blog-post.md │ ├── congratulations.md │ ├── create-a-page.md │ ├── create-a-document.md │ └── markdown-features.mdx ├── petstore_versioned │ ├── pet.tag.mdx │ ├── user.tag.mdx │ ├── 1.0.0 │ │ ├── pet.tag.mdx │ │ ├── user.tag.mdx │ │ ├── store.tag.mdx │ │ ├── logout-user.api.mdx │ │ ├── get-inventory.api.mdx │ │ ├── delete-user.api.mdx │ │ ├── delete-pet.api.mdx │ │ ├── delete-order.api.mdx │ │ ├── upload-file.api.mdx │ │ ├── update-pet-with-form.api.mdx │ │ ├── login-user.api.mdx │ │ ├── sidebar.ts │ │ ├── get-order-by-id.api.mdx │ │ ├── place-order.api.mdx │ │ └── swagger-petstore-yaml.info.mdx │ ├── store.tag.mdx │ ├── versions.json │ ├── logout-user.api.mdx │ ├── get-inventory.api.mdx │ ├── schemas │ │ └── cat.schema.mdx │ ├── delete-user.api.mdx │ ├── delete-pet.api.mdx │ ├── delete-order.api.mdx │ ├── upload-file.api.mdx │ ├── update-pet-with-form.api.mdx │ ├── login-user.api.mdx │ ├── sidebar.ts │ ├── get-order-by-id.api.mdx │ └── place-order.api.mdx └── intro.md ├── .gitattributes ├── .editorconfig ├── blog ├── 2021-08-26-welcome │ ├── docusaurus-plushie-banner.jpeg │ └── index.md ├── 2019-05-28-first-blog-post.md ├── tags.yml ├── 2021-08-01-mdx-blog-post.mdx ├── 2025-10-28-test-post.md ├── 2025-10-31-test-post2.md ├── authors.yml └── 2019-05-29-long-blog-post.md ├── src ├── theme │ ├── TagsListInline │ │ ├── styles.module.css │ │ └── index.js │ ├── Navbar │ │ └── Layout │ │ │ ├── styles.module.css │ │ │ └── index.js │ ├── Footer │ │ └── Layout │ │ │ └── index.js │ ├── BlogSidebar │ │ └── index.js │ ├── BlogLayout │ │ └── index.js │ ├── Icon │ │ ├── LightMode │ │ │ └── index.js │ │ └── DarkMode │ │ │ └── index.js │ ├── Blog │ │ └── Pages │ │ │ └── BlogAuthorsPostsPage │ │ │ └── index.js │ ├── BlogListPage │ │ └── index.js │ ├── BlogPagination │ │ └── index.js │ └── BlogPostItems │ │ └── index.js ├── lib │ └── utils.ts ├── components │ ├── Personal │ │ ├── index.js │ │ ├── ContactSection.js │ │ ├── SkillsSection.js │ │ ├── AboutSection.js │ │ └── HeroSection.js │ ├── TimeStamp.js │ ├── Homepage │ │ ├── index.js │ │ └── Features.js │ ├── ui │ │ ├── animated-gradient-text.tsx │ │ ├── avatar.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ └── pagination.tsx │ ├── LatestNews.js │ └── HeroBanner.js ├── plugins │ ├── tailwind-config.js │ ├── webpack-alias.js │ └── blog-plugin.js └── pages │ └── about-me.js ├── .prettierrc ├── .gitignore ├── jsconfig.json ├── .github └── FUNDING.yml ├── LICENSE ├── package.json └── sidebars.js /static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | '@tailwindcss/postcss': {}, 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | strict-peer-dependencies=false 3 | prefer-offline=true 4 | node-linker=hoisted 5 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | enableGlobalCache: true 3 | npmRegistryServer: "https://registry.npmjs.org" -------------------------------------------------------------------------------- /static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template/HEAD/static/img/favicon.ico -------------------------------------------------------------------------------- /static/img/docusaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template/HEAD/static/img/docusaurus.png -------------------------------------------------------------------------------- /static/img/petstore-logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template/HEAD/static/img/petstore-logo-dark.png -------------------------------------------------------------------------------- /docs/tutorial-extras/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Tutorial - Extras", 3 | "position": 3, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /static/img/docusaurus-social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template/HEAD/static/img/docusaurus-social-card.jpg -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /.yarn/** linguist-vendored 2 | /.yarn/releases/* binary 3 | /.yarn/plugins/**/* binary 4 | /.pnp.* binary linguist-generated 5 | -------------------------------------------------------------------------------- /docs/tutorial-extras/img/localeDropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template/HEAD/docs/tutorial-extras/img/localeDropdown.png -------------------------------------------------------------------------------- /docs/tutorial-extras/img/docsVersionDropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template/HEAD/docs/tutorial-extras/img/docsVersionDropdown.png -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.{js,json,yml}] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template/HEAD/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg -------------------------------------------------------------------------------- /src/theme/TagsListInline/styles.module.css: -------------------------------------------------------------------------------- 1 | .tags { 2 | display: inline; 3 | } 4 | 5 | .tag { 6 | margin: 0 0.4rem 0.5rem 0; 7 | display: inline-block; 8 | font-size: 14px; 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from 'clsx' 2 | import { twMerge } from 'tailwind-merge' 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /docs/tutorial-basics/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Tutorial - Basics", 3 | "position": 2, 4 | "link": { 5 | "type": "generated-index", 6 | "description": "5 minutes to learn the most important Docusaurus concepts." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/components/Personal/index.js: -------------------------------------------------------------------------------- 1 | export { default as HeroSection } from './HeroSection' 2 | export { default as AboutSection } from './AboutSection' 3 | export { default as SkillsSection } from './SkillsSection' 4 | export { default as ContactSection } from './ContactSection' 5 | -------------------------------------------------------------------------------- /src/theme/Navbar/Layout/styles.module.css: -------------------------------------------------------------------------------- 1 | .navbarHideable { 2 | transition: transform var(--ifm-transition-fast) ease; 3 | } 4 | 5 | .navbarHidden { 6 | transform: translate3d(0, calc(-100% - 2px), 0); 7 | } 8 | 9 | .navbarScrolled { 10 | box-shadow: var(--ifm-navbar-shadow); 11 | } 12 | -------------------------------------------------------------------------------- /src/plugins/tailwind-config.js: -------------------------------------------------------------------------------- 1 | module.exports = function tailwindPlugin(context, options) { 2 | return { 3 | name: 'tailwind-plugin', 4 | configurePostCss(postcssOptions) { 5 | postcssOptions.plugins = [require('@tailwindcss/postcss')] 6 | return postcssOptions 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier-plugin-tailwindcss"], 3 | "semi": false, 4 | "bracketSpacing": true, 5 | "arrowParens": "always", 6 | "endOfLine": "lf", 7 | "jsxSingleQuote": true, 8 | "printWidth": 100, 9 | "quoteProps": "consistent", 10 | "singleQuote": true, 11 | "trailingComma": "none", 12 | "tabWidth": 2 13 | } 14 | -------------------------------------------------------------------------------- /docs/petstore_versioned/pet.tag.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: pet 3 | title: "Pets" 4 | description: "Pets" 5 | custom_edit_url: null 6 | --- 7 | 8 | 9 | 10 | Everything about your Pets 11 | 12 | 13 | 14 | ```mdx-code-block 15 | import DocCardList from '@theme/DocCardList'; 16 | import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; 17 | 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/petstore_versioned/user.tag.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: user 3 | title: "Users" 4 | description: "Users" 5 | custom_edit_url: null 6 | --- 7 | 8 | 9 | 10 | Operations about user 11 | 12 | 13 | 14 | ```mdx-code-block 15 | import DocCardList from '@theme/DocCardList'; 16 | import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; 17 | 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/petstore_versioned/1.0.0/pet.tag.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: pet 3 | title: "Pets" 4 | description: "Pets" 5 | custom_edit_url: null 6 | --- 7 | 8 | 9 | 10 | Everything about your Pets 11 | 12 | 13 | 14 | ```mdx-code-block 15 | import DocCardList from '@theme/DocCardList'; 16 | import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; 17 | 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/petstore_versioned/1.0.0/user.tag.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: user 3 | title: "Users" 4 | description: "Users" 5 | custom_edit_url: null 6 | --- 7 | 8 | 9 | 10 | Operations about user 11 | 12 | 13 | 14 | ```mdx-code-block 15 | import DocCardList from '@theme/DocCardList'; 16 | import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; 17 | 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/petstore_versioned/store.tag.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: store 3 | title: "Petstore Orders" 4 | description: "Petstore Orders" 5 | custom_edit_url: null 6 | --- 7 | 8 | 9 | 10 | Access to Petstore orders 11 | 12 | 13 | 14 | ```mdx-code-block 15 | import DocCardList from '@theme/DocCardList'; 16 | import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; 17 | 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/petstore_versioned/1.0.0/store.tag.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: store 3 | title: "Petstore Orders" 4 | description: "Petstore Orders" 5 | custom_edit_url: null 6 | --- 7 | 8 | 9 | 10 | Access to Petstore orders 11 | 12 | 13 | 14 | ```mdx-code-block 15 | import DocCardList from '@theme/DocCardList'; 16 | import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; 17 | 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | .yarn/* 23 | !.yarn/patches 24 | !.yarn/plugins 25 | !.yarn/releases 26 | !.yarn/sdks 27 | !.yarn/versions 28 | .pnp.* 29 | -------------------------------------------------------------------------------- /static/img/react.svg: -------------------------------------------------------------------------------- 1 | 2 | React Logo 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /blog/2019-05-28-first-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: first-blog-post 3 | title: First Blog Post 4 | image: https://res.cloudinary.com/thanhnam/image/upload/v1736787946/project/docusaurus-tailwind-shadcn-template/blog_vep2ri.jpg 5 | authors: [gao-wei] 6 | tags: [hola, docusaurus] 7 | --- 8 | 9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 10 | -------------------------------------------------------------------------------- /docs/petstore_versioned/versions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "version": "2.0.0", 4 | "label": "v2.0.0", 5 | "baseUrl": "/docs/petstore_versioned/swagger-petstore-yaml" 6 | }, 7 | { 8 | "version": "1.0.0", 9 | "label": "v1.0.0", 10 | "baseUrl": "/docs/petstore_versioned/1.0.0/swagger-petstore-yaml", 11 | "downloadUrl": "https://raw.githubusercontent.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template/main/api-swagger/petstore-1.0.0.yaml" 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /blog/tags.yml: -------------------------------------------------------------------------------- 1 | hola: 2 | label: 'Hola' 3 | permalink: '/hola' 4 | description: 'Articles on the topic hola' 5 | 6 | hello: 7 | label: 'Hello' 8 | permalink: '/hello' 9 | description: 'Articles on the topic hello' 10 | 11 | docusaurus: 12 | label: 'Docusaurus' 13 | permalink: '/docusaurus' 14 | description: 'Articles on the topic docusaurus' 15 | 16 | facebook: 17 | label: 'Facebook' 18 | permalink: '/facebook' 19 | description: 'Articles on the topic facebook' 20 | -------------------------------------------------------------------------------- /static/img/x-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/TimeStamp.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | 3 | export default function TimeStamp({ timestamp }) { 4 | // Use client-side rendering for timestamp, against React Minified React error #418 and #425 5 | const [mounted, setMounted] = useState(false) 6 | 7 | useEffect(() => { 8 | setMounted(true) 9 | }, []) 10 | 11 | // Return null during SSR 12 | if (!mounted) { 13 | return null 14 | } 15 | 16 | return 17 | } 18 | -------------------------------------------------------------------------------- /static/img/email.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/theme/Footer/Layout/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function FooterLayout({ style, links, logo, copyright }) { 4 | return ( 5 |
6 |
7 | {links} 8 | {(logo || copyright) && ( 9 |
10 | {logo &&
{logo}
} 11 | {copyright} 12 |
13 | )} 14 |
15 |
16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/about-me.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Layout from '@theme/Layout' 3 | import { HeroSection, AboutSection, SkillsSection, ContactSection } from '@/components/Personal' 4 | 5 | export default function About() { 6 | return ( 7 | 11 |
12 | 13 | 14 | 15 | 16 |
17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /blog/2021-08-01-mdx-blog-post.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: mdx-blog-post 3 | title: MDX Blog Post 4 | image: https://res.cloudinary.com/thanhnam/image/upload/v1736787946/project/docusaurus-tailwind-shadcn-template/blog_vep2ri.jpg 5 | authors: [slorber, thanhnamnguyen] 6 | tags: [docusaurus] 7 | --- 8 | 9 | Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/). 10 | 11 | :::tip 12 | 13 | Use the power of React to create interactive blog posts. 14 | 15 | ```js 16 | 17 | ``` 18 | 19 | 20 | 21 | ::: 22 | -------------------------------------------------------------------------------- /src/theme/BlogSidebar/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useWindowSize } from '@docusaurus/theme-common' 3 | import BlogSidebarDesktop from '@theme/BlogSidebar/Desktop' 4 | import BlogSidebarMobile from '@theme/BlogSidebar/Mobile' 5 | 6 | export default function BlogSidebar({ sidebar, hideOnDesktop }) { 7 | const windowSize = useWindowSize() 8 | 9 | if (!sidebar?.items.length) { 10 | return null 11 | } 12 | // Mobile sidebar doesn't need to be server-rendered 13 | if (windowSize === 'mobile') { 14 | return 15 | } 16 | 17 | if (hideOnDesktop) { 18 | return <> 19 | } 20 | 21 | return 22 | } 23 | -------------------------------------------------------------------------------- /src/plugins/webpack-alias.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = function () { 4 | return { 5 | name: 'webpack-alias-plugin', 6 | configureWebpack() { 7 | return { 8 | resolve: { 9 | alias: { 10 | '@': path.resolve(__dirname, '../'), 11 | '@components': path.resolve(__dirname, '../components'), 12 | '@css': path.resolve(__dirname, '../css'), 13 | '@lib': path.resolve(__dirname, '../lib'), 14 | '@pages': path.resolve(__dirname, '../pages'), 15 | '@plugins': path.resolve(__dirname, '../plugins'), 16 | '@theme': path.resolve(__dirname, '../theme') 17 | } 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/theme/TagsListInline/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import clsx from 'clsx' 3 | import Translate from '@docusaurus/Translate' 4 | import Tag from '@theme/Tag' 5 | import styles from './styles.module.css' 6 | export default function TagsListInline({ tags }) { 7 | return ( 8 | <> 9 | 10 | 11 | Tags: 12 | 13 | 14 |
    15 | {tags.map((tag) => ( 16 |
  • 17 | 18 |
  • 19 | ))} 20 |
21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /blog/2025-10-28-test-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: test-post 3 | title: Test Blog Post 4 | image: https://res.cloudinary.com/thanhnam/image/upload/v1736787946/project/docusaurus-tailwind-shadcn-template/blog_vep2ri.jpg 5 | authors: [thanhnamnguyen] 6 | tags: [hola, docusaurus] 7 | --- 8 | 9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 10 | 11 | ## Introduction 12 | 13 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 14 | 15 | ## Main Content 16 | 17 | Praesent euismod, nunc vel consectetur interdum, nisl nisi aliquam nunc, eget aliquam nisl nisi eu nunc. Sed euismod, nunc vel consectetur interdum, nisl nisi aliquam nunc, eget aliquam nisl nisi eu nunc. 18 | -------------------------------------------------------------------------------- /blog/2025-10-31-test-post2.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: test-post-2 3 | title: Test Blog Post 2 4 | image: https://res.cloudinary.com/thanhnam/image/upload/v1736787946/project/docusaurus-tailwind-shadcn-template/blog_vep2ri.jpg 5 | authors: [thanhnamnguyen] 6 | tags: [hola, docusaurus] 7 | --- 8 | 9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 10 | 11 | ## Introduction 12 | 13 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 14 | 15 | ## Main Content 16 | 17 | Praesent euismod, nunc vel consectetur interdum, nisl nisi aliquam nunc, eget aliquam nisl nisi eu nunc. Sed euismod, nunc vel consectetur interdum, nisl nisi aliquam nunc, eget aliquam nisl nisi eu nunc. 18 | -------------------------------------------------------------------------------- /static/img/tailwind.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@/*": ["src/*"], 6 | "@components/*": ["src/components/*"], 7 | "@css/*": ["src/css/*"], 8 | "@lib/*": ["src/lib/*"], 9 | "@pages/*": ["src/pages/*"], 10 | "@plugins/*": ["src/plugins/*"], 11 | "@theme/*": ["src/theme/*"] 12 | }, 13 | "target": "ES2020", 14 | "useDefineForClassFields": true, 15 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 16 | "module": "ESNext", 17 | "skipLibCheck": true, 18 | "esModuleInterop": true, 19 | "resolveJsonModule": true, 20 | "allowSyntheticDefaultImports": true, 21 | "moduleResolution": "bundler", 22 | "allowImportingTsExtensions": true, 23 | "jsx": "react-jsx" 24 | }, 25 | "include": ["src"], 26 | "exclude": ["node_modules", "build", "dist"] 27 | } 28 | -------------------------------------------------------------------------------- /docs/tutorial-basics/deploy-your-site.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 5 3 | --- 4 | 5 | # Deploy your site 6 | 7 | Docusaurus is a **static-site-generator** (also called **[Jamstack](https://jamstack.org/)**). 8 | 9 | It builds your site as simple **static HTML, JavaScript and CSS files**. 10 | 11 | ## Build your site 12 | 13 | Build your site **for production**: 14 | 15 | ```bash 16 | npm run build 17 | ``` 18 | 19 | The static files are generated in the `build` folder. 20 | 21 | ## Deploy your site 22 | 23 | Test your production build locally: 24 | 25 | ```bash 26 | npm run serve 27 | ``` 28 | 29 | The `build` folder is now served at [http://localhost:3000/](http://localhost:3000/). 30 | 31 | You can now deploy the `build` folder **almost anywhere** easily, **for free** or very small cost (read the **[Deployment Guide](https://docusaurus.io/docs/deployment)**). 32 | -------------------------------------------------------------------------------- /src/components/Homepage/index.js: -------------------------------------------------------------------------------- 1 | import Layout from '@theme/Layout' 2 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext' 3 | 4 | import HomepageFeatures from '@/components/Homepage/Features' 5 | import LatestNews from '@/components/LatestNews' 6 | import HeroBanner from '@/components/HeroBanner' 7 | 8 | export default function Home({ homePageBlogMetadata, recentPosts }) { 9 | const { siteConfig } = useDocusaurusContext() 10 | 11 | return ( 12 | 16 |
17 | 18 | 19 | 20 |
21 |
22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: thanhnamnguyen 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /src/theme/BlogLayout/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import clsx from 'clsx' 3 | import Layout from '@theme/Layout' 4 | import BlogSidebar from '@theme/BlogSidebar' 5 | 6 | export default function BlogLayout(props) { 7 | const { sidebar, toc, children, ...layoutProps } = props 8 | const hasSidebar = sidebar && sidebar.items.length > 0 9 | 10 | return ( 11 | 12 |
13 |
14 | 15 |
22 | {children} 23 |
24 | {toc &&
{toc}
} 25 |
26 |
27 |
28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /src/components/Personal/ContactSection.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Link from '@docusaurus/Link' 3 | 4 | export default function ContactSection() { 5 | return ( 6 |
7 |
8 |

Get in Touch

9 |

10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt{' '} 11 | 17 | ut labore et dolore magna aliqua 18 | {' '} 19 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 20 |

21 |
22 |
23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /src/components/Personal/SkillsSection.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function SkillsSection() { 4 | const skills = [ 5 | 'Lorem', 6 | 'Ipsum', 7 | 'Dolor', 8 | 'Sit Amet', 9 | 'Consectetur', 10 | 'Adipiscing', 11 | 'Elit', 12 | 'Sed Do', 13 | 'Eiusmod', 14 | 'Tempor', 15 | 'Incididunt', 16 | 'Ut Labore', 17 | 'Dolore Magna', 18 | 'Aliqua' 19 | ] 20 | 21 | return ( 22 |
23 |

Skills

24 |
25 | {skills.map((skill) => ( 26 | 30 | {skill} 31 | 32 | ))} 33 |
34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /docs/tutorial-basics/create-a-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Create a Blog Post 6 | 7 | Docusaurus creates a **page for each blog post**, but also a **blog index page**, a **tag system**, an **RSS** feed... 8 | 9 | ## Create your first Post 10 | 11 | Create a file at `blog/2021-02-28-greetings.md`: 12 | 13 | ```md title="blog/2021-02-28-greetings.md" 14 | --- 15 | slug: greetings 16 | title: Greetings! 17 | authors: 18 | - name: Joel Marcey 19 | title: Co-creator of Docusaurus 1 20 | url: https://github.com/JoelMarcey 21 | image_url: https://github.com/JoelMarcey.png 22 | - name: Sébastien Lorber 23 | title: Docusaurus maintainer 24 | url: https://sebastienlorber.com 25 | image_url: https://github.com/slorber.png 26 | tags: [greetings] 27 | --- 28 | 29 | Congratulations, you have made your first post! 30 | 31 | Feel free to play around and edit this post as much as you like. 32 | ``` 33 | 34 | A new blog post is now available at [http://localhost:3000/blog/greetings](http://localhost:3000/blog/greetings). 35 | -------------------------------------------------------------------------------- /src/components/ui/animated-gradient-text.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentPropsWithoutRef } from 'react' 2 | 3 | import { cn } from '@/lib/utils' 4 | 5 | export interface AnimatedGradientTextProps extends ComponentPropsWithoutRef<'div'> { 6 | speed?: number 7 | colorFrom?: string 8 | colorTo?: string 9 | } 10 | 11 | export function AnimatedGradientText({ 12 | children, 13 | className, 14 | speed = 1, 15 | colorFrom = '#ffaa40', 16 | colorTo = '#9c40ff', 17 | ...props 18 | }: AnimatedGradientTextProps) { 19 | return ( 20 | 34 | {children} 35 | 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /blog/authors.yml: -------------------------------------------------------------------------------- 1 | endi: 2 | page: true 3 | name: Endilie Yacop Sucipto 4 | title: Maintainer of Docusaurus 5 | image_url: https://github.com/endiliey.png 6 | 7 | yangshun: 8 | page: true 9 | name: Yangshun Tay 10 | title: Front End Engineer @ Facebook 11 | image_url: https://github.com/yangshun.png 12 | 13 | slorber: 14 | page: true 15 | name: Sébastien Lorber 16 | title: Docusaurus maintainer 17 | image_url: https://github.com/slorber.png 18 | socials: 19 | x: sebastienlorber 20 | linkedin: sebastienlorber 21 | github: slorber 22 | newsletter: https://thisweekinreact.com 23 | 24 | gao-wei: 25 | page: true 26 | name: Gao Wei 27 | title: Docusaurus Core Team 28 | image_url: https://github.com/wgao19.png 29 | 30 | thanhnamnguyen: 31 | page: true 32 | name: Thành Nam Nguyễn 33 | title: Developer 34 | image_url: https://res.cloudinary.com/thanhnam/image/upload/v1715137157/project/docusaurus-material-ui-template/logo_wnw5lv.png 35 | socials: 36 | github: namnguyenthanhwork 37 | newsletter: https://wwww.thanhnamnguyen.dev/ 38 | -------------------------------------------------------------------------------- /blog/2021-08-26-welcome/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: welcome 3 | title: Welcome 4 | image: https://res.cloudinary.com/thanhnam/image/upload/v1736787946/project/docusaurus-tailwind-shadcn-template/blog_vep2ri.jpg 5 | authors: [slorber, yangshun, thanhnamnguyen] 6 | tags: [facebook, hello, docusaurus] 7 | --- 8 | 9 | [Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog). 10 | 11 | ## I. Create a new blog post {#create-a-new-blog-post} 12 | 13 | Simply add Markdown files (or folders) to the `blog` directory. 14 | 15 | Regular blog authors can be added to `authors.yml`. 16 | 17 | The blog post date can be extracted from filenames, such as: 18 | 19 | - `2019-05-30-welcome.md` 20 | - `2019-05-30-welcome/index.md` 21 | 22 | A blog post folder can be convenient to co-locate blog post images: 23 | 24 | ![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg) 25 | 26 | The blog supports tags as well! 27 | 28 | **And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config. 29 | -------------------------------------------------------------------------------- /src/theme/Icon/LightMode/index.js: -------------------------------------------------------------------------------- 1 | export default function IconLightMode(props) { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /docs/tutorial-basics/congratulations.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 6 3 | --- 4 | 5 | # Congratulations! 6 | 7 | You have just learned the **basics of Docusaurus** and made some changes to the **initial template**. 8 | 9 | Docusaurus has **much more to offer**! 10 | 11 | Have **5 more minutes**? Take a look at **[versioning](../tutorial-extras/manage-docs-versions.md)** and **[i18n](../tutorial-extras/translate-your-site.md)**. 12 | 13 | Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://github.com/facebook/docusaurus/discussions/4610) 14 | 15 | ## What's next? 16 | 17 | - Read the [official documentation](https://docusaurus.io/) 18 | - Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config) 19 | - Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration) 20 | - Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout) 21 | - Add a [search bar](https://docusaurus.io/docs/search) 22 | - Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase) 23 | - Get involved in the [Docusaurus Community](https://docusaurus.io/community/support) 24 | -------------------------------------------------------------------------------- /docs/tutorial-basics/create-a-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Create a Page 6 | 7 | Add **Markdown or React** files to `src/pages` to create a **standalone page**: 8 | 9 | - `src/pages/index.js` → `localhost:3000/` 10 | - `src/pages/foo.md` → `localhost:3000/foo` 11 | - `src/pages/foo/bar.js` → `localhost:3000/foo/bar` 12 | 13 | ## Create your first React Page 14 | 15 | Create a file at `src/pages/my-react-page.js`: 16 | 17 | ```jsx title="src/pages/my-react-page.js" 18 | import React from 'react'; 19 | import Layout from '@theme/Layout'; 20 | 21 | export default function MyReactPage() { 22 | return ( 23 | 24 |

My React page

25 |

This is a React page

26 |
27 | ); 28 | } 29 | ``` 30 | 31 | A new page is now available at [http://localhost:3000/my-react-page](http://localhost:3000/my-react-page). 32 | 33 | ## Create your first Markdown Page 34 | 35 | Create a file at `src/pages/my-markdown-page.md`: 36 | 37 | ```mdx title="src/pages/my-markdown-page.md" 38 | # My Markdown page 39 | 40 | This is a Markdown page 41 | ``` 42 | 43 | A new page is now available at [http://localhost:3000/my-markdown-page](http://localhost:3000/my-markdown-page). 44 | -------------------------------------------------------------------------------- /src/components/ui/avatar.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import * as AvatarPrimitive from '@radix-ui/react-avatar' 5 | 6 | import { cn } from '@/lib/utils' 7 | 8 | function Avatar({ className, ...props }: React.ComponentProps) { 9 | return ( 10 | 15 | ) 16 | } 17 | 18 | function AvatarImage({ className, ...props }: React.ComponentProps) { 19 | return ( 20 | 25 | ) 26 | } 27 | 28 | function AvatarFallback({ 29 | className, 30 | ...props 31 | }: React.ComponentProps) { 32 | return ( 33 | 38 | ) 39 | } 40 | 41 | export { Avatar, AvatarImage, AvatarFallback } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Thành Nam Nguyễn aka Yuu - @namnguyenthanhwork 4 | 5 | Contact Information: 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /docs/tutorial-basics/create-a-document.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Create a Document 6 | 7 | Documents are **groups of pages** connected through: 8 | 9 | - a **sidebar** 10 | - **previous/next navigation** 11 | - **versioning** 12 | 13 | ## Create your first Doc 14 | 15 | Create a Markdown file at `docs/hello.md`: 16 | 17 | ```md title="docs/hello.md" 18 | # Hello 19 | 20 | This is my **first Docusaurus document**! 21 | ``` 22 | 23 | A new document is now available at [http://localhost:3000/docs/hello](http://localhost:3000/docs/hello). 24 | 25 | ## Configure the Sidebar 26 | 27 | Docusaurus automatically **creates a sidebar** from the `docs` folder. 28 | 29 | Add metadata to customize the sidebar label and position: 30 | 31 | ```md title="docs/hello.md" {1-4} 32 | --- 33 | sidebar_label: 'Hi!' 34 | sidebar_position: 3 35 | --- 36 | 37 | # Hello 38 | 39 | This is my **first Docusaurus document**! 40 | ``` 41 | 42 | It is also possible to create your sidebar explicitly in `sidebars.js`: 43 | 44 | ```js title="sidebars.js" 45 | export default { 46 | tutorialSidebar: [ 47 | 'intro', 48 | // highlight-next-line 49 | 'hello', 50 | { 51 | type: 'category', 52 | label: 'Tutorial', 53 | items: ['tutorial-basics/create-a-document'], 54 | }, 55 | ], 56 | }; 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/tutorial-extras/manage-docs-versions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Manage Docs Versions 6 | 7 | Docusaurus can manage multiple versions of your docs. 8 | 9 | ## Create a docs version 10 | 11 | Release a version 1.0 of your project: 12 | 13 | ```bash 14 | npm run docusaurus docs:version 1.0 15 | ``` 16 | 17 | The `docs` folder is copied into `versioned_docs/version-1.0` and `versions.json` is created. 18 | 19 | Your docs now have 2 versions: 20 | 21 | - `1.0` at `http://localhost:3000/docs/` for the version 1.0 docs 22 | - `current` at `http://localhost:3000/docs/next/` for the **upcoming, unreleased docs** 23 | 24 | ## Add a Version Dropdown 25 | 26 | To navigate seamlessly across versions, add a version dropdown. 27 | 28 | Modify the `docusaurus.config.js` file: 29 | 30 | ```js title="docusaurus.config.js" 31 | export default { 32 | themeConfig: { 33 | navbar: { 34 | items: [ 35 | // highlight-start 36 | { 37 | type: 'docsVersionDropdown', 38 | }, 39 | // highlight-end 40 | ], 41 | }, 42 | }, 43 | }; 44 | ``` 45 | 46 | The docs version dropdown appears in your navbar: 47 | 48 | ![Docs Version Dropdown](./img/docsVersionDropdown.png) 49 | 50 | ## Update an existing version 51 | 52 | It is possible to edit versioned docs in their respective folder: 53 | 54 | - `versioned_docs/version-1.0/hello.md` updates `http://localhost:3000/docs/hello` 55 | - `docs/hello.md` updates `http://localhost:3000/docs/next/hello` 56 | -------------------------------------------------------------------------------- /src/components/Personal/AboutSection.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Link from '@docusaurus/Link' 3 | 4 | export default function AboutSection() { 5 | return ( 6 |
7 |

About

8 |
9 |

10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt 11 | ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation 12 | ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in 13 | reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur 14 | sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id 15 | est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium 16 | doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et 17 | quasi architecto beatae vitae dicta sunt explicabo.{' '} 18 | 24 | Learn more 25 | 26 | . 27 |

28 |
29 |
30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Tutorial Intro 6 | 7 | Let's discover **Docusaurus in less than 5 minutes**. 8 | 9 | ## Getting Started 10 | 11 | Get started by **creating a new site**. 12 | 13 | Or **try Docusaurus immediately** with **[docusaurus.new](https://docusaurus.new)**. 14 | 15 | ### What you'll need 16 | 17 | - [Node.js](https://nodejs.org/en/download/) version 18.0 or above: 18 | - When installing Node.js, you are recommended to check all checkboxes related to dependencies. 19 | 20 | ## Generate a new site 21 | 22 | Generate a new Docusaurus site using the **classic template**. 23 | 24 | The classic template will automatically be added to your project after you run the command: 25 | 26 | ```bash 27 | npm init docusaurus@latest my-website classic 28 | ``` 29 | 30 | You can type this command into Command Prompt, Powershell, Terminal, or any other integrated terminal of your code editor. 31 | 32 | The command also installs all necessary dependencies you need to run Docusaurus. 33 | 34 | ## Start your site 35 | 36 | Run the development server: 37 | 38 | ```bash 39 | cd my-website 40 | npm run start 41 | ``` 42 | 43 | The `cd` command changes the directory you're working with. In order to work with your newly created Docusaurus site, you'll need to navigate the terminal there. 44 | 45 | The `npm run start` command builds your website locally and serves it through a development server, ready for you to view at http://localhost:3000/. 46 | 47 | Open `docs/intro.md` (this page) and edit some lines: the site **reloads automatically** and displays your changes. 48 | -------------------------------------------------------------------------------- /src/components/Homepage/Features.js: -------------------------------------------------------------------------------- 1 | const FeatureList = [ 2 | { 3 | title: 'Easy to Use', 4 | Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, 5 | description: ( 6 | <> 7 | Docusaurus was designed from the ground up to be easily installed and used to get your 8 | website up and running quickly. 9 | 10 | ) 11 | }, 12 | { 13 | title: 'Focus on What Matters', 14 | Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, 15 | description: ( 16 | <> 17 | Docusaurus lets you focus on your docs, and we'll do the chores. Go ahead and move your 18 | docs into the docs directory. 19 | 20 | ) 21 | }, 22 | { 23 | title: 'Powered by React', 24 | Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, 25 | description: ( 26 | <> 27 | Extend or customize your website layout by reusing React. Docusaurus can be extended while 28 | reusing the same header and footer. 29 | 30 | ) 31 | } 32 | ] 33 | 34 | function Feature({ Svg, title, description }) { 35 | return ( 36 |
37 |
38 | 39 |
40 |
41 |

{title}

42 |

{description}

43 |
44 |
45 | ) 46 | } 47 | 48 | export default function HomepageFeatures() { 49 | return ( 50 |
51 |
52 |
53 | {FeatureList.map((props, idx) => ( 54 | 55 | ))} 56 |
57 |
58 |
59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /static/img/linkedin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/theme/Blog/Pages/BlogAuthorsPostsPage/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import clsx from 'clsx' 3 | import { PageMetadata, HtmlClassNameProvider, ThemeClassNames } from '@docusaurus/theme-common' 4 | import { 5 | useBlogAuthorPageTitle, 6 | BlogAuthorsListViewAllLabel 7 | } from '@docusaurus/theme-common/internal' 8 | import Link from '@docusaurus/Link' 9 | import { useBlogMetadata } from '@docusaurus/plugin-content-blog/client' 10 | import BlogLayout from '@theme/BlogLayout' 11 | import BlogListPaginator from '@theme/BlogListPaginator' 12 | import SearchMetadata from '@theme/SearchMetadata' 13 | import BlogPostItems from '@theme/BlogPostItems' 14 | import Author from '@theme/Blog/Components/Author' 15 | 16 | function Metadata({ author }) { 17 | const title = useBlogAuthorPageTitle(author) 18 | return ( 19 | <> 20 | 21 | 22 | 23 | ) 24 | } 25 | 26 | function ViewAllAuthorsLink() { 27 | const { authorsListPath } = useBlogMetadata() 28 | return ( 29 | 30 | 31 | 32 | ) 33 | } 34 | 35 | function Content({ author, items, sidebar, listMetadata }) { 36 | return ( 37 | 38 |
39 | 40 | {author.description &&

{author.description}

} 41 | 42 |
43 | 44 | 45 |
46 | ) 47 | } 48 | 49 | export default function BlogAuthorsPostsPage(props) { 50 | return ( 51 | 54 | 55 | 56 | 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /docs/tutorial-extras/translate-your-site.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Translate your site 6 | 7 | Let's translate `docs/intro.md` to French. 8 | 9 | ## Configure i18n 10 | 11 | Modify `docusaurus.config.js` to add support for the `fr` locale: 12 | 13 | ```js title="docusaurus.config.js" 14 | export default { 15 | i18n: { 16 | defaultLocale: 'en', 17 | locales: ['en', 'fr'], 18 | }, 19 | }; 20 | ``` 21 | 22 | ## Translate a doc 23 | 24 | Copy the `docs/intro.md` file to the `i18n/fr` folder: 25 | 26 | ```bash 27 | mkdir -p i18n/fr/docusaurus-plugin-content-docs/current/ 28 | 29 | cp docs/intro.md i18n/fr/docusaurus-plugin-content-docs/current/intro.md 30 | ``` 31 | 32 | Translate `i18n/fr/docusaurus-plugin-content-docs/current/intro.md` in French. 33 | 34 | ## Start your localized site 35 | 36 | Start your site on the French locale: 37 | 38 | ```bash 39 | npm run start -- --locale fr 40 | ``` 41 | 42 | Your localized site is accessible at [http://localhost:3000/fr/](http://localhost:3000/fr/) and the `Getting Started` page is translated. 43 | 44 | :::caution 45 | 46 | In development, you can only use one locale at a time. 47 | 48 | ::: 49 | 50 | ## Add a Locale Dropdown 51 | 52 | To navigate seamlessly across languages, add a locale dropdown. 53 | 54 | Modify the `docusaurus.config.js` file: 55 | 56 | ```js title="docusaurus.config.js" 57 | export default { 58 | themeConfig: { 59 | navbar: { 60 | items: [ 61 | // highlight-start 62 | { 63 | type: 'localeDropdown', 64 | }, 65 | // highlight-end 66 | ], 67 | }, 68 | }, 69 | }; 70 | ``` 71 | 72 | The locale dropdown now appears in your navbar: 73 | 74 | ![Locale Dropdown](./img/localeDropdown.png) 75 | 76 | ## Build your localized site 77 | 78 | Build your site for a specific locale: 79 | 80 | ```bash 81 | npm run build -- --locale fr 82 | ``` 83 | 84 | Or build your site to include all the locales at once: 85 | 86 | ```bash 87 | npm run build 88 | ``` 89 | -------------------------------------------------------------------------------- /src/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Slot } from '@radix-ui/react-slot' 3 | import { cva, type VariantProps } from 'class-variance-authority' 4 | 5 | import { cn } from '@/lib/utils' 6 | 7 | const buttonVariants = cva( 8 | 'cursor-pointer inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', 9 | { 10 | variants: { 11 | variant: { 12 | default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90', 13 | destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90', 14 | outline: 15 | 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground', 16 | secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80', 17 | ghost: 'hover:bg-accent hover:text-accent-foreground', 18 | link: 'text-primary underline-offset-4 hover:underline' 19 | }, 20 | size: { 21 | default: 'h-9 px-4 py-2', 22 | sm: 'h-8 rounded-md px-3 text-xs', 23 | lg: 'h-10 rounded-md px-8', 24 | icon: 'h-9 w-9' 25 | } 26 | }, 27 | defaultVariants: { 28 | variant: 'default', 29 | size: 'default' 30 | } 31 | } 32 | ) 33 | 34 | export interface ButtonProps 35 | extends React.ButtonHTMLAttributes, 36 | VariantProps { 37 | asChild?: boolean 38 | } 39 | 40 | const Button = React.forwardRef( 41 | ({ className, variant, size, asChild = false, ...props }, ref) => { 42 | const Comp = asChild ? Slot : 'button' 43 | return ( 44 | 45 | ) 46 | } 47 | ) 48 | Button.displayName = 'Button' 49 | 50 | export { Button, buttonVariants } 51 | -------------------------------------------------------------------------------- /src/theme/Navbar/Layout/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react' 2 | import clsx from 'clsx' 3 | import { ThemeClassNames, useThemeConfig } from '@docusaurus/theme-common' 4 | import { useHideableNavbar, useNavbarMobileSidebar } from '@docusaurus/theme-common/internal' 5 | import { translate } from '@docusaurus/Translate' 6 | import NavbarMobileSidebar from '@theme/Navbar/MobileSidebar' 7 | import styles from './styles.module.css' 8 | function NavbarBackdrop(props) { 9 | return ( 10 |
15 | ) 16 | } 17 | export default function NavbarLayout({ children }) { 18 | const { 19 | navbar: { hideOnScroll, style } 20 | } = useThemeConfig() 21 | const mobileSidebar = useNavbarMobileSidebar() 22 | const { navbarRef, isNavbarVisible } = useHideableNavbar(hideOnScroll) 23 | const [hasScrolled, setHasScrolled] = useState(false) 24 | 25 | useEffect(() => { 26 | const handleScroll = () => { 27 | setHasScrolled(window.scrollY > 40) 28 | } 29 | 30 | window.addEventListener('scroll', handleScroll) 31 | return () => window.removeEventListener('scroll', handleScroll) 32 | }, []) 33 | return ( 34 | 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /src/components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | import { cn } from '@/lib/utils' 4 | 5 | function Card({ className, ...props }: React.ComponentProps<'div'>) { 6 | return ( 7 |
15 | ) 16 | } 17 | 18 | function CardHeader({ className, ...props }: React.ComponentProps<'div'>) { 19 | return ( 20 |
28 | ) 29 | } 30 | 31 | function CardTitle({ className, ...props }: React.ComponentProps<'div'>) { 32 | return ( 33 |
38 | ) 39 | } 40 | 41 | function CardDescription({ className, ...props }: React.ComponentProps<'div'>) { 42 | return ( 43 |
48 | ) 49 | } 50 | 51 | function CardAction({ className, ...props }: React.ComponentProps<'div'>) { 52 | return ( 53 |
58 | ) 59 | } 60 | 61 | function CardContent({ className, ...props }: React.ComponentProps<'div'>) { 62 | return
63 | } 64 | 65 | function CardFooter({ className, ...props }: React.ComponentProps<'div'>) { 66 | return ( 67 |
72 | ) 73 | } 74 | 75 | export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docusaurus-tailwind-shadcn-template", 3 | "description": "Integrating Tailwind CSS and Shadcn/ui with Docusaurus website template", 4 | "author": "Thành Nam Nguyễn", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template.git" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template/issues" 11 | }, 12 | "homepage": "https://github.com/namnguyenthanhwork/docusaurus-tailwind-shadcn-template#readme", 13 | "version": "1.0.0", 14 | "private": true, 15 | "scripts": { 16 | "docusaurus": "docusaurus", 17 | "start": "docusaurus start", 18 | "build": "docusaurus build", 19 | "swizzle": "docusaurus swizzle", 20 | "deploy": "docusaurus deploy", 21 | "clear": "docusaurus clear", 22 | "serve": "docusaurus serve", 23 | "write-translations": "docusaurus write-translations", 24 | "write-heading-ids": "docusaurus write-heading-ids", 25 | "gen-api-docs": "docusaurus gen-api-docs", 26 | "clean-api-docs": "docusaurus clean-api-docs", 27 | "gen-api-docs:version": "docusaurus gen-api-docs:version", 28 | "clean-api-docs:version": "docusaurus clean-api-docs:version" 29 | }, 30 | "dependencies": { 31 | "@docusaurus/core": "^3.9.2", 32 | "@docusaurus/faster": "^3.9.2", 33 | "@docusaurus/plugin-ideal-image": "^3.9.2", 34 | "@docusaurus/preset-classic": "^3.9.2", 35 | "@docusaurus/remark-plugin-npm2yarn": "^3.9.2", 36 | "@easyops-cn/docusaurus-search-local": "^0.52.1", 37 | "@mdx-js/react": "^3.1.1", 38 | "@radix-ui/react-avatar": "^1.1.11", 39 | "@radix-ui/react-slot": "^1.2.4", 40 | "class-variance-authority": "^0.7.1", 41 | "clsx": "^2.1.1", 42 | "docusaurus-plugin-openapi-docs": "^4.5.1", 43 | "docusaurus-theme-openapi-docs": "^4.5.1", 44 | "lucide-react": "^0.555.0", 45 | "prism-react-renderer": "^2.4.1", 46 | "react": "^18.3.1", 47 | "react-dom": "^18.3.1" 48 | }, 49 | "devDependencies": { 50 | "@docusaurus/module-type-aliases": "^3.9.2", 51 | "@docusaurus/types": "^3.9.2", 52 | "@tailwindcss/postcss": "^4.1.17", 53 | "postcss": "^8.5.6", 54 | "prettier": "^3.6.2", 55 | "prettier-plugin-tailwindcss": "^0.7.1", 56 | "tailwind-merge": "^3.4.0", 57 | "tailwindcss": "^4.1.17", 58 | "tailwindcss-animate": "^1.0.7" 59 | }, 60 | "engines": { 61 | "node": ">=20.0" 62 | }, 63 | "browserslist": { 64 | "production": [ 65 | ">0.5%", 66 | "not dead", 67 | "not op_mini all" 68 | ], 69 | "development": [ 70 | "last 3 chrome version", 71 | "last 3 firefox version", 72 | "last 5 safari version" 73 | ] 74 | }, 75 | "optionalDependencies": { 76 | "postman-code-generators": "^1.14.1" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/plugins/blog-plugin.js: -------------------------------------------------------------------------------- 1 | const blogPluginExports = require('@docusaurus/plugin-content-blog') 2 | const defaultBlogPlugin = blogPluginExports.default 3 | 4 | async function blogPluginExtended(...pluginArgs) { 5 | const blogPluginInstance = await defaultBlogPlugin(...pluginArgs) 6 | const pluginOptions = pluginArgs[1] 7 | 8 | return { 9 | // Add all properties of the default blog plugin so existing functionality is preserved 10 | ...blogPluginInstance, 11 | /** 12 | * Override the default `contentLoaded` hook to access blog posts data 13 | */ 14 | contentLoaded: async function (params) { 15 | const { content, actions } = params 16 | 17 | // Get the 6 latest blog posts 18 | const recentPostsLimit = 6 19 | const recentPosts = [...content.blogPosts].splice(0, recentPostsLimit) 20 | 21 | async function createRecentPostModule(blogPost, index) { 22 | return { 23 | // Inject the metadata you need for each recent blog post 24 | blogData: await actions.createData( 25 | `home-page-recent-post-metadata-${index}.json`, 26 | JSON.stringify({ 27 | metadata: blogPost.metadata 28 | }) 29 | ), 30 | 31 | // Inject the MDX excerpt as a JSX component prop 32 | // (what's above the marker) 33 | Preview: { 34 | __import: true, 35 | // The markdown file for the blog post will be loaded by webpack 36 | path: blogPost.metadata.source, 37 | query: { 38 | truncated: true 39 | } 40 | } 41 | } 42 | } 43 | 44 | actions.addRoute({ 45 | // Add route for the home page 46 | path: '/', 47 | exact: true, 48 | 49 | // The component to use for the "Home" page route 50 | component: '@site/src/components/Homepage/index.js', 51 | 52 | // These are the props that will be passed to our "Home" page component 53 | modules: { 54 | homePageBlogMetadata: await actions.createData( 55 | 'home-page-blog-metadata.json', 56 | JSON.stringify({ 57 | blogTitle: pluginOptions.blogTitle, 58 | blogDescription: pluginOptions.blogDescription, 59 | path: pluginOptions.path, 60 | totalPosts: content.blogPosts.length, 61 | totalRecentPosts: recentPosts.length 62 | }) 63 | ), 64 | recentPosts: await Promise.all(recentPosts.map(createRecentPostModule)) 65 | } 66 | }) 67 | 68 | // Call the default overridden `contentLoaded` implementation 69 | return blogPluginInstance.contentLoaded(params) 70 | } 71 | } 72 | } 73 | 74 | module.exports = { 75 | ...blogPluginExports, 76 | default: blogPluginExtended 77 | } 78 | -------------------------------------------------------------------------------- /src/theme/BlogListPage/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import clsx from 'clsx' 3 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext' 4 | import { PageMetadata, HtmlClassNameProvider, ThemeClassNames } from '@docusaurus/theme-common' 5 | import BlogLayout from '@theme/BlogLayout' 6 | import SearchMetadata from '@theme/SearchMetadata' 7 | import BlogPostItems from '@theme/BlogPostItems' 8 | import Image from '@theme/IdealImage' 9 | import useBaseUrl from '@docusaurus/useBaseUrl' 10 | 11 | import { BlogPagination } from '../BlogPagination' 12 | 13 | function BlogListPageMetadata(props) { 14 | const { metadata } = props 15 | const { 16 | siteConfig: { title: siteTitle } 17 | } = useDocusaurusContext() 18 | const { blogDescription, blogTitle, permalink } = metadata 19 | const isBlogOnlyMode = permalink === '/' 20 | const title = isBlogOnlyMode ? siteTitle : blogTitle 21 | 22 | return ( 23 | <> 24 | 25 | 26 | 27 | ) 28 | } 29 | 30 | function BlogHomepageBanner(props) { 31 | const blogMetadata = props.metadata 32 | const imageDefault = { 33 | urlBannerBg: 34 | 'https://res.cloudinary.com/thanhnam/image/upload/v1696174608/thanhnamnguyen.dev/blog/blog-banner_othakp.png', 35 | urlAvatar: 36 | 'https://res.cloudinary.com/thanhnam/image/upload/v1715137157/project/docusaurus-material-ui-template/logo_wnw5lv.png' 37 | } 38 | 39 | return ( 40 |
41 |
42 | Blog banner 48 | avatar blog 56 |
57 |
58 |

{blogMetadata.blogTitle}

59 |

{blogMetadata.blogDescription}

60 |
61 |
62 | ) 63 | } 64 | 65 | function BlogListPageContent(props) { 66 | const { metadata, items, sidebar } = props 67 | 68 | return ( 69 | 70 | 71 | 72 | 73 | 74 | ) 75 | } 76 | 77 | export default function BlogListPage(props) { 78 | return ( 79 | 82 | 83 | 84 | 85 | ) 86 | } 87 | -------------------------------------------------------------------------------- /static/img/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/theme/BlogPagination/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useHistory } from '@docusaurus/router' 3 | import { 4 | Pagination, 5 | PaginationContent, 6 | PaginationEllipsis, 7 | PaginationItem, 8 | PaginationLink, 9 | PaginationNext, 10 | PaginationPrevious 11 | } from '@/components/ui/pagination.tsx' 12 | 13 | export const BlogPagination = ({ metadata }) => { 14 | const history = useHistory() 15 | 16 | const handleParams = () => { 17 | const path = history.location.pathname 18 | const parts = path.split('/') 19 | const pageNumber = parts[parts.length - 1] 20 | return isNaN(pageNumber) ? 1 : parseInt(pageNumber) 21 | } 22 | 23 | const page = handleParams() 24 | 25 | const handlePageChange = (value) => { 26 | if (value === page) { 27 | return 28 | } 29 | const newPagePath = value === 1 ? '/blog' : `/blog/page/${value}` 30 | history.push(newPagePath) 31 | } 32 | 33 | // Generate array of page numbers 34 | const generatePagination = (currentPage, totalPages) => { 35 | let pages = [] 36 | 37 | // Always show first page 38 | pages.push(1) 39 | 40 | if (currentPage > 3) { 41 | pages.push('ellipsis') 42 | } 43 | 44 | // Show pages around current page 45 | for ( 46 | let i = Math.max(2, currentPage - 1); 47 | i <= Math.min(totalPages - 1, currentPage + 1); 48 | i++ 49 | ) { 50 | pages.push(i) 51 | } 52 | 53 | if (currentPage < totalPages - 2) { 54 | pages.push('ellipsis') 55 | } 56 | 57 | // Always show last page 58 | if (totalPages > 1) { 59 | pages.push(totalPages) 60 | } 61 | 62 | return pages 63 | } 64 | 65 | if (metadata.totalPages <= 1) { 66 | return null 67 | } 68 | 69 | const pages = generatePagination(page, metadata.totalPages) 70 | 71 | return ( 72 | 73 | 74 | 75 | page > 1 && handlePageChange(page - 1)} 77 | className={page <= 1 ? 'hidden' : 'cursor-pointer'} 78 | /> 79 | 80 | 81 | {pages.map((pageNum, index) => ( 82 | 83 | {pageNum === 'ellipsis' ? ( 84 | 85 | ) : ( 86 | handlePageChange(pageNum)} 88 | isActive={page === pageNum} 89 | className='cursor-pointer shadow-xs' 90 | > 91 | {pageNum} 92 | 93 | )} 94 | 95 | ))} 96 | 97 | 98 | page < metadata.totalPages && handlePageChange(page + 1)} 100 | className={page >= metadata.totalPages ? 'hidden' : 'cursor-pointer'} 101 | /> 102 | 103 | 104 | 105 | ) 106 | } 107 | 108 | export default BlogPagination 109 | -------------------------------------------------------------------------------- /docs/petstore_versioned/1.0.0/logout-user.api.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: logout-user 3 | title: "Logs out current logged in user session" 4 | description: "" 5 | sidebar_label: "Logs out current logged in user session" 6 | hide_title: true 7 | hide_table_of_contents: true 8 | api: eJztV01v3DYQ/SsD5hIbWilNbnuqkaaF0bQO7ARFsGs0s+RoRZjiqCS1smrsfy+G0q4/kjS99NSeJH49zrwZch7vVMJtVMuV6iMFdV0oQ1EH2yXLXi2VKhR3FFCa50YtleMt9+mDTC5UoNixjxTV8k4ZqrF3afp9iBF7rSnGundwxFL7faFaSg0L6JaSKlSHqVFLVYkl1bSPKlSksKMgJt6pPji1VE1KXVxWVUcpJg5UxgG3Wwql5Wr3Uj114YfJLpiA1L74JzgRvdnw7WdgV1P/EexaDNR9sGm80g21ExUHxN+xF5eeEvITJcDMCSQGgwlhaKwj6AIn0sn6LYzcB5nEvU+gAxnyyaKL5dpfnPWpeQk2ArrIgBCxpgDoDbQcCLJBBAOOAr+1OxK0ecdy7VWh0tiRWioW+4Sx2vGQLbdt56y2OYoyyMH+mQP24UjZVxjDzlYZrzIWHW8ldJq7iZAh2ERLWaaWqmVj6xGkBdY/8jTnFJrDTPmfxnPHfi9Zg539/YbGz2n9kQOkxkaI2HaOiuy1Rg99JEgNAXYWbmiET7EjbdEtbmj8JBwlimma8dBlqK1LFB5Thp39mUZVKI/t3M7WFMqKDQ2hkbzYS7vmz418LwZK6GYr50yCdzOlc7tc+4+z9bX1BrhPU3BxI79XE++Aae1Xc1DuY3H9/LOuE+AA7GFlgy7rQOTZUOkpFfBsnvWFVZUNujop1/5fpHbtnz2Dc58Cm17L2Npnjs7enQtPhnXfkk9kJFdOTy868jJUc2gxnZ7mtLcRNhjJgKxe3VOZjT369aWsPZEzt7OGDGxGWH2Dw0TYlmt/nmDACKendJvIGzKnp+Kqda6PKWAiqAlTHygC17Dakpdbj8OCO/LY2UWgbt5A7p+tTU2/KTW31SVtrHNj9eUlJ2ufmF12eXVJP7D+Cohh7cYqyPfkyGAmvoRzD2iMzVFIDDGhNxjM2h+YjaNPeAsD5eAi1DTAakfecIDscLTs47d3rjaON1WLMVGoDOs4dS8mqMU9VNmak0MiHIy4kjSqrcb/M+I/nhGvA8e4uAh2az1cUuQ+aIKrBoP12weZcST4bxfA89cXl1cnIHWO7rNIs9Q99JpgsKkBWP326jXIXXbv1TAM5fCq5LCt3l9WmkPMV+OZN5AaTIBOiijovL3hFifctvdzGkMduM134SbwEPMlf+YcHFUUNLgTfgfrjMZgJF1pwZMnQ2N1Ay3eUBSMdrKZErkRun7jrM5ZMFV5u3EksaQdhZE9FWC9dr0RBtCPoNmQlAP5jzbRgWxRFiI0Dudu7Y9Hh+uaQoQ0cD5pOZHx0fTl2gMscjB+pnFqTFrlqFkWgF5EoM9ShzU7sTIzd5Atj+uE9VIpc7TWXvw7ZCdM4nHidKBNAS1vREPJJEPxJnEH2ImayUhzFRcpORXi78oX5Qup6zY5KeSHknp0+OPZL29lnEIbL+orCjur6V4DPbgy8pRKFUqzT6izeJrlQb7L+q7jINqGWrRuEg1ycXx/j6GKJ6L0a2dI7Qt1uxB1LLs8XhOmieW81vJ87A7XXF5Wdl60Gbr0nm6TWqqjwxk0wxsMN0/2qGy7fQyUZ30dTUaPkM5q8pEeEtOhbghe5hj0D8WlnDPMo/mszUtj9fb89Ztfr94sXpYvyia1LousjmNq0T8AfsvbmOWS7kMgn8SG7XTK5WEBUY4H+6fK/i4Hj3yaHj2z2kt0m6rOofXiRTbzbn6nzC+mYn4RydOp4Zhk4O5Oas+H4PZ76f6jpzCq5eq6UDsMFjeSb6vrhw+gn968V/v9XwDT1Lo= 9 | sidebar_class_name: "get api-method" 10 | info_path: docs/petstore_versioned/1.0.0/swagger-petstore-yaml 11 | custom_edit_url: null 12 | --- 13 | 14 | import MethodEndpoint from "@theme/ApiExplorer/MethodEndpoint"; 15 | import ParamsDetails from "@theme/ParamsDetails"; 16 | import RequestSchema from "@theme/RequestSchema"; 17 | import StatusCodes from "@theme/StatusCodes"; 18 | import OperationTabs from "@theme/OperationTabs"; 19 | import TabItem from "@theme/TabItem"; 20 | import Heading from "@theme/Heading"; 21 | 22 | 27 | 28 | 29 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | 54 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/components/ui/pagination.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from 'lucide-react' 3 | 4 | import { cn } from '@/lib/utils' 5 | import { Button, buttonVariants } from '@/components/ui/button' 6 | 7 | function Pagination({ className, ...props }: React.ComponentProps<'nav'>) { 8 | return ( 9 |