feat: 다크 모드 적용

This commit is contained in:
2025-03-20 18:50:31 +09:00
parent 55ac57d73c
commit b8e0a8a878
13 changed files with 94 additions and 43 deletions
+1 -1
View File
@@ -14,7 +14,7 @@
@apply -mx-[0.6rem] mt-2 flex items-center justify-center border-t border-t-[#e1e7eb] py-4; @apply -mx-[0.6rem] mt-2 flex items-center justify-center border-t border-t-[#e1e7eb] py-4;
} }
[data-mode="dark"] { [data-theme="black"] {
.card-border { .card-border {
@apply border-[#3f4042] bg-[rgba(255,255,255,0.065)]; @apply border-[#3f4042] bg-[rgba(255,255,255,0.065)];
} }
-1
View File
@@ -4,7 +4,6 @@ import presetConfig from "../../tailwind.config.preset";
export default { export default {
presets: [presetConfig], presets: [presetConfig],
darkMode: ["class", "[data-mode='dark']"],
content: [ content: [
"./src/**/*.{js,ts,jsx,tsx,mdx}", "./src/**/*.{js,ts,jsx,tsx,mdx}",
"../../packages/common/components/src/ui/**/*.{js,ts,jsx,tsx,mdx}", "../../packages/common/components/src/ui/**/*.{js,ts,jsx,tsx,mdx}",
+1 -1
View File
@@ -45,7 +45,7 @@
--container: #f1f6f9; --container: #f1f6f9;
--title: #4c5e6f; --title: #4c5e6f;
} }
[data-mode="dark"] { [data-theme="black"] {
--background: #0a0a0a; --background: #0a0a0a;
--foreground: #fafafa; --foreground: #fafafa;
--card: #0a0a0a; --card: #0a0a0a;
@@ -25,10 +25,10 @@ const preview: Preview = {
withThemeByDataAttribute({ withThemeByDataAttribute({
themes: { themes: {
light: "light", light: "light",
dark: "dark", black: "black",
}, },
defaultTheme: "light", defaultTheme: "light",
attributeName: "data-mode", attributeName: "data-theme",
}), }),
(Story) => ( (Story) => (
<div className="rounded-lg bg-background px-28 py-16"> <div className="rounded-lg bg-background px-28 py-16">
@@ -1,3 +1,4 @@
export * from "./client"; export * from "./client";
export * from "./menu"; export * from "./menu";
export * from "./site";
export * from "./user"; export * from "./user";
@@ -0,0 +1,31 @@
import { client } from "./client";
import { ENDPOINT } from "../config";
export interface SiteInfo {
siteId: string;
siteNm: string;
siteExpln: string;
siteKndCd: string;
siteKindNm: string;
siteAddr: string;
faxNumber: string;
telNo: string;
lwndCn: string;
basicSiteYn: string;
bkmkIcon: string;
useYn: string;
siteSkn: string;
regDt: string;
rgTr: string;
mdfcnDt: string;
mdFr: string;
rgTrNm: string;
mdFrNm: string;
}
export const getSiteInfo = async (siteId: string) => {
const response = await client.get<SiteInfo>(
`${ENDPOINT.CMS_SERVICE.SITES}/${siteId}`,
);
return response.data;
};
@@ -5,6 +5,7 @@ export const BASE_URL = `${PROXY_HOST}/server`;
export const ENDPOINT = { export const ENDPOINT = {
CMS_SERVICE: { CMS_SERVICE: {
MENU_ROLES: "/cms-service/api/v1/menu-roles", MENU_ROLES: "/cms-service/api/v1/menu-roles",
SITES: "/cms-service/api/v1/sites",
}, },
USER_SERVICE: { USER_SERVICE: {
USERS: "/user-service/api/v1/users", USERS: "/user-service/api/v1/users",
+2 -21
View File
@@ -10,7 +10,7 @@ export function getCookie(name: string): string | undefined {
export function setCookie( export function setCookie(
name: string, name: string,
value: string, value: string,
options: Cookies.CookieAttributes, options?: Cookies.CookieAttributes,
): void { ): void {
if (typeof window === "undefined") { if (typeof window === "undefined") {
return; return;
@@ -20,29 +20,10 @@ export function setCookie(
export function removeCookie( export function removeCookie(
name: string, name: string,
options: Cookies.CookieAttributes, options?: Cookies.CookieAttributes,
): void { ): void {
if (typeof window === "undefined") { if (typeof window === "undefined") {
return; return;
} }
Cookies.remove(name, options); Cookies.remove(name, options);
} }
export function getToken(key: string): string | undefined {
return getCookie(key);
}
export function setToken(
key: string,
token: string,
options: Cookies.CookieAttributes,
): void {
setCookie(key, token, {
...options,
path: "/",
});
}
export function removeToken(key: string): void {
removeCookie(key, { path: "/" });
}
@@ -10,16 +10,16 @@
/* 버튼 색상 */ /* 버튼 색상 */
div[role="radiogroup"][data-variant="button"][data-color="primary"] { div[role="radiogroup"][data-variant="button"][data-color="primary"] {
@apply border border-primary dark:border-[#404040]; @apply border border-primary;
} }
div[role="radiogroup"][data-variant="button"][data-color="primary"] button { div[role="radiogroup"][data-variant="button"][data-color="primary"] button {
@apply text-[#6f98bd] hover:bg-[#ecf3f9] hover:text-[#498bc7] data-[state=checked]:bg-primary data-[state=checked]:text-white dark:bg-[#505050] dark:text-[#aeb7bf] dark:hover:bg-[#525e69] dark:data-[state=checked]:bg-primary dark:data-[state=checked]:text-white; @apply text-[#6f98bd] hover:bg-[#ecf3f9] hover:text-[#498bc7] data-[state=checked]:bg-primary data-[state=checked]:text-white;
} }
div[role="radiogroup"][data-variant="button"][data-color="secondary"] { div[role="radiogroup"][data-variant="button"][data-color="secondary"] {
@apply border border-[#ababab] dark:border-[#808080]; @apply border border-[#ababab];
} }
div[role="radiogroup"][data-variant="button"][data-color="secondary"] button { div[role="radiogroup"][data-variant="button"][data-color="secondary"] button {
@apply bg-[#f3f3f3] text-[#8a8a8a] hover:bg-[#ececec] hover:text-[#808080] data-[state=checked]:bg-[#848484] data-[state=checked]:text-white dark:bg-[#505050] dark:text-[#a5a5a5] dark:hover:bg-[#444444] dark:data-[state=checked]:bg-[#848484] dark:data-[state=checked]:text-white; @apply bg-[#f3f3f3] text-[#8a8a8a] hover:bg-[#ececec] hover:text-[#808080] data-[state=checked]:bg-[#848484] data-[state=checked]:text-white;
} }
/* 버튼 모양 */ /* 버튼 모양 */
@@ -28,13 +28,37 @@
} }
div[role="radiogroup"][data-variant="button"][data-color="primary"][data-shape="rounded"] div[role="radiogroup"][data-variant="button"][data-color="primary"][data-shape="rounded"]
button { button {
@apply bg-[#70bcff] text-white hover:bg-[#6bb0ec] data-[state=checked]:bg-primary dark:bg-[#505050] dark:hover:bg-[#525e69] dark:data-[state=checked]:bg-primary; @apply bg-[#70bcff] text-white hover:bg-[#6bb0ec] data-[state=checked]:bg-primary;
} }
div[role="radiogroup"][data-variant="button"][data-color="secondary"][data-shape="rounded"] { div[role="radiogroup"][data-variant="button"][data-color="secondary"][data-shape="rounded"] {
@apply border-[#7b7b7b]; @apply border-[#7b7b7b];
} }
div[role="radiogroup"][data-variant="button"][data-color="secondary"][data-shape="rounded"] div[role="radiogroup"][data-variant="button"][data-color="secondary"][data-shape="rounded"]
button { button {
@apply bg-[#b7b7b7] text-white hover:bg-[#a9a9a9] data-[state=checked]:bg-[#797979] dark:bg-[#505050] dark:hover:bg-[#444444] dark:data-[state=checked]:bg-[#797979]; @apply bg-[#b7b7b7] text-white hover:bg-[#a9a9a9] data-[state=checked]:bg-[#797979];
}
[data-theme="black"] {
div[role="radiogroup"][data-variant="button"][data-color="primary"] {
@apply border-[#404040];
}
div[role="radiogroup"][data-variant="button"][data-color="primary"] button {
@apply bg-[#505050] text-[#aeb7bf] hover:bg-[#525e69] data-[state=checked]:bg-primary data-[state=checked]:text-white;
}
div[role="radiogroup"][data-variant="button"][data-color="secondary"] {
@apply border-[#808080];
}
div[role="radiogroup"][data-variant="button"][data-color="secondary"]
button {
@apply bg-[#505050] text-[#a5a5a5] hover:bg-[#444444] data-[state=checked]:bg-[#848484] data-[state=checked]:text-white;
}
div[role="radiogroup"][data-variant="button"][data-color="primary"][data-shape="rounded"]
button {
@apply bg-[#505050] hover:bg-[#525e69] data-[state=checked]:bg-primary;
}
div[role="radiogroup"][data-variant="button"][data-color="secondary"][data-shape="rounded"]
button {
@apply bg-[#505050] hover:bg-[#444444] data-[state=checked]:bg-[#797979];
}
} }
} }
@@ -1,8 +1,8 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { images } from "@common/assets"; import { images } from "@common/assets";
import { getUserInfo } from "../../api"; import { getCookie, setCookie } from "../../lib";
import { AUTH_USER_ID, ENDPOINT } from "../../config"; import { getSiteInfo, getUserInfo } from "../../api";
import { getToken } from "../../lib"; import { AUTH_USER_ID, ENDPOINT, SITE_ID } from "../../config";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuTrigger, DropdownMenuTrigger,
@@ -12,13 +12,28 @@ import {
import { Button } from "../button"; import { Button } from "../button";
export function Header({ viewOnly }: { viewOnly?: boolean }) { export function Header({ viewOnly }: { viewOnly?: boolean }) {
const userUniqId = getToken(AUTH_USER_ID) ?? ""; const userUniqId = getCookie(AUTH_USER_ID) ?? "";
const { data: userInfo } = useQuery({ const { data: userInfo } = useQuery({
queryKey: [ENDPOINT.USER_SERVICE.USERS], queryKey: [ENDPOINT.USER_SERVICE.USERS],
queryFn: () => getUserInfo(userUniqId), queryFn: () => getUserInfo(userUniqId),
enabled: !viewOnly, enabled: !viewOnly,
}); });
const { data: siteInfo } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.SITES, SITE_ID],
queryFn: () => getSiteInfo(SITE_ID),
select: (data) => {
if (data.siteSkn) {
const siteSkin = data.siteSkn.toLowerCase();
setCookie("data-theme", siteSkin);
document.documentElement.setAttribute("data-theme", siteSkin);
}
return data;
},
enabled: !viewOnly,
});
return ( return (
<header className="sticky top-0 z-30 box-border flex h-[5rem] w-full items-center justify-between border-b border-solid border-border bg-background"> <header className="sticky top-0 z-30 box-border flex h-[5rem] w-full items-center justify-between border-b border-solid border-border bg-background">
<div className="flex items-center"> <div className="flex items-center">
@@ -28,7 +43,7 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) {
<h1 className="flex items-center gap-4"> <h1 className="flex items-center gap-4">
<img src={images.logo} className="h-[3rem]" alt="logo" /> <img src={images.logo} className="h-[3rem]" alt="logo" />
<span className="text-[1.8rem] font-semibold text-foreground"> <span className="text-[1.8rem] font-semibold text-foreground">
통합플랫폼관리 {siteInfo?.siteNm}
</span> </span>
</h1> </h1>
</div> </div>
@@ -11,7 +11,7 @@ type Story = StoryObj<typeof LoadingWithAnimation>;
export const Primary: Story = { export const Primary: Story = {
render: () => ( render: () => (
<div className="rounded-lg bg-secondary p-10 dark:bg-transparent"> <div className="[data-theme='black']:bg-transparent rounded-lg bg-secondary p-10">
<div className="relative size-[5rem]"> <div className="relative size-[5rem]">
<LoadingWithAnimation color="primary" /> <LoadingWithAnimation color="primary" />
</div> </div>
@@ -21,7 +21,7 @@ export const Primary: Story = {
export const Secondary: Story = { export const Secondary: Story = {
render: () => ( render: () => (
<div className="rounded-lg bg-secondary p-10 dark:bg-transparent"> <div className="[data-theme='black']:bg-transparent rounded-lg bg-secondary p-10">
<div className="relative size-[5rem]"> <div className="relative size-[5rem]">
<LoadingWithAnimation color="secondary" /> <LoadingWithAnimation color="secondary" />
</div> </div>
@@ -31,7 +31,7 @@ export const Secondary: Story = {
export const PrimaryWithImage: Story = { export const PrimaryWithImage: Story = {
render: () => ( render: () => (
<div className="rounded-lg bg-secondary p-10 dark:bg-transparent"> <div className="[data-theme='black']:bg-transparent rounded-lg bg-secondary p-10">
<div className="relative size-[5rem]"> <div className="relative size-[5rem]">
<LoadingWithImage color="primary" /> <LoadingWithImage color="primary" />
</div> </div>
@@ -41,7 +41,7 @@ export const PrimaryWithImage: Story = {
export const SecondaryWithImage: Story = { export const SecondaryWithImage: Story = {
render: () => ( render: () => (
<div className="rounded-lg bg-secondary p-10 dark:bg-transparent"> <div className="[data-theme='black']:bg-transparent rounded-lg bg-secondary p-10">
<div className="relative size-[5rem]"> <div className="relative size-[5rem]">
<LoadingWithImage color="secondary" /> <LoadingWithImage color="secondary" />
</div> </div>
@@ -24,7 +24,7 @@
@apply border-b border-b-border; @apply border-b border-b-border;
} }
[data-mode="dark"] { [data-mode="black"] {
.table-ui th { .table-ui th {
@apply bg-[#5e7b9c] text-[#fff]; @apply bg-[#5e7b9c] text-[#fff];
} }
@@ -3,7 +3,6 @@ import presetConfig from "../../../tailwind.config.preset";
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
presets: [presetConfig], presets: [presetConfig],
darkMode: ["class", "[data-mode='dark']"],
content: ["./src/**/*.{ts,tsx,js,jsx}", "./.storybook/**/*.{ts,tsx,js,jsx}"], content: ["./src/**/*.{ts,tsx,js,jsx}", "./.storybook/**/*.{ts,tsx,js,jsx}"],
plugins: [require("tailwindcss-animate")], plugins: [require("tailwindcss-animate")],
}; };