docs: redesign docs collapsible categories (#1748)
* docs: redesign docs collapsible categories Closes #1341 * Fix people creation from People table page --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -3,5 +3,7 @@
|
||||
"position": 10,
|
||||
"collapsible": true,
|
||||
"collapsed": true,
|
||||
"className": "navbar-sub-menu"
|
||||
"customProps": {
|
||||
"icon": "TbPlus"
|
||||
}
|
||||
}
|
||||
@ -3,5 +3,7 @@
|
||||
"position": 3,
|
||||
"collapsible": true,
|
||||
"collapsed": false,
|
||||
"className": "navbar-sub-menu"
|
||||
"customProps": {
|
||||
"icon": "TbTerminal2"
|
||||
}
|
||||
}
|
||||
@ -251,8 +251,6 @@ const MyComponent = ({ MyIcon }: { MyIcon: IconComponent }) => {
|
||||
|
||||
For React to understand that the component is a component, you need to use PascalCase, to later instanciate it with `<MyIcon>`
|
||||
|
||||
```tsx
|
||||
|
||||
## Prop Drilling: Keep It Minimal
|
||||
|
||||
Prop drilling, in the React context, refers to the practice of passing state variables and their setters through multiple component layers, even if intermediary components don't use them. While sometimes necessary, excessive prop drilling can lead to:
|
||||
|
||||
@ -40,7 +40,7 @@ git clone git@github.com:twentyhq/twenty.git
|
||||
|
||||
|
||||
### 3. PostgreSQL database
|
||||
You also need to have a PosgresSQL database available. If you already have one available, you can skip this step.
|
||||
You also need to have a PostgreSQL database available. If you already have one available, you can skip this step.
|
||||
|
||||
If you don't, you can provision one through `docker` using the following command:
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ const config = {
|
||||
/** @type {import('@docusaurus/preset-classic').Options} */
|
||||
({
|
||||
docs: {
|
||||
breadcrumbs: false,
|
||||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
sidebarCollapsible: false,
|
||||
routeBasePath: '/',
|
||||
|
||||
@ -38,6 +38,11 @@
|
||||
--ifm-spacing-horizontal: 2rem;
|
||||
|
||||
--ifm-menu-link-padding-vertical: 0.2rem;
|
||||
|
||||
--list-items-border-color: #ebebeb;
|
||||
--category-icon-background-color: #ebebeb;
|
||||
--category-icon-border-color: #d6d6d6;
|
||||
--level-1-color: #B3B3B3;
|
||||
}
|
||||
|
||||
.markdown > h1 {
|
||||
@ -60,6 +65,10 @@
|
||||
[data-theme='dark'] {
|
||||
--ifm-color-primary: #fff;
|
||||
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
|
||||
--list-items-border-color: #292929;
|
||||
--category-icon-background-color: #292929;
|
||||
--category-icon-border-color: #333333;
|
||||
--level-1-color: #666666;
|
||||
}
|
||||
|
||||
body {
|
||||
@ -73,6 +82,10 @@ html {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding-top: 48px !important;
|
||||
}
|
||||
|
||||
.DocSearch-Button {
|
||||
height: 32px !important;
|
||||
border-radius: 8px !important;
|
||||
@ -120,6 +133,10 @@ a.menu__link, a.navbar__item {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.menu__link--external {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
li.coming-soon a::after {
|
||||
float: right;
|
||||
content: "soon";
|
||||
@ -134,33 +151,33 @@ li.coming-soon a::after {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.menu__list-item-collapsible > a {
|
||||
.theme-doc-sidebar-item-category-level-1 > .menu__link {
|
||||
text-transform: uppercase;
|
||||
font-size:11px;
|
||||
color: #B3B3B3;
|
||||
font-size: 12px;
|
||||
color: var(--level-1-color);
|
||||
}
|
||||
|
||||
.menu__list-item-collapsible > a:hover {
|
||||
color: #B3B3B3;
|
||||
}
|
||||
|
||||
.menu__list-item-collapsible > a {
|
||||
text-transform: uppercase;
|
||||
font-size:12px;
|
||||
}
|
||||
.menu__list-item-collapsible:hover {
|
||||
.menu__list-item--level1 > .menu__link--active,
|
||||
.menu__list-item--level1 > .menu__link:hover {
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
|
||||
.theme-doc-sidebar-item-category {
|
||||
.theme-doc-sidebar-item-category-level-1 {
|
||||
padding-top: 1.5rem;
|
||||
}
|
||||
|
||||
.theme-doc-sidebar-item-category-level-2 {
|
||||
cursor: pointer;
|
||||
}
|
||||
.theme-doc-sidebar-item-category-level-2 .menu__list {
|
||||
border-left: 1px solid var(--list-items-border-color);
|
||||
margin-left: var(--ifm-menu-link-padding-horizontal);
|
||||
}
|
||||
|
||||
.sidebar-item-icon {
|
||||
display: flex;
|
||||
vertical-align: center;
|
||||
padding-right: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.icon-and-text {
|
||||
@ -184,15 +201,6 @@ a.table-of-contents__link:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.navbar-sub-menu {
|
||||
padding-top: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.navbar-sub-menu .menu__link--sublist {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.docs-image {
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
|
||||
101
docs/src/theme/DocSidebarItem/Category/index.js
Normal file
101
docs/src/theme/DocSidebarItem/Category/index.js
Normal file
@ -0,0 +1,101 @@
|
||||
import Link from "@docusaurus/Link";
|
||||
import isInternalUrl from "@docusaurus/isInternalUrl";
|
||||
import {
|
||||
Collapsible,
|
||||
ThemeClassNames,
|
||||
useCollapsible,
|
||||
} from "@docusaurus/theme-common";
|
||||
import { isActiveSidebarItem } from "@docusaurus/theme-common/internal";
|
||||
import DocSidebarItems from "@theme/DocSidebarItems";
|
||||
import IconExternalLink from "@theme/Icon/ExternalLink";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
import * as icons from "../../icons";
|
||||
|
||||
const DocSidebarItemCategory = ({
|
||||
item,
|
||||
onItemClick,
|
||||
activePath,
|
||||
level,
|
||||
index,
|
||||
...props
|
||||
}) => {
|
||||
const {
|
||||
href,
|
||||
label,
|
||||
className,
|
||||
collapsible,
|
||||
autoAddBaseUrl,
|
||||
customProps = {},
|
||||
items,
|
||||
} = item;
|
||||
const isActive = isActiveSidebarItem(item, activePath);
|
||||
const isInternalLink = isInternalUrl(href);
|
||||
const IconComponent = customProps?.icon ? icons[customProps.icon] : undefined;
|
||||
|
||||
const { collapsed, setCollapsed } = useCollapsible({
|
||||
initialState: () => collapsible && !isActive && item.collapsed,
|
||||
});
|
||||
|
||||
return (
|
||||
<li
|
||||
className={clsx(
|
||||
ThemeClassNames.docs.docSidebarItemCategory,
|
||||
ThemeClassNames.docs.docSidebarItemCategoryLevel(level),
|
||||
"menu__list-item",
|
||||
`menu__list-item--level${level}`,
|
||||
className
|
||||
)}
|
||||
key={label}
|
||||
>
|
||||
<Link
|
||||
className={clsx("menu__link", {
|
||||
"menu__link--active": isActive,
|
||||
"menu__link--external": !!href && !isInternalLink,
|
||||
})}
|
||||
autoAddBaseUrl={autoAddBaseUrl}
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
aria-expanded={collapsible ? !collapsed : undefined}
|
||||
to={href}
|
||||
onClick={(e) => {
|
||||
onItemClick?.(item);
|
||||
|
||||
if (!collapsible) return;
|
||||
|
||||
if (href) {
|
||||
setCollapsed(false);
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
setCollapsed((previousCollapsed) => !previousCollapsed);
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{IconComponent ? (
|
||||
<span className="icon-and-text">
|
||||
<i className="sidebar-item-icon">
|
||||
<IconComponent />
|
||||
</i>
|
||||
{label}
|
||||
</span>
|
||||
) : (
|
||||
label
|
||||
)}
|
||||
|
||||
{!!href && !isInternalLink && <IconExternalLink />}
|
||||
</Link>
|
||||
<Collapsible lazy as="ul" className="menu__list" collapsed={collapsed}>
|
||||
<DocSidebarItems
|
||||
items={items}
|
||||
tabIndex={collapsed ? -1 : 0}
|
||||
onItemClick={onItemClick}
|
||||
activePath={activePath}
|
||||
level={level + 1}
|
||||
/>
|
||||
</Collapsible>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocSidebarItemCategory;
|
||||
@ -1,37 +1,11 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import {ThemeClassNames} from '@docusaurus/theme-common';
|
||||
import {isActiveSidebarItem} from '@docusaurus/theme-common/internal';
|
||||
import Link from '@docusaurus/Link';
|
||||
import isInternalUrl from '@docusaurus/isInternalUrl';
|
||||
import IconExternalLink from '@theme/Icon/ExternalLink';
|
||||
import styles from './styles.module.css';
|
||||
import {
|
||||
TbFaceIdError,
|
||||
TbTerminal2,
|
||||
TbCloud,
|
||||
TbServer,
|
||||
TbBolt,
|
||||
TbApps,
|
||||
TbTopologyStar,
|
||||
TbChartDots,
|
||||
TbBug,
|
||||
TbVocabulary,
|
||||
TbArrowBigRight,
|
||||
TbDeviceDesktop,
|
||||
TbBrandWindows,
|
||||
TbBugOff,
|
||||
TbBrandVscode,
|
||||
TbFolder,
|
||||
TbEyeglass,
|
||||
TbZoomQuestion,
|
||||
TbBrandFigma,
|
||||
TbPaint,
|
||||
TbChecklist,
|
||||
TbKeyboard,
|
||||
TbPencil,
|
||||
} from "react-icons/tb";
|
||||
|
||||
import Link from "@docusaurus/Link";
|
||||
import isInternalUrl from "@docusaurus/isInternalUrl";
|
||||
import { ThemeClassNames } from "@docusaurus/theme-common";
|
||||
import { isActiveSidebarItem } from "@docusaurus/theme-common/internal";
|
||||
import IconExternalLink from "@theme/Icon/ExternalLink";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
import * as icons from "../../icons";
|
||||
|
||||
const DocSidebarItemLink = ({
|
||||
item,
|
||||
@ -41,63 +15,40 @@ const DocSidebarItemLink = ({
|
||||
index,
|
||||
...props
|
||||
}) => {
|
||||
const {href, label, className, autoAddBaseUrl, customProps = {}} = item;
|
||||
const { href, label, className, autoAddBaseUrl, customProps = {} } = item;
|
||||
const isActive = isActiveSidebarItem(item, activePath);
|
||||
const isInternalLink = isInternalUrl(href);
|
||||
let icons = {
|
||||
'TbTerminal2': TbTerminal2,
|
||||
'TbCloud': TbCloud,
|
||||
'TbArrowBigRight': TbArrowBigRight,
|
||||
'TbServer': TbServer,
|
||||
'TbBolt': TbBolt,
|
||||
'TbApps': TbApps,
|
||||
'TbTopologyStar': TbTopologyStar,
|
||||
'TbChartDots': TbChartDots,
|
||||
'TbBug': TbBug,
|
||||
'TbVocabulary': TbVocabulary,
|
||||
'TbBrandWindows': TbBrandWindows,
|
||||
'TbBugOff': TbBugOff,
|
||||
'TbBrandVscode': TbBrandVscode,
|
||||
'TbDeviceDesktop': TbDeviceDesktop,
|
||||
'TbFolder': TbFolder,
|
||||
'TbEyeglass': TbEyeglass,
|
||||
'TbZoomQuestion': TbZoomQuestion,
|
||||
'TbBrandFigma': TbBrandFigma,
|
||||
'TbPaint': TbPaint,
|
||||
'TbChecklist': TbChecklist,
|
||||
'TbKeyboard': TbKeyboard,
|
||||
'TbChecklist': TbChecklist,
|
||||
'TbPencil': TbPencil,
|
||||
};
|
||||
const IconComponent = customProps?.icon
|
||||
? icons[customProps.icon]
|
||||
: icons.TbFaceIdError;
|
||||
|
||||
let IconComponent = customProps && customProps.icon ? icons[customProps.icon] : TbFaceIdError;
|
||||
return (
|
||||
<li
|
||||
className={clsx(
|
||||
ThemeClassNames.docs.docSidebarItemLink,
|
||||
ThemeClassNames.docs.docSidebarItemLinkLevel(level),
|
||||
'menu__list-item',
|
||||
className,
|
||||
"menu__list-item",
|
||||
`menu__list-item--level${level}`,
|
||||
className
|
||||
)}
|
||||
key={label}>
|
||||
key={label}
|
||||
>
|
||||
<Link
|
||||
className={clsx(
|
||||
'menu__link',
|
||||
!isInternalLink && styles.menuExternalLink,
|
||||
{
|
||||
'menu__link--active': isActive,
|
||||
},
|
||||
)}
|
||||
className={clsx("menu__link", {
|
||||
"menu__link--active": isActive,
|
||||
"menu__link--external": !isInternalLink,
|
||||
})}
|
||||
autoAddBaseUrl={autoAddBaseUrl}
|
||||
aria-current={isActive ? 'page' : undefined}
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
to={href}
|
||||
{...(isInternalLink && {
|
||||
onClick: onItemClick ? () => onItemClick(item) : undefined,
|
||||
})}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
<span className="icon-and-text">
|
||||
<i className="sidebar-item-icon">
|
||||
<IconComponent />
|
||||
<IconComponent size={customProps.iconSize} />
|
||||
</i>
|
||||
{label}
|
||||
</span>
|
||||
@ -105,6 +56,6 @@ const DocSidebarItemLink = ({
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default DocSidebarItemLink;
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
.menuExternalLink {
|
||||
align-items: center;
|
||||
}
|
||||
27
docs/src/theme/icons.js
Normal file
27
docs/src/theme/icons.js
Normal file
@ -0,0 +1,27 @@
|
||||
export {
|
||||
TbApps,
|
||||
TbArrowBackUp,
|
||||
TbArrowBigRight,
|
||||
TbBolt,
|
||||
TbBrandFigma,
|
||||
TbBrandVscode,
|
||||
TbBrandWindows,
|
||||
TbBug,
|
||||
TbBugOff,
|
||||
TbChartDots,
|
||||
TbChecklist,
|
||||
TbCloud,
|
||||
TbDeviceDesktop,
|
||||
TbEyeglass,
|
||||
TbFaceIdError,
|
||||
TbFolder,
|
||||
TbKeyboard,
|
||||
TbPaint,
|
||||
TbPencil,
|
||||
TbPlus,
|
||||
TbServer,
|
||||
TbTerminal2,
|
||||
TbTopologyStar,
|
||||
TbVocabulary,
|
||||
TbZoomQuestion,
|
||||
} from "react-icons/tb";
|
||||
Reference in New Issue
Block a user