-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add reminderCard to landing page
- Loading branch information
1 parent
00a34c9
commit da72e88
Showing
4 changed files
with
218 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import React, { useState } from "react"; | ||
import { motion, AnimatePresence } from "framer-motion"; | ||
import { Refresh } from "@/components/icons/Refresh"; | ||
import IconBtn from "@/components/nova/buttons/IconBtn"; | ||
import { | ||
Tooltip, | ||
TooltipContent, | ||
TooltipProvider, | ||
TooltipTrigger, | ||
} from "@/components/ui/tooltip"; | ||
import { quotes, type Quote } from "@/components/features/quotes/quotes"; | ||
|
||
export const QuoteCard = () => { | ||
const [currentQuote, setCurrentQuote] = useState<Quote>( | ||
quotes[Math.floor(Math.random() * quotes.length)] ?? { | ||
text: "", | ||
author: "", | ||
category: "Motivational", | ||
}, | ||
); | ||
|
||
const refreshQuote = () => { | ||
const newQuote = quotes[Math.floor(Math.random() * quotes.length)] ?? { | ||
text: "", | ||
author: "", | ||
category: "Motivational", | ||
}; | ||
setCurrentQuote(newQuote); | ||
}; | ||
|
||
return ( | ||
<div className="group w-full max-w-md rounded-2xl border-[1px] border-accent/20 bg-accent-foreground p-4 font-montserrat"> | ||
<div className="relative"> | ||
<AnimatePresence mode="wait"> | ||
<motion.div | ||
key={currentQuote.text} | ||
initial={{ opacity: 0, y: 20 }} | ||
animate={{ opacity: 1, y: 0 }} | ||
exit={{ opacity: 0, y: -20 }} | ||
transition={{ duration: 0.3 }} | ||
className="flex flex-col gap-2 text-left" | ||
> | ||
<p className="text-sm font-medium text-gray-100 md:text-xl"> | ||
“{currentQuote.text}” | ||
</p> | ||
<p className="text-xs text-gray-100 md:text-sm"> | ||
- {currentQuote.author} | ||
</p> | ||
</motion.div> | ||
</AnimatePresence> | ||
|
||
<TooltipProvider> | ||
<Tooltip delayDuration={0}> | ||
<TooltipTrigger asChild> | ||
<IconBtn | ||
onClick={refreshQuote} | ||
variant="default" | ||
className="absolute bottom-2 right-2 border-[1px] border-transparent bg-transparent text-foreground opacity-0 transition-opacity hover:border-white/60 hover:bg-white/5 group-hover:opacity-100" | ||
> | ||
<Refresh /> | ||
</IconBtn> | ||
</TooltipTrigger> | ||
<TooltipContent | ||
id="refresh" | ||
className="font-inter flex items-center gap-3 text-xs font-medium" | ||
> | ||
Refresh quote | ||
</TooltipContent> | ||
</Tooltip> | ||
</TooltipProvider> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default QuoteCard; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import React, { useState } from "react"; | ||
import { Textarea } from "@/components/ui/textarea"; | ||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; | ||
import { | ||
PuzzlePiece, | ||
FlowerLotus, | ||
Clover, | ||
HandHeart, | ||
ShootingStar, | ||
Brain, | ||
} from "@phosphor-icons/react"; | ||
|
||
type ReminderType = keyof typeof typeStyles; | ||
|
||
const typeStyles = { | ||
Gratitude: { | ||
icon: FlowerLotus, | ||
color: "#F5A524", | ||
}, | ||
Motivation: { | ||
icon: Clover, | ||
color: "#10b981", | ||
}, | ||
Affirmation: { | ||
icon: HandHeart, | ||
color: "#ec4899", | ||
}, | ||
Challenge: { | ||
icon: PuzzlePiece, | ||
color: "#F31260", | ||
}, | ||
Dream: { | ||
icon: ShootingStar, | ||
color: "#14b8a6", | ||
}, | ||
Mindset: { | ||
icon: Brain, | ||
color: "#E4E4E7", | ||
}, | ||
} as const; | ||
|
||
export const RemindersCard = () => { | ||
const [reminderText, setReminderText] = useState(""); | ||
const [selectedType, setSelectedType] = useState<ReminderType>("Gratitude"); | ||
|
||
const reminderPlaceholders: Record<ReminderType, string> = { | ||
Gratitude: | ||
"\"I'm grateful for my family's unwavering support through everything.\"", | ||
Motivation: | ||
'"I will become a successful entrepreneur and make a positive impact."', | ||
Affirmation: | ||
'"I am capable of learning and growing beyond my current limitations."', | ||
Challenge: | ||
'"I will overcome my fear of public speaking and become a confident communicator."', | ||
Dream: | ||
'"My dream is to travel to all continents and experience diverse cultures."', | ||
Mindset: | ||
'"I choose to see obstacles as opportunities for growth and learning."', | ||
}; | ||
|
||
const types = Object.keys(typeStyles) as ReminderType[]; | ||
|
||
const ReminderPreview = () => { | ||
const { icon: Icon, color } = typeStyles[selectedType]; | ||
|
||
return ( | ||
<div | ||
className="relative flex-col gap-4 rounded-3xl border-[1px] bg-[#0c0e12] p-3 text-[#d0dbe3] md:p-4" | ||
style={{ | ||
borderColor: `${color}80`, | ||
}} | ||
> | ||
<div className="mb-1 flex items-center gap-1"> | ||
<Icon size={20} color={color} weight="duotone" /> | ||
<p className="text-xs font-semibold" style={{ color }}> | ||
{selectedType} | ||
</p> | ||
</div> | ||
<p className="text-sm md:text-base"> | ||
{reminderText || reminderPlaceholders[selectedType]} | ||
</p> | ||
</div> | ||
); | ||
}; | ||
|
||
return ( | ||
<div className="flex w-full flex-col gap-8"> | ||
<div className="mx-auto w-full max-w-md"> | ||
<ReminderPreview /> | ||
</div> | ||
|
||
<div className="space-y-4 rounded-2xl border-[1px] border-accent/60 bg-accent-foreground p-4"> | ||
<RadioGroup | ||
className="grid grid-cols-3 gap-2 md:flex" | ||
value={selectedType} | ||
onValueChange={(value) => setSelectedType(value as ReminderType)} | ||
> | ||
{types.map((type) => ( | ||
<label | ||
key={type} | ||
className="w-fit cursor-pointer items-center justify-center rounded-2xl border-[1px] border-accent/60 p-2 text-xs text-muted-foreground transition-colors hover:bg-accent-foreground has-[[data-state=checked]]:border-secondary has-[[data-state=checked]]:bg-secondary-smooth-700/10 has-[[data-state=checked]]:text-secondary" | ||
> | ||
<RadioGroupItem | ||
value={type} | ||
className="sr-only after:absolute after:inset-0" | ||
/> | ||
<p className="font-medium leading-none">{type}</p> | ||
</label> | ||
))} | ||
</RadioGroup> | ||
|
||
<div className="flex w-full justify-between"> | ||
<Textarea | ||
maxLength={140} | ||
placeholder={reminderPlaceholders[selectedType]} | ||
value={reminderText} | ||
onChange={(e) => setReminderText(e.target.value)} | ||
className="md:text-md mt-2 w-full text-sm" | ||
rows={3} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default RemindersCard; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters