docs: refactor to use TypeScript, ESLint, and Tailwind CSS (#4136)

* docs(refactoring): configured eslint and typescript (#3511)

* docs: configured eslint and typescript

* fixed yarn.lock

* docs(refactoring): migrate components directory to typescript (#3517)

* docs: migrate components directory to typescript

* removed vscode settings

* fix following merge

* docs: refactored QueryNote component (#3576)

* docs: refactored first batch of theme components (#3579)

* docs: refactored second batch of theme components (#3580)

* added missing badge styles

* fix after merge

* docs(refactoring): migrated remaining component to TypeScript (#3770)

* docs(refactoring): configured eslint and typescript (#3511)

* docs: configured eslint and typescript

* fixed yarn.lock

* docs(refactoring): migrate components directory to typescript (#3517)

* docs: migrate components directory to typescript

* removed vscode settings

* fix following merge

* docs: refactored QueryNote component (#3576)

* docs: refactored first batch of theme components (#3579)

* docs: refactored second batch of theme components (#3580)

* added missing badge styles

* docs: refactoring second batch of theme components

* fix after merge

* refactored icons and other components

* docs: refactored all components

* docs(refactoring): set up and configured Tailwind Css (#3841)

* docs: added tailwind config

* docs: added more tailwind configurations

* add includes option

* added more tailwind configurations

* fix to configurations

* docs(refactoring): use tailwind css (#4134)

* docs: added tailwind config

* docs: added more tailwind configurations

* add includes option

* added more tailwind configurations

* fix to configurations

* docs(refactoring): refactored all styles to use tailwind css (#4132)

* refactored Badge component to use tailwind css

* refactored Bordered component to use tailwind css

* updated to latest docusaurus

* refactored BorderedIcon component to use tailwind css

* refactored Feedback component to use tailwind css

* refactored icons and footersociallinks to tailwind css

* start refactoring of large card

* refactored large card styling

* refactored until admonitions

* refactored until codeblock

* refactored until Tabs

* refactored Tabs (without testing

* finished refactoring styles to tailwind css

* upgraded to version 2.4.1

* general fixes

* adjusted eslint configurations

* fixed ignore files

* fixes to large card

* fix search styling

* fix npx command

* updated tabs to use isCodeTabs prop

* fixed os tabs

* removed os-tabs class in favor of general styling

* improvements to buttons

* fix for searchbar

* fixed redocly download button

* chore: added eslint code action (#4135)

* small change in commerce modules page
This commit is contained in:
Shahed Nasser
2023-05-19 14:56:48 +03:00
committed by GitHub
parent 29a88bbf98
commit 94907730d2
292 changed files with 11721 additions and 42102 deletions

View File

@@ -1,20 +0,0 @@
import React from "react"
import styles from "./styles.module.css"
import clsx from "clsx"
export default function Badge({ className, variant, children }) {
return (
<span
className={clsx(
styles.badge,
className,
variant === "purple" && styles.purpleBadge,
variant === "orange" && styles.orangeBadge,
variant === "green" && styles.greenBadge,
variant === "blue" && styles.blueBadge
)}
>
{children}
</span>
)
}

View File

@@ -0,0 +1,30 @@
import React from "react"
import clsx from "clsx"
export type BadgeProps = {
className?: string
variant: string
} & React.HTMLAttributes<HTMLSpanElement>
const Badge: React.FC<BadgeProps> = ({ className, variant, children }) => {
return (
<span
className={clsx(
"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 === "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 === "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 === "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",
className
)}
>
{children}
</span>
)
}
export default Badge

View File

@@ -1,33 +0,0 @@
.badge {
font-size: var(--medusa-label-x-small-plus-size);
line-height: var(--medusa-label-x-small-plus-line-height);
font-weight: var(--medusa-label-x-small-plus-font-weight);
padding: 1px 7px;
border-radius: var(--ifm-global-radius);
border: 1px solid;
text-align: center;
}
.purpleBadge {
background-color: var(--medusa-tag-purple-bg);
border-color: var(--medusa-tag-purple-border);
color: var(--medusa-tag-purple-text);
}
.orangeBadge {
background-color: var(--medusa-tag-orange-bg);
border-color: var(--medusa-tag-orange-border);
color: var(--medusa-tag-orange-text);
}
.greenBadge {
background-color: var(--medusa-tag-green-bg);
border-color: var(--medusa-tag-green-border);
color: var(--medusa-tag-green-text);
}
.blueBadge {
background-color: var(--medusa-tag-blue-bg);
border-color: var(--medusa-tag-blue-border);
color: var(--medusa-tag-blue-text);
}

View File

@@ -1,11 +0,0 @@
import React from "react"
import clsx from 'clsx'
import styles from './styles.module.css'
export default function Bordered ({ wrapperClassName, children }) {
return (
<span className={clsx(styles.elementWrapper, 'no-zoom-img', wrapperClassName)}>
{children}
</span>
)
}

View File

@@ -0,0 +1,22 @@
import React from "react"
import clsx from "clsx"
type BorderedProps = {
wrapperClassName?: string
} & React.HTMLAttributes<HTMLSpanElement>
const Bordered: React.FC<BorderedProps> = ({ wrapperClassName, children }) => {
return (
<span
className={clsx(
"tw-inline-flex tw-justify-center tw-items-center tw-rounded tw-p-[3px] tw-border tw-border-solid tw-border-medusa-border-strong dark:tw-border-medusa-border-strong-dark tw-mr-1 tw-w-fit tw-bg-docs-bg dark:tw-bg-docs-bg-dark",
"no-zoom-img",
wrapperClassName
)}
>
{children}
</span>
)
}
export default Bordered

View File

@@ -1,11 +0,0 @@
.elementWrapper {
display: inline-flex;
justify-content: center;
align-items: center;
border-radius: var(--ifm-global-radius);
padding: var(--bordered-padding);
border: 1px solid var(--bordered-border-color);
margin-right: var(--bordered-margin-right);
width: fit-content;
background-color: var(--ifm-background-color);
}

View File

@@ -1,21 +0,0 @@
import React from "react"
import ThemedImage from '@theme/ThemedImage'
import clsx from 'clsx'
import styles from './styles.module.css'
import Bordered from "../Bordered"
export default function BorderedIcon ({ icon = null, IconComponent = null, wrapperClassName, iconWrapperClassName, iconClassName }) {
return (
<Bordered wrapperClassName={wrapperClassName}>
<span className={clsx(styles.borderedIconWrapper, iconWrapperClassName)}>
{!IconComponent && (
<ThemedImage sources={{
light: icon.light,
dark: icon.dark || icon.light
}} className={clsx(styles.icon, iconClassName, 'bordered-icon')} />
)}
{IconComponent && <IconComponent className={clsx(styles.icon, iconClassName, 'bordered-icon')} />}
</span>
</Bordered>
)
}

View File

@@ -0,0 +1,55 @@
import React from "react"
import ThemedImage from "@theme/ThemedImage"
import clsx from "clsx"
import Bordered from "../Bordered/index"
import { IconProps } from "@site/src/theme/Icon/index"
type BorderedIconProp = {
icon?: {
light: string
dark?: string
}
IconComponent?: React.FC<IconProps>
wrapperClassName?: string
iconWrapperClassName?: string
iconClassName?: string
iconColorClassName?: string
} & React.HTMLAttributes<HTMLSpanElement>
const BorderedIcon: React.FC<BorderedIconProp> = ({
icon = null,
IconComponent = null,
wrapperClassName,
iconWrapperClassName,
iconClassName,
iconColorClassName = "",
}) => {
return (
<Bordered wrapperClassName={wrapperClassName}>
<span
className={clsx(
"tw-inline-flex tw-justify-center tw-items-center tw-rounded-sm tw-p-[2px] tw-bg-medusa-bg-component dark:tw-bg-medusa-bg-component-dark",
iconWrapperClassName
)}
>
{!IconComponent && (
<ThemedImage
sources={{
light: icon.light,
dark: icon.dark || icon.light,
}}
className={clsx(iconClassName, "bordered-icon")}
/>
)}
{IconComponent && (
<IconComponent
className={clsx(iconClassName, "bordered-icon")}
iconColorClassName={iconColorClassName}
/>
)}
</span>
</Bordered>
)
}
export default BorderedIcon

View File

@@ -1,8 +0,0 @@
.borderedIconWrapper {
display: inline-flex;
justify-content: center;
align-items: center;
border-radius: calc(var(--ifm-global-radius) / 2);
padding: var(--bordered-inside-padding);
background-color: var(--medusa-bg-component);
}

View File

@@ -0,0 +1,27 @@
import React from "react"
import clsx from "clsx"
type ButtonProps = {
className?: string
onClick?: React.MouseEventHandler<HTMLButtonElement>
disabled?: boolean
} & React.HTMLAttributes<HTMLButtonElement>
const Button: React.FC<ButtonProps> = ({
className = "",
onClick,
children,
...props
}) => {
return (
<button
className={clsx("btn-primary", className)}
onClick={onClick}
{...props}
>
{children}
</button>
)
}
export default Button

View File

@@ -1,78 +0,0 @@
import React from "react"
import { useThemeConfig } from '@docusaurus/theme-common'
import { Cloudinary } from "@cloudinary/url-gen";
import MDXImg from '@theme/MDXComponents/Img';
import { pad, imaggaScale, imaggaCrop, crop, fit, minimumPad, fill, scale, limitFit, thumbnail, limitFill, minimumFit, limitPad, fillPad } from "@cloudinary/url-gen/actions/resize";
import { byRadius } from "@cloudinary/url-gen/actions/roundCorners";
const resizeActions = {
'pad': pad,
'imaggaScale': imaggaScale,
'imaggaCrop': imaggaCrop,
'crop': crop,
'fit': fit,
'minimumPad': minimumPad,
'fill': fill,
'scale': scale,
'limitFit': limitFit,
'thumbnail': thumbnail,
'limitFill': limitFill,
'minimumFit': minimumFit,
'limitPad': limitPad,
'fillPad': fillPad
}
const imageRegex = /^https:\/\/res.cloudinary.com\/.*\/upload\/v[0-9]+\/(?<imageId>.*)$/
export default function CloudinaryImage ({ src, ...props }) {
const { cloudinaryConfig } = useThemeConfig();
const matchingRegex = src.match(imageRegex)
if (!cloudinaryConfig || !cloudinaryConfig.cloudName || !matchingRegex?.groups || !matchingRegex.groups.imageId) {
// either cloudinary isn't configured or
// could not match url to a cloudinary url
// default to docusaurus's image component
return <MDXImg src={src} {...props} />
}
const cloudinary = new Cloudinary({
cloud: {
cloudName: cloudinaryConfig.cloudName
}
});
let image = cloudinary.image(matchingRegex.groups.imageId.replaceAll('%20', ' '))
cloudinaryConfig.flags?.forEach((flag) => image.addTransformation(flag))
if (cloudinaryConfig.roundCorners) {
image.roundCorners(byRadius(cloudinaryConfig.roundCorners))
}
if (cloudinaryConfig.resize) {
const action = resizeActions[cloudinaryConfig.resize.action]
let resizeAction = action()
if (props.width || props.height) {
if (props.width) {
resizeAction = resizeAction.width(props.width)
}
if (props.height) {
resizeAction = resizeAction.height(props.height)
}
} else if (cloudinaryConfig.resize.aspectRatio) {
resizeAction = resizeAction.aspectRatio(cloudinaryConfig.resize.aspectRatio)
} else {
if (cloudinaryConfig.resize.width) {
resizeAction = resizeAction.width(cloudinaryConfig.resize.width)
}
if (cloudinaryConfig.resize.height) {
resizeAction = resizeAction.height(cloudinaryConfig.resize.height)
}
}
image.resize(resizeAction)
}
return (
<MDXImg {...props} src={image.toURL()} />
)
}

View File

@@ -0,0 +1,106 @@
import React from "react"
import { useThemeConfig } from "@docusaurus/theme-common"
// @ts-expect-error: wait until docusaurus uses type: module
import { Cloudinary } from "@cloudinary/url-gen"
import MDXImg, { Props as MDXImgProps } from "@theme/MDXComponents/Img"
import {
pad,
imaggaScale,
imaggaCrop,
crop,
fit,
minimumPad,
fill,
scale,
limitFit,
thumbnail,
limitFill,
minimumFit,
limitPad,
fillPad,
} from "@cloudinary/url-gen/actions/resize"
import { byRadius } from "@cloudinary/url-gen/actions/roundCorners"
import { ThemeConfig } from "@medusajs/docs"
const resizeActions = {
pad: pad,
imaggaScale: imaggaScale,
imaggaCrop: imaggaCrop,
crop: crop,
fit: fit,
minimumPad: minimumPad,
fill: fill,
scale: scale,
limitFit: limitFit,
thumbnail: thumbnail,
limitFill: limitFill,
minimumFit: minimumFit,
limitPad: limitPad,
fillPad: fillPad,
}
const imageRegex =
/^https:\/\/res.cloudinary.com\/.*\/upload\/v[0-9]+\/(?<imageId>.*)$/
type CloudinaryImageProps = MDXImgProps
const CloudinaryImage: React.FC<CloudinaryImageProps> = ({ src, ...props }) => {
const { cloudinaryConfig } = useThemeConfig() as ThemeConfig
const matchingRegex = src.match(imageRegex)
if (
!cloudinaryConfig ||
!matchingRegex?.groups ||
!matchingRegex.groups.imageId
) {
// either cloudinary isn't configured or
// could not match url to a cloudinary url
// default to docusaurus's image component
return <MDXImg src={src} {...props} />
}
const cloudinary = new Cloudinary({
cloud: {
cloudName: cloudinaryConfig.cloudName,
},
})
const image = cloudinary.image(
matchingRegex.groups.imageId.replaceAll("%20", " ")
)
cloudinaryConfig.flags?.forEach((flag) => image.addTransformation(flag))
if (cloudinaryConfig.roundCorners) {
image.roundCorners(byRadius(cloudinaryConfig.roundCorners))
}
if (cloudinaryConfig.resize) {
const action = resizeActions[cloudinaryConfig.resize.action]
let resizeAction = action()
if (props.width || props.height) {
if (props.width) {
resizeAction = resizeAction.width(props.width)
}
if (props.height) {
resizeAction = resizeAction.height(props.height)
}
} else if (cloudinaryConfig.resize.aspectRatio) {
resizeAction = resizeAction.aspectRatio(
cloudinaryConfig.resize.aspectRatio
)
} else {
if (cloudinaryConfig.resize.width) {
resizeAction = resizeAction.width(cloudinaryConfig.resize.width)
}
if (cloudinaryConfig.resize.height) {
resizeAction = resizeAction.height(cloudinaryConfig.resize.height)
}
}
image.resize(resizeAction)
}
return <MDXImg {...props} src={image.toURL()} />
}
export default CloudinaryImage

View File

@@ -0,0 +1,47 @@
import React, { useState, useEffect, useRef, useCallback } from "react"
// @ts-expect-error: wait until docusaurus uses type: module
import copy from "copy-text-to-clipboard"
import Tooltip from "@site/src/components/Tooltip"
import clsx from "clsx"
type CopyButtonProps = {
text: string
buttonClassName?: string
tooltipClassName?: string
} & React.HTMLAttributes<HTMLDivElement>
const CopyButton: React.FC<CopyButtonProps> = ({
text,
buttonClassName = "",
tooltipClassName = "",
children,
}) => {
const [isCopied, setIsCopied] = useState(false)
const copyTimeout = useRef(undefined)
const handleCopy = useCallback(() => {
copy(text)
setIsCopied(true)
copyTimeout.current = window.setTimeout(() => {
setIsCopied(false)
}, 1000)
}, [text])
useEffect(() => () => window.clearTimeout(copyTimeout.current), [])
return (
<Tooltip
text={isCopied ? `Copied!` : `Copy to Clipboard`}
tooltipClassName={tooltipClassName}
>
<span
className={clsx("tw-cursor-pointer", buttonClassName)}
onClick={handleCopy}
>
{children}
</span>
</Tooltip>
)
}
export default CopyButton

View File

@@ -0,0 +1,45 @@
import React from "react"
import icons from "@site/src/theme/Icon"
import BorderedIcon from "@site/src/components/BorderedIcon"
import clsx from "clsx"
type DocSidebarItemIconProps = {
icon?: string
is_title?: boolean
is_disabled?: boolean
} & React.HTMLAttributes<HTMLSpanElement>
const DocSidebarItemIcon: React.FC<DocSidebarItemIconProps> = ({
icon,
is_title,
is_disabled,
}) => {
const IconComponent = icons[icon]
return (
<>
{is_title && (
<BorderedIcon
icon={null}
IconComponent={IconComponent}
iconClassName={clsx("sidebar-item-icon")}
iconColorClassName={clsx(
is_disabled &&
"tw-stroke-medusa-icon-disabled dark:tw-stroke-medusa-icon-disabled-dark"
)}
/>
)}
{!is_title && (
<IconComponent
className={clsx("sidebar-item-icon")}
iconColorClassName={
is_disabled &&
"tw-stroke-medusa-icon-disabled dark:tw-stroke-medusa-icon-disabled-dark"
}
/>
)}
</>
)
}
export default DocSidebarItemIcon

View File

@@ -0,0 +1,92 @@
import React, { useEffect, useState } from "react"
import { request } from "@octokit/request"
// import "./index.css"
type SolutionsProps = {
feedback: boolean
message?: string
}
type GitHubSearchItem = {
url: string
html_url: string
title: string
[key: string]: unknown
}
const Solutions: React.FC<SolutionsProps> = ({ feedback, message }) => {
const [possibleSolutionsQuery, setPossibleSolutionsQuery] =
useState<string>("")
const [possibleSolutions, setPossibleSolutions] = useState<
GitHubSearchItem[]
>([])
function constructQuery(searchQuery: string) {
return `${searchQuery} repo:medusajs/medusa is:closed is:issue`
}
async function searchGitHub(query) {
return request(`GET /search/issues`, {
q: query,
sort: "updated",
per_page: 3,
})
}
useEffect(() => {
if (!feedback) {
let query = constructQuery(
// Github does not allow queries longer than 256 characters
message ? message.substring(0, 256) : document.title
)
searchGitHub(query)
.then(async (result) => {
if (!result.data.items.length && message) {
query = constructQuery(document.title)
result = await searchGitHub(query)
}
setPossibleSolutionsQuery(query)
setPossibleSolutions(result.data.items)
})
.catch((err) => console.error(err))
} else {
setPossibleSolutionsQuery("")
setPossibleSolutions([])
}
}, [feedback])
return (
<>
{possibleSolutions.length > 0 && (
<div className="tw-text-label-large-plus tw-font-normal">
<span className="tw-inline-block tw-my-1 tw-mx-0">
If you faced a problem, here are some possible solutions from
GitHub:
</span>
<ul>
{possibleSolutions.map((solution) => (
<li key={solution.url} className="tw-mb-0.5 last:tw-mb-0">
<a href={solution.html_url} target="_blank" rel="noreferrer">
{solution.title}
</a>
</li>
))}
</ul>
<span>
Explore more issues in{" "}
<a
href={`https://github.com/medusajs/medusa/issues?q=${possibleSolutionsQuery}`}
target="_blank"
rel="noreferrer"
>
the GitHub repository
</a>
</span>
</div>
)}
</>
)
}
export default Solutions

View File

@@ -1,139 +0,0 @@
.feedback-container {
padding-top: var(--ifm-base-margin-vertical);
padding-bottom: var(--ifm-base-margin-vertical);
}
.doc-footer .feedback-container {
border-top: 1px solid var(--ifm-doc-footer-border-color);
}
.inline-feedback {
display: flex;
flex-direction: row;
align-items: center;
}
.inline-question,
.feedback-message {
display: flex;
flex-direction: column;
}
.inline-feedback span {
margin-right: 24px;
font-size: var(--medusa-body-regular-size);
line-height: var(--medusa-body-regular-line-height);
font-weight: var(--medusa-body-regular-font-weight);
}
.inline-question span {
margin-bottom: calc(var(--ifm-base-margin-vertical) / 2);
}
.feedback-btn {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 6px 12px;
border-radius: var(--ifm-global-radius);
cursor: pointer;
background-color: var(--ifm-secondary-btn-background-color);
border: 1px solid var(--ifm-secondary-btn-border-color);
color: var(--ifm-secondary-btn-color);
font-size: var(--medusa-label-small-plus-size);
line-height: var(--medusa-label-small-plus-line-height);
font-weight: var(--medusa-label-small-plus-font-weight);
}
.feedback-btn:hover {
background-color: var(--ifm-secondary-btn-hover-background-color);
}
.feedback-btn:focus {
box-shadow: var(--ifm-secondary-btn-focused-shadow);
}
.feedback-btn:not(:last-child) {
margin-right: calc(var(--ifm-base-spacing) / 2);
}
.inline-question .feedback-btn {
margin-top: calc(var(--ifm-base-margin-vertical) / 2);
width: fit-content;
}
.inline-question textarea {
border-radius: 4px;
background-color: transparent;
border: 1px solid var(--ifm-base-border-color);
padding: 8px;
font-family: var(--ifm-font-family-base);
}
.feedback-message,
.solutions-wrapper {
font-size: var(--medusa-label-large-plus-size);
line-height: var(--medusa-label-large-plus-line-height);
}
.feedback-message {
font-weight: var(--medusa-label-large-plus-font-weight);
}
.solutions-wrapper {
font-weight: 400;
}
.solutions-message {
display: inline-block;
margin: calc(var(--ifm-base-margin-vertical) / 2) 0;
}
.solutions-wrapper li:not(:last-child) {
margin-bottom: calc(var(--ifm-base-margin-vertical) / 4);
}
.fade-in {
-webkit-animation: fade-in .3s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
animation: fade-in .3s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
}
@-webkit-keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.fade-out {
-webkit-animation: fade-out .3s ease-out both;
animation: fade-out .3s ease-out both;
}
@-webkit-keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}

View File

@@ -1,174 +0,0 @@
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 { request } from "@octokit/request";
export default function Feedback ({
event,
question = 'Was this page helpful?',
positiveBtn = 'Yes',
negativeBtn = 'No',
positiveQuestion = 'What was most helpful?',
negativeQuestion = 'What can we improve?',
submitBtn = 'Submit',
submitMessage = 'Thank you for helping improve our documentation!',
showPossibleSolutions = true
}) {
const [showForm, setShowForm] = useState(false);
const [submittedFeedback, setSubmittedFeedback] = useState(false);
const [loading, setLoading] = useState(false);
const inlineFeedbackRef = useRef(null);
const inlineQuestionRef = useRef(null);
const inlineMessageRef = useRef(null)
const [positiveFeedback, setPositiveFeedback] = useState(false);
const [message, setMessage] = useState("");
const [id, setId] = useState(null);
const [possibleSolutionsQuery, setPossibleSolutionsQuery] = useState('')
const [possibleSolutions, setPossibleSolutions] = useState([]);
const nodeRef = submittedFeedback ? inlineMessageRef : (showForm ? inlineQuestionRef : inlineFeedbackRef);
const isBrowser = useIsBrowser();
const location = useLocation();
function handleFeedback (e) {
const feedback = e.target.classList.contains('positive');
submitFeedback(e, feedback)
setPositiveFeedback(feedback);
setShowForm(true);
}
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);
checkAvailableSolutions(positiveFeedback, message);
resetForm();
}
})
} else {
if (showForm) {
resetForm();
}
}
}
}
function resetForm () {
setShowForm(false);
setSubmittedFeedback(true);
if (message) {
setId(null);
}
}
function constructQuery (searchQuery) {
return `${searchQuery} repo:medusajs/medusa is:closed is:issue`; //Github does not allow queries longer than 256 characters
}
function searchGitHub (query) {
return request(`GET /search/issues`, {
q: query,
sort: 'updated',
per_page: 3,
})
}
async function checkAvailableSolutions (feedback, message) {
if (showPossibleSolutions && !feedback) {
//fetch some possible solutions related to the answer.
let query = constructQuery(message ? message.substring(0, 256) : document.title)
let result = await searchGitHub(query);
if (!result.data.items.length && message) {
query = constructQuery(document.title)
result = await searchGitHub(query)
}
setPossibleSolutionsQuery(query);
setPossibleSolutions(result.data.items);
}
}
useEffect(() => {
if (!id) {
setId(uuid())
}
}, [id])
return (
<div className='feedback-container'>
<SwitchTransition mode="out-in">
<CSSTransition
key={showForm}
nodeRef={nodeRef}
timeout={300}
addEndListener={(done) => {
nodeRef.current.addEventListener("transitionend", done, false);
}}
classNames={{
enter: 'fade-in',
exit: 'fade-out'
}}
>
<>
{(!showForm && !submittedFeedback) && (
<div className='inline-feedback' ref={inlineFeedbackRef}>
<span>{question}</span>
<button className='positive feedback-btn' onClick={handleFeedback}>{positiveBtn}</button>
<button className='negative feedback-btn' onClick={handleFeedback}>{negativeBtn}</button>
</div>
)}
{(showForm && !submittedFeedback) && (
<div className='inline-question' ref={inlineQuestionRef}>
<span>{positiveFeedback ? positiveQuestion : negativeQuestion}</span>
<textarea rows={4} value={message} onChange={(e) => setMessage(e.target.value)}></textarea>
<button className='feedback-btn' onClick={submitFeedback} disabled={loading}>{submitBtn}</button>
</div>
)}
{submittedFeedback && (
<div className='feedback-message-wrapper'>
<div className='feedback-message' ref={inlineMessageRef}>
<span>{submitMessage}</span>
{possibleSolutions.length > 0 && (
<div className='solutions-wrapper'>
<span className='solutions-message'>If you faced a problem, here are some possible solutions from GitHub:</span>
<ul>
{possibleSolutions.map((solution) => (
<li key={solution.url}>
<a href={solution.html_url} target="_blank">{solution.title}</a>
</li>
))}
</ul>
<span>Explore more issues in <a
href={`https://github.com/medusajs/medusa/issues?q=${possibleSolutionsQuery}`}
target="_blank"
>
the GitHub repository
</a>
</span>
</div>
)}
</div>
</div>
)}
</>
</CSSTransition>
</SwitchTransition>
</div>
)
}

View File

@@ -0,0 +1,187 @@
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"
type FeedbackProps = {
event?: string
question?: string
positiveBtn?: string
negativeBtn?: string
positiveQuestion?: string
negativeQuestion?: string
submitBtn?: string
submitMessage?: string
showPossibleSolutions?: boolean
className?: string
} & React.HTMLAttributes<HTMLDivElement>
const Feedback: React.FC<FeedbackProps> = ({
event,
question = "Was this page helpful?",
positiveBtn = "Yes",
negativeBtn = "No",
positiveQuestion = "What was most helpful?",
negativeQuestion = "What can we improve?",
submitBtn = "Submit",
submitMessage = "Thank you for helping improve our documentation!",
showPossibleSolutions = true,
className = "",
}) => {
const [showForm, setShowForm] = useState(false)
const [submittedFeedback, setSubmittedFeedback] = useState(false)
const [loading, setLoading] = useState(false)
const inlineFeedbackRef = useRef(null)
const inlineQuestionRef = useRef(null)
const inlineMessageRef = useRef(null)
const [positiveFeedback, setPositiveFeedback] = useState(false)
const [message, setMessage] = useState("")
const [id, setId] = useState(null)
const nodeRef = submittedFeedback
? inlineMessageRef
: showForm
? inlineQuestionRef
: inlineFeedbackRef
const isBrowser = useIsBrowser()
const location = useLocation()
function handleFeedback(e) {
const feedback = e.target.classList.contains("positive")
submitFeedback(e, feedback)
setPositiveFeedback(feedback)
setShowForm(true)
}
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()
}
}
}
}
function resetForm() {
setShowForm(false)
setSubmittedFeedback(true)
if (message) {
setId(null)
}
}
useEffect(() => {
if (!id) {
setId(uuid())
}
}, [id])
return (
<div className={`tw-py-2 ${className}`}>
<SwitchTransition mode="out-in">
<CSSTransition
key={showForm}
nodeRef={nodeRef}
timeout={300}
addEndListener={(done) => {
nodeRef.current.addEventListener("transitionend", done, false)
}}
classNames={{
enter: "animate__animated animate__fadeIn",
exit: "animate__animated animate__fadeOut",
}}
>
<>
{!showForm && !submittedFeedback && (
<div
className="tw-flex tw-flex-row tw-items-center"
ref={inlineFeedbackRef}
>
<span className="tw-mr-1.5 tw-text-body-regular">
{question}
</span>
<Button
onClick={handleFeedback}
className="tw-w-fit tw-mr-0.5 last:tw-mr-0"
>
{positiveBtn}
</Button>
<Button
onClick={handleFeedback}
className="tw-w-fit tw-mr-0.5 last:tw-mr-0"
>
{negativeBtn}
</Button>
</div>
)}
{showForm && !submittedFeedback && (
<div className="tw-flex tw-flex-col" ref={inlineQuestionRef}>
<span className="tw-mb-1">
{positiveFeedback ? positiveQuestion : negativeQuestion}
</span>
<textarea
rows={4}
value={message}
onChange={(e) => setMessage(e.target.value)}
className="tw-rounded-sm tw-bg-transparent tw-border tw-border-medusa-border-base dark:tw-border-medusa-border-base-dark tw-p-1 tw-font-base"
></textarea>
<Button
onClick={submitFeedback}
disabled={loading}
className="tw-mt-1 tw-w-fit"
>
{submitBtn}
</Button>
</div>
)}
{submittedFeedback && (
<div>
<div
className="tw-flex tw-flex-col tw-text-label-large-plus"
ref={inlineMessageRef}
>
<span>{submitMessage}</span>
{showPossibleSolutions && (
<Solutions message={message} feedback={positiveFeedback} />
)}
</div>
</div>
)}
</>
</CSSTransition>
</SwitchTransition>
</div>
)
}
export default Feedback

View File

@@ -0,0 +1,43 @@
import React from "react"
import IconTwitter from "@site/src/theme/Icon/Twitter"
import IconGitHub from "@site/src/theme/Icon/GitHub"
import IconDiscord from "@site/src/theme/Icon/Discord"
import IconLinkedIn from "@site/src/theme/Icon/LinkedIn"
import { SocialLink } from "@medusajs/docs"
type SocialLinksProps = {
links?: SocialLink[]
} & React.HTMLAttributes<HTMLDivElement>
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" />
),
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" />
),
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" />
),
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" />
),
}
return (
<div className="tw-flex tw-items-center">
{links.map((link) => (
<a
className="tw-group tw-ml-1 first:tw-ml-0"
href={link.href}
key={link.type}
>
{socialIcons[link.type]}
</a>
))}
</div>
)
}
export default SocialLinks

View File

@@ -1,130 +0,0 @@
.large-card {
background-color: var(--large-card-bg);
border: 1px solid var(--large-card-border-color);
border-radius: var(--ifm-global-radius);
padding: calc(var(--ifm-base-margin-vertical) * 3) var(--ifm-base-spacing) calc(var(--ifm-base-margin-vertical) / 2);
display: flex;
flex-direction: column;
justify-content: space-between;
margin-bottom: var(--ifm-base-margin-vertical);
position: relative;
}
.large-card:not(.large-card-soon):hover,
.large-card:not(.large-card-soon):hover:before {
background-color: var(--large-card-bg-hover);
}
.large-card-soon:hover a {
pointer-events: none;
}
.large-card-soon:hover .large-card-title,
.large-card-soon:hover .large-card-content {
color: var(--medusa-text-disabled);
}
.large-card:before,
.large-card:after {
content: '';
position: absolute;
left: 0;
width: 100%;
border-radius: var(--ifm-global-radius);
}
.large-card:before {
z-index: 1;
height: calc(var(--ifm-base-margin-vertical) * 4);
top: 0;
background-image: var(--large-card-bg-image);
background-color: var(--large-card-bg);
}
.large-card:nth-child(3n+1):before {
background-position-x: 2%;
background-position-y: 52%;
}
.large-card:nth-child(3n + 2):before {
background-position-x: 19%;
background-position-y: 16%;
}
.large-card:nth-child(3n + 3):before {
background-position-x: 17%;
background-position-y: 50%;
}
.large-card:after {
z-index: 2;
left: 0;
top: calc(var(--ifm-base-margin-vertical) * 2);
height: calc(var(--ifm-base-margin-vertical) * 2);
background: var(--large-card-fade-effect);
}
.large-card:not(.large-card-soon):hover:after {
background: var(--large-card-fade-effect-hover);
}
.large-card > * {
z-index: 3;
}
.large-card-bordered-icon-wrapper {
--bordered-padding: var(--large-card-icon-wrapper-padding);
margin-bottom: calc(var(--ifm-base-margin-vertical) / 2);
}
.large-card-icon-wrapper {
--bordered-inside-padding: var(--large-card-icon-inside-padding);
}
.large-card-icon {
width: var(--large-card-icon-size);
height: var(--large-card-icon-size);
}
.large-card-heading {
margin-bottom: calc(var(--ifm-base-margin-vertical) / 4);
}
.large-card-title {
color: var(--ifm-color-primary);
font-size: var(--medusa-label-regular-plus-size);
line-height: var(--medusa-label-regular-plus-line-height);
font-weight: var(--medusa-label-regular-plus-font-weight);
}
.large-card-content {
font-size: var(--medusa-body-regular-size);
line-height: var(--medusa-body-regular-line-height);
font-weight: var(--medusa-body-regular-font-weight);
}
.large-card-title,
.large-card-content {
transition: all var(--ifm-transition-fast) ease;
}
.large-card-content ul {
padding-left: var(--ifm-base-spacing);
}
.large-card-link {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 4;
border-radius: var(--ifm-global-radius);
}
.large-card-badge {
position: absolute;
top: calc(var(--ifm-base-margin-vertical) / 2);
right: var(--ifm-base-spacing);
}

View File

@@ -1,43 +0,0 @@
import React from "react"
import './index.css'
import BorderedIcon from "../BorderedIcon"
import clsx from 'clsx';
import Badge from "../Badge";
export default function LargeCard ({
Icon,
image,
title,
action: {
href
},
isSoon = false,
children
}) {
return (
<article className={clsx(
'large-card',
isSoon && 'large-card-soon'
)}>
<div>
{isSoon && <Badge variant={'purple'} className={'large-card-badge'}>Guide coming soon</Badge>}
{(Icon || image) && (
<BorderedIcon
IconComponent={Icon}
icon={image}
iconClassName='large-card-icon'
wrapperClassName='large-card-bordered-icon-wrapper'
iconWrapperClassName='large-card-icon-wrapper'
/>
)}
<div className="large-card-heading">
<span className="large-card-title">{title}</span>
</div>
<div className="large-card-content">
{children}
</div>
</div>
<a href={href} className="large-card-link"></a>
</article>
)
}

View File

@@ -0,0 +1,96 @@
import React from "react"
import BorderedIcon from "../BorderedIcon"
import clsx from "clsx"
import Badge from "../Badge"
import { IconProps } from "@site/src/theme/Icon/index"
type LargeCardProps = {
Icon: React.FC<IconProps>
image: {
light: string
dark?: string
}
title: string
action: {
href: string
}
isSoon?: boolean
} & React.HTMLAttributes<HTMLDivElement>
const LargeCard: React.FC<LargeCardProps> = ({
Icon,
image,
title,
action: { href },
isSoon = false,
children,
}) => {
return (
<article
className={clsx(
"tw-group tw-bg-docs-bg-surface dark:tw-bg-docs-bg-surface-dark",
"tw-border tw-border-solid tw-border-medusa-border-base dark:tw-border-medusa-border-base-dark tw-rounded",
"tw-pt-6 tw-pb-1 tw-px-1 tw-mb-2",
"tw-flex tw-flex-col tw-justify-between tw-relative",
"before:tw-content-[''] before:tw-absolute before:tw-left-0 before:tw-w-full before:tw-rounded before:tw-z-[1] before:tw-h-8 before:tw-top-0",
"before:tw-bg-large-card dark:before:tw-bg-large-card-dark before:tw-bg-docs-bg-surface dark:before:tw-bg-docs-bg-surface-dark",
"[&: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%]",
"after:tw-content-[''] after:tw-absolute after:tw-left-0 after:tw-w-full after:tw-rounded",
"after:tw-z-[2] after:tw-left-0 after:tw-top-4 after:tw-height-4 after:tw-bg-large-card-fade dark:after:tw-bg-large-card-fade-dark",
!isSoon &&
"hover:after:tw-bg-large-card-fade-hover dark:hover:after:tw-bg-large-card-fade-hover",
!isSoon &&
"hover:tw-bg-medusa-bg-subtle-hover dark:hover:tw-bg-medusa-bg-base-hover-dark",
!isSoon &&
"hover:before:tw-bg-medusa-bg-subtle-hover dark:hover:before:tw-bg-medusa-bg-base-hover-dark"
)}
>
<div className={clsx("tw-z-[3]")}>
{isSoon && (
<Badge variant={"purple"} className="tw-absolute tw-top-1 tw-right-1">
Guide coming soon
</Badge>
)}
{(Icon || image) && (
<BorderedIcon
IconComponent={Icon}
icon={image}
iconClassName="tw-w-[20px] tw-h-[20px]"
wrapperClassName="tw-mb-1"
iconWrapperClassName="tw-p-[6px]"
/>
)}
<div className="tw-mb-0.5">
<span
className={clsx(
isSoon &&
"group-hover:tw-text-medusa-text-disabled dark:group-hover:tw-text-medusa-text-disabled-dark",
"tw-text-medusa-text-base dark:tw-text-medusa-text-base-dark tw-text-label-regular-plus",
"tw-transition-all tw-duration-200 tw-ease-ease"
)}
>
{title}
</span>
</div>
<div
className={clsx(
isSoon &&
"group-hover:tw-text-medusa-text-disabled dark:group-hover:tw-text-medusa-text-disabled-dark",
"tw-transition-all tw-duration-200 tw-ease-ease tw-text-body-regular"
)}
>
{children}
</div>
</div>
<a
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"
)}
></a>
</article>
)
}
export default LargeCard

View File

@@ -1,10 +0,0 @@
import React from "react"
import clsx from 'clsx'
export default function LargeCardList ({ colSize, className, children }) {
return (
<section className={clsx('cards-grid', `grid-${colSize || '4'}`, className)}>
{children}
</section>
)
}

View File

@@ -0,0 +1,21 @@
import React from "react"
import clsx from "clsx"
type LargeCardListProps = {
colSize?: string
className?: string
} & React.HTMLAttributes<HTMLDivElement>
const LargeCardList: React.FC<LargeCardListProps> = ({
colSize = "4",
className,
children,
}) => {
return (
<section className={clsx("cards-grid", `grid-${colSize}`, className)}>
{children}
</section>
)
}
export default LargeCardList

View File

@@ -0,0 +1,28 @@
import React from "react"
import CopyButton from "@site/src/components/CopyButton"
import type { Props } from "@theme/MDXComponents/Code"
import clsx from "clsx"
const MDXInlineCode: React.FC<Props> = (props) => {
return (
<CopyButton
text={props.children as string}
buttonClassName={clsx(
"tw-bg-transparent tw-border-0 tw-p-0 tw-inline tw-text-medusa-text-subtle dark:tw-text-medusa-text-subtle-dark",
"active:[&>code]:tw-bg-medusa-bg-subtle-pressed dark:active:[&>code]:tw-bg-medusa-bg-subtle-pressed-dark",
"focus:[&>code]:tw-bg-medusa-bg-subtle-pressed dark:focus:[&>code]:tw-bg-medusa-bg-subtle-pressed-dark",
"hover:[&>code]:tw-bg-medusa-bg-subtle-hover dark:hover:[&>code]:tw-bg-medusa-bg-base-hover-dark"
)}
>
<code
{...props}
className={clsx(
"tw-border tw-border-solid tw-border-medusa-border-base dark:tw-border-medusa-border-base-dark",
"tw-text-medusa-text-subtle dark:tw-text-medusa-text-subtle-dark tw-leading-6"
)}
/>
</CopyButton>
)
}
export default MDXInlineCode

View File

@@ -0,0 +1,46 @@
import React from "react"
import Tooltip from "@site/src/components/Tooltip"
import { NavbarAction } from "@medusajs/docs"
import Icon from "@site/src/theme/Icon"
import clsx from "clsx"
type NavbarActionsProps = {
items: NavbarAction[]
} & React.HTMLAttributes<HTMLDivElement>
const NavbarActions: React.FC<NavbarActionsProps> = ({ items = [] }) => {
return (
<div className="lg:tw-block tw-hidden">
{items.map((item, index) => {
switch (item.type) {
case "link":
// eslint-disable-next-line no-case-declarations
const ItemIcon = item.icon ? Icon[item.icon] : null
return (
<Tooltip text={item.title} key={index}>
<a
href={item.href}
title={item.title}
// className={`${ItemIcon ? "navbar-link-icon" : ""} ${
// item.className || ""
// }`}
className={clsx(
ItemIcon &&
"tw-bg-medusa-button-secondary dark:tw-bg-medusa-button-secondary-dark tw-border tw-border-solid tw-border-medusa-border-base dark:tw-border-medusa-border-base-dark tw-rounded tw-w-2 tw-h-2 tw-flex tw-justify-center tw-items-center hover:tw-bg-medusa-button-secondary-hover dark:hover:tw-bg-medusa-button-secondary-hover-dark",
item.className
)}
>
{item.label}
{ItemIcon && <ItemIcon />}
</a>
</Tooltip>
)
default:
return <></>
}
})}
</div>
)
}
export default NavbarActions

View File

@@ -1,25 +0,0 @@
import React from "react";
import { useQueryStringValue } from "@docusaurus/theme-common/internal"
import Admonition from "@theme/Admonition"
export default function QueryNote ({
query: {
key,
value = ''
},
//admonition props
admonition,
children
}) {
const queryValue = useQueryStringValue(key)
return (
<>
{queryValue === value && (
<Admonition {...admonition}>
{children}
</Admonition>
)}
</>
)
}

View File

@@ -0,0 +1,29 @@
import Admonition, { Props as AdmonitionProps } from "@theme/Admonition"
import { useQueryStringValue } from "@docusaurus/theme-common/internal"
import React from "react"
type QueryNoteProps = {
query: {
key: string
value?: string
}
admonition: AdmonitionProps
} & React.HTMLAttributes<HTMLDivElement>
const QueryNote: React.FC<QueryNoteProps> = ({
query: { key, value = "" },
admonition,
children,
}) => {
const queryValue = useQueryStringValue(key)
return (
<>
{queryValue === value && (
<Admonition {...admonition}>{children}</Admonition>
)}
</>
)
}
export default QueryNote

View File

@@ -0,0 +1,44 @@
import React from "react"
import Head from "@docusaurus/Head"
import { useLocation } from "@docusaurus/router"
import useDocusaurusContext from "@docusaurus/useDocusaurusContext"
import type { TOCItem } from "@docusaurus/mdx-loader"
type StructuredDataHowToProps = {
toc: readonly TOCItem[]
title: string
}
const StructuredDataHowTo: React.FC<StructuredDataHowToProps> = ({
toc,
title,
}) => {
const location = useLocation()
const {
siteConfig: { url },
} = useDocusaurusContext()
const mainUrl = `${url}/${location.pathname}`
return (
<Head>
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "HowTo",
name: title,
step: [
toc
.filter((item) => item.level === 2)
.map((item) => ({
"@type": "HowToStep",
text: item.value,
url: `${mainUrl}#${item.id}`,
})),
],
})}
</script>
</Head>
)
}
export default StructuredDataHowTo

View File

@@ -0,0 +1,33 @@
import React from "react"
import useDocusaurusContext from "@docusaurus/useDocusaurusContext"
import Head from "@docusaurus/Head"
type StructuredDataSearchboxProps = React.HTMLAttributes<HTMLScriptElement>
const StructuredDataSearchbox: React.FC<StructuredDataSearchboxProps> = () => {
const {
siteConfig: { url },
} = useDocusaurusContext()
return (
<Head>
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "WebSite",
url,
potentialAction: {
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate: `${url}/search?q={search_term_string}`,
},
"query-input": "required name=search_term_string",
},
})}
</script>
</Head>
)
}
export default StructuredDataSearchbox

View File

@@ -0,0 +1,40 @@
import React, { useState, useEffect } from "react"
import { Tooltip as ReactTooltip } from "react-tooltip"
import type { ITooltip } from "react-tooltip"
import uuid from "react-uuid"
import "react-tooltip/dist/react-tooltip.css"
type TooltipProps = {
text: string
tooltipClassName?: string
} & React.HTMLAttributes<HTMLSpanElement> &
ITooltip
const Tooltip: React.FC<TooltipProps> = ({
text,
tooltipClassName = "",
children,
}) => {
const [elementId, setElementId] = useState(null)
useEffect(() => {
if (!elementId) {
setElementId(uuid())
}
}, [elementId])
return (
<>
<span id={elementId} data-tooltip-content={text}>
{children}
</span>
<ReactTooltip
anchorId={elementId}
className={tooltipClassName}
wrapper="span"
/>
</>
)
}
export default Tooltip

View File

@@ -1,12 +0,0 @@
import React from 'react';
import ThemedImage from '@theme/ThemedImage';
export default function UiIcon ({ lightIcon, darkIcon = '', alt = '' }) {
return (
<ThemedImage alt={alt} sources={{
light: lightIcon,
dark: darkIcon || lightIcon
}} className="ui-icon" />
)
}

View File

@@ -0,0 +1,27 @@
import React from "react"
import ThemedImage from "@theme/ThemedImage"
type UiIconProps = {
lightIcon: string
darkIcon?: string
alt?: string
}
const UiIcon: React.FC<UiIconProps> = ({
lightIcon,
darkIcon = "",
alt = "",
}) => {
return (
<ThemedImage
alt={alt}
sources={{
light: lightIcon,
dark: darkIcon || lightIcon,
}}
className="tw-align-sub tw-w-[20px] tw-h-[20px]"
/>
)
}
export default UiIcon

View File

@@ -1,18 +0,0 @@
import React from "react"
const CloseIcon = ({ fill = "black" }) => (
<svg
width="15"
height="15"
viewBox="0 0 9 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.05 7.76L0.51 7.22L3.79 3.92L0.51 0.62L1.05 0.0799997L4.33 3.38L7.59 0.0799997L8.13 0.62L4.85 3.92L8.13 7.22L7.59 7.76L4.33 4.48L1.05 7.76Z"
fill={fill}
/>
</svg>
)
export default CloseIcon

View File

@@ -1,48 +0,0 @@
import React from "react"
const ConfLogo = ({ fill }) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 371.2226 96">
<title>medusa-logo-one-colour-rgb</title>
<g id="black-rgb">
<path
id="logoMark"
d="M77.8271,15.6225,56.08,3.0664a22.8877,22.8877,0,0,0-22.8877,0L11.4438,15.6225A22.8877,22.8877,0,0,0,0,35.4438V60.5562A22.8877,22.8877,0,0,0,11.4438,80.3775L33.1919,92.9336a22.8877,22.8877,0,0,0,22.8877,0L77.8271,80.3775A22.8876,22.8876,0,0,0,89.271,60.5562V35.4438A22.8876,22.8876,0,0,0,77.8271,15.6225ZM44.6357,70.3178A22.3178,22.3178,0,1,1,66.9531,48,22.3176,22.3176,0,0,1,44.6357,70.3178Z"
style="fill: #0a3149"
/>
<g id="type">
<path
id="type_CompoundPathItem_"
d="M163.5361,22.6571h14.1416V71.662H169.206V30.078L155.625,71.662h-8.8907l-13.581-41.0948V71.662h-8.4707V22.6571h14.2109l12.3906,39.2734Z"
style="fill: #0a3149"
/>
<path
id="type_CompoundPathItem_2"
d="M220.4453,60.6c-2.03,7.3516-8.2608,12.042-17.0118,12.042-10.9209,0-17.8525-7.3515-17.8525-18.4824s7.001-18.4814,18.0625-18.4814c12.3213,0,18.6914,9.24,15.332,20.7216H194.0517c.7012,5.8106,3.9209,9.2413,9.5215,9.2413,3.92,0,7.001-1.82,8.1914-5.0411Zm-26.253-9.871H211.414c.49-5.04-2.38-8.33-7.9111-8.33C198.2529,42.3993,195.0322,45.34,194.1923,50.7294Z"
style="fill: #0a3149"
/>
<path
id="type_CompoundPathItem_3"
d="M252.5742,22.6571h7.9814V71.662h-7.9814V66.4813a13.8489,13.8489,0,0,1-11.9014,6.1611c-9.24,0-15.752-7.3515-15.752-18.4824,0-11.06,6.4415-18.4814,15.752-18.4814a13.85,13.85,0,0,1,11.9014,6.16Zm.3506,31.5029c0-6.9306-3.9209-11.4814-9.8018-11.4814-5.95,0-9.87,4.5508-9.87,11.4814s3.92,11.4815,9.87,11.4815C249.0039,65.6415,252.9248,61.0907,252.9248,54.16Z"
style="fill: #0a3149"
/>
<path
id="type_CompoundPathItem_4"
d="M290.2333,36.6581h7.9805V71.662h-7.9805V65.3612c-2.4511,4.69-6.4414,7.1406-11.3417,7.1406-9.7305,0-11.2715-9.6611-11.2715-15.8916V36.6581h7.98V56.5409c0,4.62,1.0508,9.03,6.0918,9.03,5.18,0,8.541-4.62,8.541-11.0605Z"
style="fill: #0a3149"
/>
<path
id="type_CompoundPathItem_5"
d="M304.0888,59.1307H311.79c-.49,4.3408,2.7305,7.07,8.1914,7.07,4.2695,0,7.1406-1.68,7.1406-4.2,0-7.0009-22.5429-1.96-22.5429-15.0517,0-7,6.5107-11.27,14.9824-11.27,9.3808,0,16.1709,5.25,14.7011,13.1611h-7.7714c.98-3.99-2.17-6.7207-7-6.7207-4.0606,0-6.7207,1.82-6.7207,4.34,0,7.0713,22.6123,1.6807,22.6123,14.9825,0,7.07-6.3711,11.2011-15.4717,11.2011C310.04,72.6424,303.5292,67.6014,304.0888,59.1307Z"
style="fill: #0a3149"
/>
<path
id="type_CompoundPathItem_6"
d="M371.2226,51.78V71.662H363.872V65.5711a13.7856,13.7856,0,0,1-12.6015,7.0713c-7.42,0-12.0411-4.3408-12.0411-10.4316,0-7.07,6.16-11.3408,16.0313-11.3408a36.6377,36.6377,0,0,1,7.9814.91c0-5.3213-1.8906-9.1709-7.4912-9.1709-4.2,0-6.791,2.1-5.95,6.02H341.749c-1.89-7.77,4.9707-12.9511,14.0722-12.9511C366.0419,35.6786,371.2226,42.0487,371.2226,51.78Zm-7.7,6.0909a25.2,25.2,0,0,0-7.6308-1.19c-5.7413,0-8.5411,2.1006-8.5411,5.32,0,2.8008,2.1,4.27,5.53,4.27A10.8339,10.8339,0,0,0,363.5224,57.871Z"
style="fill: #0a3149"
/>
</g>
</g>
</svg>
)
export default ConfLogo