diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..9955fa57 Binary files /dev/null and b/.DS_Store differ diff --git a/.github/workflows/dev-cicd.yml b/.github/workflows/dev-cicd.yml index f2e2fc9c..d018fa33 100644 --- a/.github/workflows/dev-cicd.yml +++ b/.github/workflows/dev-cicd.yml @@ -43,6 +43,9 @@ jobs: - name: Lint code run: pnpm lint + - name: Build email + run: pnpm email:build + - name: Build project run: pnpm build diff --git a/.github/workflows/prod-cicd.yml b/.github/workflows/prod-cicd.yml index 291e8cbd..e64128c6 100644 --- a/.github/workflows/prod-cicd.yml +++ b/.github/workflows/prod-cicd.yml @@ -43,6 +43,9 @@ jobs: - name: Lint code run: pnpm run lint + - name: Build email + run: pnpm email:build + - name: Build project run: pnpm run build diff --git a/.github/workflows/staging-cicd.yml b/.github/workflows/staging-cicd.yml index 2bbb9b80..f5eabfd2 100644 --- a/.github/workflows/staging-cicd.yml +++ b/.github/workflows/staging-cicd.yml @@ -43,6 +43,9 @@ jobs: - name: Lint code run: pnpm run lint + - name: Build email + run: pnpm email:build + - name: Build project run: pnpm run build diff --git a/app/.DS_Store b/app/.DS_Store new file mode 100644 index 00000000..021dd6b7 Binary files /dev/null and b/app/.DS_Store differ diff --git a/app/components/BlogCards.tsx b/app/components/BlogCards.tsx index e7ee6a68..3c3b080b 100644 --- a/app/components/BlogCards.tsx +++ b/app/components/BlogCards.tsx @@ -1,5 +1,3 @@ -import type { FC } from "react"; - interface BlogCardProperties { title: string; description: string; @@ -12,7 +10,7 @@ interface BlogCardProperties { link: string; } -const BlogCard: FC = ({ +const BlogCard: React.FC = ({ title, description, date, @@ -29,6 +27,7 @@ const BlogCard: FC = ({
+ {tag}
diff --git a/app/components/BlogPost.tsx b/app/components/BlogPost.tsx new file mode 100644 index 00000000..e6f90eb4 --- /dev/null +++ b/app/components/BlogPost.tsx @@ -0,0 +1,75 @@ +import RecentBlogCard from "./RecentBlogCard"; +import { Button } from "./ui/button"; + +const blogPosts = [ + { + title: "The Power of Networking: How to Build Meaningful connections", + date: "Jul 12, 2024", + timeRead: "5 mins read", + image: "/images/business.jpg", + description: "Business", + variant: 0, + }, + { + title: "The Global Impact of Climate Change: A Look at the Evidence", + date: "Jul 12, 2024", + timeRead: "5 mins read", + image: "/images/nature.png", + description: "World News", + variant: 1, + }, + { + title: "5 Easy and Delicious Recipes for Busy Weeknights", + date: "Jul 12, 2024", + timeRead: "5 mins read", + image: "/images/food1.jpg", + description: "Food", + variant: 2, + }, + { + title: "5 Simple Habits to Improve Your Mental Wellbeing", + date: "Jul 12, 2024", + timeRead: "5 mins read", + image: "/images/yoga.jpg", + description: "Lifestyle", + variant: 3, + }, + { + title: "The Ultimate Guide to Dressing Stylishly with Fewer Clothes", + date: "Jul 12, 2024", + timeRead: "5 mins read", + image: "/images/fashion.jpg", + description: "Fashion", + variant: 4, + }, + { + title: "The Future of Travel: What Will the World Look Like in 2030?", + date: "Jul 12, 2024", + timeRead: "5 mins read", + image: "/images/person with glasses.jpg", + description: "World News", + variant: 5, + }, +]; + +const BlogPost = () => { + return ( +
+

+ Recent Blog posts +

+
+ {blogPosts.map((post, index) => ( + + ))} +
+
+ +
+
+ ); +}; + +export default BlogPost; diff --git a/app/components/CommentBox.tsx b/app/components/CommentBox.tsx new file mode 100644 index 00000000..0a6ccd1f --- /dev/null +++ b/app/components/CommentBox.tsx @@ -0,0 +1,69 @@ +import { + Forward, + MessageCircle, + Share2, + ThumbsDown, + ThumbsUp, +} from "lucide-react"; + +type CommentProperties = { + userPicUrl: string; + userDisplayName: string; + userTagName: string; + commentContent: string; + pubDate: string; + likeCount: number; +}; + +const CommentBox = ({ + userPicUrl, + userDisplayName, + userTagName, + commentContent, + pubDate, + likeCount, +}: CommentProperties) => { + return ( +
+ Profile Pic +
+
+

+ {userDisplayName} +

+

+ @{userTagName} +

+
+
+ {commentContent} +
+
+

+ {pubDate} +

+
+
+ + + + + +
+
+
+ ); +}; + +export default CommentBox; diff --git a/app/components/Dialog/Dialog.tsx b/app/components/Dialog/Dialog.tsx new file mode 100644 index 00000000..5d23a97a --- /dev/null +++ b/app/components/Dialog/Dialog.tsx @@ -0,0 +1,56 @@ +import { + AlertDialog, + AlertDialogAction, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "~/components/ui/alert-dialog"; +import { Button } from "~/components/ui/button"; + +type Variants = + | "default" + | "destructive" + | "outline" + | "link" + | "ghost" + | "secondary"; + +type DialogProperties = { + headerText: string; + description?: string; + footer: React.ReactNode[]; + triggerText: string; + variants: Variants | null | undefined; +}; + +export default function Dialog({ + headerText, + description, + footer, + triggerText, + variants, +}: DialogProperties) { + return ( + + + + + + + {headerText} + {description} + + + {footer.map((item, index) => ( + + {item} + + ))} + + + + ); +} diff --git a/app/components/EmailSubRenewal/EmailRenewal.tsx b/app/components/EmailSubRenewal/EmailRenewal.tsx new file mode 100644 index 00000000..3ab8e378 --- /dev/null +++ b/app/components/EmailSubRenewal/EmailRenewal.tsx @@ -0,0 +1,101 @@ +import React from "react"; + +import { Button } from "../../components/ui/button"; + +export interface SubscriptionProperties { + title: string; + name: string; + image: string; + email: string; + renewalDate: string; + renewalPrice: string; + renewalPeriod: string; + reviewSubscriptionLink: string; + renewSubscriptionLink: string; +} + +const Subscription: React.FC = ({ + title, + name, + image, + email, + renewalDate, + renewalPrice, + renewalPeriod, + reviewSubscriptionLink, + renewSubscriptionLink, +}) => { + return ( +
+
+ +
+
{title}
+
+
+
+
+ Hi {name}, +
+
+
+
+ We hope you are enjoying your subscription, which will renew soon. +
+
+
+ Your Renewal Date +
+ + {renewalDate} + +
+
+ + {`Your subscription for `} + + {renewalPrice}/{renewalPeriod} features + + {` will automatically renew on ${renewalDate}. To avoid being charged, you should cancel at least a day before the renewal date. To learn more or cancel, `} + + + review subscription + + . +
+
+ To keep your subscription, you can renew your plan for the next + month. +
+
+ +
+
+
Regards,
+
Boilerplate
+
+
+ {`If you have questions, please visit our `} + + FAQs + + + {`, or email us at `} + {email} + {`. Our team can answer questions about your subscription status. To unsubscribe from future subscription renewal reminders, `} + + + + click here {reviewSubscriptionLink} + + . + +
+
+
+ ); +}; + +export default Subscription; diff --git a/app/components/HeroSection.tsx b/app/components/HeroSection.tsx new file mode 100644 index 00000000..8dd1a3c3 --- /dev/null +++ b/app/components/HeroSection.tsx @@ -0,0 +1,28 @@ +import React from "react"; + +import { Button } from "./ui/button"; + +const HeroSection: React.FC = () => { + return ( +
+ hero img +
+
+ Unlock Industry Insights: Get
+ Essential Tips & Boilerplate
Hacks +
+ + +
+
+ ); +}; + +export default HeroSection; diff --git a/app/components/Logo.tsx b/app/components/Logo.tsx new file mode 100644 index 00000000..d20ac7f2 --- /dev/null +++ b/app/components/Logo.tsx @@ -0,0 +1,13 @@ +export default function Logo({ expanded }: { expanded: boolean }) { + return ( +

+ logo +

+ ); +} diff --git a/app/components/NoSearchResults.tsx b/app/components/NoSearchResults.tsx new file mode 100644 index 00000000..c6360a8b --- /dev/null +++ b/app/components/NoSearchResults.tsx @@ -0,0 +1,43 @@ +import { FC } from "react"; + +interface NoSearchResultsProperties { + searchText: string; +} + +const NoSearchResults: FC = ({ searchText }) => { + const isVisible = true; + + return ( +
+
+ No search results +
+ Sorry, No result found for " {searchText ?? "Product Web"} " +
+
+ You might want to try looking for another job title +
+
+
+ ); +}; + +export default NoSearchResults; diff --git a/app/components/PricingPage/PricingCard.tsx b/app/components/PricingPage/PricingCard.tsx new file mode 100644 index 00000000..62bac905 --- /dev/null +++ b/app/components/PricingPage/PricingCard.tsx @@ -0,0 +1,69 @@ +import { Check, X } from "lucide-react"; + +import { Button } from "~/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "~/components/ui/card"; + +interface PricingCardProperties { + title: string; + price: string; + period: string; + description: string; + features: { text: string; included: boolean }[]; + buttonText: string; + borderColor: string; + onClick: () => void; + isSelected: boolean; +} + +const PricingCard = ({ + title, + price, + period, + description, + features, + buttonText, + borderColor, + onClick, + isSelected, +}: PricingCardProperties) => { + return ( + + + {title} + + {price} /{period} + + + {description} + + + + {features.map((feature, index) => ( + + {feature.included ? : } {feature.text} + + ))} + + + + + + ); +}; + +export default PricingCard; diff --git a/app/components/PricingPage/PricingPage.tsx b/app/components/PricingPage/PricingPage.tsx new file mode 100644 index 00000000..6daa70b3 --- /dev/null +++ b/app/components/PricingPage/PricingPage.tsx @@ -0,0 +1,123 @@ +import { useState } from "react"; + +import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"; +import PricingCard from "./PricingCard"; + +const PricingPage = () => { + const [selectedCard, setSelectedCard] = useState(); + + const handleCardClick = (cardName: string) => { + setSelectedCard(cardName); + }; + + return ( +
+
+

+ Pricing +

+
+

+ Simple and Affordable Pricing + Plan +

+

+ Our flexible plans are designed to scale with your business. We have + a plan for you. +

+
+ + + + Monthly + Annual (save 20%) + + + handleCardClick("basic-monthly")} + isSelected={selectedCard === "basic-monthly"} + /> + handleCardClick("premium-monthly")} + isSelected={selectedCard === "premium-monthly"} + /> + + + handleCardClick("basic-annual")} + isSelected={selectedCard === "basic-annual"} + /> + handleCardClick("premium-annual")} + isSelected={selectedCard === "premium-annual"} + /> + + +
+
+ ); +}; + +export default PricingPage; diff --git a/app/components/Profile.tsx b/app/components/Profile.tsx new file mode 100644 index 00000000..6a5c56c8 --- /dev/null +++ b/app/components/Profile.tsx @@ -0,0 +1,17 @@ +export default function Profile({ expanded }: { expanded: boolean }) { + return ( +
+
+
+

+ Your Profile +

+

+ Login +

+
+
+ ); +} diff --git a/app/components/RecentBlogCard.tsx b/app/components/RecentBlogCard.tsx new file mode 100644 index 00000000..9781b46c --- /dev/null +++ b/app/components/RecentBlogCard.tsx @@ -0,0 +1,59 @@ +import { Link } from "@remix-run/react"; + +interface RecentBlogcardProperties { + title: string; + date: string; + timeRead: string; + href: string; + image: string; + description: string; + variant: number; +} + +const RecentBlogCard = ({ + title, + date, + timeRead, + href, + image, + description, + variant, +}: RecentBlogcardProperties) => { + const descriptionStyles = [ + "bg-[#f97316]", + "bg-[#EAB308]", + "bg-[#6DC347]", + "bg-[#7F0682]", + "bg-[#6DC347]", + "bg-[#EAB308]", + ]; + + return ( + +
+

+ {description} +

+ {title} +
+ {title} +
+
+

{date}

+

{timeRead}

+
+
+ + ); +}; + +export default RecentBlogCard; diff --git a/app/components/SuperAdminSideBar/SuperAdminSideNavBar.tsx b/app/components/SuperAdminSideBar/SuperAdminSideNavBar.tsx index 76d0444f..2e080cdf 100644 --- a/app/components/SuperAdminSideBar/SuperAdminSideNavBar.tsx +++ b/app/components/SuperAdminSideBar/SuperAdminSideNavBar.tsx @@ -38,7 +38,7 @@ export function AdminSideNavBar() { ); return ( -