Skip to content

Commit

Permalink
feat: Implement dark mode in ChatHeader (#252)
Browse files Browse the repository at this point in the history
* feat: Implement dark mode in ChatHeader

* feat: solving warnings

* feat: Update TypingIndicator

* feat: implementing persistent theme

* feat: Implement useEffect in useTheme

* feat: Implement useCallBack
  • Loading branch information
lazaroysr96 authored Nov 24, 2024
1 parent e7f8857 commit 2fae8fc
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 25 deletions.
13 changes: 4 additions & 9 deletions src/components/SmartActionBar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {useClientStore} from "@/hooks/matrix/useConnection"
import useTheme from "@/hooks/util/useTheme"
import useTranslation from "@/hooks/util/useTranslation"
import {LangKey} from "@/lang/allKeys"
import {cn} from "@/utils/utils"
import {SyncState} from "matrix-js-sdk"
import React, {useState} from "react"
import React from "react"
import {type FC} from "react"
import {type IconType} from "react-icons"
import {IoContrast, IoGlobe} from "react-icons/io5"
Expand All @@ -21,13 +22,7 @@ const SmartActionBar: FC<{className?: string}> = ({className}) => {
const {syncState} = useClientStore()
const {t} = useTranslation()

const [isDarkTheme, setIsDarkTheme] = useState(false)

document.querySelectorAll("html")[0].className = isDarkTheme ? "dark" : ""

const handleSwitchTheme = (): void => {
setIsDarkTheme(prevIsDarkTheme => !prevIsDarkTheme)
}
const {toggleTheme} = useTheme()

return (
<div
Expand All @@ -38,7 +33,7 @@ const SmartActionBar: FC<{className?: string}> = ({className}) => {
<SmartAction
aria-label={t(LangKey.SwitchTheme)}
icon={IoContrast}
onClick={handleSwitchTheme}>
onClick={toggleTheme}>
{t(LangKey.SwitchTheme)}
</SmartAction>

Expand Down
22 changes: 12 additions & 10 deletions src/components/TypingIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {stringToColor} from "@/utils/util"
import Avatar from "boring-avatars"
import useTranslation from "@/hooks/util/useTranslation"
import {LangKey} from "@/lang/allKeys"
import {Text} from "./ui/typography"

export type TypingIndicatorUser = {
displayName: string
Expand All @@ -29,19 +30,20 @@ const TypingIndicator: FC<TypingIndicatorProps> = ({users}) => {
}

return users.map((user, index) => (
<span key={index}>
<span
className="font-semibold"
<Text className="truncate" key={index} size="2">
<Text
size="2"
weight="semibold"
style={{color: stringToColor(user.userId)}}>
{user.displayName}
</span>
</Text>

{index < usersLength - 2
? ", "
: index === usersLength - 2
? t(LangKey.And)
: ""}
</span>
</Text>
))
}, [t, users, usersLength])

Expand All @@ -55,15 +57,15 @@ const TypingIndicator: FC<TypingIndicatorProps> = ({users}) => {
<div className={index === 1 || index === 2 ? "-ml-2.5" : ""}>
<Avatar
key={index}
size={24}
size={20}
name={user.displayName}
variant="beam"
/>
</div>
) : (
<img
className={twMerge(
"size-6 rounded-full",
"size-5 rounded-full",
index === 1 || index === 2 ? "-ml-2.5" : ""
)}
key={index}
Expand All @@ -74,7 +76,7 @@ const TypingIndicator: FC<TypingIndicatorProps> = ({users}) => {
)
}, [users, usersLength])

const dotClass = "h-2 w-2 animate-dot-jump rounded-full bg-neutral-300"
const dotClass = "size-2 animate-dot-jump rounded-full bg-neutral-300"

return (
<div className="inline-flex items-center gap-3">
Expand All @@ -88,9 +90,9 @@ const TypingIndicator: FC<TypingIndicatorProps> = ({users}) => {

<div className="flex">{typingUserElements}</div>

<div>
<Text size="2" className="xs:max-w-80 w-max max-w-none truncate">
{who} {verbForm} {t(LangKey.Typing)}
</div>
</Text>
</div>
)
}
Expand Down
6 changes: 3 additions & 3 deletions src/components/ui/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const SelectTrigger = React.forwardRef<
{...props}>
{children}
<SelectPrimitive.Icon asChild>
<CaretSortIcon className="h-4 w-4 opacity-50" />
<CaretSortIcon className="size-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
))
Expand Down Expand Up @@ -120,9 +120,9 @@ const SelectItem = React.forwardRef<
className
)}
{...props}>
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
<span className="absolute right-2 flex size-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
<CheckIcon className="size-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const toastVariants = cva(
{
variants: {
variant: {
default: "border bg-background dark:bg-neutral-900 text-foreground",
default: "border bg-background text-foreground dark:bg-neutral-900",
destructive:
"group border-destructive bg-destructive text-destructive-foreground",
},
Expand Down
4 changes: 2 additions & 2 deletions src/containers/RoomContainer/ChatHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ const ChatHeader: FC<ChatHeaderProps> = ({
<header className="flex size-full h-12 w-full flex-col justify-center gap-1 border-b border-b-neutral-200 px-2 py-1 dark:border-b-neutral-700">
<div className="flex w-full items-center justify-center">
<div className="m-2 flex w-full items-center gap-1">
<LiaSlackHash className="size-5 text-blue-800" />
<LiaSlackHash className="size-5 text-blue-800 dark:text-blue-400" />

<Heading
level="h5"
className="w-max max-w-56 truncate text-blue-800 sm:max-w-md">
className="w-max max-w-56 truncate text-blue-800 dark:text-blue-400 sm:max-w-md">
{roomName}
</Heading>

Expand Down
33 changes: 33 additions & 0 deletions src/hooks/util/useTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {useCallback, useEffect, useState} from "react"

type UseThemeReturnType = {
toggleTheme: () => void
isDarkMode: boolean
}

const useTheme = (): UseThemeReturnType => {
const savedTheme = localStorage.getItem("darkMode")
const isDarkMode = savedTheme ? JSON.parse(savedTheme) : false

const [isDarkTheme, setIsDarkTheme] = useState(isDarkMode)

useEffect(() => {
const html = document.documentElement

if (isDarkTheme) {
html.classList.add("dark")
} else {
html.classList.remove("dark")
}

localStorage.setItem("darkMode", JSON.stringify(isDarkTheme))
}, [isDarkTheme])

const toggleTheme = useCallback(() => {
setIsDarkTheme(!isDarkTheme)
}, [isDarkTheme])

return {toggleTheme, isDarkMode}
}

export default useTheme

0 comments on commit 2fae8fc

Please sign in to comment.