Skip to content

테마 커스터마이징

@vuepkg/calendar는 런타임 JS 없이 CSS 변수만으로 완전한 테마 커스터마이징을 지원합니다.

브랜드 컬러 변경

CSS 변수를 덮어쓰는 것만으로 전체 테마가 변경됩니다:

css
/* 예: 초록 계열 브랜드 */
:root {
  --vp-color-primary: #16a34a;
  --vp-color-primary-hover: #15803d;
  --vp-color-primary-subtle: #dcfce7;
}

다크 모드

prefers-color-scheme 미디어 쿼리와 .vp-dark 클래스를 모두 지원합니다.

html
<!-- 다크 모드 강제 적용 -->
<html class="vp-dark">
  ...
</html>
ts
// 토글 구현 예시
const toggleDark = () => document.documentElement.classList.toggle('vp-dark')

주요 CSS 변수

색상 토큰

css
:root {
  /* Semantic */
  --vp-color-primary: #2563eb;
  --vp-color-primary-hover: #1d4ed8;
  --vp-color-primary-subtle: #dbeafe;
  --vp-color-danger: #dc2626;
  --vp-color-danger-subtle: #fee2e2;

  /* 텍스트 */
  --vp-color-text: #111827;
  --vp-color-text-muted: #6b7280;

  /* 배경 */
  --vp-color-surface: #ffffff;
  --vp-color-surface-raised: #f9fafb;
}

캘린더 컴포넌트 토큰

css
:root {
  --vp-calendar-bg: var(--vp-color-surface);
  --vp-calendar-border: var(--vp-color-border);
  --vp-calendar-radius: 12px;
  --vp-calendar-min-height: 500px;

  /* 그리드 */
  --vp-grid-line: #e5e7eb;
  --vp-grid-hour-stripe: #f3f4f6;

  /* 현재 시간 표시기 */
  --vp-current-time-color: #ef4444;

  /* 오늘 날짜 */
  --vp-today-badge-bg: var(--vp-color-primary);
  --vp-today-badge-text: #ffffff;
}

일정 유형 색상

scheduleTypeOptions prop으로 일정 유형별 색상을 정의합니다:

vue
<script setup lang="ts">
import type { ScheduleTypeOption } from '@vuepkg/calendar'

const scheduleTypeOptions: ScheduleTypeOption[] = [
  {
    type: 'meeting',
    label: '회의',
    color: '#1565c0',           // 텍스트·테두리 색상
    backgroundColor: '#e3f2fd', // 배경 색상
  },
  {
    type: 'task',
    label: '업무',
    color: '#6a1b9a',
    backgroundColor: '#f3e5f5',
  },
]
</script>

<template>
  <ScheduleCalendar
    :schedules="schedules"
    :schedule-type-options="scheduleTypeOptions"
    ...
  />
</template>

기본값(SCHEDULE_TYPE_OPTIONS)을 extend할 수도 있습니다:

ts
import { SCHEDULE_TYPE_OPTIONS } from '@vuepkg/calendar'

const scheduleTypeOptions = [
  ...SCHEDULE_TYPE_OPTIONS,
  { type: 'project', label: '프로젝트', color: '#0f766e', backgroundColor: '#ccfbf1' },
]

Tailwind CSS 프로젝트에서 사용하기

Tailwind를 쓰는 앱과 함께 사용할 수 있습니다. shadcn-vue처럼 임의 요소에 class="bg-blue-500 rounded-lg"를 붙여 스타일을 바꾸는 방식 대신, #event/#day-cell/#toolbar/#month-overflow-item scoped slot으로 해당 영역의 마크업 자체를 Tailwind 클래스가 붙은 콘텐츠로 교체할 수 있습니다.

이 라이브러리의 커스터마이징 경로는 CSS 변수(--vp-*), scheduleTypeOptions, 그리고 scoped slot 세 가지입니다. CSS 변수는 톤 조정에, slot은 마크업 자체를 Tailwind로 다시 그릴 때 씁니다.

무엇이 되고, 무엇이 안 되는가

시도결과
<ScheduleCalendar class="m-4 shadow-xl" />루트 컨테이너에 class가 합쳐짐. margin·shadow 등 라이브러리가 지정하지 않은 속성은 적용됨
<ScheduleCalendar class="rounded-2xl border-gray-200" />라이브러리 scoped CSS가 border-radius·border를 이미 지정 → 충돌·무시될 수 있음
일정 칩·월간 셀·툴바에 Tailwind class#event/#day-cell/#toolbar slot으로 가능 — 소비자가 직접 Tailwind 마크업을 렌더 (§ scoped slot)
scheduleTypeOptionsbackgroundColor인라인 style로 적용 → Tailwind bg-*보다 우선

권장: Tailwind 팔레트 → CSS 변수 연결

@vuepkg/calendar/style.css는 theme·ui 스타일을 포함합니다. import 순서는 보통 Tailwind → 캘린더 순입니다.

css
/* app.css — Tailwind v4 예시 */
@import "tailwindcss";
@import "@vuepkg/calendar/style.css";

@theme {
  --color-brand: #16a34a;
  --color-brand-subtle: #dcfce7;
}

:root {
  --vp-color-primary: var(--color-brand);
  --vp-color-primary-subtle: var(--color-brand-subtle);
  --vp-calendar-radius: 0.75rem; /* rounded-xl에 맞춤 */
}

Tailwind v3를 쓰는 경우에도 동일한 원칙입니다. :root에서 --vp-*만 덮어쓰면 캘린더 전체 톤이 맞춰집니다.

일정 색상과 Tailwind

scheduleTypeOptionshex/rgb 문자열을 받습니다. Tailwind 색을 쓰려면 팔레트 값을 가져와 넣습니다.

ts
// Tailwind 기본 blue-100 / blue-800 예시 (임의)
const scheduleTypeOptions = [
  { type: 'meeting', label: '회의', color: '#1e40af', backgroundColor: '#dbeafe' },
]

루트 wrapper 패턴

캘린더 바깥 레이아웃은 Tailwind로 자유롭게 꾸밀 수 있습니다.

vue
<div class="h-screen p-4 flex flex-col">
  <ScheduleCalendar
    class="flex-1 min-h-0"
    :schedules="schedules"
    ...
  />
</div>

ScheduleCalendar에 넘긴 class는 루트 .schedule-calendar에 합쳐지지만, height: 100% 등 라이브러리 기본 레이아웃과 겹치는 속성은 주의하세요. 부모 높이 지정은 여전히 필수입니다.

scoped slot으로 Tailwind 마크업 직접 렌더

ScheduleCalendartoolbar/day-cell/event/month-overflow-item 4개 scoped slot을 제공합니다. 미사용 시 기존 마크업이 그대로 렌더되는 opt-in 방식이라, 필요한 영역만 Tailwind로 다시 그릴 수 있습니다.

vue
<ScheduleCalendar v-model:view="view" v-model:date="date" :schedules="schedules">
  <template #event="{ schedule, source, typeStyle, onSelect }">
    <button
      type="button"
      class="w-full truncate rounded-md px-2 py-0.5 text-xs font-semibold text-left"
      :style="{ color: typeStyle.color, backgroundColor: typeStyle.backgroundColor }"
      @click="onSelect?.()"
    >
      {{ schedule.title }}
    </button>
  </template>
</ScheduleCalendar>
  • event slot은 칩/바/시간 그리드 블록 6개 컨텍스트를 공용으로 커버합니다. source로 컨텍스트를 구분해 다르게 렌더할 수 있습니다.
  • week-timed/day-timed(주간·일간 시간 그리드) 컨텍스트는 드래그 이동·리사이즈가 슬롯 바깥 wrapper에서 처리되므로 onSelect가 전달되지 않습니다 — 슬롯 콘텐츠는 순수 표시 전용입니다.
  • day-cell은 월간 셀의 내부 콘텐츠만 교체합니다. 키보드 이동(roving tabindex)·role="gridcell"은 라이브러리가 계속 관리합니다.
  • List 뷰는 #list-cell-title 등 컬럼별 슬롯으로 셀 내부만 교체합니다. 행 클릭·키보드는 DataTable이 유지합니다. Participant 기본 표시는 참가자 없을 때 -입니다.
  • 전체 API·slot props 타입: architecture.md § Scoped Slots.
vue
<ScheduleCalendar v-model:view="view" v-model:date="date" :schedules="schedules">
  <template #list-cell-title="{ row }">
    <span class="font-medium text-slate-900">{{ row.title }}</span>
  </template>
</ScheduleCalendar>

완전한 Tailwind UI가 필요할 때: headless

내부 요소마다 Tailwind 클래스를 쓰고 싶다면 @vuepkg/calendar/headless로 로직만 가져와 직접 마크업을 구성하세요.

ts
import { useCalendar, useScheduleCalendarHost } from '@vuepkg/calendar/headless'

ScheduleCalendar 스타일드 컴포넌트는 빠른 통합용, headless는 디자인 시스템 완전 통제용입니다.

로드맵 (문서·기능)

  • 현재: CSS 변수 + scheduleTypeOptions + scoped slot(#toolbar/#day-cell/#event/#month-overflow-item/#list-cell-*) + headless

Released under the MIT License.