DayFlowCalendar ์ปดํฌ๋ํธ
DayFlowCalendar๋ ํ์ฌ ์ ํ๋ ๋ทฐ๋ฅผ ๋ ๋๋งํ๊ณ ๋ ์ด์์์ ์ฒ๋ฆฌํ๋ฉฐ ์ฌ์ด๋๋ฐ๋ ์ด๋ฒคํธ ์์ธ ๋ํ์์ ๊ฐ์ ์ ํ์ UI๋ฅผ ์ฐ๊ฒฐํด ์ฃผ๋ ์์ ์ปดํฌ๋ํธ์
๋๋ค. useCalendarApp ๋ฐ ๋ทฐ ํฉํ ๋ฆฌ ํจ์์ ํจ๊ป ์ฌ์ฉํ๋ฉด ์์ฃผ ์ ์ ์ฝ๋๋ก ์์ ํ ๋์ํ๋ ์บ๋ฆฐ๋๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
import {
DayFlowCalendar,
useCalendarApp,
createWeekView,
ViewType,
} from '@dayflow/react';
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
import '@dayflow/core/dist/styles.css';
export function CalendarDemo() {
const calendar = useCalendarApp({
views: [createWeekView()],
defaultView: ViewType.WEEK,
initialDate: new Date(),
events: [],
plugins: [createSidebarPlugin()],
});
return <DayFlowCalendar calendar={calendar} />;
}<template>
<DayFlowCalendar :calendar="calendar" />
</template>
<script setup>
import { DayFlowCalendar, useCalendarApp } from '@dayflow/vue';
import { createWeekView, ViewType } from '@dayflow/core';
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
import '@dayflow/core/dist/styles.css';
const calendar = useCalendarApp({
views: [createWeekView()],
defaultView: ViewType.WEEK,
initialDate: new Date(),
events: [],
plugins: [createSidebarPlugin()],
});
</script>import { Component } from '@angular/core';
import { createWeekView, ViewType } from '@dayflow/core';
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
import { DayFlowCalendarModule } from '@dayflow/angular';
import '@dayflow/core/dist/styles.css';
@Component({
selector: 'app-root',
standalone: true,
imports: [DayFlowCalendarModule],
template: `
<dayflow-calendar [calendar]="calendar"></dayflow-calendar>
`
})
export class AppComponent {
calendar = {
views: [createWeekView()],
defaultView: ViewType.WEEK,
initialDate: new Date(),
events: [],
plugins: [createSidebarPlugin()],
};
}<script>
import { DayFlowCalendar, useCalendarApp } from '@dayflow/svelte';
import { createWeekView, ViewType } from '@dayflow/core';
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
import '@dayflow/core/dist/styles.css';
const calendar = useCalendarApp({
views: [createWeekView()],
defaultView: ViewType.WEEK,
initialDate: new Date(),
events: [],
plugins: [createSidebarPlugin()],
});
</script>
<DayFlowCalendar {calendar} />์ด ์ปดํฌ๋ํธ๋ useCalendarApp์ด ๋ฐํํ calendar ๊ฐ์ฒด๋ฅผ ๋ฐ์ ํ์ฑ ๋ทฐ๋ฅผ ํ์ธํ๊ณ ํด๋น ๋ทฐ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํฉ๋๋ค. ํด๋ฐ๋ ์ง์ ๋ง๋ UI๋ฅผ DayFlowCalendar ์์ ๋ฐฐ์นํ ์ ์์ง๋ง, ๋ค์ ๊ธฐ๋ฅ์ ์ด๋ฏธ ํฌํจ๋์ด ์์ต๋๋ค:
- ์ ํ์ ์บ๋ฆฐ๋ ์ฌ์ด๋๋ฐ(
createSidebarPlugin์ผ๋ก ์ถ๊ฐ) - ์ด๋ฒคํธ ์์ธ ๋ํ์์ ์ง์(
useEventDetailDialog๋๋ ์ฌ์ฉ์ ์ ์ ๋ ๋๋ฌ๋ก ์ ์ด) - ์บ๋ฆฐ๋๋ฅผ ์ผ๊ณ ๋๊ฑฐ๋ ๋ทฐ๊ฐ ๋ฐ๋ ๋ ๋ ์ด์์ ์๋ ๊ฐฑ์
Props
| Prop | ํ์ | ํ์ ์ฌ๋ถ | ์ค๋ช |
|---|---|---|---|
calendar | UseCalendarAppReturn | ํ์ | useCalendarApp์ ๋ฐํ๊ฐ์
๋๋ค. ์ํ, ๋ฑ๋ก๋ ๋ทฐ, ์ฌ์ด๋๋ฐ ์ค์ , ์บ๋ฆฐ๋ ๋์์ ์ ๊ณตํฉ๋๋ค. |
collapsedSafeAreaLeft | number | ์ ํ | ์ฌ์ด๋๋ฐ๊ฐ ์ ํ์ ๋์ ์ผ์ชฝ ์ฌ๋ฐฑ(px)์ ๋๋ค. ์๋ฅผ ๋ค์ด macOS ์ฐฝ ๋ฒํผ ์์ญ์ ํผํ๋ ๋ฐ ์ฌ์ฉํฉ๋๋ค. |
search | CalendarSearchProps | ์ ํ | ๋ด์ฅ ๊ฒ์ ๊ธฐ๋ฅ์ ๋ํ ์ค์ ์ ๋๋ค. |
์ฌ๋กฏ ๊ธฐ๋ฐ ์ปค์คํฐ๋ง์ด์ง(์ด๋ฒคํธ ์ฝํ ์ธ , ์์ธ ํจ๋ ์ฝํ ์ธ , ์์ธ ๋ํ์์, ์์ ์ ํ๊ธฐ ๋ฑ)์ props๊ฐ ์๋๋ผ ๊ฐ ํ๋ ์์ํฌ์ ๋ค์ดํฐ๋ธ ์ฌ๋กฏ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ์ ์ฒด ๋ชฉ๋ก์ Content Slots๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๊ฒ์ ์ค์
search prop์ผ๋ก ๋ด์ฅ ๊ฒ์์ ๋์์ ์กฐ์ ํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก๋ ์ด๋ฒคํธ์ ์ ๋ชฉ๊ณผ ์ค๋ช
์ ๋ก์ปฌ์์ ๊ฒ์ํฉ๋๋ค.
<DayFlowCalendar
calendar={calendar}
search={{
debounceDelay: 500,
emptyText: 'No events found',
onSearch: async keyword => {
// Custom async search (e.g., from an API)
return fetch(`/api/search?q=${keyword}`).then(res => res.json());
},
}}
/><template>
<DayFlowCalendar
:calendar="calendar"
:search="{
debounceDelay: 500,
emptyText: 'No events found',
onSearch: handleSearch,
}"
/>
</template>
<script setup>
import { DayFlowCalendar } from '@dayflow/vue';
const handleSearch = async (keyword) => {
// Custom async search (e.g., from an API)
return fetch(`/api/search?q=${keyword}`).then(res => res.json());
};
</script>import { Component } from '@angular/core';
import { DayFlowCalendarModule } from '@dayflow/angular';
@Component({
selector: 'app-root',
standalone: true,
imports: [DayFlowCalendarModule],
template: `
<dayflow-calendar
[calendar]="calendar"
[search]="searchConfig"
>
</dayflow-calendar>
`
})
export class AppComponent {
calendar = {
// ... calendar app config
};
searchConfig = {
debounceDelay: 500,
emptyText: 'No events found',
onSearch: async (keyword: string) => {
return fetch(`/api/search?q=${keyword}`).then(res => res.json());
}
};
}<script>
import { DayFlowCalendar } from '@dayflow/svelte';
const handleSearch = async (keyword) => {
return fetch(`/api/search?q=${keyword}`).then(res => res.json());
};
</script>
<DayFlowCalendar
{calendar}
search={{
debounceDelay: 500,
emptyText: 'No events found',
onSearch: handleSearch,
}}
/>๊ฒ์ Props
| ์ต์ | ์ค๋ช |
|---|---|
debounceDelay | ๊ฒ์์ ์คํํ๊ธฐ ์ ์ ๊ธฐ๋ค๋ฆฌ๋ ์๊ฐ(๋ฐ๋ฆฌ์ด)์ ๋๋ค. |
onSearch | ํค์๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ค๋ ๋น๋๊ธฐ ํจ์์ ๋๋ค. |
customSearch | ์ง์ ์์ฑํ ๋ก์ง์ผ๋ก ์ด๋ฒคํธ๋ฅผ ๋ก์ปฌ์์ ํํฐ๋งํ๋ ๋๊ธฐ ํจ์์ ๋๋ค. |
onResultClick | ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ํด๋ฆญํ์ ๋ ์คํ๋๋ ์ ํ์ ์ฝ๋ฐฑ์
๋๋ค. ๋ด์ฅ ๋ด๋น๊ฒ์ด์
๋์(์ด๋ฒคํธ ๋ ์ง๋ก ์ด๋, ์ด๋ฒคํธ ๊ฐ์กฐ, ๋ชจ๋ฐ์ผ์์ ๊ฒ์ UI ๋ซ๊ธฐ)์ ์คํํ๋ defaultAction ์ฝ๋ฐฑ์ด ํจ๊ป ์ ๋ฌ๋ฉ๋๋ค. defaultAction()์ ํธ์ถํ์ง ์์ผ๋ฉด ๋ด๋น๊ฒ์ด์
๊ณผ UI ์ํ๋ฅผ ์ง์ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. |
emptyText | ๊ฒฐ๊ณผ๊ฐ ์์ ๋ ํ์ํ ๋ฌธ๊ตฌ์ ๋๋ค. |
timeFormat | ๊ฒ์ ๊ฒฐ๊ณผ ํ์์ ์ฌ์ฉํ ์๊ฐ ํ์์
๋๋ค('12h' ๋๋ '24h'). useCalendarApp์ ์ ์ญ timeFormat์ด ์ค์ ๋์ด ์์ผ๋ฉด ๊ทธ ์ค์ ์ด ์ฐ์ ํฉ๋๋ค. |
์ฌ์ด๋๋ฐ ๋์
์ฌ์ด๋๋ฐ๋ @dayflow/plugin-sidebar ํ๋ฌ๊ทธ์ธ์ ์ค์นํ๋ฉด ์ถ๊ฐ๋ฉ๋๋ค:
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
const calendar = useCalendarApp({
views: [createWeekView()],
plugins: [
createSidebarPlugin({
width: 280,
initialCollapsed: false,
createCalendarMode: 'modal', // 'inline' or 'modal'
}),
],
});
return <DayFlowCalendar calendar={calendar} />;<template>
<DayFlowCalendar :calendar="calendar" />
</template>
<script setup>
import { DayFlowCalendar, useCalendarApp } from '@dayflow/vue';
import { createWeekView } from '@dayflow/core';
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
const calendar = useCalendarApp({
views: [createWeekView()],
plugins: [
createSidebarPlugin({
width: 280,
initialCollapsed: false,
createCalendarMode: 'modal',
}),
],
});
</script>import { Component } from '@angular/core';
import { createWeekView } from '@dayflow/core';
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
import { DayFlowCalendarModule } from '@dayflow/angular';
@Component({
selector: 'app-root',
standalone: true,
imports: [DayFlowCalendarModule],
template: `
<dayflow-calendar [calendar]="calendar"></dayflow-calendar>
`
})
export class AppComponent {
calendar = {
views: [createWeekView()],
plugins: [
createSidebarPlugin({
width: 280,
initialCollapsed: false,
createCalendarMode: 'modal',
}),
],
};
}<script>
import { DayFlowCalendar, useCalendarApp } from '@dayflow/svelte';
import { createWeekView } from '@dayflow/core';
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
const calendar = useCalendarApp({
views: [createWeekView()],
plugins: [
createSidebarPlugin({
width: 280,
initialCollapsed: false,
createCalendarMode: 'modal',
}),
],
});
</script>
<DayFlowCalendar {calendar} />createSidebarPlugin()์ ํ๋ฌ๊ทธ์ธ์ ์ถ๊ฐํ๋ฉด ์บ๋ฆฐ๋ ํํฐ์ ์ ์ฒด ํ ๊ธ ์ปจํธ๋กค์ด ํฌํจ๋ ๊ธฐ๋ณธ ์ฌ์ด๋๋ฐ(DefaultCalendarSidebar)๊ฐ ๋ ๋๋ง๋ฉ๋๋ค.- ๋๋น, ๊ธฐ๋ณธ ์ ํ ์ํ, ์์ฑ ๋ชจ๋(
createCalendarMode)๋ฅผ ์กฐ์ ํ๊ฑฐ๋render๋๋renderSidebarHeader๋ก ์ง์ ๋ง๋ ๋ ๋๋ฌ๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. ๋ ๋๋ฌ๋CalendarSidebarRenderProps(render์ ๊ฒฝ์ฐ) ๋๋SidebarHeaderSlotArgs(renderSidebarHeader์ ๊ฒฝ์ฐ)๋ฅผ ์ ๋ฌ๋ฐ์ผ๋ฏ๋ก, ํจ๊ป ์ ๊ณต๋๋ ์ฝ๋ฐฑ๊ณผ ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋๋ก ํ์ฉํ ์ ์์ต๋๋ค.
์ด๋ฒคํธ ์์ธ ํ์ ๋ฐฉ์
DayFlow๋ ์ด๋ฒคํธ ์์ธ๋ฅผ ํ์ํ๋ ์ธ ๊ฐ์ง ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค:
- ๊ธฐ๋ณธ ํจ๋ ๋ชจ๋ โ
useEventDetailDialog๊ฐfalse(๊ธฐ๋ณธ๊ฐ)์ด๋ฉด ์ด๋ฒคํธ ์์ธ๋ฅผ ์ด ๋ ๋ด์ฅ ํ๋กํ ํจ๋์ธDefaultEventDetailPanel์ด ํ์๋ฉ๋๋ค. ๋ฐ์คํฌํฑ์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋๋ธ ํด๋ฆญ(eventDetailTrigger: 'dbClick'),eventDetailTrigger: 'click'์ผ๋ก ์ค์ ํ๋ฉด ํ ๋ฒ ํด๋ฆญ์ผ๋ก ์ด๋ฆฝ๋๋ค. ํฐ์น ์ ๋ ฅ์์๋ ํญ์ ํญ์ผ๋ก ์ด๋ฆฝ๋๋ค. - ๋ํ์์ ๋ชจ๋ โ
useCalendarApp์์useEventDetailDialog: true๋ก ์ค์ ํ๋ฉด ํ๋ฉด ๊ฐ์ด๋ฐ์ ํ์๋๋ ๋ด์ฅ ๋ชจ๋ฌ์ด ํ์ฑํ๋ฉ๋๋ค.eventDetailDialog์ฌ๋กฏ์ ์ฌ์ฉํ๋ฉด ์ง์ ๋ง๋ ๋ํ์์๋ก ๊ต์ฒดํ ์ ์์ต๋๋ค. - ์์ ํ ์ฌ์ฉํ์ง ์๊ธฐ โ ์ฑ ์ฝ๋ฐฑ์ผ๋ก ์ ์ดํ๋ ์์ฒด ์ด๋ฒคํธ ๋ชจ๋ฌ์ด ์ด๋ฏธ ์๋ค๋ฉด,
useCalendarApp์์useEventDetailPanel: false๋ก ์ค์ ํด ํ๋กํ ํจ๋์ ๋นํ์ฑํํ์ธ์.
// Suppress the built-in panel โ use your own modal triggered elsewhere
const calendar = useCalendarApp({
...
useEventDetailPanel: false,
});
return <DayFlowCalendar calendar={calendar} />;<template>
<DayFlowCalendar :calendar="calendar" />
</template>
<script setup>
import { DayFlowCalendar, useCalendarApp } from '@dayflow/vue';
// Suppress the built-in panel โ use your own modal triggered elsewhere
const calendar = useCalendarApp({
...
useEventDetailPanel: false,
});
</script>import { Component } from '@angular/core';
import { DayFlowCalendarModule } from '@dayflow/angular';
@Component({
selector: 'app-root',
standalone: true,
imports: [DayFlowCalendarModule],
template: `
<dayflow-calendar [calendar]="calendar"></dayflow-calendar>
`
})
export class AppComponent {
// Suppress the built-in panel โ use your own modal triggered elsewhere
calendar = {
...
useEventDetailPanel: false,
};
}<script>
import { DayFlowCalendar, useCalendarApp } from '@dayflow/svelte';
// Suppress the built-in panel โ use your own modal triggered elsewhere
const calendar = useCalendarApp({
...
useEventDetailPanel: false,
});
</script>
<DayFlowCalendar {calendar} />// Custom panel content (keeps the default panel chrome)
<DayFlowCalendar
calendar={calendar}
eventDetailContent={({ event, onClose }) => (
<div className='p-4'>
<h2>{event.title}</h2>
<button onClick={onClose}>Close</button>
</div>
)}
/><template>
<DayFlowCalendar :calendar="calendar">
<!-- Custom panel content (keeps the default panel chrome) -->
<template #eventDetailContent="{ event, onClose }">
<div class="p-4">
<h2>{{ event.title }}</h2>
<button @click="onClose()">Close</button>
</div>
</template>
</DayFlowCalendar>
</template>
<script setup>
import { DayFlowCalendar } from '@dayflow/vue';
</script><!-- Custom panel content (keeps the default panel chrome) -->
<dayflow-calendar
[calendar]="calendar"
[eventDetailContent]="detailContent"
>
</dayflow-calendar>
<ng-template #detailContent let-args>
<div class="p-4">
<h2>{{ args.event.title }}</h2>
<button (click)="args.onClose()">Close</button>
</div>
</ng-template><DayFlowCalendar {calendar} eventDetailContent={CustomDetailContent} />
<!-- CustomDetailContent.svelte -->
<script lang="ts">
import type { EventDetailContentSlotArgs } from '@dayflow/core';
let { event, onClose } = $props<EventDetailContentSlotArgs>();
</script>
<div class="p-4">
<h2>{event.title}</h2>
<button onclick={onClose}>Close</button>
</div>// Custom dialog (requires useEventDetailDialog: true in useCalendarApp)
<DayFlowCalendar
calendar={calendar}
eventDetailDialog={({ event, isOpen, onClose }) => (
<MyDialog isOpen={isOpen} onClose={onClose}>
<EventForm event={event} />
</MyDialog>
)}
/><template>
<DayFlowCalendar :calendar="calendar">
<!-- Custom dialog -->
<template #eventDetailDialog="{ event, isOpen, onClose }">
<MyDialog :isOpen="isOpen" @close="onClose()">
<EventForm :event="event" />
</MyDialog>
</template>
</DayFlowCalendar>
</template>
<script setup>
import { DayFlowCalendar } from '@dayflow/vue';
import MyDialog from './MyDialog.vue';
import EventForm from './EventForm.vue';
</script><!-- Custom dialog -->
<dayflow-calendar
[calendar]="calendar"
[eventDetailDialog]="dialog"
>
</dayflow-calendar>
<ng-template #dialog let-args>
<my-dialog [isOpen]="args.isOpen" (close)="args.onClose()">
<event-form [event]="args.event"></event-form>
</my-dialog>
</ng-template><DayFlowCalendar {calendar} eventDetailDialog={MyCustomDialog} />
<!-- MyCustomDialog.svelte -->
<script lang="ts">
import type { EventDetailDialogSlotArgs } from '@dayflow/core';
import MyDialog from './MyDialog.svelte';
import EventForm from './EventForm.svelte';
let { event, isOpen, onClose } = $props<EventDetailDialogSlotArgs>();
</script>
<MyDialog {isOpen} {onClose}>
<EventForm {event} />
</MyDialog>์์ฝํ๋ฉด, DayFlowCalendar๋ ๋ ์ด์์, ์ฌ์ด๋๋ฐ ์ฐ๊ฒฐ, ์ด๋ฒคํธ ์์ธ ์ฒ๋ฆฌ ๊ฐ์ ์กฐ์จ ๊ณ์ธต์ ๋ด๋นํฉ๋๋ค. ๋๋ถ์ ์ฌ๋ฌ๋ถ์ useCalendarApp ์ค์ ๊ณผ ๊ทธ ์ฃผ๋ณ์ ์ ํ ๊ฒฝํ์ ๋ง๋๋ ๋ฐ ์ง์คํ ์ ์์ต๋๋ค.