upload slideshow, adjust .gitignore, frontend animation to prevent screen burn-in, and server configured for MS GRAPH App-Only Auth

This commit is contained in:
Sura Hanna 2024-05-23 17:51:04 -04:00
parent 82c08dc9be
commit 1aad4c2275
62 changed files with 52 additions and 1843 deletions

4
.gitignore vendored
View File

@ -130,6 +130,4 @@ dist
.yarn/install-state.gz .yarn/install-state.gz
.pnp.* .pnp.*
certs/ frontend-dev/
slideshow/*

View File

@ -1,3 +1,25 @@
# vizwall_screensaver # vizwall_screensaver
Screensaver that marries the slideshow, the daily schedule, and the vizwall_homepage This is a screensaver for the Visualization Wall in ER 1431-03.
To implement on server: first, environment variables would need to be set in a .env file.
A .env.example file is supplied. The values will be supplied privately.
To start the webpage: first, clone the repo.
second, change your current working directory to the root of the repo.
third, run npm install.
finally, run npm start.
Alternatively, perhaps ideally, a process manager which can restart the node server on server reboot or crash would be implemented to run the server.
pm2 is a popular process manager for node.js applications.
To install pm2, run `npm install pm2 -g`.
To start the server with pm2, run `pm2 start server.js`.
To make the application run on server reboot, run `pm2 startup` and follow the instructions.
Read more about pm2 here: https://www.npmjs.com/package/pm2
This will start the server on port specified in .env || 8080 by default.

View File

@ -1,124 +0,0 @@
{
"value": [
{
"subject": "Team Standup Meeting",
"start": {
"dateTime": "2024-04-12T08:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T09:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-00 Open Space"
},
"organizer": {
"emailAddress": {
"address": "organizer1@example.com",
"name": "John Doe"
}
}
},
{
"subject": "Project Discussion",
"start": {
"dateTime": "2024-04-12T10:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-00 Open Space"
},
"organizer": {
"emailAddress": {
"address": "organizer2@example.com",
"name": "Jane Smith"
}
}
},
{
"subject": "Client Call",
"start": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-00 Open Space"
},
"organizer": {
"emailAddress": {
"address": "organizer3@example.com",
"name": "Alice Johnson"
}
}
},
{
"subject": "Lunch Break",
"start": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T13:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-00 Open Space"
},
"organizer": {
"emailAddress": {
"address": "organizer4@example.com",
"name": "Bob White"
}
}
},
{
"subject": "Design Review",
"start": {
"dateTime": "2024-04-12T14:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T15:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-00 Open Space"
},
"organizer": {
"emailAddress": {
"address": "organizer5@example.com",
"name": "Clara Green"
}
}
},
{
"subject": "Wrap-Up Meeting",
"start": {
"dateTime": "2024-04-12T16:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T17:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-00 Open Space"
},
"organizer": {
"emailAddress": {
"address": "organizer6@example.com",
"name": "Daniel Blue"
}
}
}
]
}

View File

@ -1,124 +0,0 @@
{
"value": [
{
"subject": "Team Standup Meeting",
"start": {
"dateTime": "2024-04-12T08:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T09:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-03 Visualization Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer1@example.com",
"name": "John Doe"
}
}
},
{
"subject": "Project Discussion",
"start": {
"dateTime": "2024-04-12T10:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-03 Visualization Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer2@example.com",
"name": "Jane Smith"
}
}
},
{
"subject": "Client Call",
"start": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-03 Visualization Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer3@example.com",
"name": "Alice Johnson"
}
}
},
{
"subject": "Lunch Break",
"start": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T13:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-03 Visualization Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer4@example.com",
"name": "Bob White"
}
}
},
{
"subject": "Design Review",
"start": {
"dateTime": "2024-04-12T14:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T15:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-03 Visualization Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer5@example.com",
"name": "Clara Green"
}
}
},
{
"subject": "Wrap-Up Meeting",
"start": {
"dateTime": "2024-04-12T16:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T17:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-03 Visualization Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer6@example.com",
"name": "Daniel Blue"
}
}
}
]
}

View File

@ -1,124 +0,0 @@
{
"value": [
{
"subject": "Team Standup Meeting",
"start": {
"dateTime": "2024-04-12T08:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T09:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-33 Ideation Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer1@example.com",
"name": "John Doe"
}
}
},
{
"subject": "Project Discussion",
"start": {
"dateTime": "2024-04-12T10:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-33 Ideation Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer2@example.com",
"name": "Jane Smith"
}
}
},
{
"subject": "Client Call",
"start": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-33 Ideation Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer3@example.com",
"name": "Alice Johnson"
}
}
},
{
"subject": "Lunch Break",
"start": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T13:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-33 Ideation Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer4@example.com",
"name": "Bob White"
}
}
},
{
"subject": "Design Review",
"start": {
"dateTime": "2024-04-12T14:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T15:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-33 Ideation Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer5@example.com",
"name": "Clara Green"
}
}
},
{
"subject": "Wrap-Up Meeting",
"start": {
"dateTime": "2024-04-12T16:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T17:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-33 Ideation Lab"
},
"organizer": {
"emailAddress": {
"address": "organizer6@example.com",
"name": "Daniel Blue"
}
}
}
]
}

View File

@ -1,124 +0,0 @@
{
"value": [
{
"subject": "Team Standup Meeting",
"start": {
"dateTime": "2024-04-12T08:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T09:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-37 Multipurpose Room"
},
"organizer": {
"emailAddress": {
"address": "organizer1@example.com",
"name": "John Doe"
}
}
},
{
"subject": "Project Discussion",
"start": {
"dateTime": "2024-04-12T10:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-37 Multipurpose Room"
},
"organizer": {
"emailAddress": {
"address": "organizer2@example.com",
"name": "Jane Smith"
}
}
},
{
"subject": "Client Call",
"start": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-37 Multipurpose Room"
},
"organizer": {
"emailAddress": {
"address": "organizer3@example.com",
"name": "Alice Johnson"
}
}
},
{
"subject": "Lunch Break",
"start": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T13:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-37 Multipurpose Room"
},
"organizer": {
"emailAddress": {
"address": "organizer4@example.com",
"name": "Bob White"
}
}
},
{
"subject": "Design Review",
"start": {
"dateTime": "2024-04-12T14:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T15:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-37 Multipurpose Room"
},
"organizer": {
"emailAddress": {
"address": "organizer5@example.com",
"name": "Clara Green"
}
}
},
{
"subject": "Wrap-Up Meeting",
"start": {
"dateTime": "2024-04-12T16:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T17:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-37 Multipurpose Room"
},
"organizer": {
"emailAddress": {
"address": "organizer6@example.com",
"name": "Daniel Blue"
}
}
}
]
}

View File

@ -1,124 +0,0 @@
{
"value": [
{
"subject": "Team Standup Meeting",
"start": {
"dateTime": "2024-04-12T08:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T09:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-39 Conference Room"
},
"organizer": {
"emailAddress": {
"address": "organizer1@example.com",
"name": "John Doe"
}
}
},
{
"subject": "Project Discussion",
"start": {
"dateTime": "2024-04-12T10:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-39 Conference Room"
},
"organizer": {
"emailAddress": {
"address": "organizer2@example.com",
"name": "Jane Smith"
}
}
},
{
"subject": "Client Call",
"start": {
"dateTime": "2024-04-12T11:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-39 Conference Room"
},
"organizer": {
"emailAddress": {
"address": "organizer3@example.com",
"name": "Alice Johnson"
}
}
},
{
"subject": "Lunch Break",
"start": {
"dateTime": "2024-04-12T12:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T13:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-39 Conference Room"
},
"organizer": {
"emailAddress": {
"address": "organizer4@example.com",
"name": "Bob White"
}
}
},
{
"subject": "Design Review",
"start": {
"dateTime": "2024-04-12T14:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T15:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-39 Conference Room"
},
"organizer": {
"emailAddress": {
"address": "organizer5@example.com",
"name": "Clara Green"
}
}
},
{
"subject": "Wrap-Up Meeting",
"start": {
"dateTime": "2024-04-12T16:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2024-04-12T17:00:00",
"timeZone": "Eastern Standard Time"
},
"location": {
"displayName": "ER 1431-39 Conference Room"
},
"organizer": {
"emailAddress": {
"address": "organizer6@example.com",
"name": "Daniel Blue"
}
}
}
]
}

View File

@ -1,240 +0,0 @@
function populateTable(resourceUPN, events, container) {
console.log(events);
// Create a wrapper for the resource and its events
const resourceWrapper = document.createElement('div');
resourceWrapper.className = 'resource-wrapper';
// Create a row for the resource title
const titleRow = document.createElement('div');
titleRow.className = 'title-row';
switch (resourceUPN.split("@")[0]) {
case "s-er-1431-00":
titleRow.innerHTML = 'ER 1431-00 Open Space';
break;
case "s-er-1431-03":
titleRow.innerHTML = 'ER 1431-03 Visualization Lab';
break;
case "s-er-1431-33":
titleRow.innerHTML = 'ER 1431-33 Ideation Lab';
break;
case "s-er-1431-37":
titleRow.innerHTML = 'ER 1431-37 Multipurpose Room';
break;
case "s-er-1431-39":
titleRow.innerHTML = 'ER 1431-39 Conference Room';
break;
}
resourceWrapper.appendChild(titleRow);
// Create a grid for events
const eventGrid = document.createElement('div');
eventGrid.className = 'event-row';
events.forEach((event, index) => {
const eventCell = document.createElement('div');
eventCell.className = 'flex-cell';
const title = event.subject;
const organizer = event.organizer.emailAddress.name;
const startTime = formatUTCTime(event.start.dateTime + 'Z');
const endTime = formatUTCTime(event.end.dateTime + 'Z');
const titleDiv = document.createElement('div');
titleDiv.textContent = title;
const organizerDiv = document.createElement('div');
organizerDiv.textContent = organizer;
organizerDiv.className = 'organizer';
const timeDiv = document.createElement('div');
timeDiv.className = 'time-range';
timeDiv.innerHTML = `${startTime} - ${endTime}`;
eventCell.appendChild(titleDiv);
eventCell.appendChild(organizerDiv);
eventCell.appendChild(timeDiv);
eventGrid.appendChild(eventCell);
});
resourceWrapper.appendChild(eventGrid);
container.appendChild(resourceWrapper);
}
function formatUTCTime(date) {
const etDate = new Date(date.toLocaleString("en-US", { timeZone: "America/New_York" }));
const hours = etDate.getHours();
const minutes = etDate.getMinutes().toString().padStart(2, '0');
return `<span class="time">${hours}</span><span class="separator">:</span><span class="time">${minutes}</span>`;
}
async function fetchAllEvents() {
console.log("fetching events");
const response = await fetch('http://localhost:8080/api/events');
const allEvents = await response.json();
console.log(allEvents);
const resourcesContainer = document.getElementById('resources-container');
resourcesContainer.innerHTML = '';
const keys = Object.keys(allEvents);
keys.forEach((key) => {
console.log(allEvents[key]);
populateTable(key, allEvents[key].value, resourcesContainer);
});
}
function updateTime(showSeparator) {
let timeString = formatUTCTime(new Date());
if (!showSeparator) {
timeString = timeString.replace(':', ' ');
}
document.getElementById('time').innerHTML = timeString;
}
function updateFontSize(elementId) {
const element = document.getElementById(elementId);
const textLength = element.textContent.length;
if (textLength <= 83) {
element.style.fontSize = '5em';
} else if (textLength <= 166) {
element.style.fontSize = '4em';
} else {
element.style.fontSize = '3em';
}
}
// Function to fetch and display a quote
async function fetchAndDisplayQuote() {
try {
const response = await fetch('http://localhost:8080/api/quotes');
if (response.ok) {
const data = await response.json();
const quotes = data.results;
const randomIndex = Math.floor(Math.random() * quotes.length);
const randomQuote = quotes[randomIndex];
document.getElementById('quote').innerHTML = `<i>${randomQuote.content}</i>`;
updateFontSize('quote');
document.getElementById('author').innerHTML = `${randomQuote.author}`;
} else {
console.error('Failed to fetch data');
}
} catch (error) {
console.error('An error occurred:', error);
}
}
// Fetch Current Weather
async function fetchWeather() {
const response = await fetch('http://localhost:8080/api/weather');
const data = await response.json();
if (data.cod === 200) {
const temperature = data.main.temp;
const description = data.weather[0].description;
const iconCode = data.weather[0].icon;
const iconUrl = `https://openweathermap.org/img/wn/${iconCode}.png`
document.getElementById("weather-icon-container").innerHTML = `<img id="weather-icon" alt="Weather Icon" src="${iconUrl}">`;
document.getElementById("temperature").innerHTML = `${temperature}°`;
document.getElementById("description").innerHTML = `${description}`;
} else {
document.getElementById("weather").innerText = 'Weather data unavailable';
}
}
// Display Current Time
function displayTime() {
const now = new Date();
const timeHtml = formatUTCTime(now);
document.getElementById("time").innerHTML = timeHtml;
setTimeout(displayTime, 60000);
}
// Slideshow
async function fetchSlideshowImages() {
try {
const response = await fetch('http://localhost:8080/api/slideshow');
if (!response.ok) {
throw new Error('Failed to fetch slideshow images');
}
const images = await response.json();
updateSlideshow(images);
} catch (error) {
console.error('Error fetching slideshow images:', error);
}
}
function createSlideshowElement(src) {
const img = document.createElement('img');
// img.src = src;
img.src = `http://localhost:8080${src}`;
img.className = 'slideshow-img';
img.style.width = '100%';
img.style.maxHeight = '100vh';
img.style.objectFit = 'cover';
const filename = src.split('/').pop().split('.')[0]; // Extracts filename without extension
// Set the filename as the alt text
img.alt = filename;
// If you also want to set the title attribute
img.title = filename;
return img;
}
let currentIndex = 0;
function updateSlideshow(images) {
if (images.length === 0) {
console.log('No images found for the slideshow.');
return;
}
const slideshowContainer = document.getElementById('slideshow');
slideshowContainer.innerHTML = '';
const imageElement = createSlideshowElement(images[currentIndex]);
slideshowContainer.appendChild(imageElement);
// Wait a little bit before starting the fade-in to ensure it's loaded
setTimeout(() => { imageElement.style.opacity = '1'; }, 100);
// Clean up the previous image after the new one has faded in
setTimeout(() => {
while (slideshowContainer.children.length > 1) {
slideshowContainer.removeChild(slideshowContainer.firstChild);
}
}, 100);
currentIndex = (currentIndex + 1) % images.length;
setTimeout(() => updateSlideshow(images), 30000); // Change image every 5 seconds
}
let showSeparator = true;
fetchAndDisplayQuote();
setInterval(fetchAndDisplayQuote, 60 * 60 * 1000);
fetchWeather();
setInterval(fetchWeather, 15 * 60 * 1000);
updateTime(showSeparator);
setInterval(() => {
updateTime(showSeparator);
showSeparator = !showSeparator;
}, 1000);
fetchSlideshowImages();
fetchAllEvents();
setInterval(fetchAllEvents, 5 * 60 * 1000);

View File

@ -1,758 +0,0 @@
{
"name": "vwss-frontend",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vwss-frontend",
"version": "0.0.0",
"devDependencies": {
"vite": "^5.1.6"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
"integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
"integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
"integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
"integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
"integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
"integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
"integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
"integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
"integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
"integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
"integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
"integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
"integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
"integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
"integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
"integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
"integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
"integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
"integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
"integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
"integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
"integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
"integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
"integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz",
"integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz",
"integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz",
"integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz",
"integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz",
"integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz",
"integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz",
"integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz",
"integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz",
"integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz",
"integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz",
"integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz",
"integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"dev": true
},
"node_modules/esbuild": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.19.12",
"@esbuild/android-arm": "0.19.12",
"@esbuild/android-arm64": "0.19.12",
"@esbuild/android-x64": "0.19.12",
"@esbuild/darwin-arm64": "0.19.12",
"@esbuild/darwin-x64": "0.19.12",
"@esbuild/freebsd-arm64": "0.19.12",
"@esbuild/freebsd-x64": "0.19.12",
"@esbuild/linux-arm": "0.19.12",
"@esbuild/linux-arm64": "0.19.12",
"@esbuild/linux-ia32": "0.19.12",
"@esbuild/linux-loong64": "0.19.12",
"@esbuild/linux-mips64el": "0.19.12",
"@esbuild/linux-ppc64": "0.19.12",
"@esbuild/linux-riscv64": "0.19.12",
"@esbuild/linux-s390x": "0.19.12",
"@esbuild/linux-x64": "0.19.12",
"@esbuild/netbsd-x64": "0.19.12",
"@esbuild/openbsd-x64": "0.19.12",
"@esbuild/sunos-x64": "0.19.12",
"@esbuild/win32-arm64": "0.19.12",
"@esbuild/win32-ia32": "0.19.12",
"@esbuild/win32-x64": "0.19.12"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"dev": true
},
"node_modules/postcss": {
"version": "8.4.36",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.36.tgz",
"integrity": "sha512-/n7eumA6ZjFHAsbX30yhHup/IMkOmlmvtEi7P+6RMYf+bGJSUHc3geH4a0NSZxAz/RJfiS9tooCTs9LAVYUZKw==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"source-map-js": "^1.1.0"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/rollup": {
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
"integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==",
"dev": true,
"dependencies": {
"@types/estree": "1.0.5"
},
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.13.0",
"@rollup/rollup-android-arm64": "4.13.0",
"@rollup/rollup-darwin-arm64": "4.13.0",
"@rollup/rollup-darwin-x64": "4.13.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.13.0",
"@rollup/rollup-linux-arm64-gnu": "4.13.0",
"@rollup/rollup-linux-arm64-musl": "4.13.0",
"@rollup/rollup-linux-riscv64-gnu": "4.13.0",
"@rollup/rollup-linux-x64-gnu": "4.13.0",
"@rollup/rollup-linux-x64-musl": "4.13.0",
"@rollup/rollup-win32-arm64-msvc": "4.13.0",
"@rollup/rollup-win32-ia32-msvc": "4.13.0",
"@rollup/rollup-win32-x64-msvc": "4.13.0",
"fsevents": "~2.3.2"
}
},
"node_modules/source-map-js": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.1.0.tgz",
"integrity": "sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/vite": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.6.tgz",
"integrity": "sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==",
"dev": true,
"dependencies": {
"esbuild": "^0.19.3",
"postcss": "^8.4.35",
"rollup": "^4.2.0"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^18.0.0 || >=20.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
},
"peerDependencies": {
"@types/node": "^18.0.0 || >=20.0.0",
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
"lightningcss": {
"optional": true
},
"sass": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
}
}
}

View File

@ -1,14 +0,0 @@
{
"name": "vwss-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^5.1.6"
}
}

View File

@ -1,178 +0,0 @@
/* schedule-styles.css */
:root {
--font-size: 1vw;
--width: 65vw;
--img-margin: -2vw;
}
@media (orientation: landscape) {
:root {
--font-size: 1vh;
--width: 65vh;
--img-margin: -2vh;
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
height: 100%;
font-size: var(--font-size);
}
body {
height: 100%;
font-family: "Calibri", sans-serif;
background-color: black;
color: #FFFFFF;
}
.header {
text-align: center;
width: 100%;
}
.resource-wrapper {
/* display: flex; */
/* flex-direction: column; */
/* justify-content: space-around; */
width: 100%;
/* overflow-x: hidden; */
}
.title-row {
font-weight: bold;
font-size: 3em;
padding: 0.25em 0;
}
.event-row {
display: flex;
flex-wrap: nowrap;
overflow-x: hidden;
font-size: 3em;
}
.flex-row {
display: flex;
flex-direction: row;
}
.flex-cell {
display: flex;
flex-direction: column;
justify-content: start;
align-items: left;
flex: 0 0 633px;
margin-right: 0.5em;
}
.organizer {
font-weight: lighter;
font-style: italic;
}
#horizontal-logo {
width: 100%;
/* margin: 2em 0 1em 0; */
}
#resources-container {
width: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: start;
}
.time-range {
font-weight: lighter;
}
#grid {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
gap: 1em;
height: 100%;
}
#schedule-container {
height: 100%;
grid-column: 1;
padding: 2em;
}
#homepage-container {
grid-column: 3;
padding: 2em;
text-align: center;
display: flex;
flex-direction: column;
height: 100%;
}
.top-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 50%;
}
#time-weather-container {
display: grid;
grid-template-columns: 1fr 1fr;
align-items: center;
width: 100%;
height: 100%;
font-size: 5em;
font-weight: bold;
}
.time {
font-family: 'Calibri', sans-serif;
}
.separator {
font-family: 'Courier New', monospace;
}
#slideshow {
grid-column: 2;
overflow: hidden;
}
.slideshow-img {
transition: opacity 1s ease-in-out;
opacity: 0;
}
#weather-icon {
align-self: end; /* Aligns the icon to the end of its grid cell */
width: 2em;
margin: var(--img-margin);
}
#temperature {
align-self: start; /* Aligns the temperature text to the start of its grid cell */
}
#description {
font-weight: lighter;
}
#quote {
font-size: 5em;
margin: 0 10%;
max-height: 40vh;
text-align: left;
}
#author {
margin-top: 2.5%;
font-size: 4em;
width: 75%;
text-align: right;
}

View File

@ -1,9 +0,0 @@
import { defineConfig } from 'vite';
export default defineConfig({
server: {
proxy: {
'/api': 'http://localhost:8080',
},
},
});

View File

@ -84,15 +84,14 @@ function initializeGraphForUserAuth(settings, deviceCodeCallback) {
module.exports.initializeGraphForUserAuth = initializeGraphForUserAuth; module.exports.initializeGraphForUserAuth = initializeGraphForUserAuth;
async function getCalendarView(resourceUPN, startDateTime, endDateTime) { async function getCalendarView(resourceUPN, startDateTime, endDateTime) {
if (!_userClient) { if (!_appClient) {
throw new Error('Graph has not been initialized for user auth'); throw new Error('Graph has not been initialized for user auth');
} }
try { try {
const apiUrl = `/users/${resourceUPN}/calendarView?startDateTime=${startDateTime}&endDateTime=${endDateTime}`; const apiUrl = `/users/${resourceUPN}/calendarView?startDateTime=${startDateTime}&endDateTime=${endDateTime}`;
console.log(apiUrl);
const calendarView = const calendarView =
await _userClient?.api(apiUrl) await _appClient?.api(apiUrl)
.get(); .get();
if (calendarView && calendarView.value) { if (calendarView && calendarView.value) {

View File

@ -0,0 +1 @@
(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const t of document.querySelectorAll('link[rel="modulepreload"]'))i(t);new MutationObserver(t=>{for(const s of t)if(s.type==="childList")for(const r of s.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&i(r)}).observe(document,{childList:!0,subtree:!0});function o(t){const s={};return t.integrity&&(s.integrity=t.integrity),t.referrerPolicy&&(s.referrerPolicy=t.referrerPolicy),t.crossOrigin==="use-credentials"?s.credentials="include":t.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function i(t){if(t.ep)return;t.ep=!0;const s=o(t);fetch(t.href,s)}})();function M(n,e,o){e.sort((r,l)=>new Date(r.start.dateTime)-new Date(l.start.dateTime));const i=document.createElement("div");i.className="resource-wrapper";const t=document.createElement("div");switch(t.className="title-row",n.split("@")[0]){case"s-er-1431-00":t.innerHTML="ER 1431-00 Open Space";break;case"s-er-1431-03":t.innerHTML="ER 1431-03 Visualization Lab";break;case"s-er-1431-33":t.innerHTML="ER 1431-33 Ideation Room";break;case"s-er-1431-37":t.innerHTML="ER 1431-37 Multipurpose Room";break;case"s-er-1431-39":t.innerHTML="ER 1431-39 Conference Room";break}i.appendChild(t);const s=document.createElement("div");if(s.className="event-row",e.forEach((r,l)=>{if(l<3){const a=document.createElement("div");a.className="flex-cell";const v=r.subject.length>18?r.subject.substring(0,18)+"...":r.subject,C=!r.location.displayName||r.organizer.emailAddress.address===n?"Walk-Up":r.organizer.emailAddress.name,L=h(r.start.dateTime+"Z"),I=h(r.end.dateTime+"Z");if(new Date(r.end.dateTime)>new Date){const p=document.createElement("div");p.textContent=v;const d=document.createElement("div");d.textContent=C,d.className="organizer";const m=document.createElement("div");m.className="time-range",m.innerHTML=`${L} - ${I}`,a.appendChild(p),a.appendChild(d),a.appendChild(m),s.appendChild(a)}}}),s.children.length===0){const r=document.createElement("div");r.className="flex-cell",r.textContent="No upcoming meetings at this time",s.appendChild(r)}i.appendChild(s),o.appendChild(i)}function h(n){const e=new Date(n),o=e.getHours(),i=e.getMinutes().toString().padStart(2,"0");return`<span class="time">${o}</span><span class="separator">:</span><span class="time">${i}</span>`}async function f(){console.log("fetching events");const e=await(await fetch("http://localhost:8080/api/events")).json(),o=document.getElementById("resources-container");o.innerHTML="",Object.keys(e).forEach(t=>{M(t,e[t],o)})}function g(n){let e=h(new Date);n||(e=e.replace(":"," ")),document.getElementById("time").innerHTML=e}function b(n){const e=document.getElementById(n),o=e.textContent.length;o<=83?e.style.fontSize="5em":o<=166?e.style.fontSize="4em":e.style.fontSize="3em"}async function w(){try{const n=await fetch("http://localhost:8080/api/quotes");if(n.ok){const o=(await n.json()).results,i=Math.floor(Math.random()*o.length),t=o[i];document.getElementById("quote").innerHTML=`<i>${t.content}</i>`,b("quote"),document.getElementById("author").innerHTML=`${t.author}`}else console.error("Failed to fetch data")}catch(n){console.error("An error occurred:",n)}}async function y(){const e=await(await fetch("http://localhost:8080/api/weather")).json();if(e.cod===200){const o=e.main.temp,i=e.weather[0].description,s=`https://openweathermap.org/img/wn/${e.weather[0].icon}.png`;document.getElementById("weather-icon-container").innerHTML=`<img id="weather-icon" alt="Weather Icon" src="${s}">`,document.getElementById("temperature").innerHTML=`${o}°`,document.getElementById("description").innerHTML=`${i}`}else document.getElementById("weather").innerText="Weather data unavailable"}async function H(){try{const n=await fetch("http://localhost:8080/api/slideshow");if(!n.ok)throw new Error("Failed to fetch slideshow images");const e=await n.json();E(e)}catch(n){console.error("Error fetching slideshow images:",n)}}function N(n){const e=document.createElement("img");e.src=`http://localhost:8080${n}`,e.className="slideshow-img",e.style.width="100%",e.style.maxHeight="100vh",e.style.objectFit="cover";const o=n.split("/").pop().split(".")[0];return e.alt=o,e.title=o,e}let u=0;function E(n){if(n.length===0){console.log("No images found for the slideshow.");return}const e=document.getElementById("slideshow");e.innerHTML="";const o=N(n[u]);e.appendChild(o),setTimeout(()=>{o.style.opacity="1"},100),setTimeout(()=>{for(;e.children.length>1;)e.removeChild(e.firstChild)},100),u=(u+1)%n.length,setTimeout(()=>E(n),3e4)}const T=document.getElementById("welcome-message");function S(){T.classList.add("visible")}function x(){T.classList.remove("visible")}setInterval(function(){S(),setTimeout(x,3e4)},6e5);w();setInterval(w,60*60*1e3);y();setInterval(y,5*60*1e3);let c=!0;g(c);setInterval(()=>{g(c),c=!c},1e3);H();f();setInterval(f,3*60*1e3);

View File

@ -0,0 +1 @@
:root{--font-size: 1vw;--width: 65vw;--img-margin: -2vw}@media (orientation: landscape){:root{--font-size: 1vh;--width: 65vh;--img-margin: -2vh}}*{margin:0;padding:0;box-sizing:border-box}html{height:100%;font-size:var(--font-size)}body{height:100%;font-family:Calibri,sans-serif;background-color:#000;color:#fff}.header{text-align:center;width:100%;flex-grow:0}.resource-wrapper{width:100%}.title-row{font-weight:700;font-size:3em;padding:.25em 0}.event-row{display:flex;flex-wrap:nowrap;overflow-x:hidden;font-size:3em}.flex-row{display:flex;flex-direction:row}.flex-cell{display:flex;flex-direction:column;flex-grow:1;flex-basis:33%;justify-content:start;align-items:left;margin-right:.5em}.organizer{font-weight:lighter;font-style:italic}.horizontal-logo{width:100%}#resources-container{width:100%;height:100%;overflow:hidden;display:flex;flex-direction:column;justify-content:space-between;flex-grow:1}#grid{display:grid;grid-template-columns:1fr 2fr 1fr;height:100%;width:100%}#schedule-container{height:100%;grid-column:1;padding:2em;display:flex;flex-direction:column}#schedule-container .header{margin-bottom:3em}#homepage-container{grid-column:3;padding:2em;text-align:center;display:flex;flex-direction:column;height:100%}.top-container{display:flex;flex-direction:column;justify-content:center;align-items:center;height:50%}#time-weather-container{display:grid;grid-template-columns:1fr 1fr;align-items:center;width:100%;font-size:5em;font-weight:700}.time{font-family:Calibri,sans-serif}.separator{font-family:Courier New,monospace}#slideshow{grid-column:2;overflow:hidden}.slideshow-img{transition:opacity .5s ease-in-out;opacity:0}#bottom-section{display:flex;flex-direction:column;justify-content:center;align-items:center}#weather-icon{align-self:end;width:2em;margin:var(--img-margin)}#temperature{align-self:start}#description{font-weight:lighter}#quote{font-size:5em;margin:0 10%;max-height:40vh;text-align:left}#author{margin-top:2.5%;font-size:4em;width:75%;text-align:right}#welcome-message{position:fixed;top:0;left:0;width:100%;height:100vh;background:linear-gradient(124deg,#ff7d68,#f17b7b,#f1d67b,#f0f17b,#7bf190,#7bebf1,#847bf1,#f370ff,#f8a9ff);background-size:1800% 1800%;animation:rainbow 30s ease infinite;justify-content:center;align-items:center;color:#fff;font-size:2em;display:flex;z-index:1001;padding:20em;opacity:0;transition:opacity 1s linear}#welcome-message.visible{opacity:1}@keyframes rainbow{0%{background-position:0% 82%}50%{background-position:100% 19%}to{background-position:0% 82%}}

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -5,15 +5,21 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>NGCI Daily Schedule</title> <title>NGCI Daily Schedule</title>
<link rel="stylesheet" href="style.css">
<script type="module" crossorigin src="/assets/index-DDszHAtm.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Dt4LGvko.css">
</head> </head>
<body> <body>
<div id="welcome-message">
<img class="horizontal-logo" src="ngci-logo-white-wide.svg" alt="Next-Generation Cities Institute">
</div>
<div id="grid"> <div id="grid">
<div id="schedule-container"> <div id="schedule-container">
<div class="header"> <div class="header">
<img id="horizontal-logo" src="ngci-logo-white-wide.svg" alt="Next-Generation Cities Institute"> <img class="horizontal-logo" src="ngci-logo-white-wide.svg" alt="Next-Generation Cities Institute">
</div> </div>
<div id="resources-container"></div> <div id="resources-container"></div>
</div> </div>
@ -22,7 +28,7 @@
<div id="homepage-container"> <div id="homepage-container">
<div class="header"> <div class="header">
<img id="horizontal-logo" src="ngci-logo-white-wide.svg" alt="Next-Generation Cities Institute"> <img class="horizontal-logo" src="ngci-logo-white-wide.svg" alt="Next-Generation Cities Institute">
</div> </div>
<div class="top-container"> <div class="top-container">
<div id="time-weather-container"> <div id="time-weather-container">
@ -41,7 +47,6 @@
</div> </div>
</div> </div>
<script type="module" src="frontend.js"></script>
</body> </body>
</html> </html>

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -15,6 +15,7 @@ const HTTP_PORT = process.env.HTTP_PORT || 8080;
const app = express(); const app = express();
const slideshowDir = './slideshow'; const slideshowDir = './slideshow';
app.use(express.static(path.join(__dirname, 'public')));
app.use(cors({ app.use(cors({
origin: 'http://localhost:5173' origin: 'http://localhost:5173'
@ -33,30 +34,31 @@ app.use(express.static('public'));
// //
// GRAPH API SECTION - APP ONLY AUTH // GRAPH API SECTION - APP ONLY AUTH
// //
// msGraphHelper.initializeGraphForAppOnlyAuth(settings); msGraphHelper.initializeGraphForAppOnlyAuth(settings);
const data = fs.readFileSync('./resourceUPNs.json', 'utf8'); const data = fs.readFileSync('./resourceUPNs.json', 'utf8');
const resourceUPNs = JSON.parse(data); const resourceUPNs = JSON.parse(data);
function pollAPI() {
events = {};
}
app.get('/api/events', async (req, res) => { app.get('/api/events', async (req, res) => {
try { try {
let events = {};
let now = new Date(); let now = new Date();
let startDateTime = new Date(now); let startDateTime = new Date(now);
startDateTime.setHours(8, 0, 0, 0); // startDateTime.setHours(8, 0, 0, 0);
let endDateTime = new Date(now); let endDateTime = new Date(now);
endDateTime.setHours(17, 0, 0, 0); endDateTime.setHours(20, 0, 0, 0);
if (startDateTime > endDateTime) {
// Exit early since there are no relevant events to display
return res.json({});
}
let events = {};
for (const resource of resourceUPNs) { for (const resource of resourceUPNs) {
try { try {
const data = const data =
// msGraphHelper.getCalendarView(resource, startDateTime.toISOString(), endDateTime.toISOString()); await msGraphHelper.getCalendarView(resource, startDateTime.toISOString(), endDateTime.toISOString());
fs.readFileSync(`./events/${resource}.json`, 'utf8'); // fs.readFileSync(`./events/${resource}.json`, 'utf8');
const resourceEvents = JSON.parse(data); const resourceEvents = data;
events[resource] = resourceEvents; events[resource] = resourceEvents;
// console.log(`${new Date()}: Grabbed events for ${resource}`); // console.log(`${new Date()}: Grabbed events for ${resource}`);
} catch (error) { } catch (error) {
@ -74,8 +76,8 @@ app.get('/api/weather', async (req, res) => {
try { try {
const lat = 45.49; const lat = 45.49;
const lon = -73.58; const lon = -73.58;
const appid = process.env.OPENWEATHER_APPID; const appId = process.env.OPENWEATHER_APPID;
const url = `https://api.openweathermap.org/data/2.5/weather?units=metric&lat=${lat}&lon=${lon}&appid=${appid}`; const url = `https://api.openweathermap.org/data/2.5/weather?units=metric&lat=${lat}&lon=${lon}&appid=${appId}`;
const response = await fetch(url); const response = await fetch(url);

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

BIN
slideshow/20220305_Alps.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 MiB

BIN
slideshow/ChukchiSea.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

BIN
slideshow/IceGreatLakes.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

BIN
slideshow/Image_006.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

BIN
slideshow/Image_013.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

BIN
slideshow/Layout 1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB