Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENHANCEMENT] Polish the dark mode; Overhaul submit form; Fix dark mode skeleton components; #67

Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e9a320a
feat: Add `dark` color to the theme
chinmaykunkikar Nov 30, 2023
afa1350
feat: Completey overhaul the Create blog form
chinmaykunkikar Nov 30, 2023
17f652c
chore: Remove stale css dark theme variables
chinmaykunkikar Nov 30, 2023
75c4c2c
refactor: Changed all colors from *-gray-* and white to *-slate-* or …
chinmaykunkikar Nov 30, 2023
583eb97
refactor: Overhaul the homepage
chinmaykunkikar Nov 30, 2023
a5f779b
style: Remove some unnecessary `tracking`
chinmaykunkikar Dec 1, 2023
955d2d0
fix: Use margin instead of padding
chinmaykunkikar Dec 1, 2023
286a6a7
fix: Add classes to make the app more responsive on smaller screens
chinmaykunkikar Dec 1, 2023
ea05ef3
feat: Add a `light` theme to tailwind config
chinmaykunkikar Dec 1, 2023
fe49972
fix: Remove Latest post border in dark mode
chinmaykunkikar Dec 1, 2023
cd40261
style: Use original breakpoint widths for cards
chinmaykunkikar Dec 1, 2023
62088b1
feat: Add skeletons for dark mode (fixes #64)
chinmaykunkikar Dec 1, 2023
4f5f5b9
styles: Add custom font to tailwind config
chinmaykunkikar Dec 1, 2023
842ecf7
styles: Add some visual hierarchy by adjusting text sizes.
chinmaykunkikar Dec 1, 2023
2612958
styles: Overhaul modal styling; add dark mode
chinmaykunkikar Dec 1, 2023
ce2f99a
styles: Change some styles of the submit form again
chinmaykunkikar Dec 1, 2023
6efdfd1
feat: Introduce a `CategoryPill` component to replace `category-props`
chinmaykunkikar Dec 1, 2023
89fb796
fix: Fix category pill colors
chinmaykunkikar Dec 1, 2023
9f5a0d3
chore: Run `prettier`
chinmaykunkikar Dec 1, 2023
2fe4e5f
styles: Fix `DetailsPage` styling according to themes
chinmaykunkikar Dec 2, 2023
a227346
style: Make add blog page mobile responsive; Move header along the form;
chinmaykunkikar Dec 2, 2023
758448d
refactor: `normalColor` -> `defaultColor`
chinmaykunkikar Dec 2, 2023
56c7b8f
refactor: Add a util to get categories and their respective colors
chinmaykunkikar Dec 4, 2023
28ac078
styles: Fix navigation button alignments on blog and details pages
chinmaykunkikar Dec 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
"components": "@/components",
"utils": "@/lib/utils"
}
}
}
34 changes: 18 additions & 16 deletions frontend/src/components/blog-feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { useEffect, useState } from 'react';
import FeaturedPostCard from '@/components/featured-post-card';
import LatestPostCard from '@/components/latest-post-card';
import { CATEGORIES } from '@/constants/categories';
import { categoryProps } from '@/utils/category-props';
import { FeaturedPostCardSkeleton } from '@/components/skeletons/featured-post-card-skeleton';
import { LatestPostCardSkeleton } from '@/components/skeletons/latest-post-card-skeleton';
import CategoryPill from '@/components/category-pill';

chinmaykunkikar marked this conversation as resolved.
Show resolved Hide resolved
export default function BlogFeed() {
const [selectedCategory, setSelectedCategory] = useState('featured');
Expand Down Expand Up @@ -40,15 +40,18 @@ export default function BlogFeed() {
}, []);

return (
<div className="container mx-auto py-6">
<div className="mx-auto my-6">
<div className="-mx-4 flex flex-wrap">
<div className="w-full p-4 md:w-2/3">
<h1 className="mb-4 text-2xl font-semibold dark:text-white">
<div className="-mb-1 tracking-wide text-slate-500 dark:text-dark-tertiary">
What's hot?
</div>
<h1 className="mb-2 text-2xl font-semibold dark:text-dark-primary">
{selectedCategory === 'featured'
? 'Featured Posts'
: `Posts related to "${selectedCategory}"`}
</h1>
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-6">
{posts.length === 0
? Array(5)
.fill(0)
Expand All @@ -60,30 +63,29 @@ export default function BlogFeed() {
</div>
<div className="w-full p-4 md:w-1/3">
<div className="mb-6">
<div className="text-gray-500 dark:text-white">Discover by topic</div>
<h2 className="mb-4 text-2xl font-semibold dark:text-white">Categories</h2>
<div className="flex flex-wrap gap-2">
<div className="-mb-1 tracking-wide text-light-tertiary dark:text-dark-tertiary">
Discover by topic
</div>
<h2 className="mb-2 text-2xl font-semibold dark:text-dark-primary">Categories</h2>
<div className="flex flex-wrap gap-3 dark:rounded-lg dark:bg-dark-card dark:p-3">
{CATEGORIES.map((category) => (
<button
key={category}
onClick={() =>
setSelectedCategory(selectedCategory === category ? 'featured' : category)
}
className={
selectedCategory === category
? categoryProps(category, true)
: categoryProps(category)
}
>
{category}
<CategoryPill category={category} selected={selectedCategory === category} />
</button>
chinmaykunkikar marked this conversation as resolved.
Show resolved Hide resolved
))}
</div>
</div>
<div>
<div className="text-gray-500 dark:text-white">What's new ?</div>
<h2 className="mb-4 text-2xl font-semibold dark:text-white">Latest Posts</h2>
<div className="flex flex-col gap-2">
<div className="-mb-1 tracking-wide text-slate-500 dark:text-dark-tertiary">
What's new?
</div>
<h2 className="mb-2 text-2xl font-semibold dark:text-dark-primary">Latest Posts</h2>
<div className="flex flex-col gap-4">
{latestPosts.length === 0
? Array(5)
.fill(0)
Expand Down
44 changes: 44 additions & 0 deletions frontend/src/components/category-pill.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { twMerge } from 'tailwind-merge';

interface CategoryPillProps extends React.HTMLAttributes<HTMLSpanElement> {
category: string;
selected?: boolean;
}

export default function CategoryPill({ category, selected = false }: CategoryPillProps) {
const categoryDefaultColors: any = {
Travel: 'bg-pink-200 dark:bg-pink-900',
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we say String instead of any

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I forgot about that cheeky any while I was trying something out. Apologies, and thanks for pointing that out.
To answer your concern, I'm afraid we can't change that to a simple string type to the object that has the categories as their keys . We'll have to define a type something like:

type categoryColorsType = {
    Travel: string,
    Mountains: string,
    ...
}

This seems redundant to me. We'll have to keep editing the type if we wish to change the categories.

Let's figure out a different way for this.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops I almost missed the key value pairs.
Can we use something like this
const categoryColors = new Map<string, string>([["travel", "classes"], ["mountains","classes"]])
we would have to then stringify the category when needed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aargh, okay! :P
I have an idea based on this.
I'll have to put this on hold for another day (back to draft PR).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure 😂, just one thing shall we do string, string or any other plans you have got?

Nature: 'bg-green-200 dark:bg-green-900',
City: 'bg-yellow-200 dark:bg-yellow-900',
Adventure: 'bg-blue-200 dark:bg-blue-900',
Beaches: 'bg-purple-200 dark:bg-purple-900',
Landmarks: 'bg-red-200 dark:bg-red-900',
Mountains: 'bg-teal-200 dark:bg-teal-900',
};
const categorySelectedColors: any = {
Travel: 'bg-pink-500/80',
chinmaykunkikar marked this conversation as resolved.
Show resolved Hide resolved
Nature: 'bg-green-500/80',
City: 'bg-yellow-500/80',
Adventure: 'bg-blue-500/80',
Beaches: 'bg-purple-500/80',
Landmarks: 'bg-red-500/80',
Mountains: 'bg-teal-500/80',
};

const selectedColor =
category in categorySelectedColors ? categorySelectedColors[category] : 'bg-cyan-500/80';

const defaultColor =
category in categoryDefaultColors ? categoryDefaultColors[category] : 'bg-cyan-200 dark:bg-cyan-900';

return (
<span
className={twMerge(
'cursor-pointer rounded-3xl px-3 py-1 text-xs font-medium text-light-primary/80 dark:text-dark-primary/80',
selected ? selectedColor : defaultColor
)}
>
{category}
</span>
);
}
24 changes: 13 additions & 11 deletions frontend/src/components/featured-post-card.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
import { useNavigate } from 'react-router-dom';
import Post from '@/types/post-type';
import formatPostTime from '@/utils/format-post-time';
import { categoryProps } from '@/utils/category-props';
import CategoryPill from '@/components/category-pill';

export default function FeaturedPostCard({ post }: { post: Post }) {
const navigate = useNavigate();
return (
<div
className="flex h-48 cursor-pointer gap-4 rounded-lg bg-white p-2 dark:bg-dark-textfield"
className="flex h-48 cursor-pointer gap-2 rounded-lg bg-light dark:bg-dark-card"
onClick={() => navigate('/details-page', { state: { post } })}
>
<div className="w-1/3">
<img
src={post.imageLink}
alt={post.title}
className="h-full w-full rounded-lg object-cover"
className="h-full w-full rounded-lg object-cover shadow-lg"
/>
</div>
<div className="flex h-full w-2/3 flex-col gap-2">
<div className="text-xl font-semibold dark:text-white">{post.title}</div>
<div className="flex h-full w-2/3 flex-col gap-2 p-2">
<div className="text-xl font-semibold text-light-title dark:text-dark-title">
{post.title}
</div>
<div className="flex flex-wrap gap-2">
{post.categories.map((category, index) => (
<span key={index} className={categoryProps(category)}>
{category}
</span>
<CategoryPill key={`${category}-${index}`} category={category} />
))}
</div>
<div className="line-clamp-2 text-gray-600">
<p className="overflow-ellipsis dark:text-white">{post.description}</p>
<div className="line-clamp-2">
<p className="overflow-ellipsis text-light-description dark:text-dark-description">
{post.description}
</p>
</div>
<div className="mb-1 flex flex-1 items-end text-xs text-gray-500 dark:text-white">
<div className="flex flex-1 items-end text-xs text-light-info dark:text-dark-info">
{post.authorName} • {formatPostTime(post.timeOfPost)}
</div>
</div>
Expand Down
16 changes: 8 additions & 8 deletions frontend/src/components/latest-post-card.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { useNavigate } from 'react-router-dom';
import linkIcon from '@/assets/svg/link.svg';
import Post from '@/types/post-type';
import { categoryProps } from '@/utils/category-props';
import formatPostTime from '@/utils/format-post-time';
import CategoryPill from '@/components/category-pill';
export default function LatestPostCard({ post }: { post: Post }) {
const navigate = useNavigate();
return (
<div
className="cursor-pointer rounded-lg bg-white p-2 py-2 shadow-sm dark:bg-dark-textfield"
className="cursor-pointer rounded-lg border border-slate-200 bg-slate-50 p-3 dark:border-none dark:bg-dark-card"
onClick={() => navigate('/details-page', { state: { post } })}
>
<div className="flex">
<div className="mb-2 flex flex-1 flex-wrap gap-2 ">
<div className="mb-2 flex flex-1 flex-wrap gap-2">
{post.categories.map((category, index) => (
<span key={index} className={categoryProps(category)}>
{category}
</span>
<CategoryPill key={`${category}-${index}`} category={category} />
))}
</div>
<img src={linkIcon} className="h-3 w-3" onClick={() => navigate(-1)} />
</div>
<div className="mb-2 line-clamp-2 text-xl font-semibold dark:text-white">{post.title}</div>
<div className="text-xs text-gray-500 dark:text-white">
<div className="mb-2 line-clamp-2 font-semibold text-light-title dark:text-dark-title">
{post.title}
</div>
<div className="text-xs text-light-info dark:text-dark-info">
{post.authorName} • {formatPostTime(post.timeOfPost)}
</div>
</div>
Expand Down
24 changes: 13 additions & 11 deletions frontend/src/components/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,29 @@ const ModalComponent: React.FC<ModalProps> = ({
role="dialog"
aria-modal="false"
>
<div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
<div className="fixed inset-0 bg-slate-800/50 bg-opacity-75 transition-opacity"></div>

<div className="fixed inset-0 z-10 w-screen overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<div className="relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
<div className="bg-white px-4 pb-4 pt-5 sm:p-6 sm:pb-4">
<div className="relative transform overflow-hidden rounded-lg bg-light text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg">
<div className="bg-light px-4 pb-4 pt-5 dark:bg-dark sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left">
<div className="mt-3 text-center sm:text-left">
<h3
className="text-base font-semibold leading-6 text-gray-900"
className="text-base font-semibold leading-6 text-light-primary dark:text-dark-primary"
id="modal-title"
>
Select Post Image
Choose a post cover image
</h3>
<div className="mt-2">
<div className="grid grid-cols-3 gap-4">
{imageUrls.map((imageUrl) => (
<div
key={imageUrl}
className={`cursor-pointer border p-2 ${
selectedImage === imageUrl ? 'border-blue-500' : 'border-gray-300'
className={`aspect-square cursor-pointer overflow-clip border ${
selectedImage === imageUrl
? 'border-4 border-blue-300'
: 'border-slate-300'
} rounded-md`}
onClick={() => handleImageSelect(imageUrl)}
>
Expand All @@ -60,18 +62,18 @@ const ModalComponent: React.FC<ModalProps> = ({
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6">
<div className="bg-light px-4 py-3 dark:bg-dark sm:flex sm:flex-row-reverse sm:px-6">
<button
type="button"
name="imageLink"
className="inline-flex w-full justify-center rounded-md bg-green-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-green-500 sm:ml-3 sm:w-auto"
className="inline-flex w-full justify-center rounded-md bg-light-primary px-3 py-2 text-sm font-semibold text-light shadow-sm hover:bg-light-secondary dark:bg-dark-primary dark:text-dark dark:hover:bg-dark-secondary sm:ml-3 sm:w-auto"
onClick={handleSelector}
>
Select
</button>
<button
type="button"
className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:mt-0 sm:w-auto"
className="mt-3 inline-flex w-full justify-center rounded-md bg-light px-3 py-2 text-sm font-semibold text-light-primary shadow-sm ring-1 ring-inset ring-slate-300 hover:bg-slate-200 dark:bg-dark dark:text-dark-primary dark:hover:bg-dark-secondary/25 sm:mt-0 sm:w-auto"
onClick={() => {
setModal(false);
}}
Expand Down
30 changes: 16 additions & 14 deletions frontend/src/components/post-card.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
import { useNavigate } from 'react-router-dom';
import Post from '@/types/post-type';
import formatPostTime from '@/utils/format-post-time';
import { categoryProps } from '@/utils/category-props';
import CategoryPill from '@/components/category-pill';

export default function PostCard({ post }: { post: Post }) {
const navigate = useNavigate();
return (
<div
className="w-full cursor-pointer p-4 md:w-1/2 lg:w-1/3 xl:w-1/4"
onClick={() => navigate('/details-page', { state: { post } })}
>
<div className="rounded-lg bg-white shadow-md dark:bg-dark-textfield">
<div className="w-full md:w-1/2 lg:w-1/3 xl:w-1/4">
<div
className="m-4 cursor-pointer rounded-lg bg-light shadow-md dark:bg-dark-card"
onClick={() => navigate('/details-page', { state: { post } })}
>
<img
src={post.imageLink}
alt={post.title}
className="h-48 w-full rounded-lg object-cover"
className="h-48 w-full rounded-t-lg object-cover"
/>
<div className="p-4">
<div className="mb-2 text-xs text-gray-500 dark:text-white">
<div className="mb-1 text-xs text-light-info dark:text-dark-info">
{post.authorName} • {formatPostTime(post.timeOfPost)}
</div>
<h2 className="mb-2 line-clamp-1 text-xl font-semibold dark:text-white">{post.title}</h2>
<p className="line-clamp-2 text-gray-600 dark:text-white">{post.description}</p>
<div className="mt-4 flex flex-wrap gap-2 dark:text-black">
<h2 className="mb-2 line-clamp-1 text-lg font-semibold text-light-title dark:text-dark-title">
{post.title}
</h2>
<p className="line-clamp-2 text-sm text-light-description dark:text-dark-description">
{post.description}
</p>
<div className="mt-4 flex flex-wrap gap-2">
{post.categories.map((category, index) => (
<span key={index} className={categoryProps(category)}>
{category}
</span>
<CategoryPill key={`${category}-${index}`} category={category} />
))}
</div>
</div>
Expand Down
43 changes: 25 additions & 18 deletions frontend/src/components/skeletons/featured-post-card-skeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,33 @@ import { Skeleton } from '@/components/ui/skeleton';

export const FeaturedPostCardSkeleton = () => {
return (
<div className="flex h-48 gap-4 rounded-lg bg-white">
<div className="flex rounded-lg bg-light dark:bg-dark-card">
{/* for image */}
<div className="w-1/3">
{/* for image */}
<Skeleton className="h-full w-full rounded-lg bg-gray-200" />
<Skeleton className="h-full w-full rounded-lg bg-slate-200 dark:bg-slate-700" />
</div>
<div className="flex h-full w-2/3 flex-col gap-2">
{/* for title */}
<Skeleton className="h-6 w-full bg-gray-200 text-xl" />
<Skeleton className="h-6 w-2/3 bg-gray-200 text-xl" />
<div className="flex flex-wrap gap-2">
{/* for categories */}
<Skeleton className="h-6 w-16 rounded-3xl bg-gray-200" />
<Skeleton className="h-6 w-16 rounded-3xl bg-gray-200" />
<Skeleton className="h-6 w-16 rounded-3xl bg-gray-200" />
</div>
{/* for description */}
<Skeleton className="line-clamp-2 h-12 w-full bg-gray-200" />
<div className="mb-1 flex flex-1 items-end">
{/* for author and time */}
<Skeleton className="h-5 w-1/3 bg-gray-200" />
<div className="flex h-48 w-2/3 gap-4 rounded-lg p-3">
<div className="flex w-full flex-col gap-3">
{/* for title */}
<Skeleton className="h-6 w-11/12 bg-slate-200 dark:bg-slate-700" />
<Skeleton className="h-6 w-2/3 bg-slate-200 dark:bg-slate-700" />
<div className="flex flex-wrap gap-2">
{/* for categories */}
{Array(3)
.fill(0)
.map((_, index) => (
<Skeleton
key={index}
className="h-6 w-16 rounded-full bg-slate-200 dark:bg-slate-700"
/>
))}
</div>
{/* for description */}
<Skeleton className="line-clamp-2 h-12 w-10/12 bg-slate-200 dark:bg-slate-700" />
<div className="mb-1 flex flex-1 items-end">
{/* for author and time */}
<Skeleton className="h-3 w-1/3 bg-slate-200 dark:bg-slate-700" />
</div>
</div>
</div>
</div>
Expand Down
Loading