mirror of
https://github.com/zadam/trilium.git
synced 2025-10-20 23:29:02 +02:00
feat(collections/calendar): use own UI for header
This commit is contained in:
parent
49c80f0e0b
commit
afc17f41f6
@ -293,6 +293,11 @@ button.close:hover {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.icon-action.btn {
|
||||
padding: 0 8px;
|
||||
min-width: unset !important;
|
||||
}
|
||||
|
||||
.ui-widget-content a:not(.ui-tabs-anchor) {
|
||||
color: #337ab7 !important;
|
||||
}
|
||||
|
@ -587,7 +587,17 @@
|
||||
"september": "September",
|
||||
"october": "October",
|
||||
"november": "November",
|
||||
"december": "December"
|
||||
"december": "December",
|
||||
"week": "Week",
|
||||
"week_previous": "Previous week",
|
||||
"week_next": "Next week",
|
||||
"month": "Month",
|
||||
"month_previous": "Previous month",
|
||||
"month_next": "Next month",
|
||||
"year": "Year",
|
||||
"year_previous": "Previous year",
|
||||
"year_next": "Next year",
|
||||
"list": "List"
|
||||
},
|
||||
"close_pane_button": {
|
||||
"close_this_pane": "Close this pane"
|
||||
|
@ -59,4 +59,21 @@ body.desktop:not(.zen) .calendar-container .fc-toolbar.fc-header-toolbar {
|
||||
font-size: 0.85em;
|
||||
opacity: 0.85;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* #region Header */
|
||||
.calendar-header {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.calendar-header .btn {
|
||||
min-width: unset !important;
|
||||
}
|
||||
|
||||
.calendar-header > .title {
|
||||
flex-grow: 1;
|
||||
}
|
||||
/* #endregion */
|
@ -16,18 +16,50 @@ import date_notes from "../../../services/date_notes";
|
||||
import appContext from "../../../components/app_context";
|
||||
import { DateClickArg } from "@fullcalendar/interaction";
|
||||
import FNote from "../../../entities/fnote";
|
||||
import Button, { ButtonGroup } from "../../react/Button";
|
||||
import ActionButton from "../../react/ActionButton";
|
||||
import { RefObject } from "preact";
|
||||
|
||||
interface CalendarViewData {
|
||||
|
||||
}
|
||||
|
||||
interface CalendarViewData {
|
||||
type: string;
|
||||
name: string;
|
||||
previousText: string;
|
||||
nextText: string;
|
||||
}
|
||||
|
||||
const CALENDAR_VIEWS = [
|
||||
"timeGridWeek",
|
||||
"dayGridMonth",
|
||||
"multiMonthYear",
|
||||
"listMonth"
|
||||
{
|
||||
type: "timeGridWeek",
|
||||
name: t("calendar.week"),
|
||||
previousText: t("calendar.week_previous"),
|
||||
nextText: t("calendar.week_next")
|
||||
},
|
||||
{
|
||||
type: "dayGridMonth",
|
||||
name: t("calendar.month"),
|
||||
previousText: t("calendar.month_previous"),
|
||||
nextText: t("calendar.month_next")
|
||||
},
|
||||
{
|
||||
type: "multiMonthYear",
|
||||
name: t("calendar.year"),
|
||||
previousText: t("calendar.year_previous"),
|
||||
nextText: t("calendar.year_next")
|
||||
},
|
||||
{
|
||||
type: "listMonth",
|
||||
name: t("calendar.list"),
|
||||
previousText: t("calendar.month_previous"),
|
||||
nextText: t("calendar.month_next")
|
||||
}
|
||||
]
|
||||
|
||||
const SUPPORTED_CALENDAR_VIEW_TYPE = CALENDAR_VIEWS.map(v => v.type);
|
||||
|
||||
// Here we hard-code the imports in order to ensure that they are embedded by webpack without having to load all the languages.
|
||||
export const LOCALE_MAPPINGS: Record<LOCALE_IDS, (() => Promise<{ default: LocaleInput }>) | null> = {
|
||||
de: () => import("@fullcalendar/core/locales/de"),
|
||||
@ -83,20 +115,18 @@ export default function CalendarView({ note, noteIds }: ViewModeProps<CalendarVi
|
||||
|
||||
return (plugins &&
|
||||
<div className="calendar-view" ref={containerRef}>
|
||||
<CalendarHeader calendarRef={calendarRef} />
|
||||
<Calendar
|
||||
events={eventBuilder}
|
||||
calendarRef={calendarRef}
|
||||
plugins={plugins}
|
||||
tabIndex={100}
|
||||
initialView={initialView.current && CALENDAR_VIEWS.includes(initialView.current) ? initialView.current : "dayGridMonth"}
|
||||
headerToolbar={{
|
||||
start: "title",
|
||||
end: `${CALENDAR_VIEWS.join(",")} today prev,next`
|
||||
}}
|
||||
initialView={initialView.current && SUPPORTED_CALENDAR_VIEW_TYPE.includes(initialView.current) ? initialView.current : "dayGridMonth"}
|
||||
headerToolbar={false}
|
||||
firstDay={firstDayOfWeek ?? 0}
|
||||
weekends={!hideWeekends}
|
||||
weekNumbers={weekNumbers}
|
||||
height="100%"
|
||||
height="90%"
|
||||
nowIndicator
|
||||
handleWindowResize={false}
|
||||
locale={locale}
|
||||
@ -113,6 +143,31 @@ export default function CalendarView({ note, noteIds }: ViewModeProps<CalendarVi
|
||||
);
|
||||
}
|
||||
|
||||
function CalendarHeader({ calendarRef }: { calendarRef: RefObject<FullCalendar> }) {
|
||||
const currentViewType = calendarRef.current?.view?.type;
|
||||
const currentViewData = CALENDAR_VIEWS.find(v => calendarRef.current && v.type === currentViewType);
|
||||
|
||||
return (
|
||||
<div className="calendar-header">
|
||||
<span className="title">{calendarRef.current?.view.title}</span>
|
||||
<ButtonGroup>
|
||||
{CALENDAR_VIEWS.map(viewData => (
|
||||
<Button
|
||||
text={viewData.name.toLocaleLowerCase()}
|
||||
className={currentViewType === viewData.type ? "active" : ""}
|
||||
onClick={() => calendarRef.current?.changeView(viewData.type)}
|
||||
/>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
<Button text="today" onClick={() => calendarRef.current?.today()} />
|
||||
<ButtonGroup>
|
||||
<ActionButton icon="bx bx-chevron-left" text={currentViewData?.previousText ?? ""} frame onClick={() => calendarRef.current?.prev()} />
|
||||
<ActionButton icon="bx bx-chevron-right" text={currentViewData?.nextText ?? ""} frame onClick={() => calendarRef.current?.next()} />
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function usePlugins(isEditable: boolean, isCalendarRoot: boolean) {
|
||||
const [ plugins, setPlugins ] = useState<PluginDef[]>();
|
||||
|
||||
|
@ -11,18 +11,19 @@ export interface ActionButtonProps {
|
||||
onClick?: (e: MouseEvent) => void;
|
||||
triggerCommand?: CommandNames;
|
||||
noIconActionClass?: boolean;
|
||||
frame?: boolean;
|
||||
}
|
||||
|
||||
export default function ActionButton({ text, icon, className, onClick, triggerCommand, titlePosition, noIconActionClass }: ActionButtonProps) {
|
||||
export default function ActionButton({ text, icon, className, onClick, triggerCommand, titlePosition, noIconActionClass, frame }: ActionButtonProps) {
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const [ keyboardShortcut, setKeyboardShortcut ] = useState<string[]>();
|
||||
|
||||
|
||||
useStaticTooltip(buttonRef, {
|
||||
title: keyboardShortcut?.length ? `${text} (${keyboardShortcut?.join(",")})` : text,
|
||||
placement: titlePosition ?? "bottom",
|
||||
fallbackPlacements: [ titlePosition ?? "bottom" ]
|
||||
});
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (triggerCommand) {
|
||||
keyboard_actions.getAction(triggerCommand, true).then(action => setKeyboardShortcut(action?.effectiveShortcuts));
|
||||
@ -31,8 +32,8 @@ export default function ActionButton({ text, icon, className, onClick, triggerCo
|
||||
|
||||
return <button
|
||||
ref={buttonRef}
|
||||
class={`${className ?? ""} ${!noIconActionClass ? "icon-action" : "btn"} ${icon}`}
|
||||
onClick={onClick}
|
||||
class={`${className ?? ""} ${!noIconActionClass ? "icon-action" : "btn"} ${icon} ${frame ? "btn btn-primary" : ""}`}
|
||||
onClick={onClick}
|
||||
data-trigger-command={triggerCommand}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { RefObject } from "preact";
|
||||
import type { ComponentChildren, RefObject } from "preact";
|
||||
import type { CSSProperties } from "preact/compat";
|
||||
import { useMemo } from "preact/hooks";
|
||||
import { memo } from "preact/compat";
|
||||
@ -72,4 +72,12 @@ const Button = memo(({ name, buttonRef, className, text, onClick, keyboardShortc
|
||||
);
|
||||
});
|
||||
|
||||
export default Button;
|
||||
export function ButtonGroup({ children }: { children: ComponentChildren }) {
|
||||
return (
|
||||
<div className="btn-group" role="group">
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Button;
|
||||
|
Loading…
x
Reference in New Issue
Block a user