Skip to content

Commit

Permalink
feat: optimize new user guide
Browse files Browse the repository at this point in the history
  • Loading branch information
DIYgod committed Oct 21, 2024
1 parent 8678de0 commit 4583b3b
Show file tree
Hide file tree
Showing 12 changed files with 266 additions and 371 deletions.
15 changes: 12 additions & 3 deletions apps/renderer/src/modules/activation/ActivationModalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { Input } from "~/components/ui/input"
import { useCurrentModal } from "~/components/ui/modal"
import { getFetchErrorMessage } from "~/lib/error-parser"
import { cn } from "~/lib/utils"
import confettiUrl from "~/lottie/confetti.lottie?url"
import { auth } from "~/queries/auth"
import { useInvitationMutation } from "~/queries/invitations"
Expand All @@ -26,7 +27,13 @@ const formSchema = z.object({
code: z.string().min(1),
})
const absoluteConfettiUrl = new URL(confettiUrl, import.meta.url).href
export const ActivationModalContent = () => {
export const ActivationModalContent = ({
className,
hideDescription,
}: {
className?: string
hideDescription?: boolean
}) => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
})
Expand Down Expand Up @@ -64,14 +71,16 @@ export const ActivationModalContent = () => {
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="w-[512px] max-w-full overflow-hidden px-0.5"
className={cn("w-[512px] max-w-full overflow-hidden px-0.5", className)}
>
<FormField
control={form.control}
name="code"
render={({ field }) => (
<FormItem className="flex flex-col items-center gap-2 md:block">
<FormLabel className="!text-foreground">{t("activation.description")}</FormLabel>
{!hideDescription && (
<FormLabel className="!text-foreground">{t("activation.description")}</FormLabel>
)}
<FormControl>
<Input
className="font-mono placeholder:font-default"
Expand Down
16 changes: 11 additions & 5 deletions apps/renderer/src/modules/discover/recommendations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import { useMemo } from "react"
import { useTranslation } from "react-i18next"

import { useAuthQuery } from "~/hooks/common"
import { isASCII } from "~/lib/utils"
import { cn, isASCII } from "~/lib/utils"
import { Queries } from "~/queries"

import { RecommendationCard } from "./recommendations-card"

export function Recommendations() {
export function Recommendations({
hideTitle,
className,
}: {
hideTitle?: boolean
className?: string
}) {
const rsshubPopular = useAuthQuery(
Queries.discover.rsshubCategory({
category: "popular",
Expand Down Expand Up @@ -56,10 +62,10 @@ export function Recommendations() {
}

return (
<div className="mt-8">
<div className="text-center text-lg font-bold">{t("discover.popular")}</div>
<div className={cn(!hideTitle && "mt-8")}>
{!hideTitle && <div className="text-center text-lg font-bold">{t("discover.popular")}</div>}

<div className="mt-4 grid grid-cols-3 gap-4 px-3">
<div className={cn("mt-4 grid grid-cols-3 gap-4 px-3", className)}>
{keys.map((key) => (
<RecommendationCard key={key} data={data[key]} routePrefix={key} />
))}
Expand Down
12 changes: 0 additions & 12 deletions apps/renderer/src/modules/new-user-guide/atoms.ts

This file was deleted.

148 changes: 66 additions & 82 deletions apps/renderer/src/modules/new-user-guide/guide-modal-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@ import { mountLottie } from "~/components/ui/lottie-container"
import { Markdown } from "~/components/ui/markdown/Markdown"
import { useI18n } from "~/hooks/common"
import confettiUrl from "~/lottie/confetti.lottie?url"
import { MyWalletSection } from "~/modules/power/my-wallet-section"
import { settings } from "~/queries/settings"

import { ActivationModalContent } from "../activation/ActivationModalContent"
import { DiscoverImport } from "../discover/import"
import { ProfileSettingForm } from "../profile/profile-setting-form"
import { settingSyncQueue } from "../settings/helper/sync-queue"
import { LanguageSelector } from "../settings/tabs/general"
import { useHaveUsedOtherRSSReader } from "./atoms"
import { BehaviorGuide } from "./steps/behavior"
import { TrendingFeeds } from "./steps/feeds"
import { Introduction } from "./steps/introduction"
import { RookieCheck } from "./steps/rookie"
import { RSSHubGuide } from "./steps/rsshub"

const containerWidth = 600
Expand Down Expand Up @@ -51,7 +50,7 @@ function Intro() {
return (
<div className="w-[50ch] space-y-4 text-balance text-center">
<Logo className="mx-auto size-20" />
<p className="mt-5 text-xl font-semibold">{t("new_user_guide.intro.title")}</p>
<p className="mt-5 text-xl font-bold">{t("new_user_guide.intro.title")}</p>
<p className="text-lg">{t("new_user_guide.intro.description")}</p>
<LanguageSelector containerClassName="px-16" contentClassName="z-10" />
</div>
Expand All @@ -73,90 +72,67 @@ export function GuideModalContent({ onClose }: { onClose: () => void }) {
const t = useI18n()
const [step, setStep] = useState(0)
const [direction, setDirection] = useState(1)
const haveUsedOtherRSSReader = useHaveUsedOtherRSSReader()

const guideSteps = useMemo(
() =>
[
{
icon: "i-mgc-grid-cute-re",
title: "Features",
content: createElement(Introduction, {
features: [
{
icon: "i-mgc-magic-2-cute-re",
title: t.settings("titles.actions"),
description: t.app("new_user_guide.step.features.actions.description"),
},
{
icon: "i-mgc-department-cute-re",
title: t.settings("titles.integration"),
description: t.app("new_user_guide.step.features.integration.description"),
},
{
icon: "i-mgc-rada-cute-re",
title: t.settings("titles.lists"),
description: t.settings("lists.info"),
},
{
icon: "i-mgc-hotkey-cute-re",
title: t.settings("titles.shortcuts"),
description: (
<p>
{t.app("new_user_guide.step.features.shortcuts.description1")}{" "}
<Trans
i18nKey="new_user_guide.step.features.shortcuts.description2"
components={{
kbd: <Kbd>H</Kbd>,
}}
/>
</p>
),
},
],
}),
title: t.app("new_user_guide.step.migrate.profile"),
content: <ProfileSettingForm className="w-[500px]" buttonClassName="text-center !mt-8" />,
icon: "i-mgc-user-setting-cute-re",
},
{
title: "Power",
icon: "i-mgc-power",
content: (
<Markdown className="max-w-xl">
{t.app("new_user_guide.step.power.description")}
</Markdown>
),
title: t.app("new_user_guide.step.activation.title"),
description: t.app("new_user_guide.step.activation.description"),
content: <ActivationModalContent className="w-[500px]" hideDescription />,
icon: "i-mgc-love-cute-re",
},
{
title: t.app("new_user_guide.step.start_question.title"),
content: createElement(RookieCheck),
icon: "i-mgc-question-cute-re",
title: t.app("new_user_guide.step.migrate.wallet"),
content: <MyWalletSection className="w-[600px]" />,
icon: <i className="i-mgc-power text-accent" />,
},
haveUsedOtherRSSReader && {
title: t.app("new_user_guide.step.behavior.title"),
{
title: t.app("new_user_guide.step.behavior.unread_question.content"),
description: t.app("new_user_guide.step.behavior.unread_question.description"),
content: createElement(BehaviorGuide),
icon: tw`i-mingcute-cursor-3-line`,
icon: tw`i-mgc-cursor-3-cute-re`,
},
{
title: t.app("new_user_guide.step.migrate.title"),
content: createElement(DiscoverImport),
icon: "i-mgc-file-import-cute-re",
},
{
title: t.app("new_user_guide.step.rsshub.title"),
description: t.app("new_user_guide.step.rsshub.info"),
content: createElement(RSSHubGuide),
icon: <img src={RSSHubIcon} className="size-[22px]" />,
},
haveUsedOtherRSSReader
? {
title: t.app("new_user_guide.step.import.title"),
content: createElement(DiscoverImport),
icon: "i-mingcute-file-import-line",
}
: {
title: t.app("new_user_guide.step.trending.title"),
content: createElement(TrendingFeeds),
icon: "i-mgc-trending-up-cute-re",
},
{
title: t.app("new_user_guide.step.shortcuts.title"),
content: (
<div className="w-[400px] space-y-2">
<p>{t.app("new_user_guide.step.shortcuts.description1")}</p>
<p>
<Trans
i18nKey="new_user_guide.step.shortcuts.description2"
components={{
kbd: <Kbd>H</Kbd>,
}}
/>
</p>
</div>
),
icon: "i-mgc-hotkey-cute-re",
},
].filter((i) => !!i) as {
title: string
icon: React.ReactNode
content: FunctionComponentElement<object>
description?: string
}[],
[haveUsedOtherRSSReader, t],
[t],
)

const totalSteps = useMemo(() => guideSteps.length, [guideSteps])
Expand All @@ -179,20 +155,9 @@ export function GuideModalContent({ onClose }: { onClose: () => void }) {
return (
<m.div
layout
className="relative flex flex-col items-center justify-center overflow-hidden rounded-xl border bg-theme-background"
className="relative flex min-h-[80%] w-4/5 flex-col items-center justify-center overflow-hidden rounded-xl bg-theme-background shadow-xl"
>
{!!title && (
<h1 className="absolute left-6 top-4 flex items-center gap-2 text-xl font-bold">
{typeof guideSteps[step - 1].icon === "string" ? (
<i className={clsx(guideSteps[step - 1].icon, "size-[22px]")} />
) : (
guideSteps[step - 1].icon
)}
{title}
</h1>
)}

<div className="relative mx-auto flex w-full max-w-3xl items-center">
<div className="center relative mx-auto w-full">
<AnimatePresence initial={false} custom={direction} mode="popLayout">
<m.div
key={step - 1}
Expand All @@ -205,8 +170,27 @@ export function GuideModalContent({ onClose }: { onClose: () => void }) {
x: { type: "spring", stiffness: 300, damping: 30 },
opacity: { duration: 0.1 },
}}
className="mt-20 px-6 pb-24"
className="mt-12 px-20 pb-24"
>
{!!title && (
<div className="mb-6">
<h1 className="mb-2 flex w-full items-center justify-center gap-2 text-xl font-bold">
{typeof guideSteps[step - 1].icon === "string" ? (
<i className={clsx(guideSteps[step - 1].icon, "size-[22px]")} />
) : (
guideSteps[step - 1].icon
)}
{title}
</h1>
{!!guideSteps[step - 1].description && (
<div className="text-center text-sm text-theme-vibrancyFg">
<Markdown className="max-w-full text-sm">
{guideSteps[step - 1].description!}
</Markdown>
</div>
)}
</div>
)}
{status === "initial" ? (
<Intro />
) : status === "active" ? (
Expand All @@ -225,7 +209,7 @@ export function GuideModalContent({ onClose }: { onClose: () => void }) {
))}
</div>
<div className="flex gap-2">
{step !== 0 && step <= totalSteps && (
{step !== 0 && (
<Button
onClick={() => {
if (step > 0) {
Expand Down
44 changes: 32 additions & 12 deletions apps/renderer/src/modules/new-user-guide/steps/behavior.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,37 @@ import { useTranslation } from "react-i18next"
import { setGeneralSetting } from "~/atoms/settings/general"
import { Radio, RadioGroup } from "~/components/ui/radio-group"

type Behavior = "default" | "disabled" | ""
type Behavior = "radical" | "balanced" | "conservative"

export function BehaviorGuide() {
const [value, setValue] = useState<Behavior>("")
const [value, setValue] = useState<Behavior>("balanced")
const { t } = useTranslation("app")

const updateSettings = (behavior: Behavior) => {
setGeneralSetting("hoverMarkUnread", behavior === "default")
setGeneralSetting("scrollMarkUnread", behavior === "default")
switch (behavior) {
case "radical": {
setGeneralSetting("hoverMarkUnread", true)
setGeneralSetting("scrollMarkUnread", true)
setGeneralSetting("renderMarkUnread", true)
break
}
case "balanced": {
setGeneralSetting("hoverMarkUnread", true)
setGeneralSetting("scrollMarkUnread", true)
setGeneralSetting("renderMarkUnread", false)
break
}
case "conservative": {
setGeneralSetting("hoverMarkUnread", false)
setGeneralSetting("scrollMarkUnread", false)
setGeneralSetting("renderMarkUnread", false)
break
}
}
}

return (
<div className="space-y-4">
<h2 className="mb-6 text-xl font-semibold">
{t("new_user_guide.step.behavior.unread_question.content")}
</h2>
<div className="space-y-8">
<div className="flex flex-col gap-4">
<RadioGroup
value={value}
Expand All @@ -29,14 +44,19 @@ export function BehaviorGuide() {
}}
>
<Radio
wrapperClassName="border rounded-lg p-4 has-[:checked]:bg-theme-accent-50 has-[:checked]:text-theme-accent-900 has-[:checked]:border-theme-accent-200"
wrapperClassName="border rounded-lg p-3 has-[:checked]:bg-theme-accent has-[:checked]:text-white transition-colors"
label={t("new_user_guide.step.behavior.unread_question.option1")}
value="default"
value="radical"
/>
<Radio
wrapperClassName="border rounded-lg p-4 has-[:checked]:bg-theme-accent-50 has-[:checked]:text-theme-accent-900 has-[:checked]:border-theme-accent-200"
wrapperClassName="border rounded-lg p-3 has-[:checked]:bg-theme-accent has-[:checked]:text-white transition-colors"
label={t("new_user_guide.step.behavior.unread_question.option2")}
value="disabled"
value="balanced"
/>
<Radio
wrapperClassName="border rounded-lg p-3 has-[:checked]:bg-theme-accent has-[:checked]:text-white transition-colors"
label={t("new_user_guide.step.behavior.unread_question.option3")}
value="conservative"
/>
</RadioGroup>
</div>
Expand Down
Loading

0 comments on commit 4583b3b

Please sign in to comment.