Implement custom header formatting (v1.33.0)
This commit is contained in:
parent
889282381f
commit
b827f39722
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.32.0",
|
||||
"version": "1.33.0",
|
||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -263,6 +263,8 @@ const translations: Record<string, any> = {
|
||||
headerDisplayMonth: "Month Name",
|
||||
headerDisplayMonthYear: "Month & Year",
|
||||
headerDisplayDate: "Full Date",
|
||||
headerDisplayCustom: "Custom",
|
||||
headerCustomFormatLabel: "Format string (e.g. DD.MM.YYYY)",
|
||||
language: "Language",
|
||||
dateFormat: "Date Format",
|
||||
timeFormat: "Time Format",
|
||||
@ -471,6 +473,8 @@ const translations: Record<string, any> = {
|
||||
headerDisplayMonth: "Monatsname",
|
||||
headerDisplayMonthYear: "Monat & Jahr",
|
||||
headerDisplayDate: "Vollständiges Datum",
|
||||
headerDisplayCustom: "Benutzerdefiniert",
|
||||
headerCustomFormatLabel: "Format (z.B. DD.MM.YYYY)",
|
||||
listView: "Liste",
|
||||
notes: "Notizen",
|
||||
notesSidebar: "Notizen-Seitenleiste",
|
||||
@ -682,6 +686,8 @@ const translations: Record<string, any> = {
|
||||
headerDisplayMonth: "Nom du mois",
|
||||
headerDisplayMonthYear: "Mois & Année",
|
||||
headerDisplayDate: "Date complète",
|
||||
headerDisplayCustom: "Personnalisé",
|
||||
headerCustomFormatLabel: "Format (ex: DD.MM.YYYY)",
|
||||
language: "Langue",
|
||||
dateFormat: "Format de date",
|
||||
timeFormat: "Format d'heure",
|
||||
@ -891,6 +897,8 @@ const translations: Record<string, any> = {
|
||||
headerDisplayMonth: "Nombre del mes",
|
||||
headerDisplayMonthYear: "Mes y Año",
|
||||
headerDisplayDate: "Fecha completa",
|
||||
headerDisplayCustom: "Personalizado",
|
||||
headerCustomFormatLabel: "Formato (ej. DD.MM.YYYY)",
|
||||
language: "Idioma",
|
||||
dateFormat: "Formato de fecha",
|
||||
timeFormat: "Formato de hora",
|
||||
@ -1100,6 +1108,8 @@ const translations: Record<string, any> = {
|
||||
headerDisplayMonth: "Nome del mese",
|
||||
headerDisplayMonthYear: "Mese e Anno",
|
||||
headerDisplayDate: "Data completa",
|
||||
headerDisplayCustom: "Personalizzato",
|
||||
headerCustomFormatLabel: "Formato (es. DD.MM.YYYY)",
|
||||
language: "Lingua",
|
||||
dateFormat: "Formato data",
|
||||
timeFormat: "Formato ora",
|
||||
@ -1424,6 +1434,37 @@ function getCWReferenceDate(days: Date[]): Date {
|
||||
return new Date(first.getTime() - distToMonday * 86400000);
|
||||
}
|
||||
|
||||
// Format a custom header string using tokens
|
||||
function formatCustomHeader(format: string, days: Date[], language: string, t: any): string {
|
||||
if (!format) return "";
|
||||
const refDate = getCWReferenceDate(days);
|
||||
const today = new Date();
|
||||
|
||||
let result = format;
|
||||
|
||||
// [TODAY] token
|
||||
result = result.replace(/\[TODAY\]/g, today.toLocaleDateString(language, { day: '2-digit', month: '2-digit', year: 'numeric' }));
|
||||
|
||||
// YYYY
|
||||
result = result.replace(/YYYY/g, refDate.getFullYear().toString());
|
||||
|
||||
// WW (ISO Week)
|
||||
result = result.replace(/WW/g, getWeekNumber(refDate).toString().padStart(2, '0'));
|
||||
result = result.replace(/W/g, getWeekNumber(refDate).toString());
|
||||
|
||||
// MMMM (Month Name Long)
|
||||
result = result.replace(/MMMM/g, refDate.toLocaleDateString(language, { month: 'long' }));
|
||||
result = result.replace(/MMM/g, refDate.toLocaleDateString(language, { month: 'short' }));
|
||||
result = result.replace(/MM/g, (refDate.getMonth() + 1).toString().padStart(2, '0'));
|
||||
result = result.replace(/M/g, (refDate.getMonth() + 1).toString());
|
||||
|
||||
// DD (Day)
|
||||
result = result.replace(/DD/g, refDate.getDate().toString().padStart(2, '0'));
|
||||
result = result.replace(/D/g, refDate.getDate().toString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check if an event is an all-day event
|
||||
// Defined outside component to avoid stale closure issues in useCallbacks
|
||||
const isAllDayEvent = (event: CalendarEvent): boolean => {
|
||||
@ -1803,7 +1844,8 @@ export default function WeeklyView() {
|
||||
weekdayCase?: "normal" | "capitalize" | "uppercase";
|
||||
customWeekdayNames?: string;
|
||||
dateVerticalAlign?: "top" | "middle" | "bottom";
|
||||
headerDisplay?: "kw" | "month" | "month_year" | "date";
|
||||
headerDisplay?: "kw" | "month" | "month_year" | "date" | "custom";
|
||||
headerCustomFormat?: string;
|
||||
lightTheme?: any;
|
||||
darkTheme?: any;
|
||||
}>({
|
||||
@ -5474,6 +5516,8 @@ export default function WeeklyView() {
|
||||
<span>{getCWReferenceDate(getVisibleDays()).toLocaleDateString(language, { day: '2-digit', month: '2-digit', year: 'numeric' })}</span>
|
||||
) : profile.headerDisplay === "month_year" ? (
|
||||
<span>{getCWReferenceDate(getVisibleDays()).toLocaleDateString(language, { month: 'long', year: 'numeric' })}</span>
|
||||
) : profile.headerDisplay === "custom" ? (
|
||||
<span>{formatCustomHeader(profile.headerCustomFormat || "KW WW | YYYY", getVisibleDays(), language, t)}</span>
|
||||
) : (
|
||||
<>
|
||||
<span>KW{getWeekNumber(getCWReferenceDate(getVisibleDays())).toString().padStart(2, "0")}</span>
|
||||
@ -5731,7 +5775,9 @@ export default function WeeklyView() {
|
||||
? getCWReferenceDate(getVisibleDays()).toLocaleDateString(language, { month: "long", year: "numeric" })
|
||||
: profile.headerDisplay === "date"
|
||||
? getCWReferenceDate(getVisibleDays()).toLocaleDateString(language, { day: '2-digit', month: '2-digit', year: 'numeric' })
|
||||
: `KW ${getWeekNumber(getCWReferenceDate(getVisibleDays())).toString().padStart(2, "0")}`
|
||||
: profile.headerDisplay === "custom"
|
||||
? formatCustomHeader(profile.headerCustomFormat || "KW WW | YYYY", getVisibleDays(), language, t)
|
||||
: `KW ${getWeekNumber(getCWReferenceDate(getVisibleDays())).toString().padStart(2, "0")}`
|
||||
}
|
||||
</span>
|
||||
{(profile.headerDisplay === "kw" || profile.headerDisplay === "month" || !profile.headerDisplay) && (
|
||||
@ -9694,7 +9740,8 @@ function SettingsSidebar({
|
||||
weekdayCase?: "normal" | "capitalize" | "uppercase";
|
||||
customWeekdayNames?: string;
|
||||
dateVerticalAlign?: "top" | "middle" | "bottom";
|
||||
headerDisplay?: "kw" | "month" | "month_year" | "date";
|
||||
headerDisplay?: "kw" | "month" | "month_year" | "date" | "custom";
|
||||
headerCustomFormat?: string;
|
||||
}>({
|
||||
name: "",
|
||||
email: "",
|
||||
@ -9709,6 +9756,7 @@ function SettingsSidebar({
|
||||
focusTimerDuration: 25,
|
||||
focusBreakDuration: 5,
|
||||
headerDisplay: "kw",
|
||||
headerCustomFormat: "KW WW | YYYY",
|
||||
cellDuration: 30,
|
||||
viewStyle: "list",
|
||||
fontSize: "M",
|
||||
@ -10852,7 +10900,37 @@ function SettingsSidebar({
|
||||
>
|
||||
{t.headerDisplayDate}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setProfile({ ...profile, headerDisplay: "custom" });
|
||||
saveSetting("headerDisplay", "custom");
|
||||
}}
|
||||
className={`px-4 py-2 text-sm rounded transition-colors ${profile.headerDisplay === "custom" ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
|
||||
>
|
||||
{t.headerDisplayCustom}
|
||||
</button>
|
||||
</div>
|
||||
{profile.headerDisplay === "custom" && (
|
||||
<div className="mt-2">
|
||||
<label style={{ fontSize: "0.75rem", color: "var(--weekly-settings-label)", display: "block", marginBottom: "4px" }}>
|
||||
{t.headerCustomFormatLabel}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={profile.headerCustomFormat || ""}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value;
|
||||
setProfile({ ...profile, headerCustomFormat: val });
|
||||
saveSetting("headerCustomFormat", val);
|
||||
}}
|
||||
placeholder="KW WW | YYYY or DD.MM.YYYY"
|
||||
className="w-full px-3 py-1.5 text-sm rounded border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white"
|
||||
/>
|
||||
<div className="mt-1 text-[10px] text-gray-500 leading-tight">
|
||||
Tokens: WW (Week), YYYY (Year), MMMM (Month Name), MM (Month Num), DD (Day), [TODAY] (Active Date)
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Kanban Stages Settings */}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user