- TypeScript 87%
- Dockerfile 6.5%
- JavaScript 6.3%
- CSS 0.2%
|
All checks were successful
deploy / build-and-push (release) Successful in 2m14s
|
||
|---|---|---|
| .forgejo/workflows | ||
| deploy/podman | ||
| public | ||
| src | ||
| .env.example | ||
| .gitignore | ||
| config.toml.example | ||
| Dockerfile | ||
| eslint.config.mjs | ||
| LICENSE | ||
| next.config.js | ||
| package.json | ||
| pnpm-lock.yaml | ||
| postcss.config.cjs | ||
| prettier.config.js | ||
| README.md | ||
| tailwind.config.ts | ||
| tsconfig.json | ||
Event Display
An app to display events from a nextcloud calendar in the entry hall of the Stadtteilzentrum Nordstadt e.V. in Hannover.
Development
Prerequisites
- Node.js 18 or higher
- npm (comes with Node.js)
Setup
- Clone the repository
- Copy the example config file and adjust it to your needs:
cp config.toml.example config.toml - Edit
config.tomlwith your Nextcloud calendar URLs and credentials - Copy the example environment file:
cp .env.example .env.local - Install dependencies:
npx pnpm install - Start the development server:
npx pnpm dev
The app will be available at http://localhost:3000.
Development Features
- Hot reload: Changes to source files are automatically reflected
- TypeScript support with type checking
- ESLint for code quality
- Prettier for code formatting
Useful Commands
npx pnpm dev # Start development server
npx pnpm build # Build for production
npx pnpm start # Start production server
npx pnpm lint # Run linter
Running
A container image is published to the Forgejo package registry whenever a release is published:
git.hannover.ccc.de/buergerschule/event-display:latest (also tagged with the release tag and the
commit SHA).
it can be used in a docker-compose.yml like this:
services:
event-display:
image: "git.hannover.ccc.de/buergerschule/event-display:latest"
environment:
CONFIG_PATH: /config.toml
ports:
- "3000:3000"
volumes:
- ./config.toml:/config.toml
You can also build the docker image yourself using the Dockerfile
For the production deployment — rootless Podman with systemd Quadlets, pulling this image via
podman auto-update — see deploy/podman/README.md.
Configuration
There is a config.toml to configure every important aspect of the app. The path for this file can be set using the CONFIG_PATH environment variable. If this variable is not set, the app will look for a config.toml in the current working directory.
Here is an example configuration:
[frontend]
# The title of the page displayed at the top of the page
title = "Veranstaltungen in der Bürgerschule"
# The url of the logo displayed in the top right corner
icon = "/logo.png"
# The theme color, used for everything colored in the app
themeColor = "#EC6500"
# the time (in seconds) for scrolling to the next page of events when pagination is happening because of a lot of events (optional, default: 10)
scrollInterval = 10
[calendar]
# The timezone of the calendar
timeZone = "Europe/Berlin"
# The interval (in seconds) to refresh loaded events from the calendar
refreshInterval = 300
# The calendars to load events from
# name: The name of the room the calendar is for (displayed below the title of the event)
# url: The url of the calendar (found as the "Internal URL" in the nextcloud calendar settings)
# location: The location of the room the calendar is for, displayed on the right of the event list (optional, default: "")
# hideName: If the name of the room should be hidden in the event list (below the title) (optional, default: false)
calendars = [
{ name = "Raum A", url = "https://cloud.example.de/remote.php/dav/calendars/kalendar/raum-a/", location = "2. OG", hideName = false },
{ name = "Raum B", url = "https://cloud.example.de/remote.php/dav/calendars/kalendar/raum-b/", location = "2. OG", hideName = false },
]
# events that contain these keywords in their iCal categories will be ignored and not shown in the event list
ignoreKeywords = ["!intern!", "!privat!"]
# keywords that will be removed from event titles and mark events as "open end" if found in iCal categories
openEndKeywords = ["offen", "openend"]
# time in minutes after which an event is considered to be in the past and will be removed from the event list (0 means events will not be removed)
timeout = 0
# the auth information for the nextcloud instance (app password), the user must have read access to the calendars specified above
# type: The type of authentication, currently only "basic" is supported (optional)
auth = { type = "basic", username = "kalendar", password = "abcdefg" }
API
GET /api/hours
Returns the start time of the first event and the end time of the last event of a given day as JSON. All-day events and private events (see ignoreKeywords) are excluded.
Query parameters:
date(optional): the day to query, inYYYY-MM-DDformat. Defaults to the current day if omitted. The date is interpreted in the timezone configured under[calendar] timeZone.
Example:
curl "http://localhost:3000/api/hours?date=2026-06-10"
Example response:
{
"date": "2026-06-10",
"timeZone": "Europe/Berlin",
"first": "2026-06-10T08:00:00+02:00",
"last": "2026-06-10T18:00:00+02:00",
"eventCount": 5
}
first/last: ISO 8601 timestamps of the earliest start and latest end, in the configured timezone (including its UTC offset).nullif there are no matching events.eventCount: the number of events considered.
A request with an invalid date returns HTTP 400; an error while fetching the calendar returns HTTP 502.
License
This software is licensed under GNU Affero General Public License V3. For more details see LICENSE.
Financing
This software has been built from public money. For more info, why publicly funded software should be public code, visit https://publiccode.eu/, an initiative by Free Software Foundation Europe.