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:
92
www/docs/src/components/Feedback/Solutions/index.tsx
Normal file
92
www/docs/src/components/Feedback/Solutions/index.tsx
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
187
www/docs/src/components/Feedback/index.tsx
Normal file
187
www/docs/src/components/Feedback/index.tsx
Normal 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
|
||||
Reference in New Issue
Block a user