@ershadsarabi/jalcal
v1.0.3
Published
تقویم شمسی سبکِ Vanilla JS با نمای ماه/روز و Drag & Drop رویدادها
Maintainers
Readme
# @ershadsarabi/jalcal
تقویم شمسی سبکِ **Vanilla JS** با نمای **ماه** و **روز**، پشتیبانی از **Drag & Drop**، و API کامل برای **CRUD رویدادها**.
بدون وابستگی به jQuery. استایلها و توابع namespaced هستند؛ CSS زیر `.jalcal` و توابع کمکی با پیشوند `jalcal_` استفاده میشوند.
---
## قابلیتها
- تقویم جلالی دقیق (تبدیل گِرِگوری ⇄ جلالی داخلی و بدون وابستگی)
- نمای **ماه** با ۶ هفته ثابت و نمای **روز** با اسلاتهای ساعتی + بخش **تمامروزی**
- بارگذاری رویدادها از JSON، لینک رویداد اختیاری، رنگ دلخواه، وضعیت done/undone
- Drag & Drop بین روزها (در ماه) و بین ساعتها/تمامروزی (در روز)
- انتخاب ماه/سال با پاپآپ اختصاصی، ناوبری ماه/روز با دکمههای prev/next
- API رویدادها: **add/update/remove/eventDone/eventUndone**
- Hookها: **onCellClick**، **onEventClick**، **onEventDrag**، **onEventDrop**
- استایل تمیز با CSS Variables قابلسفارشیسازی
---
## نصب
```bash
npm i @ershadsarabi/jalcalاستفاده سریع (ESM)
<div id="calendar" style="height:600px;"></div>
<script type="module">
import jalcal from '@ershadsarabi/jalcal';
import '@ershadsarabi/jalcal/style.css';
const events = [
{ id:1, title:'جلسه', start:'1404/08/23 09:00', end:'1404/08/23 11:00', allDay:false, status:false, color:'#1976d2' },
{ id:2, title:'آموزش', start:'1404/08/24 14:00', end:'1404/08/24 15:30', allDay:false, status:true, color:'#43a047' },
{ id:3, title:'تعطیل', start:'1404/08/25', end:'1404/08/25', allDay:true, status:false, color:'#e53935' }
];
const cal = jalcal('#calendar', {
events,
onCellClick: ({ jy, jm, jd, hour, allDay, events, cell }) => {},
onEventClick: ({ id, event, jy, jm, jd, events }) => {},
onEventDrag: ({ id, event, from }) => {},
onEventDrop: ({ id, event, from, to }) => {}
});
// ناوبری
// cal.today(); cal.next(); cal.prev();
// تغییر نما
// cal.setView('day'); cal.setView('month');
</script>استفاده از CDN (UMD)
<link rel="stylesheet" href="https://unpkg.com/@ershadsarabi/jalcal/dist/jalcal.css">
<div id="calendar" style="height:600px"></div>
<script src="https://unpkg.com/@ershadsarabi/jalcal/dist/jalcal.umd.js"></script>
<script>
// در UMD آبجکت گلوبال Jalcal در دسترس است
const cal = Jalcal('#calendar', {
events: []
});
</script>ساختار داده رویداد
type JalcalEvent = {
id: string | number; // الزامی و یکتا
title?: string; // عنوان رویداد
description?: string; // توضیحات (در UI پایه استفاده نمیشود)
start: string; // "YYYY/MM/DD HH:MM" یا "YYYY/MM/DD"
end?: string; // اختیاری با همان فرمت start
allDay?: boolean; // true = تمامروزی
status?: boolean; // true = done (نمایش خطخورده و کمرنگ)
color?: string; // مثل "#1976d2" برای استایل
eventLink?: string; // لینک جزئیات (target=_blank)
// سایر فیلدهای اختیاری آزاد
};- اگر
startبدون زمان باشد یاallDay = true، رویداد تمامروزی رندر میشود. endاختیاری است. در جابهجایی روز، تاریخendهم با اختلاف روزی جابهجا میشود.- ترتیب نمایش: رویدادهای تمامروزی در ابتدا، سپس رویدادهای زمانی بر اساس
HH:MM.
گزینههای سازنده
type Options = {
events?: JalcalEvent[]; // پیشفرض []
onCellClick?: (args) => any | false;
onEventClick?: (args) => any | false;
onEventDrag?: (args) => any | false;
onEventDrop?: (args) => any | false;
};امضای Hookها
onCellClick: (args: {
jy: number; jm: number; jd: number;
hour?: number | null; // در نمای روز مقداردهی میشود
allDay?: boolean; // در نمای روز برای بخش تمامروزی true میشود
events: JalcalEvent[]; // رویدادهای همان روز
cell: HTMLElement; // عنصر کلیکشده
}) => any | false;
onEventClick: (args: {
id: string|number;
event: JalcalEvent;
jy?: number; jm?: number; jd?: number;
events?: JalcalEvent[]; // رویدادهای آن روز
}) => any | false;
onEventDrag: (args: {
id: string|number;
event: JalcalEvent;
from: { jy:number; jm:number; jd:number; hh?:number|null; mm?:number|null };
}) => any | false;
onEventDrop: (args: {
id: string|number;
event: JalcalEvent;
from: { jy:number; jm:number; jd:number; hh?:number|null; mm?:number|null };
to: { jy:number; jm:number; jd:number; hh?:number|null }; // در نمای روز شامل ساعت مقصد
monthContext: { jy:number; jm:number }; // ماهی که نمای ماه بر اساس آن رندر شده
}) => any | false;- برگرداندن false از هر Hook مربوط، عملیات پیشفرض را متوقف میکند (مثلاً Drop را کنسل میکند).
متدهای API
const api = jalcal('#calendar', options);
// رندر
api.renderMonth(jy, jm);
api.renderDay(jy, jm, jd);
// نما
api.setView('month' | 'day');
api.getView(); // 'month' | 'day'
// ناوبری
api.today(); // جهش به امروز (ماه یا روز)
api.next(); // ماه بعد یا روز بعد
api.prev(); // ماه قبل یا روز قبل
// CRUD
api.addEvent(event);
api.updateEvent(partialEventWithId);
api.removeEvent(id);
api.eventDone(id);
api.eventUndone(id);
// داده
api.getEvents(); // آرایه کپیشدهمثال: افزودن/ویرایش/حذف
const cal = jalcal('#calendar', { events: [] });
// افزودن
cal.addEvent({
id: 101,
title: 'Daily Standup',
start: '1404/08/27 09:30',
end: '1404/08/27 10:00',
allDay: false,
color: '#1976d2'
});
// ویرایش
cal.updateEvent({
id: 101,
title: 'Daily Scrum',
color: '#1565c0'
});
// انجامشده
cal.eventDone(101);
// بازگردانی
cal.eventUndone(101);
// حذف
cal.removeEvent(101);مثال: کنترل Drag & Drop سفارشی
const cal = jalcal('#calendar', {
events: [...],
onEventDrop: ({ id, event, from, to }) => {
// اعتبارسنجی
const isWeekend = (jy,jm,jd) => {
const w = jalcal_weekdaySat0_J(jy,jm,jd); // 0=شنبه ... 6=جمعه
return w === 6; // جمعه
};
if (isWeekend(to.jy, to.jm, to.jd)) {
alert('جابجایی به جمعه مجاز نیست');
return false; // لغو Drop
}
// ذخیره سمت سرور (async). اگر میخواهی بلوکه کنی، خودت state را برگردان.
// این کتابخانه drop را اعمال میکند و UI را رندر میکند.
}
});مثال: سوییچ برنامهریزیشده بین نمای روز/ماه
// دکمههای سفارشی خودت
document.querySelector('#btn-month').onclick = () => {
cal.setView('month');
};
document.querySelector('#btn-day').onclick = () => {
// پیشفرض: "روز جاری" باید نمایش داده شود
const now = new Date();
const j = jalcal_toJalaali(now.getUTCFullYear(), now.getUTCMonth()+1, now.getUTCDate());
cal.renderDay(j.jy, j.jm, j.jd);
};رفتار پیشفرض دکمههای نمای روز
- در سربرگ تقویم، روی دکمه «روز» کلیک شود، بهصورت پیشفرض روز جاری نمایش داده میشود.
- عنوان نمای روز: «نام روز، YYYY/MM/DD» به فارسی. مثال:
سهشنبه، ۱۴۰۴/۰۸/۲۳.
پاپآپ انتخاب ماه/سال
- کلیک روی عنوان ماه/سال در سربرگ → پاپآپ انتخاب ماه همان سال.
- دکمههای «‹ ›» برای پیمایش سال. دکمه وسط سال با استایل قابل خواندن.
- دکمه سال → پاپآپ انتخاب سال (شبکه ۵×۵، سال مرکز در وسط).
- انتخاب سال → پاپآپ سال بسته میشود، پاپآپ ماه همان سال تنظیم و بازمیماند تا ماه انتخاب شود.
سفارشیسازی ظاهر با CSS Variables
.jalcal{
--border:#e5e7eb;
--muted:#9aa0a6;
--bg:#f8f9fa;
--bg2:#f3f4f6;
--primary:#1a73e8; /* رنگ اصلی دکمهها و اِلِمانها */
--text:#111827;
--today-bg:#FFF6DF; /* پسزمینه روز جاری */
}برای تمامصفحه: والد را 100% ارتفاع بده. مثال:
html,body,#app,#calendar { height:100%; }
یکپارچهسازی با فریمورکها
React (ESM)
import { useEffect, useRef } from 'react';
import jalcal from '@ershadsarabi/jalcal';
import '@ershadsarabi/jalcal/style.css';
export default function Calendar() {
const ref = useRef(null);
useEffect(() => {
if (!ref.current) return;
const api = jalcal(ref.current, { events: [] });
return () => { /* در صورت نیاز: پاکسازی خاصی لازم ندارد */ };
}, []);
return <div ref={ref} style={{height:'600px'}} />;
}Next.js
- Import سمت کلاینت. SSR برای DOM لازم نیست. از dynamic import با
ssr:falseاستفاده کن.
// app/components/Calendar.tsx
'use client';
import { useEffect, useRef } from 'react';
import jalcal from '@ershadsarabi/jalcal';
import '@ershadsarabi/jalcal/style.css';
export default function Calendar() {
const el = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!el.current) return;
jalcal(el.current, { events: [] });
}, []);
return <div ref={el} style={{height:'600px'}} />;
}نکات فنی
- فرمت تاریخ ورودی:
"YYYY/MM/DD"یا"YYYY/MM/DD HH:MM". ارقام فارسی نیز پشتیبانی میشود. - Drag & Drop از HTML5 API استفاده میکند. اگر Hookها داده را رد نکنند، تقویم خودش state داخلی را بهروز و رندر میکند.
- تمام توابع کمکی و الگوریتم جلالی داخل پکیج پیادهسازی شدهاند. وابستگی خارجی وجود ندارد.
- RTL بهصورت پیشفرض. LTR نیز با تغییر
directionقابل استفاده است. - مرورگرهای مدرن پشتیبانی میشوند. IE پشتیبانی نمیشود.
توسعه و بیلد
سورس:
src/jalcal.jsوsrc/jalcal.cssخروجی بیلد:
- ESM:
dist/index.mjs - CJS:
dist/index.cjs - UMD:
dist/jalcal.umd.js - CSS:
dist/jalcal.css
- ESM:
اسکریپتها:
npm run buildانتشار:
npm login
npm version patch # یا minor/major
npm publish --access publicLicense
MIT
نویسنده
Ershad Sarabi
سایت
ershad.id.ir
