docs: documentation changes for release (#4300)
* docs: added manage reservations user guide (#4290) * docs: added manage reservations user guide * removed feature flag details * docs: added how-to for custom reservations (#4292) * docs: added how-to for custom reservations * eslint fixes * docs: added product module documentation (#4287) * docs: added product module documentation * added details about optional environment variables * small fixes * Remove reference link * added example usages * added link to sample project * address PR feedback * docs: moved product module guide + added product module tabs (#4307) * added product module tab * adjust design of badge * docs: added onboarding features (#4168) * added marketplace page * added subscription roadmap * added rating for onboarding * added learning path components * small fixes * fix build error * fix eslint errors * change roadmaps to recipes * small change in text * optimize learning path and notifications * fix tracking usage * fix eslint errors * added enter/exit animation * allow starting a path using a query parameter * fix gap between notifications * address vercel comments * fixed links issue * changed create-medusa-app docs steps * move troubleshooting section * improved tracking across docs * fix build errors * remove console * added a note about `boilerplate` option * added troubleshooting section for eagain * added invite option in cli reference * added track event for finished onboarding * update boilerplate option name * redesigned learning path component * docs: added how to create widget docs (#4318) * docs: added how to create widget docs * remove development guide * added types * docs: added details about createCustomAdminHooks (#4288) * docs: added details about createCustomAdminHooks * small improvement * added missing import * small changes * docs: added onboarding guide (#4320) * docs: added how to create widget docs * remove development guide * docs: added onboarding guide * added types * added recipes link * small adjustments * fixed eslint errors * styling fixes * change to singular product module * updated the what's new section * shorten down medusa react card * updated tailwind configurations * fix build error * fix newspaper icon * style fixes * change modal shadow * fix color of line numbers * fix code fade color * docs: updated admin documentations * eslint fixes * text changes * added a note about beta version * remove empty object argument * remove demo repo url * fix selection color for code headers * general fixes * fix eslint error * changed code theme * added preparation step * changes regarding beta version * Update docs/content/modules/products/serverless-module.md Co-authored-by: Riqwan Thamir <rmthamir@gmail.com> * Update docs/content/modules/products/serverless-module.md Co-authored-by: Riqwan Thamir <rmthamir@gmail.com> --------- Co-authored-by: Riqwan Thamir <rmthamir@gmail.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
@@ -13,12 +13,21 @@ const Badge: React.FC<BadgeProps> = ({ className, variant, children }) => {
|
||||
"tw-text-label-x-small-plus tw-py-px tw-px-0.4 tw-rounded tw-border tw-border-solid tw-text-center",
|
||||
variant === "purple" &&
|
||||
"tw-bg-medusa-tag-purple-bg dark:tw-bg-medusa-tag-purple-bg-dark tw-text-medusa-tag-purple-text dark:tw-text-medusa-tag-purple-text-dark tw-border-medusa-tag-purple-border dark:tw-border-medusa-tag-purple-border-dark",
|
||||
variant === "purple-dark" &&
|
||||
"tw-bg-medusa-tag-purple-bg-dark tw-text-medusa-tag-purple-text-dark tw-border-medusa-tag-purple-border-dark",
|
||||
variant === "orange" &&
|
||||
"tw-bg-medusa-tag-orange-bg dark:tw-bg-medusa-tag-orange-bg-dark tw-text-medusa-tag-orange-text dark:tw-text-medusa-tag-orange-text-dark tw-border-medusa-tag-orange-border dark:tw-border-medusa-tag-orange-border-dark",
|
||||
variant === "orange-dark" &&
|
||||
"tw-bg-medusa-tag-orange-bg-dark tw-text-medusa-tag-orange-text-dark tw-border-medusa-tag-orange-border-dark",
|
||||
variant === "green" &&
|
||||
"tw-bg-medusa-tag-green-bg dark:tw-bg-medusa-tag-green-bg-dark tw-text-medusa-tag-green-text dark:tw-text-medusa-tag-green-text-dark tw-border-medusa-tag-green-border dark:tw-border-medusa-tag-green-border-dark",
|
||||
variant === "green-dark" &&
|
||||
"tw-bg-medusa-tag-green-bg-dark tw-text-medusa-tag-green-text-dark tw-border-medusa-tag-green-border-dark",
|
||||
variant === "blue" &&
|
||||
"tw-bg-medusa-tag-blue-bg dark:tw-bg-medusa-tag-blue-bg-dark tw-text-medusa-tag-blue-text dark:tw-text-medusa-tag-blue-text-dark tw-border-medusa-tag-blue-border dark:tw-border-medusa-tag-blue-border-dark",
|
||||
variant === "blue-dark" &&
|
||||
"tw-bg-medusa-tag-blue-bg-dark tw-text-medusa-tag-blue-text-dark tw-border-medusa-tag-blue-border-dark",
|
||||
"badge",
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from "react"
|
||||
import clsx from "clsx"
|
||||
|
||||
type ButtonProps = {
|
||||
btnTypeClassName?: string
|
||||
className?: string
|
||||
onClick?: React.MouseEventHandler<HTMLButtonElement>
|
||||
disabled?: boolean
|
||||
@@ -9,13 +10,18 @@ type ButtonProps = {
|
||||
|
||||
const Button: React.FC<ButtonProps> = ({
|
||||
className = "",
|
||||
btnTypeClassName,
|
||||
onClick,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
className={clsx("btn-primary", className)}
|
||||
className={clsx(
|
||||
!btnTypeClassName?.length && "btn-primary",
|
||||
btnTypeClassName,
|
||||
className
|
||||
)}
|
||||
onClick={onClick}
|
||||
{...props}
|
||||
>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useRef, useState, useEffect } from "react"
|
||||
import { CSSTransition, SwitchTransition } from "react-transition-group"
|
||||
// import "./index.css"
|
||||
|
||||
import useIsBrowser from "@docusaurus/useIsBrowser"
|
||||
import { useLocation } from "@docusaurus/router"
|
||||
import uuid from "react-uuid"
|
||||
import Solutions from "./Solutions/index"
|
||||
import Button from "../Button"
|
||||
import { useUser } from "@site/src/providers/User"
|
||||
|
||||
type FeedbackProps = {
|
||||
event?: string
|
||||
@@ -50,6 +50,7 @@ const Feedback: React.FC<FeedbackProps> = ({
|
||||
|
||||
const isBrowser = useIsBrowser()
|
||||
const location = useLocation()
|
||||
const { track } = useUser()
|
||||
|
||||
function handleFeedback(e) {
|
||||
const feedback = e.target.classList.contains("positive")
|
||||
@@ -60,35 +61,28 @@ const Feedback: React.FC<FeedbackProps> = ({
|
||||
|
||||
function submitFeedback(e, feedback = null) {
|
||||
if (isBrowser) {
|
||||
if (window.analytics) {
|
||||
if (showForm) {
|
||||
setLoading(true)
|
||||
}
|
||||
window.analytics.track(
|
||||
event,
|
||||
{
|
||||
url: location.pathname,
|
||||
label: document.title,
|
||||
feedback:
|
||||
(feedback !== null && feedback) ||
|
||||
(feedback === null && positiveFeedback)
|
||||
? "yes"
|
||||
: "no",
|
||||
message: message?.length ? message : null,
|
||||
uuid: id,
|
||||
},
|
||||
function () {
|
||||
if (showForm) {
|
||||
setLoading(false)
|
||||
resetForm()
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
if (showForm) {
|
||||
resetForm()
|
||||
}
|
||||
if (showForm) {
|
||||
setLoading(true)
|
||||
}
|
||||
track(
|
||||
event,
|
||||
{
|
||||
url: location.pathname,
|
||||
label: document.title,
|
||||
feedback:
|
||||
(feedback !== null && feedback) ||
|
||||
(feedback === null && positiveFeedback)
|
||||
? "yes"
|
||||
: "no",
|
||||
message: message?.length ? message : null,
|
||||
},
|
||||
function () {
|
||||
if (showForm) {
|
||||
setLoading(false)
|
||||
resetForm()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +104,13 @@ const Feedback: React.FC<FeedbackProps> = ({
|
||||
<div className={`tw-py-2 ${className}`}>
|
||||
<SwitchTransition mode="out-in">
|
||||
<CSSTransition
|
||||
key={showForm}
|
||||
key={
|
||||
showForm
|
||||
? "show_form"
|
||||
: !submittedFeedback
|
||||
? "feedback"
|
||||
: "submitted_feedback"
|
||||
}
|
||||
nodeRef={nodeRef}
|
||||
timeout={300}
|
||||
addEndListener={(done) => {
|
||||
|
||||
@@ -12,16 +12,16 @@ type SocialLinksProps = {
|
||||
const SocialLinks: React.FC<SocialLinksProps> = ({ links = [] }) => {
|
||||
const socialIcons = {
|
||||
twitter: (
|
||||
<IconTwitter iconColorClassName="tw-fill-medusa-icon-placeholder dark:tw-fill-medusa-icon-placeholder-dark group-hover:tw-fill-medusa-icon-secondary dark:group-hover:tw-fill-medusa-icon-secondary-dark" />
|
||||
<IconTwitter iconColorClassName="tw-fill-medusa-icon-muted dark:tw-fill-medusa-icon-muted-dark group-hover:tw-fill-medusa-icon-subtle dark:group-hover:tw-fill-medusa-icon-subtle-dark" />
|
||||
),
|
||||
github: (
|
||||
<IconGitHub iconColorClassName="tw-fill-medusa-icon-placeholder dark:tw-fill-medusa-icon-placeholder-dark group-hover:tw-fill-medusa-icon-secondary dark:group-hover:tw-fill-medusa-icon-secondary-dark" />
|
||||
<IconGitHub iconColorClassName="tw-fill-medusa-icon-muted dark:tw-fill-medusa-icon-muted-dark group-hover:tw-fill-medusa-icon-subtle dark:group-hover:tw-fill-medusa-icon-subtle-dark" />
|
||||
),
|
||||
discord: (
|
||||
<IconDiscord iconColorClassName="tw-fill-medusa-icon-placeholder dark:tw-fill-medusa-icon-placeholder-dark group-hover:tw-fill-medusa-icon-secondary dark:group-hover:tw-fill-medusa-icon-secondary-dark" />
|
||||
<IconDiscord iconColorClassName="tw-fill-medusa-icon-muted dark:tw-fill-medusa-icon-muted-dark group-hover:tw-fill-medusa-icon-subtle dark:group-hover:tw-fill-medusa-icon-subtle-dark" />
|
||||
),
|
||||
linkedin: (
|
||||
<IconLinkedIn iconColorClassName="tw-fill-medusa-icon-placeholder dark:tw-fill-medusa-icon-placeholder-dark group-hover:tw-fill-medusa-icon-secondary dark:group-hover:tw-fill-medusa-icon-secondary-dark" />
|
||||
<IconLinkedIn iconColorClassName="tw-fill-medusa-icon-muted dark:tw-fill-medusa-icon-muted-dark group-hover:tw-fill-medusa-icon-subtle dark:group-hover:tw-fill-medusa-icon-subtle-dark" />
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ type LargeCardProps = {
|
||||
dark?: string
|
||||
}
|
||||
title: string
|
||||
action: {
|
||||
href: string
|
||||
action?: {
|
||||
href?: string
|
||||
}
|
||||
isSoon?: boolean
|
||||
className?: string
|
||||
@@ -23,7 +23,9 @@ const LargeCard: React.FC<LargeCardProps> = ({
|
||||
Icon,
|
||||
image,
|
||||
title,
|
||||
action: { href },
|
||||
action: { href } = {
|
||||
href: "",
|
||||
},
|
||||
isSoon = false,
|
||||
className = "",
|
||||
children,
|
||||
@@ -38,6 +40,9 @@ const LargeCard: React.FC<LargeCardProps> = ({
|
||||
"[&:nth-child(3n+1):before]:tw-bg-[2%_52%] [&:nth-child(3n+2):before]:tw-bg-[19%_16%] [&:nth-child(3n+3):before]:tw-bg-[17%_50%]",
|
||||
!isSoon &&
|
||||
"hover:tw-bg-medusa-bg-subtle-hover dark:hover:tw-bg-medusa-bg-base-hover-dark hover:tw-shadow-card-hover dark:hover:tw-shadow-card-hover-dark",
|
||||
!isSoon &&
|
||||
"group-hover:tw-bg-medusa-bg-subtle-hover dark:group-hover:tw-bg-medusa-bg-base-hover-dark group-hover:tw-shadow-card-hover dark:group-hover:tw-shadow-card-hover-dark",
|
||||
"tw-transition-all tw-duration-200 tw-ease-ease",
|
||||
"large-card",
|
||||
className
|
||||
)}
|
||||
@@ -79,13 +84,15 @@ const LargeCard: React.FC<LargeCardProps> = ({
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
href={href}
|
||||
className={clsx(
|
||||
"tw-absolute tw-top-0 tw-left-0 tw-w-full tw-h-full tw-z-[4] tw-rounded",
|
||||
isSoon && "group-hover:tw-pointer-events-none"
|
||||
)}
|
||||
></Link>
|
||||
{href && (
|
||||
<Link
|
||||
href={href}
|
||||
className={clsx(
|
||||
"tw-absolute tw-top-0 tw-left-0 tw-w-full tw-h-full tw-z-[4] tw-rounded",
|
||||
isSoon && "group-hover:tw-pointer-events-none"
|
||||
)}
|
||||
></Link>
|
||||
)}
|
||||
</article>
|
||||
)
|
||||
}
|
||||
|
||||
42
www/docs/src/components/LearningPath/Finish/index.tsx
Normal file
42
www/docs/src/components/LearningPath/Finish/index.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { LearningPathStepType } from "@site/src/providers/LearningPath"
|
||||
import React from "react"
|
||||
import Rating from "../../Rating"
|
||||
|
||||
export type LearningPathFinishType =
|
||||
| {
|
||||
type: "rating"
|
||||
step: Omit<LearningPathStepType, "descriptionJSX"> & {
|
||||
eventName?: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
type: "custom"
|
||||
step: LearningPathStepType & {
|
||||
descriptionJSX: JSX.Element
|
||||
}
|
||||
}
|
||||
|
||||
type LearningPathFinishProps = LearningPathFinishType & {
|
||||
onRating?: () => void
|
||||
}
|
||||
|
||||
const LearningPathFinish: React.FC<LearningPathFinishProps> = ({
|
||||
type,
|
||||
step,
|
||||
onRating,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{type === "rating" && (
|
||||
<Rating event={step.eventName} onRating={onRating} />
|
||||
)}
|
||||
{type === "custom" && (
|
||||
<span className="tw-text-label-small tw-text-medusa-text-subtle dark:tw-text-medusa-text-subtle-dark">
|
||||
{step.descriptionJSX}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default LearningPathFinish
|
||||
33
www/docs/src/components/LearningPath/Icon/index.tsx
Normal file
33
www/docs/src/components/LearningPath/Icon/index.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl"
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
|
||||
type LearningPathIconProps = {
|
||||
className?: string
|
||||
imgClassName?: string
|
||||
} & React.AllHTMLAttributes<HTMLDivElement>
|
||||
|
||||
const LearningPathIcon: React.FC<LearningPathIconProps> = ({
|
||||
className = "",
|
||||
imgClassName = "",
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"tw-rounded-full tw-shadow-card-rest dark:tw-shadow-card-rest-dark tw-w-3 tw-h-3 tw-bg-button-neutral dark:tw-bg-button-neutral-dark",
|
||||
"tw-flex tw-justify-center tw-items-center tw-flex-none",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<img
|
||||
src={useBaseUrl("/img/learning-path-img.png")}
|
||||
className={clsx(
|
||||
"tw-rounded-full tw-w-[40px] tw-h-[40px] no-zoom-img",
|
||||
imgClassName
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LearningPathIcon
|
||||
41
www/docs/src/components/LearningPath/Steps/Actions/index.tsx
Normal file
41
www/docs/src/components/LearningPath/Steps/Actions/index.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import Button from "@site/src/components/Button"
|
||||
import { useLearningPath } from "@site/src/providers/LearningPath"
|
||||
import React from "react"
|
||||
|
||||
type LearningPathStepActionsType = {
|
||||
onFinish?: () => void
|
||||
onClose?: () => void
|
||||
} & React.AllHTMLAttributes<HTMLDivElement>
|
||||
|
||||
const LearningPathStepActions: React.FC<LearningPathStepActionsType> = ({
|
||||
onFinish,
|
||||
onClose,
|
||||
}) => {
|
||||
const { hasNextStep, nextStep, endPath } = useLearningPath()
|
||||
|
||||
const handleFinish = () => {
|
||||
if (onFinish) {
|
||||
onFinish()
|
||||
} else {
|
||||
endPath()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="tw-flex tw-gap-0.5 tw-p-1 tw-justify-end tw-items-center">
|
||||
<Button onClick={onClose}>Close</Button>
|
||||
{hasNextStep() && (
|
||||
<Button onClick={nextStep} btnTypeClassName="btn-inverted">
|
||||
Next
|
||||
</Button>
|
||||
)}
|
||||
{!hasNextStep() && (
|
||||
<Button onClick={handleFinish} btnTypeClassName="btn-inverted">
|
||||
Finish
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LearningPathStepActions
|
||||
84
www/docs/src/components/LearningPath/Steps/index.tsx
Normal file
84
www/docs/src/components/LearningPath/Steps/index.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import { useLearningPath } from "@site/src/providers/LearningPath"
|
||||
import React from "react"
|
||||
import LearningPathStepActions from "./Actions"
|
||||
import clsx from "clsx"
|
||||
import IconCircleDottedLine from "@site/src/theme/Icon/CircleDottedLine"
|
||||
import IconCheckCircleSolid from "@site/src/theme/Icon/CheckCircleSolid"
|
||||
import IconCircleMiniSolid from "@site/src/theme/Icon/CircleMiniSolid"
|
||||
import Link from "@docusaurus/Link"
|
||||
|
||||
type LearningPathStepsProps = {
|
||||
onFinish?: () => void
|
||||
onClose?: () => void
|
||||
}
|
||||
|
||||
const LearningPathSteps: React.FC<LearningPathStepsProps> = ({ ...rest }) => {
|
||||
const { path, currentStep, goToStep } = useLearningPath()
|
||||
|
||||
if (!path) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{path.steps.map((step, index) => (
|
||||
<div
|
||||
className={clsx(
|
||||
"tw-border-0 tw-border-b tw-border-solid tw-border-medusa-border-base dark:tw-border-medusa-border-base-dark",
|
||||
"tw-relative tw-p-1"
|
||||
)}
|
||||
key={index}
|
||||
>
|
||||
<div className={clsx("tw-flex tw-items-center tw-gap-1")}>
|
||||
<div className="tw-w-2 tw-flex-none tw-flex tw-items-center tw-justify-center">
|
||||
{index === currentStep && (
|
||||
<IconCircleDottedLine
|
||||
className="tw-shadow-active dark:tw-shadow-active-dark tw-rounded-full"
|
||||
iconColorClassName="tw-stroke-medusa-icon-interactive dark:tw-stroke-medusa-icon-interactive-dark"
|
||||
/>
|
||||
)}
|
||||
{index < currentStep && (
|
||||
<IconCheckCircleSolid iconColorClassName="tw-fill-medusa-icon-interactive dark:tw-fill-medusa-icon-interactive-dark" />
|
||||
)}
|
||||
{index > currentStep && <IconCircleMiniSolid />}
|
||||
</div>
|
||||
<span
|
||||
className={clsx(
|
||||
"tw-text-label-regular-plus tw-text-medusa-text-base dark:tw-text-medusa-text-base-dark"
|
||||
)}
|
||||
>
|
||||
{step.title}
|
||||
</span>
|
||||
</div>
|
||||
{index === currentStep && (
|
||||
<div className={clsx("tw-flex tw-items-center tw-gap-1")}>
|
||||
<div className="tw-w-2 tw-flex-none"></div>
|
||||
<div
|
||||
className={clsx(
|
||||
"tw-text-body-regular tw-text-medusa-text-subtle dark:tw-text-medusa-text-subtle-dark tw-mt-1"
|
||||
)}
|
||||
>
|
||||
{step.descriptionJSX ?? step.description}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{index < currentStep && (
|
||||
<Link
|
||||
href={step.path}
|
||||
className={clsx(
|
||||
"tw-absolute tw-top-0 tw-left-0 tw-w-full tw-h-full"
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
goToStep(index)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<LearningPathStepActions {...rest} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LearningPathSteps
|
||||
96
www/docs/src/components/LearningPath/index.tsx
Normal file
96
www/docs/src/components/LearningPath/index.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import { useLearningPath } from "@site/src/providers/LearningPath"
|
||||
import { useNotifications } from "@site/src/providers/NotificationProvider"
|
||||
import { getLearningPath } from "@site/src/utils/learning-paths"
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl"
|
||||
import Button from "../Button"
|
||||
import IconCircleMiniSolid from "@site/src/theme/Icon/CircleMiniSolid"
|
||||
import LearningPathIcon from "./Icon"
|
||||
|
||||
type LearningPathProps = {
|
||||
pathName: string
|
||||
className?: string
|
||||
} & React.AllHTMLAttributes<HTMLDivElement>
|
||||
|
||||
const LearningPath: React.FC<LearningPathProps> = ({
|
||||
pathName,
|
||||
className = "",
|
||||
}) => {
|
||||
const path = getLearningPath(pathName)
|
||||
if (!path) {
|
||||
throw new Error("Learning path does not exist.")
|
||||
}
|
||||
const { startPath, path: currentPath } = useLearningPath()
|
||||
const notificationContext = useNotifications()
|
||||
|
||||
const handleClick = () => {
|
||||
if (notificationContext && currentPath?.notificationId) {
|
||||
notificationContext.removeNotification(currentPath.notificationId)
|
||||
}
|
||||
startPath(path)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"tw-rounded tw-shadow-card-rest dark:tw-shadow-card-rest-dark tw-bg-docs-bg-surface dark:tw-bg-docs-bg-surface-dark tw-mt-1.5 tw-mb-4",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
"tw-flex tw-items-center tw-gap-1 tw-p-1 tw-border-0 tw-border-b tw-border-solid tw-border-medusa-border-base dark:tw-border-medusa-border-base-dark"
|
||||
)}
|
||||
>
|
||||
<LearningPathIcon />
|
||||
<div className={clsx("tw-flex-auto")}>
|
||||
<span
|
||||
className={clsx(
|
||||
"tw-text-medusa-text-base dark:tw-text-medusa-text-base-dark tw-text-label-large-plus tw-block"
|
||||
)}
|
||||
>
|
||||
{path.label}
|
||||
</span>
|
||||
{path.description && (
|
||||
<span
|
||||
className={clsx(
|
||||
"tw-text-medusa-text-subtle dark:tw-text-medusa-text-subtle-dark tw-text-label-regular tw-mt-[4px] tw-inline-block"
|
||||
)}
|
||||
>
|
||||
{path.description}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<Button onClick={handleClick} className={clsx("tw-flex-initial")}>
|
||||
Start Path
|
||||
</Button>
|
||||
</div>
|
||||
{path.steps.map((step, index) => (
|
||||
<div
|
||||
className={clsx(
|
||||
"tw-flex tw-items-center tw-p-1 tw-gap-1",
|
||||
index !== path.steps.length - 1 &&
|
||||
"tw-border-0 tw-border-b tw-border-solid tw-border-medusa-border-base dark:tw-border-medusa-border-base-dark"
|
||||
)}
|
||||
key={index}
|
||||
>
|
||||
<div
|
||||
className={clsx("tw-w-3 tw-flex tw-items-center tw-justify-center")}
|
||||
>
|
||||
<IconCircleMiniSolid iconColorClassName="tw-stroke-medusa-icon-muted dark:tw-stroke-medusa-icon-muted-dark" />
|
||||
</div>
|
||||
<span
|
||||
className={clsx(
|
||||
"tw-text-medusa-text-base dark:tw-text-medusa-text-base-dark tw-text-label-regular-plus"
|
||||
)}
|
||||
>
|
||||
{step.title}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LearningPath
|
||||
61
www/docs/src/components/Notification/Container/index.tsx
Normal file
61
www/docs/src/components/Notification/Container/index.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import {
|
||||
NotificationItemType,
|
||||
useNotifications,
|
||||
} from "@site/src/providers/NotificationProvider"
|
||||
import React from "react"
|
||||
import NotificationItem from "../Item"
|
||||
import { CSSTransition, TransitionGroup } from "react-transition-group"
|
||||
import clsx from "clsx"
|
||||
|
||||
const NotificationContainer = () => {
|
||||
const { notifications, removeNotification } = useNotifications()
|
||||
|
||||
const handleClose = (notification: NotificationItemType) => {
|
||||
notification.onClose?.()
|
||||
removeNotification(notification.id)
|
||||
}
|
||||
|
||||
const renderFilteredNotifications = (
|
||||
condition: (notificaiton: NotificationItemType) => boolean,
|
||||
className?: string
|
||||
) => {
|
||||
return (
|
||||
<TransitionGroup className={className}>
|
||||
{notifications.filter(condition).map((notification) => (
|
||||
<CSSTransition
|
||||
key={notification.id}
|
||||
timeout={200}
|
||||
classNames={{
|
||||
enter: "animate__animated animate__slideInRight animate__fastest",
|
||||
exit: "animate__animated animate__slideOutRight animate__fastest",
|
||||
}}
|
||||
>
|
||||
<NotificationItem
|
||||
{...notification}
|
||||
onClose={() => handleClose(notification)}
|
||||
className={clsx(
|
||||
notification.className,
|
||||
"!tw-relative !tw-top-0 !tw-bottom-0 !tw-right-0"
|
||||
)}
|
||||
/>
|
||||
</CSSTransition>
|
||||
))}
|
||||
</TransitionGroup>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderFilteredNotifications(
|
||||
(notification) => notification.placement === "top",
|
||||
"tw-flex tw-fixed tw-flex-col tw-gap-0.5 md:tw-right-1 tw-right-0 md:tw-top-1 tw-top-0 tw-z-[400] md:tw-w-auto tw-w-full"
|
||||
)}
|
||||
{renderFilteredNotifications(
|
||||
(notification) => notification.placement !== "top",
|
||||
"tw-flex tw-flex-col tw-gap-0.5 tw-fixed md:tw-right-1 tw-right-0 md:tw-bottom-1 tw-bottom-0 tw-z-[400] md:tw-w-auto tw-w-full"
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotificationContainer
|
||||
@@ -0,0 +1,90 @@
|
||||
import React from "react"
|
||||
import { NotificationItemProps } from "../.."
|
||||
import clsx from "clsx"
|
||||
import IconInformationCircleSolid from "@site/src/theme/Icon/InformationCircleSolid"
|
||||
import IconXCircleSolid from "@site/src/theme/Icon/XCircleSolid"
|
||||
import IconExclamationCircleSolid from "@site/src/theme/Icon/ExclamationCircleSolid"
|
||||
import IconCheckCircleSolid from "@site/src/theme/Icon/CheckCircleSolid"
|
||||
import Button from "@site/src/components/Button"
|
||||
|
||||
type NotificationItemLayoutDefaultProps = NotificationItemProps & {
|
||||
handleClose: () => void
|
||||
}
|
||||
|
||||
const NotificationItemLayoutDefault: React.FC<
|
||||
NotificationItemLayoutDefaultProps
|
||||
> = ({
|
||||
type = "info",
|
||||
title = "",
|
||||
text = "",
|
||||
children,
|
||||
isClosable = true,
|
||||
handleClose,
|
||||
CustomIcon,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className={clsx("tw-flex tw-gap-1 tw-p-1")}>
|
||||
{type !== "none" && (
|
||||
<div
|
||||
className={clsx(
|
||||
type !== "custom" &&
|
||||
"tw-w-2 tw-flex tw-justify-center tw-items-center"
|
||||
)}
|
||||
>
|
||||
{type === "info" && (
|
||||
<IconInformationCircleSolid iconColorClassName="tw-fill-medusa-support-info dark:tw-fill-medusa-support-info-dark" />
|
||||
)}
|
||||
{type === "error" && (
|
||||
<IconXCircleSolid iconColorClassName="tw-fill-medusa-tag-red-icon dark:tw-fill-medusa-tag-red-icon-dark" />
|
||||
)}
|
||||
{type === "warning" && (
|
||||
<IconExclamationCircleSolid iconColorClassName="tw-fill-medusa-tag-orange-icon dark:tw-fill-medusa-tag-orange-icon-dark" />
|
||||
)}
|
||||
{type === "success" && (
|
||||
<IconCheckCircleSolid iconColorClassName="tw-fill-medusa-tag-green-icon dark:tw-fill-medusa-tag-green-icon-dark" />
|
||||
)}
|
||||
{type === "custom" && CustomIcon}
|
||||
</div>
|
||||
)}
|
||||
<span
|
||||
className={clsx(
|
||||
"tw-text-label-regular-plus",
|
||||
"tw-text-medusa-text-base dark:tw-text-medusa-text-base-dark"
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
</div>
|
||||
{(text || children) && (
|
||||
<div
|
||||
className={clsx(
|
||||
"tw-flex tw-pt-0 tw-pr-1 tw-pb-1.5 tw-pl-1 tw-gap-1",
|
||||
"tw-border-0 tw-border-b tw-border-solid tw-border-medusa-border-base dark:tw-border-medusa-border-base-dark"
|
||||
)}
|
||||
>
|
||||
<div className="tw-w-2 tw-flex-none"></div>
|
||||
<div className={clsx("tw-flex tw-flex-col", children && "tw-gap-1")}>
|
||||
{text && (
|
||||
<span
|
||||
className={clsx(
|
||||
"tw-text-body-regular tw-text-medusa-text-subtle dark:tw-text-medusa-text-subtle-dark"
|
||||
)}
|
||||
>
|
||||
{text}
|
||||
</span>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isClosable && (
|
||||
<div className={clsx("tw-p-1 tw-flex tw-justify-end tw-items-center")}>
|
||||
<Button onClick={handleClose}>Close</Button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotificationItemLayoutDefault
|
||||
63
www/docs/src/components/Notification/Item/index.tsx
Normal file
63
www/docs/src/components/Notification/Item/index.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import clsx from "clsx"
|
||||
import React, { Children, ReactElement, useEffect, useRef } from "react"
|
||||
import NotificationItemLayoutDefault from "./Layout/Default"
|
||||
|
||||
export type NotificationItemProps = {
|
||||
layout?: "default" | "empty"
|
||||
type?: "info" | "error" | "warning" | "success" | "custom" | "none"
|
||||
CustomIcon?: React.ReactNode
|
||||
title?: string
|
||||
text?: string
|
||||
className?: string
|
||||
children?: ReactElement
|
||||
isClosable?: boolean
|
||||
placement?: "top" | "bottom"
|
||||
show?: boolean
|
||||
setShow?: (value: boolean) => void
|
||||
onClose?: () => void
|
||||
} & React.HTMLAttributes<HTMLDivElement>
|
||||
|
||||
const Notification = ({
|
||||
className = "",
|
||||
placement = "bottom",
|
||||
show = true,
|
||||
layout = "default",
|
||||
setShow,
|
||||
onClose,
|
||||
children,
|
||||
...rest
|
||||
}: NotificationItemProps) => {
|
||||
const handleClose = () => {
|
||||
setShow?.(false)
|
||||
onClose?.()
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"md:tw-max-w-[320px] md:tw-w-[320px] tw-w-full tw-bg-medusa-bg-base dark:tw-bg-medusa-bg-base-dark tw-rounded",
|
||||
"tw-shadow-flyout dark:tw-shadow-flyout-dark",
|
||||
"tw-fixed md:tw-right-1 tw-left-0 tw-block tw-z-[400]",
|
||||
placement === "bottom" && "md:tw-bottom-1 tw-bottom-0",
|
||||
placement === "top" && "md:tw-top-1 tw-top-0",
|
||||
"tw-opacity-100 tw-transition-opacity tw-duration-200 tw-ease-ease",
|
||||
!show && "!tw-opacity-0",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{layout === "default" && (
|
||||
<NotificationItemLayoutDefault {...rest} handleClose={handleClose}>
|
||||
{children}
|
||||
</NotificationItemLayoutDefault>
|
||||
)}
|
||||
{layout === "empty" &&
|
||||
Children.map(children, (child) =>
|
||||
React.cloneElement(child, {
|
||||
onClose: handleClose,
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Notification
|
||||
80
www/docs/src/components/Rating/index.tsx
Normal file
80
www/docs/src/components/Rating/index.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import { useUser } from "@site/src/providers/User"
|
||||
import IconStar from "@site/src/theme/Icon/Star"
|
||||
import IconStarSolid from "@site/src/theme/Icon/StarSolid"
|
||||
import clsx from "clsx"
|
||||
import React, { useRef, useState } from "react"
|
||||
|
||||
type RatingProps = {
|
||||
event?: string
|
||||
className?: string
|
||||
onRating?: () => void
|
||||
} & React.HTMLAttributes<HTMLDivElement>
|
||||
|
||||
const Rating: React.FC<RatingProps> = ({
|
||||
event = "rating",
|
||||
className = "",
|
||||
onRating,
|
||||
}) => {
|
||||
const [rating, setRating] = useState(0)
|
||||
const [hoverRating, setHoverRating] = useState(0)
|
||||
const starElms = useRef<HTMLElement[]>([])
|
||||
const starArr = Array.from(Array(5).keys())
|
||||
const { track } = useUser()
|
||||
|
||||
const handleRating = (selectedRating: number) => {
|
||||
if (rating) {
|
||||
return
|
||||
}
|
||||
setHoverRating(0)
|
||||
setRating(selectedRating)
|
||||
for (let i = 0; i < selectedRating; i++) {
|
||||
starElms.current[i].classList.add("animate__animated", "animate__tada")
|
||||
}
|
||||
track(
|
||||
event,
|
||||
{
|
||||
rating: selectedRating,
|
||||
},
|
||||
() => onRating?.()
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={clsx("tw-flex tw-gap-0.5", className)}>
|
||||
{starArr.map((i) => {
|
||||
const isSelected =
|
||||
(rating !== 0 && rating - 1 >= i) ||
|
||||
(hoverRating !== 0 && hoverRating - 1 >= i)
|
||||
return (
|
||||
<button
|
||||
className="transparent-button"
|
||||
ref={(element) => {
|
||||
if (starElms.current.length - 1 < i) {
|
||||
starElms.current.push(element)
|
||||
}
|
||||
}}
|
||||
key={i}
|
||||
onMouseOver={() => {
|
||||
if (!rating) {
|
||||
setHoverRating(i + 1)
|
||||
}
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
if (!rating) {
|
||||
setHoverRating(0)
|
||||
}
|
||||
}}
|
||||
onClick={() => handleRating(i + 1)}
|
||||
>
|
||||
{!isSelected && <IconStar />}
|
||||
{isSelected && (
|
||||
<IconStarSolid iconColorClassName="tw-fill-medusa-tag-orange-icon dark:tw-fill-medusa-tag-orange-icon-dark" />
|
||||
)}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Rating
|
||||
Reference in New Issue
Block a user