docs: improve UX of recipe learning path (#5477)
* docs: improve UX of recipe learning path * fix icon colors
This commit is contained in:
1 parent
ea2ee343f0
commit
7f9c4dea66
9 files changed
+231
-164
No files matched your search
@@ -1,15 +1,18 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { useLearningPath } from "../../../../providers/LearningPath"
|
import { useLearningPath } from "../../../../providers/LearningPath"
|
||||||
import { Button } from "docs-ui"
|
import { Button } from "docs-ui"
|
||||||
|
import { ArrowDownLeftMini, ArrowDownMini } from "@medusajs/icons"
|
||||||
|
|
||||||
type LearningPathStepActionsType = {
|
type LearningPathStepActionsType = {
|
||||||
onFinish?: () => void
|
onFinish?: () => void
|
||||||
onClose?: () => void
|
onClose?: () => void
|
||||||
|
setCollapsed: React.Dispatch<React.SetStateAction<boolean>>
|
||||||
} & React.AllHTMLAttributes<HTMLDivElement>
|
} & React.AllHTMLAttributes<HTMLDivElement>
|
||||||
|
|
||||||
const LearningPathStepActions: React.FC<LearningPathStepActionsType> = ({
|
const LearningPathStepActions: React.FC<LearningPathStepActionsType> = ({
|
||||||
onFinish,
|
onFinish,
|
||||||
onClose,
|
onClose,
|
||||||
|
setCollapsed,
|
||||||
}) => {
|
}) => {
|
||||||
const { hasNextStep, nextStep, endPath } = useLearningPath()
|
const { hasNextStep, nextStep, endPath } = useLearningPath()
|
||||||
|
|
||||||
@@ -22,18 +25,34 @@ const LearningPathStepActions: React.FC<LearningPathStepActionsType> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-0.5 p-1 justify-end items-center">
|
<div className="flex p-1 justify-between items-center">
|
||||||
<Button onClick={onClose}>Close</Button>
|
<div>
|
||||||
{hasNextStep() && (
|
<Button
|
||||||
<Button onClick={nextStep} variant="primary">
|
onClick={() => setCollapsed(true)}
|
||||||
Next
|
variant="secondary"
|
||||||
|
className="!text-medusa-fg-subtle !p-[6px]"
|
||||||
|
>
|
||||||
|
<ArrowDownLeftMini className="flip-y hidden md:inline" />
|
||||||
|
<ArrowDownMini className="inline md:hidden" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</div>
|
||||||
{!hasNextStep() && (
|
<div className="flex gap-0.5 items-center">
|
||||||
<Button onClick={handleFinish} variant="primary">
|
{hasNextStep() && (
|
||||||
Finish
|
<>
|
||||||
</Button>
|
<Button onClick={onClose} variant="secondary">
|
||||||
)}
|
Close
|
||||||
|
</Button>
|
||||||
|
<Button onClick={nextStep} variant="primary">
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{!hasNextStep() && (
|
||||||
|
<Button onClick={handleFinish} variant="primary">
|
||||||
|
Finish
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { useLearningPath } from "@site/src/providers/LearningPath"
|
import { useLearningPath } from "@site/src/providers/LearningPath"
|
||||||
import React from "react"
|
import React, { useCallback, useEffect, useRef, useState } from "react"
|
||||||
import LearningPathStepActions from "./Actions"
|
import LearningPathStepActions from "./Actions"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import IconCircleDottedLine from "@site/src/theme/Icon/CircleDottedLine"
|
import IconCircleDottedLine from "@site/src/theme/Icon/CircleDottedLine"
|
||||||
import Link from "@docusaurus/Link"
|
import Link from "@docusaurus/Link"
|
||||||
import { CheckCircleSolid, CircleMiniSolid } from "@medusajs/icons"
|
import { CheckCircleSolid, CircleMiniSolid, ListBullet } from "@medusajs/icons"
|
||||||
|
import { Badge, Button } from "docs-ui"
|
||||||
|
import { CSSTransition, SwitchTransition } from "react-transition-group"
|
||||||
|
|
||||||
type LearningPathStepsProps = {
|
type LearningPathStepsProps = {
|
||||||
onFinish?: () => void
|
onFinish?: () => void
|
||||||
@@ -13,66 +15,140 @@ type LearningPathStepsProps = {
|
|||||||
|
|
||||||
const LearningPathSteps: React.FC<LearningPathStepsProps> = ({ ...rest }) => {
|
const LearningPathSteps: React.FC<LearningPathStepsProps> = ({ ...rest }) => {
|
||||||
const { path, currentStep, goToStep } = useLearningPath()
|
const { path, currentStep, goToStep } = useLearningPath()
|
||||||
|
const [collapsed, setCollapsed] = useState(false)
|
||||||
|
const stepsRef = useRef<HTMLDivElement>(null)
|
||||||
|
const buttonRef = useRef<HTMLButtonElement>(null)
|
||||||
|
const nodeRef: React.RefObject<HTMLElement> = collapsed ? buttonRef : stepsRef
|
||||||
|
|
||||||
|
const handleScroll = useCallback(() => {
|
||||||
|
if (window.scrollY > 100 && !collapsed) {
|
||||||
|
// automatically collapse steps
|
||||||
|
setCollapsed(true)
|
||||||
|
} else if (
|
||||||
|
(window.scrollY === 0 ||
|
||||||
|
window.scrollY + window.innerHeight >= document.body.scrollHeight) &&
|
||||||
|
collapsed
|
||||||
|
) {
|
||||||
|
// automatically open steps
|
||||||
|
setCollapsed(false)
|
||||||
|
}
|
||||||
|
}, [collapsed])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener("scroll", handleScroll)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("scroll", handleScroll)
|
||||||
|
}
|
||||||
|
}, [handleScroll])
|
||||||
|
|
||||||
if (!path) {
|
if (!path) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<SwitchTransition>
|
||||||
<div className="overflow-auto basis-3/4">
|
<CSSTransition
|
||||||
{path.steps.map((step, index) => (
|
key={collapsed ? "show_path" : "show_button"}
|
||||||
<div
|
nodeRef={nodeRef}
|
||||||
className={clsx(
|
timeout={300}
|
||||||
"border-0 border-b border-solid border-medusa-border-base",
|
addEndListener={(done) => {
|
||||||
"relative p-1"
|
nodeRef.current?.addEventListener("transitionend", done, false)
|
||||||
)}
|
}}
|
||||||
key={index}
|
classNames={{
|
||||||
>
|
enter: "animate-maximize animate-fast",
|
||||||
<div className={clsx("flex items-center gap-1")}>
|
exit: "animate-minimize animate-fast",
|
||||||
<div className="w-2 flex-none flex items-center justify-center">
|
}}
|
||||||
{index === currentStep && (
|
>
|
||||||
<IconCircleDottedLine
|
<>
|
||||||
|
{!collapsed && (
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
"bg-medusa-bg-base shadow-flyout dark:shadow-flyout-dark rounded",
|
||||||
|
"transition-transform origin-bottom-right flex flex-col"
|
||||||
|
)}
|
||||||
|
ref={stepsRef}
|
||||||
|
>
|
||||||
|
<div className="overflow-auto basis-3/4">
|
||||||
|
{path.steps.map((step, index) => (
|
||||||
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"shadow-active dark:shadow-active-dark rounded-full",
|
"border-0 border-b border-solid border-medusa-border-base",
|
||||||
"!text-ui-fg-interactive"
|
"relative p-1"
|
||||||
)}
|
)}
|
||||||
/>
|
key={index}
|
||||||
)}
|
>
|
||||||
{index < currentStep && (
|
<div className={clsx("flex items-center gap-1")}>
|
||||||
<CheckCircleSolid className="text-ui-fg-interactive" />
|
<div className="w-2 flex-none flex items-center justify-center">
|
||||||
)}
|
{index === currentStep && (
|
||||||
{index > currentStep && (
|
<IconCircleDottedLine
|
||||||
<CircleMiniSolid className="text-ui-fg-subtle" />
|
className={clsx(
|
||||||
)}
|
"shadow-active dark:shadow-active-dark rounded-full",
|
||||||
|
"!text-ui-fg-interactive"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{index < currentStep && (
|
||||||
|
<CheckCircleSolid className="text-ui-fg-interactive" />
|
||||||
|
)}
|
||||||
|
{index > currentStep && (
|
||||||
|
<CircleMiniSolid className="text-ui-fg-subtle" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className={clsx(
|
||||||
|
"text-compact-medium-plus text-medusa-fg-base"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{step.title}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{index === currentStep && (
|
||||||
|
<div className={clsx("flex items-center gap-1")}>
|
||||||
|
<div className="w-2 flex-none"></div>
|
||||||
|
<div
|
||||||
|
className={clsx("text-medium text-ui-fg-subtle mt-1")}
|
||||||
|
>
|
||||||
|
{step.descriptionJSX ?? step.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Link
|
||||||
|
href={step.path}
|
||||||
|
className={clsx("absolute top-0 left-0 w-full h-full")}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
goToStep(index)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<span
|
<LearningPathStepActions setCollapsed={setCollapsed} {...rest} />
|
||||||
className={clsx("text-compact-medium-plus text-medusa-fg-base")}
|
|
||||||
>
|
|
||||||
{step.title}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
{index === currentStep && (
|
)}
|
||||||
<div className={clsx("flex items-center gap-1")}>
|
{collapsed && (
|
||||||
<div className="w-2 flex-none"></div>
|
<Button
|
||||||
<div className={clsx("text-medium text-ui-fg-subtle mt-1")}>
|
variant="secondary"
|
||||||
{step.descriptionJSX ?? step.description}
|
className={clsx(
|
||||||
</div>
|
"!p-[10px] !shadow-flyout dark:!shadow-flyout-dark !text-medusa-fg-subtle w-fit h-fit",
|
||||||
</div>
|
"rounded-full border-0 mr-0 ml-auto fixed md:relative max-[767px]:bottom-1 max-[767px]:right-1 "
|
||||||
)}
|
)}
|
||||||
<Link
|
onClick={() => setCollapsed(false)}
|
||||||
href={step.path}
|
buttonRef={buttonRef}
|
||||||
className={clsx("absolute top-0 left-0 w-full h-full")}
|
>
|
||||||
onClick={(e) => {
|
<ListBullet />
|
||||||
e.preventDefault()
|
<Badge
|
||||||
goToStep(index)
|
variant="blue"
|
||||||
}}
|
className={clsx("absolute -top-0.25 -right-0.25")}
|
||||||
/>
|
>
|
||||||
</div>
|
!
|
||||||
))}
|
</Badge>
|
||||||
</div>
|
</Button>
|
||||||
<LearningPathStepActions {...rest} />
|
)}
|
||||||
</>
|
</>
|
||||||
|
</CSSTransition>
|
||||||
|
</SwitchTransition>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
import { useCallback, useMemo } from "react"
|
|
||||||
|
|
||||||
export type OptionType = {
|
|
||||||
value: string
|
|
||||||
label: string
|
|
||||||
index?: string
|
|
||||||
isAllOption?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SelectOptions = {
|
|
||||||
value: string | string[]
|
|
||||||
multiple?: boolean
|
|
||||||
options: OptionType[]
|
|
||||||
setSelected?: (value: string | string[]) => void
|
|
||||||
addSelected?: (value: string) => void
|
|
||||||
removeSelected?: (value: string) => void
|
|
||||||
handleAddAll?: (isAllSelected: boolean) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
const useSelect = ({
|
|
||||||
value,
|
|
||||||
options,
|
|
||||||
multiple = false,
|
|
||||||
setSelected,
|
|
||||||
addSelected,
|
|
||||||
removeSelected,
|
|
||||||
handleAddAll,
|
|
||||||
}: SelectOptions) => {
|
|
||||||
const isValueSelected = useCallback(
|
|
||||||
(val: string) => {
|
|
||||||
return (
|
|
||||||
(typeof value === "string" && val === value) ||
|
|
||||||
(Array.isArray(value) && value.includes(val))
|
|
||||||
)
|
|
||||||
},
|
|
||||||
[value]
|
|
||||||
)
|
|
||||||
|
|
||||||
// checks if there are multiple selected values
|
|
||||||
const hasSelectedValues = useMemo(() => {
|
|
||||||
return multiple && Array.isArray(value) && value.length > 0
|
|
||||||
}, [value, multiple])
|
|
||||||
|
|
||||||
// checks if there are any selected values,
|
|
||||||
// whether multiple or one
|
|
||||||
const hasSelectedValue = useMemo(() => {
|
|
||||||
return hasSelectedValues || (typeof value === "string" && value.length)
|
|
||||||
}, [hasSelectedValues, value])
|
|
||||||
|
|
||||||
const selectedValues: OptionType[] = useMemo(() => {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
const selectedValue = options.find((option) => option.value === value)
|
|
||||||
return selectedValue ? [selectedValue] : []
|
|
||||||
} else if (Array.isArray(value)) {
|
|
||||||
return options.filter((option) => value.includes(option.value))
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}, [options, value])
|
|
||||||
|
|
||||||
const isAllSelected = useMemo(() => {
|
|
||||||
return Array.isArray(value) && value.length === options.length
|
|
||||||
}, [options, value])
|
|
||||||
|
|
||||||
const handleChange = (selectedValue: string, wasSelected: boolean) => {
|
|
||||||
if (multiple) {
|
|
||||||
wasSelected
|
|
||||||
? removeSelected?.(selectedValue)
|
|
||||||
: addSelected?.(selectedValue)
|
|
||||||
} else {
|
|
||||||
setSelected?.(selectedValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSelectAll = () => {
|
|
||||||
if (handleAddAll) {
|
|
||||||
handleAddAll(isAllSelected)
|
|
||||||
} else {
|
|
||||||
setSelected?.(options.map((option) => option.value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
isValueSelected,
|
|
||||||
hasSelectedValue,
|
|
||||||
hasSelectedValues,
|
|
||||||
selectedValues,
|
|
||||||
isAllSelected,
|
|
||||||
handleChange,
|
|
||||||
handleSelectAll,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useSelect
|
|
||||||
@@ -9,6 +9,7 @@ import { useThemeConfig } from "@docusaurus/theme-common"
|
|||||||
import { ThemeConfig } from "@medusajs/docs"
|
import { ThemeConfig } from "@medusajs/docs"
|
||||||
import SearchProvider from "../Search"
|
import SearchProvider from "../Search"
|
||||||
import LearningPathProvider from "../LearningPath"
|
import LearningPathProvider from "../LearningPath"
|
||||||
|
import SkipToContent from "@theme/SkipToContent"
|
||||||
|
|
||||||
type DocsProvidersProps = {
|
type DocsProvidersProps = {
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
@@ -25,7 +26,10 @@ const DocsProviders = ({ children }: DocsProvidersProps) => {
|
|||||||
<ModalProvider>
|
<ModalProvider>
|
||||||
<SearchProvider>
|
<SearchProvider>
|
||||||
<LearningPathProvider>
|
<LearningPathProvider>
|
||||||
<NotificationProvider>{children}</NotificationProvider>
|
<NotificationProvider>
|
||||||
|
<SkipToContent />
|
||||||
|
{children}
|
||||||
|
</NotificationProvider>
|
||||||
</LearningPathProvider>
|
</LearningPathProvider>
|
||||||
</SearchProvider>
|
</SearchProvider>
|
||||||
</ModalProvider>
|
</ModalProvider>
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import React from "react"
|
||||||
|
import clsx from "clsx"
|
||||||
|
import { translate } from "@docusaurus/Translate"
|
||||||
|
import { useBackToTopButton } from "@docusaurus/theme-common/internal"
|
||||||
|
import { Button, useNotifications } from "docs-ui"
|
||||||
|
import { ArrowUpMini } from "@medusajs/icons"
|
||||||
|
|
||||||
|
export default function BackToTopButton(): JSX.Element {
|
||||||
|
const { shown, scrollToTop } = useBackToTopButton({ threshold: 300 })
|
||||||
|
const { notifications } = useNotifications()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
aria-label={translate({
|
||||||
|
id: "theme.BackToTopButton.buttonAriaLabel",
|
||||||
|
message: "Scroll back to top",
|
||||||
|
description: "The ARIA label for the back to top button",
|
||||||
|
})}
|
||||||
|
className={clsx(
|
||||||
|
"fixed right-1 rounded-full !p-[10px] !border-0",
|
||||||
|
"shadow-flyout dark:shadow-flyout-dark !text-medusa-fg-subtle",
|
||||||
|
"!transition-all opacity-0 scale-0 invisible",
|
||||||
|
shown && "!opacity-100 !scale-100 !visible",
|
||||||
|
notifications.length && "bottom-4",
|
||||||
|
!notifications.length && "bottom-1"
|
||||||
|
)}
|
||||||
|
variant="secondary"
|
||||||
|
onClick={scrollToTop}
|
||||||
|
>
|
||||||
|
<ArrowUpMini />
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ export const NotificationItemLayoutDefault: React.FC<
|
|||||||
closeButtonText = "Close",
|
closeButtonText = "Close",
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="bg-medusa-bg-base w-full h-full shadow-flyout dark:shadow-flyout-dark rounded-docs_DEFAULT">
|
||||||
<div className={clsx("flex gap-docs_1 p-docs_1")}>
|
<div className={clsx("flex gap-docs_1 p-docs_1")}>
|
||||||
{type !== "none" && (
|
{type !== "none" && (
|
||||||
<div
|
<div
|
||||||
@@ -79,6 +79,6 @@ export const NotificationItemLayoutDefault: React.FC<
|
|||||||
<Button onClick={handleClose}>{closeButtonText}</Button>
|
<Button onClick={handleClose}>{closeButtonText}</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -36,8 +36,7 @@ export const NotificationItem = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"md:max-w-[320px] md:w-[320px] w-full bg-medusa-bg-base rounded-docs_DEFAULT",
|
"md:max-w-[320px] md:w-[320px] w-full",
|
||||||
"shadow-flyout dark:shadow-flyout-dark max-h-[calc(100vh-90px)]",
|
|
||||||
"fixed md:right-docs_1 left-0 md:m-docs_1",
|
"fixed md:right-docs_1 left-0 md:m-docs_1",
|
||||||
placement === "bottom" && "md:bottom-docs_1 bottom-0",
|
placement === "bottom" && "md:bottom-docs_1 bottom-0",
|
||||||
placement === "top" && "md:top-docs_1 top-0",
|
placement === "top" && "md:top-docs_1 top-0",
|
||||||
|
|||||||
@@ -24,7 +24,15 @@ export const NotificationContainer = () => {
|
|||||||
className?: string
|
className?: string
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
<TransitionGroup className={className}>
|
<TransitionGroup
|
||||||
|
className={clsx(
|
||||||
|
"flex fixed flex-col gap-docs_0.5 right-0",
|
||||||
|
"md:w-auto w-full overflow-y-auto",
|
||||||
|
"max-h-[50%] md:max-h-[calc(100vh-57px)]",
|
||||||
|
notifications.length && "max-[768px]:h-[50%]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
{notifications.filter(condition).map((notification) => (
|
{notifications.filter(condition).map((notification) => (
|
||||||
<CSSTransition
|
<CSSTransition
|
||||||
key={notification.id}
|
key={notification.id}
|
||||||
@@ -52,11 +60,11 @@ export const NotificationContainer = () => {
|
|||||||
<>
|
<>
|
||||||
{renderFilteredNotifications(
|
{renderFilteredNotifications(
|
||||||
(notification) => notification.placement === "top",
|
(notification) => notification.placement === "top",
|
||||||
"flex fixed flex-col gap-docs_0.5 right-0 top-0 md:w-auto w-full max-h-[calc(100vh-57px)] overflow-y-auto"
|
"top-0"
|
||||||
)}
|
)}
|
||||||
{renderFilteredNotifications(
|
{renderFilteredNotifications(
|
||||||
(notification) => notification.placement !== "top",
|
(notification) => notification.placement !== "top",
|
||||||
"flex flex-col gap-docs_0.5 fixed right-0 bottom-0 md:w-auto w-full max-h-[calc(100vh-57px)] overflow-y-auto"
|
"bottom-0"
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -560,6 +560,22 @@ module.exports = {
|
|||||||
opacity: 0.3,
|
opacity: 0.3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
minimize: {
|
||||||
|
from: {
|
||||||
|
transform: "scale(1)",
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
transform: "scale(0)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
maximize: {
|
||||||
|
from: {
|
||||||
|
transform: "scale(0)",
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
transform: "scale(1)",
|
||||||
|
},
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
animation: {
|
animation: {
|
||||||
fadeIn: "fadeIn 500ms",
|
fadeIn: "fadeIn 500ms",
|
||||||
@@ -576,6 +592,8 @@ module.exports = {
|
|||||||
slideInLeft: "slideInLeft 500ms",
|
slideInLeft: "slideInLeft 500ms",
|
||||||
slideOutLeft: "slideOutLeft 500ms",
|
slideOutLeft: "slideOutLeft 500ms",
|
||||||
pulsingDots: "pulsingDots 1s alternate infinite",
|
pulsingDots: "pulsingDots 1s alternate infinite",
|
||||||
|
minimize: "minimize 500ms",
|
||||||
|
maximize: "maximize 500ms",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
@@ -686,6 +704,9 @@ module.exports = {
|
|||||||
display: "none",
|
display: "none",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
".flip-y": {
|
||||||
|
transform: "rotateY(180deg)",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
addComponents({
|
addComponents({
|
||||||
".btn-secondary-icon": {
|
".btn-secondary-icon": {
|
||||||
|
|||||||
Reference in new issue
Block a user