Skip to content

Commit

Permalink
Merge pull request #1571 from ecency/feature/editor-tour
Browse files Browse the repository at this point in the history
Submit intro tour
  • Loading branch information
feruzm authored Mar 15, 2024
2 parents efccd02 + 77140cd commit dcf5cea
Show file tree
Hide file tree
Showing 11 changed files with 274 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/common/components/community-selector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ export class CommunitySelector extends BaseComponent<Props, State> {
<>
<a
href="#"
id="community-picker"
className="community-selector"
onClick={(e) => {
e.preventDefault();
Expand Down
6 changes: 5 additions & 1 deletion src/common/components/editor-toolbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,11 @@ export function EditorToolbar({

return (
<>
<div className={_c(`editor-toolbar ${sm ? "toolbar-sm" : ""}`)} ref={rootRef}>
<div
id="editor-toolbar"
className={_c(`editor-toolbar ${sm ? "toolbar-sm" : ""}`)}
ref={rootRef}
>
<Tooltip content={_t("editor-toolbar.bold")}>
<div className="editor-tool" onClick={bold}>
{formatBoldSvg}
Expand Down
5 changes: 4 additions & 1 deletion src/common/components/tag-selector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,10 @@ export class TagSelector extends Component<Props, State> {

return (
<>
<div className={_c(`tag-selector ${tags.length > 0 ? "has-tags" : ""}`)}>
<div
id="submit-tags-selector"
className={_c(`tag-selector ${tags.length > 0 ? "has-tags" : ""}`)}
>
<SuggestionList
renderer={(x: string) => {
return (
Expand Down
10 changes: 9 additions & 1 deletion src/common/features/ui/core/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { createContext, PropsWithChildren } from "react";
import { useSet } from "react-use";

export * from "./intro-step.interface";

export const UIContext = createContext<{
openPopovers: Set<string>;
addOpenPopover: (v: string) => void;
Expand All @@ -17,7 +19,13 @@ export function UIManager({ children }: PropsWithChildren<unknown>) {
);

return (
<UIContext.Provider value={{ openPopovers, addOpenPopover, removeOpenPopover }}>
<UIContext.Provider
value={{
openPopovers,
addOpenPopover,
removeOpenPopover
}}
>
{children}
</UIContext.Provider>
);
Expand Down
5 changes: 5 additions & 0 deletions src/common/features/ui/core/intro-step.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface IntroStep {
title: string;
message: string;
targetSelector: string;
}
1 change: 1 addition & 0 deletions src/common/features/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from "./alert";
export * from "./badge";
export * from "./pagination";
export * from "./core";
export * from "./intro-tour";
4 changes: 4 additions & 0 deletions src/common/features/ui/intro-tour/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.intro-tour-focused {
//z-index: 1041 !important;
position: relative !important;
}
154 changes: 154 additions & 0 deletions src/common/features/ui/intro-tour/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import React, { useEffect, useMemo, useState } from "react";
import { IntroStep } from "@ui/core";
import { useMountedState } from "react-use";
import { usePopper } from "react-popper";
import { createPortal } from "react-dom";
import { classNameObject } from "../../../helper/class-name-object";
import { Button } from "@ui/button";
import useLocalStorage from "react-use/lib/useLocalStorage";
import { PREFIX } from "../../../util/local-storage";
import "./index.scss";
import { DOMRect } from "sortablejs";

interface Props {
steps: IntroStep[];
id: string;
enabled: boolean;
forceActivation: boolean;
setForceActivation: (v: boolean) => void;
}

export function IntroTour({ steps, id, enabled, forceActivation, setForceActivation }: Props) {
const [currentStep, setCurrentStep, clearCurrentStep] = useLocalStorage<number | undefined>(
PREFIX + `_it_${id}`,
undefined
);
const [isFinished, setIsFinished] = useLocalStorage(PREFIX + `_itf_${id}`, false);

const [host, setHost] = useState<any>();
const [popperElement, setPopperElement] = useState<any>();
const [hostRect, setHostRect] = useState<DOMRect>();

const isMounted = useMountedState();
const popper = usePopper(host, popperElement, {
placement: "top"
});

const step = useMemo(
() => (typeof currentStep === "number" ? steps[currentStep] : undefined),
[currentStep, steps]
);
const totalSteps = useMemo(() => steps.length, [steps]);
const isFirstStep = useMemo(
() => typeof currentStep === "number" && currentStep > 0,
[currentStep]
);
const isLastStep = useMemo(() => steps.length - 1 === currentStep, [steps, currentStep]);
const clipPath = useMemo(
() =>
hostRect
? `polygon(0% 0%, 0% 100%, ${hostRect.x}px 100%, ${hostRect.x}px ${hostRect.y}px, ${
hostRect.x + hostRect.width
}px ${hostRect.y}px, ${hostRect.x + hostRect.width}px ${
hostRect.y + hostRect.height
}px, ${hostRect.x}px ${hostRect.y + hostRect.height}px, ${
hostRect.x
}px 100%, 100% 100%, 100% 0%)`
: "unset",
[hostRect]
);

// Detect enablement and set default step if there aren't any persistent step
useEffect(() => {
if (typeof currentStep === "undefined" && !isFinished && enabled) {
setCurrentStep(0);
}
}, [currentStep, enabled, isFinished]);

useEffect(() => {
if (forceActivation) {
setCurrentStep(0);
setIsFinished(false);

setForceActivation(false);
}
}, [forceActivation]);

// Re-attach host element based on host element
useEffect(() => {
host?.classList.remove("intro-tour-focused");

if (step) {
const nextHost = document.querySelector(step.targetSelector);
setHost(nextHost);

if (nextHost) {
setHostRect(nextHost.getBoundingClientRect());
nextHost.classList.add("intro-tour-focused");
}
} else {
setHost(null);
}
}, [step]);

const nextStep = () => {
if (typeof currentStep === "number" && currentStep < totalSteps - 1) {
setCurrentStep(currentStep + 1);
}
};

const prevStep = () => {
if (typeof currentStep === "number" && currentStep > 0) {
setCurrentStep(currentStep - 1);
}
};

const finish = () => {
clearCurrentStep();
setIsFinished(true);
};

return isMounted() && !isFinished ? (
<>
{createPortal(
<div
className={classNameObject({
"bg-black opacity-[50%] z-[1040] fixed top-0 left-0 right-0 bottom-0": true
})}
style={{ clipPath }}
onClick={() => finish()}
/>,
document.querySelector("#modal-overlay-container")!!
)}
{step &&
createPortal(
<div
className="p-3 border border-[--border-color] bg-white rounded-2xl flex flex-col gap-4 z-[1041] min-w-[200px] max-w-[400px]"
style={popper.styles.popper}
{...popper.attributes.popper}
ref={setPopperElement}
>
<div className="text-blue-dark-sky text-sm uppercase flex justify-between">
<span className="text-xs text-gray-600 mr-3">
{currentStep! + 1} of {steps.length}
</span>
{step?.title}
</div>
<div>{step?.message}</div>
<div className="flex justify-end gap-2 border-t border-[--border-color] pt-3">
{isFirstStep && (
<Button onClick={() => prevStep()} outline={true}>
Previous
</Button>
)}
{!isLastStep && <Button onClick={() => nextStep()}>Next</Button>}
{isLastStep && <Button onClick={() => finish()}>Finish</Button>}
</div>
</div>,
document.querySelector("#popper-container")!!
)}
</>
) : (
<></>
);
}
11 changes: 11 additions & 0 deletions src/common/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,7 @@
"title-placeholder": "Title",
"body-placeholder": "Tell your story...",
"reward": "Reward",
"take-tour": "Take a tour",
"reward-hint": "Set author reward ratio for liquid and staked tokens",
"reward-default": "Default 50% / 50%",
"reward-sp": "Power Up 100%",
Expand Down Expand Up @@ -2387,5 +2388,15 @@
"title": "Boost+",
"sub-title": "Boost your account using Ecency points",
"already-boosted-account": "This account boosted already"
},
"submit-tour": {
"title": "Post creating",
"title-hint": "You may to set any title for your post",
"tags-hint": "Tags helps to find out your post by special keywords",
"body-hint": "Post body is rich text which may contain various of different components, styles",
"community-hint": "Post may be attached to specific community which helps to promote your post within community members",
"toolbar-hint": "Toolbar allow to insert a lot of different components, apply formatting, insert images, videos and links",
"advanced-hint": "Configure advanced settings such as scheduling, beneficiaries",
"help-hint": "Have any questions? Check out help center"
}
}
4 changes: 2 additions & 2 deletions src/common/pages/submit/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@
background: transparent;
border: none;

&:focus {
&:focus, &.intro-tour-focused {
@include themify(day) {
background: lighten($yellow, 46);
@apply bg-warning-046;
}

@include themify(night) {
Expand Down
Loading

0 comments on commit dcf5cea

Please sign in to comment.