feat: 다크 모드 적용
This commit is contained in:
@@ -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)];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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")],
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user