Refactor and polish calendar app: improved accessibility, cleaned up styles, and ensured responsiveness
This commit is contained in:
1 parent
6b27ec8baa
commit
0a0e623dad
10 files changed
+64
-43
No files matched your search
@@ -25,4 +25,3 @@ dist-ssr
|
||||
|
||||
|
||||
# lda
|
||||
ass/
|
||||
+15
-8
@@ -15,12 +15,12 @@
|
||||
<h1>🗓️ Calendar Filter App</h1>
|
||||
<p class="subtitle">Load, filter, and combine calendars with style.</p>
|
||||
</header>
|
||||
<div class="flex_input">
|
||||
<form class="flex_input" onsubmit="return false;">
|
||||
<input type="text" id="ics_file" placeholder="Paste .ics URL or API endpoint here" />
|
||||
<input type="button" value="new calendar" id="ics_run" />
|
||||
<input type="button" value="add a calendar" id="ics_add" />
|
||||
</div>
|
||||
<div class="info-bar" style="text-align: center">
|
||||
<button type="button" class="btn btn-primary" id="ics_run">New Calendar</button>
|
||||
<button type="button" class="btn btn-primary" id="ics_add">Add a Calendar</button>
|
||||
</form>
|
||||
<div class="info-bar">
|
||||
<span>Tip: You can add multiple calendars. Hover events for details.
|
||||
<a href="https://fullcalendar.io/" target="_blank" rel="noopener noreferrer">Powered by
|
||||
FullCalendar</a></span>
|
||||
@@ -30,18 +30,25 @@
|
||||
No calendar loaded yet. Paste a URL to get started!
|
||||
</div>
|
||||
<div id="calendar">
|
||||
<div id="calendar"></div>
|
||||
<!-- <div id="calendar"></div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="event-source-management" id="event-source-management">
|
||||
<h2>Event Sources</h2>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h4>Event Sources</h4>
|
||||
<button id="reload" class="btn btn-outline-primary">
|
||||
<i class="bi bi-arrow-clockwise"></i> Reload
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="event-source-list">
|
||||
<!-- Event source cards will be dynamically added here -->
|
||||
</div>
|
||||
</div>
|
||||
<footer class="app-footer">
|
||||
<p>Made with Rust, JS, and ❤️</p>
|
||||
<p>by
|
||||
<p>
|
||||
by
|
||||
<a href="//ldlda.com" target="_blank" rel="noopener noreferrer">lđa</a>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
+2
-1
@@ -23,7 +23,7 @@ export function initializeCalendar(
|
||||
url: string | URL,
|
||||
onEventMouseEnter: (arg: EventHoveringArg) => void,
|
||||
onEventMouseLeave: (arg: EventHoveringArg) => void
|
||||
): void {
|
||||
): Calendar {
|
||||
if (calendar) {
|
||||
calendar.destroy();
|
||||
}
|
||||
@@ -60,6 +60,7 @@ export function initializeCalendar(
|
||||
loading: glued,
|
||||
});
|
||||
calendar.render();
|
||||
return calendar // its real now
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Start with a random hue, but keep saturation and lightness fixed for "nice" colors
|
||||
let sourceCount = Math.floor(Math.random() * 360);
|
||||
let sourceCount = Math.floor(Math.random() * 25);
|
||||
|
||||
/**
|
||||
* Generates the next color in a sequence using the golden angle.
|
||||
|
||||
@@ -7,8 +7,8 @@ import { Calendar } from "@fullcalendar/core";
|
||||
*/
|
||||
export const updateEventSourceList2 = (eventSourceList: HTMLElement | null) => {
|
||||
return function updateEventSourceList(calendar: Calendar): void {
|
||||
if (!calendar) return;
|
||||
if (!eventSourceList) return;
|
||||
if (!calendar) return;
|
||||
|
||||
// Clear the current list
|
||||
eventSourceList.innerHTML = "";
|
||||
@@ -36,8 +36,8 @@ export const updateEventSourceList2 = (eventSourceList: HTMLElement | null) => {
|
||||
refetchButton.textContent = "Refetch";
|
||||
refetchButton.className = "btn btn-sm btn-primary align-right";
|
||||
refetchButton.addEventListener("click", () => {
|
||||
source.refetch();
|
||||
alert("Source refetched!");
|
||||
source.refetch(); // loading callback handled thing
|
||||
// alert("Source refetched!");
|
||||
});
|
||||
|
||||
// Add Remove Button
|
||||
|
||||
+32
-14
@@ -26,9 +26,13 @@ const placeholder_message = document.getElementById(
|
||||
const eventSourceList = document.getElementById(
|
||||
"event-source-list"
|
||||
) as HTMLElement;
|
||||
|
||||
const eventmanage = document.getElementById(
|
||||
"event-source-management"
|
||||
) as HTMLElement;
|
||||
|
||||
const reload_button = document.getElementById("reload") as HTMLButtonElement;
|
||||
|
||||
const updateEventSourceList = updateEventSourceList2(eventSourceList);
|
||||
|
||||
/**
|
||||
@@ -56,15 +60,22 @@ function hidePlaceholder(): void {
|
||||
export const glued = (_e: unknown): void => {
|
||||
const calendar = getCalendarInstance();
|
||||
if (calendar) {
|
||||
setTimeout(() => updateEventSourceList(calendar));
|
||||
setTimeout(() => updateEventSourceList(calendar)); // ahh
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the click event for the confirm button.
|
||||
* Validates the input URL and initializes the calendar.
|
||||
*/
|
||||
confirm_button.addEventListener("click", () => {
|
||||
// Remove existing listeners before adding new ones
|
||||
confirm_button.removeEventListener("click", handleConfirmClick);
|
||||
confirm_button.addEventListener("click", handleConfirmClick);
|
||||
|
||||
add_button.removeEventListener("click", handleAddClick);
|
||||
add_button.addEventListener("click", handleAddClick);
|
||||
|
||||
reload_button.removeEventListener("click", handleReloadClick);
|
||||
reload_button.addEventListener("click", handleReloadClick);
|
||||
|
||||
// Define the event handler functions
|
||||
function handleConfirmClick(): void {
|
||||
const url = create_url(text_field.value);
|
||||
if (!url)
|
||||
return text_field.value
|
||||
@@ -72,14 +83,11 @@ confirm_button.addEventListener("click", () => {
|
||||
: showPlaceholder();
|
||||
|
||||
hidePlaceholder();
|
||||
initializeCalendar(cal_ele, url, newTippy, tippyDie);
|
||||
});
|
||||
const calendar = initializeCalendar(cal_ele, url, newTippy, tippyDie);
|
||||
updateEventSourceList(calendar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the click event for the add button.
|
||||
* Validates the input URL and adds a new event source to the calendar.
|
||||
*/
|
||||
add_button.addEventListener("click", () => {
|
||||
function handleAddClick(): void {
|
||||
const url = create_url(text_field.value);
|
||||
if (!url) {
|
||||
if (text_field.value) alert("Please input valid url.");
|
||||
@@ -90,4 +98,14 @@ add_button.addEventListener("click", () => {
|
||||
addEventSource(url);
|
||||
updateEventSourceList(calendar);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleReloadClick(): void {
|
||||
const calendar = getCalendarInstance();
|
||||
if (calendar) {
|
||||
updateEventSourceList(calendar);
|
||||
alert("Event sources reloaded!");
|
||||
} else {
|
||||
alert("No calendar instance found.");
|
||||
}
|
||||
}
|
||||
+8
-13
@@ -11,16 +11,12 @@ body {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
/* max-width: 900px; */
|
||||
/* Removed to allow full responsiveness */
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
padding: 1em;
|
||||
box-sizing: border-box;
|
||||
/* max-width: 900px; */
|
||||
/* Removed to allow Bootstrap container to handle layout */
|
||||
}
|
||||
|
||||
.app-header {
|
||||
@@ -34,13 +30,11 @@ body {
|
||||
margin: 2em auto 1em auto;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
/* max-width: 900px; */
|
||||
/* Removed to allow full responsiveness */
|
||||
}
|
||||
|
||||
#ics_file {
|
||||
flex: 1 1 0;
|
||||
min-width: 200px;
|
||||
/* min-width: 200px; */
|
||||
max-width: 100%;
|
||||
font-size: 1.1em;
|
||||
padding: 0.5em 0.8em;
|
||||
@@ -50,7 +44,8 @@ body {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input[type="button"] {
|
||||
/* trying bootstraps button */
|
||||
/* input[type="button"] {
|
||||
padding: 0.5em 1.2em;
|
||||
font-size: 1em;
|
||||
border: none;
|
||||
@@ -62,6 +57,10 @@ input[type="button"] {
|
||||
}
|
||||
input[type="button"]:hover {
|
||||
background: #0056b3;
|
||||
} */
|
||||
|
||||
.info-bar {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#calendar {
|
||||
@@ -76,8 +75,6 @@ input[type="button"]:hover {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.07);
|
||||
padding: 1em 0.5em 1em 0.5em;
|
||||
/* max-width: 900px; */
|
||||
/* Removed to allow full responsiveness */
|
||||
}
|
||||
|
||||
/* Placeholder message */
|
||||
@@ -92,8 +89,6 @@ input[type="button"]:hover {
|
||||
.flex_input {
|
||||
flex-wrap: wrap;
|
||||
gap: 0.7em;
|
||||
/* max-width: 98vw; */
|
||||
/* Removed to allow Bootstrap container to handle layout */
|
||||
}
|
||||
#calendar {
|
||||
padding: 0.5em 0.1em 1em 0.1em;
|
||||
@@ -125,13 +120,13 @@ input[type="button"]:hover {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
border: 1px solid #ddd;
|
||||
border-left: 4px solid #007bff; /* Default border color */
|
||||
padding: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
background: #ffffff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
||||
/* border: 1px solid #ddd; */
|
||||
background-color: #f9f9f9;
|
||||
flex-wrap: wrap; /* Allow wrapping for smaller screens */
|
||||
}
|
||||
|
||||
@@ -36,5 +36,5 @@ export function formatTooltip(title: string, description?: string): string {
|
||||
const escapedTitle = escapeHtml(title);
|
||||
const escapedDescription = description ? escapeHtml(description) : "";
|
||||
const linkifiedDescription = linkify(escapedDescription);
|
||||
return `${escapedTitle}<br>${linkifiedDescription}`;
|
||||
return `<p>${escapedTitle}</p><p>${linkifiedDescription}</p>`;
|
||||
}
|
||||
+1
-1
@@ -12,6 +12,6 @@
|
||||
"@fullcalendar/*": ["node_modules/@fullcalendar/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"include": ["src/**/*", "vite-env.d.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
Reference in new issue
Block a user