From 283a8cc9b12dca0651c73160dea43f3b49cd0084 Mon Sep 17 00:00:00 2001 From: Eric Date: Sat, 9 Aug 2025 10:21:55 +0200 Subject: [PATCH 1/8] First version of calender (issue 1) --- .../calendar/AddToCalendarButton.svelte | 137 ++++- src/lib/components/calendar/Calendar.svelte | 418 ++++++++++++++- .../calendar/EventAdminPanel.svelte | 437 ++++++++++++++++ .../calendar/EventCreationModal.svelte | 471 +++++++++++++++++ .../components/calendar/EventInfoModal.svelte | 339 ++++++++++-- src/lib/components/calendar/EventsList.svelte | 490 ++++++++++++++++++ .../calendar/EventsListAgenda.svelte | 315 +++++++++++ .../calendar/OpenInMapsButton.svelte | 125 ++++- src/lib/components/calendar/events.js | 162 +++++- src/lib/locales/translations.js | 38 +- src/lib/services/calendarService.js | 75 ++- src/lib/stores/eventsStore.js | 120 +++++ src/routes/events/+page.svelte | 410 ++++++++++++--- static/global.css | 39 +- static/icons/heart.svg | 4 + 15 files changed, 3436 insertions(+), 144 deletions(-) create mode 100644 src/lib/components/calendar/EventAdminPanel.svelte create mode 100644 src/lib/components/calendar/EventCreationModal.svelte create mode 100644 src/lib/components/calendar/EventsList.svelte create mode 100644 src/lib/components/calendar/EventsListAgenda.svelte create mode 100644 src/lib/stores/eventsStore.js create mode 100644 static/icons/heart.svg diff --git a/src/lib/components/calendar/AddToCalendarButton.svelte b/src/lib/components/calendar/AddToCalendarButton.svelte index 8cdbb8be..d2a7f6cd 100644 --- a/src/lib/components/calendar/AddToCalendarButton.svelte +++ b/src/lib/components/calendar/AddToCalendarButton.svelte @@ -1,10 +1,139 @@ - + + +
+ + + {#if showDropdown} + + {/if} +
\ No newline at end of file diff --git a/src/lib/components/calendar/Calendar.svelte b/src/lib/components/calendar/Calendar.svelte index fb6446e1..fed9f6e8 100644 --- a/src/lib/components/calendar/Calendar.svelte +++ b/src/lib/components/calendar/Calendar.svelte @@ -5,9 +5,16 @@ import Calendar from '@event-calendar/core'; import DayGrid from '@event-calendar/day-grid'; import TimeGrid from "@event-calendar/time-grid"; + import ListPlugin from '@event-calendar/list'; import { events } from "$lib/components/calendar/events.js"; + import { eventsStore, needsApproval } from '$lib/stores/eventsStore.js'; + import { currentLanguage } from '$lib/stores/languageStore.js'; import EventInfoModal from './EventInfoModal.svelte'; + import EventCreationModal from './EventCreationModal.svelte'; + import EventsListAgenda from './EventsListAgenda.svelte'; + import EventsList from './EventsList.svelte'; + $: lang = $currentLanguage; function handleEventClick(info) { event = info.event; @@ -18,12 +25,31 @@ function closeEventInfoModal() { isOpen = false; } + + function openEventCreationModal() { + showCreateModal = true; + } + + function closeEventCreationModal() { + showCreateModal = false; + } + + function handleListEventClick(selectedEvent) { + event = selectedEvent; + isOpen = true; + } + + function toggleViewType() { + currentViewType = currentViewType === 'calendar' ? 'list' : 'calendar'; + } const currentView = writable("dayGridMonth"); function checkViewportAndSetView() { if (window.innerWidth <= 800) { $currentView = "timeGridDay"; + } else { + $currentView = "dayGridMonth"; } } @@ -37,33 +63,399 @@ }); let event; - let isOpen; - - let plugins = [TimeGrid, DayGrid]; - let options = { + let isOpen = false; + let showCreateModal = false; + let currentViewType = 'calendar'; // 'calendar' or 'list' + let plugins = [TimeGrid, DayGrid, ListPlugin]; + + // Combine static events with user-created events + $: allEvents = [ + ...events, + ...$eventsStore.filter(e => !$needsApproval || e.status === 'approved') + ]; + + $: options = { view: $currentView, - events: events, + events: allEvents, eventClick: handleEventClick, + headerToolbar: { + start: 'prev,next today', + center: 'title', + end: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth' + }, + buttonText: { + today: lang === 'de' ? 'Heute' : 'Today', + dayGridMonth: lang === 'de' ? 'Monat' : 'Month', + timeGridWeek: lang === 'de' ? 'Woche' : 'Week', + timeGridDay: lang === 'de' ? 'Tag' : 'Day', + listMonth: lang === 'de' ? 'Agenda' : 'Agenda' + }, + height: 'auto', + eventColor: '#667eea', + eventTextColor: '#fff', + dayMaxEvents: 3, + moreLinkText: lang === 'de' ? 'weitere' : 'more', + noEventsText: lang === 'de' ? 'Keine Events' : 'No events', + firstDay: 1, // Start week on Monday }; -
+ + + +
+
+

{lang === 'de' ? 'Event-Kalender' : 'Events Calendar'}

+

+ {lang === 'de' ? 'Entdecke und teile Events in der Berner Community' : 'Discover and share events in the Bern community'} +

+
+ +
+ +
+
+ +
+
+ + {lang === 'de' ? 'Regelmäßige Events' : 'Regular Events'} +
+
+ + {lang === 'de' ? 'Community Events' : 'Community Events'} +
+
- + +
+ {#if currentViewType === 'list'} + + {:else} +
+ +
+ {/if} +
+ +
+
+ {allEvents.length} + {lang === 'de' ? 'Events insgesamt' : 'Total Events'} +
+
+ {$eventsStore.filter(e => e.status === 'pending').length} + {lang === 'de' ? 'Wartend' : 'Pending'} +
+
+ {$eventsStore.filter(e => e.status === 'approved').length} + {lang === 'de' ? 'Genehmigt' : 'Approved'} +
+
- - \ No newline at end of file diff --git a/src/lib/components/calendar/EventAdminPanel.svelte b/src/lib/components/calendar/EventAdminPanel.svelte new file mode 100644 index 00000000..b346da1a --- /dev/null +++ b/src/lib/components/calendar/EventAdminPanel.svelte @@ -0,0 +1,437 @@ + + +
e.key === 'Escape' && onClose()}>
+ +{#if isOpen} + +{/if} + + diff --git a/src/lib/components/calendar/EventCreationModal.svelte b/src/lib/components/calendar/EventCreationModal.svelte new file mode 100644 index 00000000..0dc77bc8 --- /dev/null +++ b/src/lib/components/calendar/EventCreationModal.svelte @@ -0,0 +1,471 @@ + + +
e.key === 'Escape' && onClose()}>
+ +{#if isOpen} + +{/if} + + diff --git a/src/lib/components/calendar/EventInfoModal.svelte b/src/lib/components/calendar/EventInfoModal.svelte index 74e7cd4a..b34e3fa0 100644 --- a/src/lib/components/calendar/EventInfoModal.svelte +++ b/src/lib/components/calendar/EventInfoModal.svelte @@ -2,10 +2,41 @@ import dayjs from "dayjs"; import AddToCalendarButton from "./AddToCalendarButton.svelte"; import OpenInMapsButton from "./OpenInMapsButton.svelte"; + import { eventsStore } from '$lib/stores/eventsStore.js'; + import { currentLanguage } from '$lib/stores/languageStore.js'; export let event = {}; export let isOpen; export let onClose; + + $: lang = $currentLanguage; + + function handleShare() { + if (navigator.share) { + navigator.share({ + title: event?.title, + text: `Check out this event: ${event?.title}`, + url: window.location.href + }); + } else { + // Fallback: copy to clipboard + const shareText = `${event?.title} - ${dayjs(event?.start).format('MMMM D, YYYY')} at ${event?.extendedProps?.location}`; + navigator.clipboard.writeText(shareText).then(() => { + alert(lang === 'de' ? 'Event-Details wurden in die Zwischenablage kopiert!' : 'Event details copied to clipboard!'); + }); + } + } + + function handleLike() { + if (event?.id) { + eventsStore.toggleLike(event.id); + } + } + + // Increment views when modal opens + $: if (isOpen && event?.id) { + eventsStore.incrementViews(event.id); + } @@ -18,24 +49,112 @@ class="img" on:click={onClose} /> -

{event?.title}

+
+

{event?.title}

+ {#if event?.extendedProps?.category} + {event.extendedProps.category} + {/if} +
+ +
+ {#if event?.likes !== undefined} + 👥 {event.views || 0} {lang === 'de' ? 'Aufrufe' : 'views'} + ❤️ {event.likes || 0} {lang === 'de' ? 'Likes' : 'likes'} + {/if} +
+ +
- - - - - Details Page - + + + + + + + + {#if event?.extendedProps?.slug} + + + {lang === 'de' ? 'Details-Seite' : 'Details Page'} + + {/if}
@@ -45,6 +164,14 @@ .eye-icon { background-image: url("/icons/go-to-details.svg"); } + + .heart-icon { + background-image: url("/icons/heart.svg"); + } + + .share-icon { + background-image: url("/icons/share.svg"); + } .backdrop { position: fixed; @@ -61,51 +188,165 @@ .event-info { display: none; - position: absolute; + position: fixed; inset: 0; - text-align: center; + text-align: left; padding: 1em; align-items: center; justify-content: center; + z-index: 4; } .inner-wrapper { position: relative; display: flex; flex-direction: column; - gap: 1em; + gap: 1.5em; background: white; min-width: 50%; + max-width: 600px; + max-height: 80vh; + overflow-y: auto; box-shadow: 0 0 20px rgba(0, 0, 0, 0.267) inset, 0 5px 30px rgba(0, 0, 0, 0.384); z-index: 5; - color: black; - padding: 2em 5em; - border-radius: .5em; + color: #333 !important; + padding: 2em 2.5em; + border-radius: 12px; + } + + .inner-wrapper h3, + .inner-wrapper p, + .inner-wrapper div, + .inner-wrapper span { + color: #333 !important; + } + + .event-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 1rem; + margin-bottom: 1rem; + } + + .category-badge { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 0.25rem 0.75rem; + border-radius: 20px; + font-size: 0.75rem; + font-weight: 500; + text-transform: capitalize; + white-space: nowrap; + } + + .event-meta { + display: flex; + gap: 1rem; + margin-bottom: 1rem; + font-size: 0.9rem; + color: #666; + } + + .meta-item { + display: flex; + align-items: center; + gap: 0.25rem; } .infos { display: flex; flex-direction: column; - gap: .5em; + gap: 1rem; + list-style: none; + margin: 0; + padding: 0; + } + + .info-item { + display: flex; + align-items: flex-start; + gap: 1rem; + padding: 1rem; + background: #f8f9fa; + border-radius: 8px; + border-left: 4px solid #667eea; + } + + .info-icon { + font-size: 1.2rem; + min-width: 24px; + } + + .info-content { + flex: 1; + } + + .info-content a { + color: #667eea; + text-decoration: none; + word-break: break-all; + } + + .info-content a:hover { + text-decoration: underline; } - h3 { padding: 0; margin: 0; + font-size: 1.5rem; + font-weight: 600; + color: #333 !important; + flex: 1; } - ul { - list-style: none; - margin: 0; - padding: 0; - } - - .buttonsContainer { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 0.75rem; + margin-top: 1rem; + } + + .event-modal-button { display: flex; - flex-direction: column; - gap: .5em; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 1rem; + background: white; + border: 2px solid #e1e1e1; + border-radius: 8px; + text-decoration: none; + color: #333; + font-weight: 500; + transition: all 0.2s ease; + cursor: pointer; + font-size: 0.9rem; + justify-content: center; + } + + .event-modal-button:hover { + border-color: #667eea; + background: #f8f9ff; + transform: translateY(-1px); + } + + .like-btn:hover { + border-color: #e74c3c; + background: #fdf2f2; + } + + .share-btn:hover { + border-color: #27ae60; + background: #f2fdf5; + } + + .icon { + width: 16px; + height: 16px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; } .isOpen { @@ -115,14 +356,14 @@ .unfocus { position: absolute; inset: 0; - background: none; + background: rgba(0, 0, 0, 0.5); cursor: default !important; - z-index: 4; + z-index: 3; } #close { background: radial-gradient(red, rgb(90, 0, 0)); - box-shadow: 0 0 2px 1p white inset; + box-shadow: 0 0 2px 1px white inset; position: absolute; right: 0; top: 0; @@ -132,7 +373,10 @@ border-radius: 100%; transition: all .1s ease; opacity: .6; + border: none; + cursor: pointer; } + #close::before { content: ''; position: absolute; @@ -146,6 +390,7 @@ opacity: .6; width: 15px; } + #close:hover { opacity: 1; } @@ -155,4 +400,30 @@ background-position: center; background-size: contain; } + + @media (max-width: 768px) { + .inner-wrapper { + min-width: 90%; + max-width: 95%; + padding: 1.5rem; + } + + .buttonsContainer { + grid-template-columns: 1fr; + } + + .event-header { + flex-direction: column; + align-items: flex-start; + } + + .info-item { + flex-direction: column; + gap: 0.5rem; + } + + .info-icon { + align-self: flex-start; + } + } \ No newline at end of file diff --git a/src/lib/components/calendar/EventsList.svelte b/src/lib/components/calendar/EventsList.svelte new file mode 100644 index 00000000..a6e0f61e --- /dev/null +++ b/src/lib/components/calendar/EventsList.svelte @@ -0,0 +1,490 @@ + + +
+
+

{lang === 'de' ? 'Kommende Events' : 'Upcoming Events'}

+

+ {sortedEvents.length} {lang === 'de' ? 'Events geplant' : 'events scheduled'} +

+
+ + {#if Object.keys(groupedEvents).length === 0} +
+
📅
+

{lang === 'de' ? 'Keine kommenden Events' : 'No upcoming events'}

+

{lang === 'de' ? 'Erstelle das erste Event für die Community!' : 'Create the first event for the community!'}

+
+ {:else} + {#each Object.entries(groupedEvents) as [date, dayEvents]} +
+
+

{getRelativeDate(date)}

+ {dayjs(date).format('MMMM D, YYYY')} + {dayEvents.length} +
+ +
+ {#each dayEvents as event} +
onEventClick(event)} + on:keydown={(e) => e.key === 'Enter' && onEventClick(event)} + tabindex="0" + role="button" + > +
+ {dayjs(event.start).format('h:mm A')} + {#if event.end} + + {dayjs(event.end).diff(dayjs(event.start), 'hours')}h {dayjs(event.end).diff(dayjs(event.start), 'minutes') % 60}m + + {/if} +
+ +
+
{event.title}
+ + {#if event.extendedProps?.location} +
+ 📍 + {event.extendedProps.location} +
+ {/if} + + {#if event.extendedProps?.description} +

+ {event.extendedProps.description.slice(0, 120)}{event.extendedProps.description.length > 120 ? '...' : ''} +

+ {/if} + +
+ {#if event.extendedProps?.category} + {event.extendedProps.category} + {/if} + + {#if event.extendedProps?.organizerName} + + {lang === 'de' ? 'von' : 'by'} {event.extendedProps.organizerName} + + {/if} + + {#if event.likes !== undefined || event.views !== undefined} +
+ {#if event.views} + 👥 {event.views} + {/if} + {#if event.likes} + ❤️ {event.likes} + {/if} +
+ {/if} +
+
+ +
+ +
+
+ {/each} +
+
+ {/each} + {/if} +
+ + diff --git a/src/lib/components/calendar/EventsListAgenda.svelte b/src/lib/components/calendar/EventsListAgenda.svelte new file mode 100644 index 00000000..7f93eb09 --- /dev/null +++ b/src/lib/components/calendar/EventsListAgenda.svelte @@ -0,0 +1,315 @@ + + +
+ {#if Object.keys(groupedEvents).length === 0} +
+
📅
+

{lang === 'de' ? 'Keine bevorstehenden Events' : 'No upcoming events'}

+

{lang === 'de' ? 'Fügen Sie ein neues Event hinzu, um loszulegen!' : 'Add a new event to get started!'}

+
+ {:else} + {#each Object.entries(groupedEvents) as [date, dayEvents]} +
+
+
{dayjs(date).format('D')}
+
+
{dayjs(date).format('MMM, ddd').toUpperCase()}
+ {#if isToday(date)} +
+ ● +
+ {/if} +
+
+ +
+ {#each dayEvents as event} +
handleEventClick(event)} + on:keydown={(e) => e.key === 'Enter' && handleEventClick(event)} + role="button" + tabindex="0" + > +
+
{dayjs(event.start).format('h:mma')}
+
+ {event.title} + {#if event.extendedProps?.soldOut} + (Sold out) + {/if} +
+
+ {/each} +
+
+ {/each} + {/if} +
+ + diff --git a/src/lib/components/calendar/OpenInMapsButton.svelte b/src/lib/components/calendar/OpenInMapsButton.svelte index b80a636a..5029dc8d 100644 --- a/src/lib/components/calendar/OpenInMapsButton.svelte +++ b/src/lib/components/calendar/OpenInMapsButton.svelte @@ -1,11 +1,128 @@ - + +{#if location} +
+ + + {#if showDropdown} + + {/if} +
+{/if} \ No newline at end of file diff --git a/src/lib/components/calendar/events.js b/src/lib/components/calendar/events.js index 641c5d7f..ca27837c 100644 --- a/src/lib/components/calendar/events.js +++ b/src/lib/components/calendar/events.js @@ -1,26 +1,156 @@ - -let start = new Date(2024, 3, 6, 8, 0); -let end = new Date(2024, 3, 6, 10, 0); - +// Sample events with dates in August 2025 and beyond +const now = new Date(2025, 7, 8); // August 8, 2025 +const today = new Date(now); export const events = [ { - title: "BlaBla Language Exchange", - start: new Date(2024, 3, 7, 19, 0), - end: new Date(2024, 3, 7, 22, 0), - extendedProps: { slug: "blabla-language-exchange" } + id: 'static-1', + title: "Speed Friending | Pre-Parade Matching", + start: new Date(2025, 7, 9, 10, 30), // August 9, 2025, 10:30 AM + end: new Date(2025, 7, 9, 12, 0), // 12 PM + extendedProps: { + slug: "speed-friending", + description: "Meet new people in a fun speed dating style event focused on making friendships!", + location: "Café Des Amis, Bern", + category: "social", + organizerName: "Connect Bern Social" + } + }, + { + id: 'static-2', + title: "Street Parade 2025", + start: new Date(2025, 7, 9, 12, 0), // August 9, 2025, 12 PM + end: new Date(2025, 7, 9, 18, 0), // 6 PM + extendedProps: { + slug: "street-parade-2025", + description: "Join the biggest street parade celebration in Bern with music, dancing and great vibes!", + location: "Bundesplatz, Bern", + category: "cultural", + organizerName: "Street Parade Bern" + } + }, + { + id: 'static-3', + title: "Float & Chill", + start: new Date(2025, 7, 10, 13, 30), // August 10, 2025, 1:30 PM + end: new Date(2025, 7, 10, 17, 0), // 5 PM + extendedProps: { + slug: "float-and-chill", + description: "Relax and float down the Aare river with friends. Perfect for hot summer days!", + location: "Schwellenmätteli, Bern", + category: "outdoor", + organizerName: "Aare Floating Club", + soldOut: true + } + }, + { + id: 'static-4', + title: "Comedy & Socializing", + start: new Date(2025, 7, 13, 19, 30), // August 13, 2025, 7:30 PM + end: new Date(2025, 7, 13, 22, 0), // 10 PM + extendedProps: { + slug: "comedy-socializing", + description: "Enjoy stand-up comedy and meet new people in a relaxed social setting.", + location: "Comedy Club Bern", + category: "social", + organizerName: "Bern Comedy Society" + } + }, + { + id: 'static-5', + title: "Meditation, Ice & Breathwork | 3h Workshop", + start: new Date(2025, 7, 16, 10, 0), // August 16, 2025, 10 AM + end: new Date(2025, 7, 16, 13, 0), // 1 PM + extendedProps: { + slug: "meditation-ice-breathwork", + description: "Intensive 3-hour workshop combining meditation, ice bath therapy, and breathwork techniques.", + location: "Wellness Center Bern", + category: "education", + organizerName: "Mindful Bern" + } }, { - title: "Karaoke Night at Delfino", - start: new Date(2024, 3, 5, 21, 0), - end: new Date(2024, 3, 5, 23, 0), - extendedProps: { slug: "karaoke-night-delfino" } + id: 'static-6', + title: "Mystery Matches - Blindfolded speed dating", + start: new Date(2025, 7, 20, 19, 30), // August 20, 2025, 7:30 PM + end: new Date(2025, 7, 20, 22, 30), // 10:30 PM + extendedProps: { + slug: "mystery-matches-speed-dating", + description: "Unique speed dating experience where first impressions are based on conversation, not looks!", + location: "Event Hall Bern", + category: "social", + organizerName: "Dating Events Bern" + } + }, + { + id: 'static-5', + title: "Vegan Food Festival", + start: new Date(2025, 7, 20, 11, 0), // August 20, 2025, 11 AM + end: new Date(2025, 7, 20, 19, 0), // 7 PM + extendedProps: { + slug: "vegan-food-festival", + description: "Discover delicious plant-based cuisine from local vendors. Live music, workshops, and family activities.", + location: "Münsterplatz, Bern", + category: "food", + organizerName: "Vegan Bern Association" + } + }, + { + id: 'static-6', + title: "Art Gallery Opening: Modern Swiss Artists", + start: new Date(2025, 7, 22, 17, 0), // August 22, 2025, 5 PM + end: new Date(2025, 7, 22, 21, 0), // 9 PM + extendedProps: { + slug: "art-gallery-opening", + description: "Opening night for our new exhibition featuring contemporary Swiss artists. Wine and appetizers provided.", + location: "Kunstmuseum Bern", + category: "art", + organizerName: "Kunstmuseum Bern", + website: "https://kunstmuseumbern.ch" + } + }, + { + id: 'static-7', + title: "Business Networking Breakfast", + start: new Date(2025, 7, 25, 7, 30), // August 25, 2025, 7:30 AM + end: new Date(2025, 7, 25, 9, 30), // 9:30 AM + extendedProps: { + slug: "business-networking-breakfast", + description: "Connect with local entrepreneurs and business professionals over breakfast. Great opportunity to expand your network.", + location: "Hotel Schweizerhof Bern", + category: "business", + organizerName: "Bern Business Network", + contactInfo: "events@bernbusiness.ch" + } + }, + + { + id: 'static-9', + title: "German Language Class", + start: new Date(2025, 8, 2, 18, 0), // September 2, 2025, 6 PM + end: new Date(2025, 8, 2, 20, 0), // 8 PM + extendedProps: { + slug: "german-language-class", + description: "Improve your German language skills in a supportive group environment. Beginner to intermediate levels.", + location: "Autonomous School of Bern", + category: "education", + organizerName: "Denk:Mal Language School", + website: "https://denkmal-bern.ch" + } }, { - title: "Meetup", - start: start, - end: end, - extendedProps: { slug: "meetup" } + id: 'static-10', + title: "Cultural Walking Tour: Old Town Bern", + start: new Date(2025, 8, 5, 14, 0), // September 5, 2025, 2 PM + end: new Date(2025, 8, 5, 16, 30), // 4:30 PM + extendedProps: { + slug: "cultural-walking-tour", + description: "Discover the rich history and culture of Bern's UNESCO World Heritage Old Town with our expert guide.", + location: "Meeting point: Zytglogge", + category: "cultural", + organizerName: "Bern Tourism", + website: "https://bern.com" + } } ]; \ No newline at end of file diff --git a/src/lib/locales/translations.js b/src/lib/locales/translations.js index bb355356..19ab2654 100644 --- a/src/lib/locales/translations.js +++ b/src/lib/locales/translations.js @@ -4,17 +4,47 @@ export const t = { "groups": "Gruppen", "places-description": "Hier ist eine Liste cooler Orte, wo man gesellig sein kann.", "swiss-tips-description": "Tips & Tricks für das Leben in Bern und in der Schweiz.", - "events-description": "Hier sind unterschiedliche Events in und rundum Bern zu finden.", + "events-description": "Hier sind unterschiedliche Events in und rundum Bern zu finden. Du kannst eigene Events hinzufügen und sie im interaktiven Kalender entdecken!", "logo-description": "Eine Sammlung von Gruppen in Bern", - "groups-description": "In diesen Gruppen findet man verschiedenste Aktivitäten und Leute. Falls du eine Frage hast, kannst du gerne in der Connect Bern Gruppe nachfragen." + "groups-description": "In diesen Gruppen findet man verschiedenste Aktivitäten und Leute. Falls du eine Frage hast, kannst du gerne in der Connect Bern Gruppe nachfragen.", + "create-event": "Event erstellen", + "manage-events": "Events verwalten", + "pending-approval": "Wartend auf Genehmigung", + "event-approved": "Event genehmigt", + "event-rejected": "Event abgelehnt", + "upcoming-events": "Kommende Events", + "events-scheduled": "Events geplant", + "no-upcoming-events": "Keine kommenden Events", + "create-first-event": "Erstelle das erste Event für die Community!", + "calendar-view": "Kalenderansicht", + "list-view": "Listenansicht", + "show-details": "Details anzeigen", + "today": "Heute", + "tomorrow": "Morgen", + "by-organizer": "von" }, en: { "search-groups": "Search groups...", "groups": "Groups", "swiss-tips-description": "Tips & Tricks for living in Berne and Switzerland!", "places-description": "Here's a list of cool places where you can be a social butterfly.", - "events-description": "Here you can find different organized events in and around Berne that you can partake in.", + "events-description": "Here you can find different organized events in and around Berne that you can partake in. You can add your own events and discover them in the interactive calendar!", "logo-description": "Collection of social groups in Berne", - "groups-description": "In these groups you can do many different things. If you have a general question, feel free to ask in the Connect Bern group. People will be happy to help out." + "groups-description": "In these groups you can do many different things. If you have a general question, feel free to ask in the Connect Bern group. People will be happy to help out.", + "create-event": "Create Event", + "manage-events": "Manage Events", + "pending-approval": "Pending Approval", + "event-approved": "Event Approved", + "event-rejected": "Event Rejected", + "upcoming-events": "Upcoming Events", + "events-scheduled": "events scheduled", + "no-upcoming-events": "No upcoming events", + "create-first-event": "Create the first event for the community!", + "calendar-view": "Calendar View", + "list-view": "List View", + "show-details": "Show details", + "today": "Today", + "tomorrow": "Tomorrow", + "by-organizer": "by" } } \ No newline at end of file diff --git a/src/lib/services/calendarService.js b/src/lib/services/calendarService.js index 433ddc6e..3b8f749f 100644 --- a/src/lib/services/calendarService.js +++ b/src/lib/services/calendarService.js @@ -1,17 +1,78 @@ +function formatDate(date) { + return date.toISOString().replace(/-|:|\.\d\d\d/g, ""); +} + function generateGoogleCalendarLink(event) { const baseUrl = "https://www.google.com/calendar/render?action=TEMPLATE"; - let start = event.start.toISOString().replace(/-|:|\.\d\d\d/g, ""); - let end = event.end.toISOString().replace(/-|:|\.\d\d\d/g, ""); - - // If your event uses specific time zones, adjust 'start' and 'end' accordingly before this step + const start = formatDate(event.start); + const end = formatDate(event.end); const params = new URLSearchParams({ text: event.title, dates: `${start}/${end}`, - details: event.description, - location: event.location, + details: event.extendedProps?.description || event.description || '', + location: event.extendedProps?.location || event.location || '', trp: false, // Mark as busy }); return `${baseUrl}&${params.toString()}`; -} \ No newline at end of file +} + +function generateAppleCalendarLink(event) { + // Apple Calendar uses .ics files, so we'll generate an ICS file + return generateICSFile(event); +} + +function generateOutlookCalendarLink(event) { + const baseUrl = "https://outlook.live.com/calendar/0/deeplink/compose"; + const start = event.start.toISOString(); + const end = event.end.toISOString(); + + const params = new URLSearchParams({ + subject: event.title, + startdt: start, + enddt: end, + body: event.extendedProps?.description || event.description || '', + location: event.extendedProps?.location || event.location || '', + }); + + return `${baseUrl}?${params.toString()}`; +} + +function generateICSFile(event) { + const start = formatDate(event.start); + const end = formatDate(event.end); + const now = formatDate(new Date()); + + const icsContent = [ + 'BEGIN:VCALENDAR', + 'VERSION:2.0', + 'PRODID:-//Connect Bern//Events Calendar//EN', + 'CALSCALE:GREGORIAN', + 'BEGIN:VEVENT', + `UID:${event.id || Date.now()}@connectbern.ch`, + `DTSTAMP:${now}`, + `DTSTART:${start}`, + `DTEND:${end}`, + `SUMMARY:${event.title}`, + `DESCRIPTION:${(event.extendedProps?.description || event.description || '').replace(/\n/g, '\\n')}`, + `LOCATION:${event.extendedProps?.location || event.location || ''}`, + 'STATUS:CONFIRMED', + 'TRANSP:OPAQUE', + 'END:VEVENT', + 'END:VCALENDAR' + ].join('\r\n'); + + // Create and download the ICS file + const blob = new Blob([icsContent], { type: 'text/calendar;charset=utf-8' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = `${event.title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.ics`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); +} + +export { generateGoogleCalendarLink, generateAppleCalendarLink, generateOutlookCalendarLink, generateICSFile }; \ No newline at end of file diff --git a/src/lib/stores/eventsStore.js b/src/lib/stores/eventsStore.js new file mode 100644 index 00000000..7ddd9f81 --- /dev/null +++ b/src/lib/stores/eventsStore.js @@ -0,0 +1,120 @@ +import { writable } from 'svelte/store'; +import { browser } from '$app/environment'; + +// Initialize events from localStorage or default data +function createEventsStore() { + let initialEvents = []; + + // Load events from localStorage if in browser + if (browser) { + const stored = localStorage.getItem('connectbern-events'); + if (stored) { + try { + const parsed = JSON.parse(stored); + initialEvents = parsed.map(event => ({ + ...event, + start: new Date(event.start), + end: new Date(event.end), + createdAt: event.createdAt ? new Date(event.createdAt) : new Date() + })); + } catch (e) { + console.error('Error parsing stored events:', e); + } + } + } + + const { subscribe, set, update } = writable(initialEvents); + + return { + subscribe, + set, + update, + addEvent: (eventData) => { + const newEvent = { + id: Date.now().toString(), + ...eventData, + createdAt: new Date(), + status: 'pending', // pending, approved, rejected + likes: 0, + views: 0 + }; + + update(events => { + const updated = [...events, newEvent]; + if (browser) { + localStorage.setItem('connectbern-events', JSON.stringify(updated)); + } + return updated; + }); + }, + updateEvent: (id, updates) => { + update(events => { + const updated = events.map(event => + event.id === id ? { ...event, ...updates } : event + ); + if (browser) { + localStorage.setItem('connectbern-events', JSON.stringify(updated)); + } + return updated; + }); + }, + deleteEvent: (id) => { + update(events => { + const updated = events.filter(event => event.id !== id); + if (browser) { + localStorage.setItem('connectbern-events', JSON.stringify(updated)); + } + return updated; + }); + }, + approveEvent: (id) => { + update(events => { + const updated = events.map(event => + event.id === id ? { ...event, status: 'approved' } : event + ); + if (browser) { + localStorage.setItem('connectbern-events', JSON.stringify(updated)); + } + return updated; + }); + }, + rejectEvent: (id) => { + update(events => { + const updated = events.map(event => + event.id === id ? { ...event, status: 'rejected' } : event + ); + if (browser) { + localStorage.setItem('connectbern-events', JSON.stringify(updated)); + } + return updated; + }); + }, + incrementViews: (id) => { + update(events => { + const updated = events.map(event => + event.id === id ? { ...event, views: (event.views || 0) + 1 } : event + ); + if (browser) { + localStorage.setItem('connectbern-events', JSON.stringify(updated)); + } + return updated; + }); + }, + toggleLike: (id) => { + update(events => { + const updated = events.map(event => + event.id === id ? { ...event, likes: (event.likes || 0) + 1 } : event + ); + if (browser) { + localStorage.setItem('connectbern-events', JSON.stringify(updated)); + } + return updated; + }); + } + }; +} + +export const eventsStore = createEventsStore(); + +// Store for managing approval workflow +export const needsApproval = writable(true); // Set to false for free-for-all mode diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index 1f5bcda8..a250f4ce 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -6,141 +6,435 @@ -
+

Events

{@html t[lang]['events-description']}

+ +
+ {#if !isAdmin} + + {:else} +
+ +
+ {/if} +
-
    + + + + + showAdminPanel = false} + /> +
+ + +
+
+

{lang === 'de' ? 'Regelmäßige Events in Bern' : 'Regular Events in Bern'}

+

{lang === 'de' ? 'Diese Events finden regelmäßig statt - schaut auf den entsprechenden Plattformen für aktuelle Termine.' : 'These events happen regularly - check the respective platforms for current dates.'}

+
+ + -
  • - Monday: +
    +

    {lang === 'de' ? 'Wöchentliche Events' : 'Weekly Events'}

    + +
    +

    {lang === 'de' ? 'Montag:' : 'Monday:'}

    • - Denk:Mal - Swiss German course, join the WhatsApp Group + Denk:Mal - {lang === 'de' ? 'Schweizerdeutsch Kurs, tritt der' : 'Swiss German course, join the'} WhatsApp Group {lang === 'de' ? 'bei' : ''}
    -
  • - -
  • - Tuesday: + + +
    +

    {lang === 'de' ? 'Dienstag:' : 'Tuesday:'}

    • - Every 3rd Tuesday: -
      - Join fellow hackers and infosec professionals every 3rd Tuesday of - the month for a relaxed meetup with drinks in various Swiss cities. - It's free, except for special events. - - beerontuesday.ch - + {lang === 'de' ? 'Jeden 3. Dienstag:' : 'Every 3rd Tuesday:'}
      + {lang === 'de' ? 'Treffe andere Hacker und Infosec Profis jeden 3. Dienstag des Monats für ein entspanntes Meetup mit Drinks in verschiedenen Schweizer Städten. Kostenlos, außer bei speziellen Events.' : 'Join fellow hackers and infosec professionals every 3rd Tuesday of the month for a relaxed meetup with drinks in various Swiss cities. It\'s free, except for special events.'} + beerontuesday.ch +
    • - International Meetup Blabla language exchange + International Meetup BlaBla language exchange
    • CCC weekly meeting
    -
  • - - + -
  • - Wednesday: +
    +

    {lang === 'de' ? 'Mittwoch:' : 'Wednesday:'}

    • - Once a month posterum for games night - second Wednesday of the month usually. + {lang === 'de' ? 'Einmal im Monat:' : 'Once a month:'} Pusterum {lang === 'de' ? 'Spieleabend - normalerweise am zweiten Mittwoch des Monats' : 'games night - usually second Wednesday of the month'}
    • - After work - JYoB, every first Wednesday of the month + After work - JYoB: {lang === 'de' ? 'jeden ersten Mittwoch des Monats' : 'every first Wednesday of the month'}
    • - Social get together of effective altruism group. + {lang === 'de' ? 'Soziales Treffen der Effective Altruism Gruppe' : 'Social get together of effective altruism group'}
    -
  • - + -
  • - Thursday: +
    +

    {lang === 'de' ? 'Donnerstag:' : 'Thursday:'}

    • - English club (Englishclub.ch) + English club (Englishclub.ch)
    • - Once a month Polyamorous meetup on the first Thursday of the month usually. + {lang === 'de' ? 'Einmal im Monat:' : 'Once a month:'} {lang === 'de' ? 'Polyamorie-Meetup am ersten Donnerstag des Monats' : 'Polyamory meetup on the first Thursday of the month'}
    • - Chess club + {lang === 'de' ? 'Schachclub' : 'Chess club'}
    • - German language exchange meetup (usually gut gelaunt or grosse Schanze check MeetUp) + {lang === 'de' ? 'Deutscher Sprachaustausch (meist Gut Gelaunt oder Große Schanze, schaut auf MeetUp)' : 'German language exchange (usually Gut Gelaunt or Große Schanze, check MeetUp)'}
    • - Erupt games night + Erupt {lang === 'de' ? 'Spieleabend' : 'game night'}
    -
  • - -
  • - Friday: + + +
    +

    {lang === 'de' ? 'Freitag:' : 'Friday:'}

    -
  • + -
  • - Saturday: +
    +

    {lang === 'de' ? 'Samstag:' : 'Saturday:'}

    • - Karaoke night at DELFINO + {lang === 'de' ? 'Karaoke-Nacht im' : 'Karaoke night at'} DELFINO
    • - Once a month from 17.00 to 23.00 https://patt.be + {lang === 'de' ? 'Einmal im Monat:' : 'Once a month:'} 17:00-23:00 patt.be {lang === 'de' ? '(wenn sie einen Tag haben, ansonsten bleibt es wie es war, aber vielleicht das Schreiben verbessern)' : '(when they have a day otherwise keep it where it was but maybe improve the writing)'}
    -
  • - + +
    -
    - -
    + \ No newline at end of file diff --git a/static/global.css b/static/global.css index 450240de..f7524ba1 100644 --- a/static/global.css +++ b/static/global.css @@ -4,9 +4,24 @@ } -// calendar widget +/* calendar widget */ .ec { - --ec-text-color: #ffffff !important; + --ec-text-color: #333333 !important; +} +.ec-button { + background: #667eea !important; + color: white !important; + border: none !important; +} +.ec-button:hover { + background: #5a6fd8 !important; +} +.ec-today-button { + background: #27ae60 !important; + color: white !important; +} +.ec-today-button:hover { + background: #219a52 !important; } .ec-event { cursor: pointer !important; @@ -60,7 +75,7 @@ } -// lists +/* lists */ ul, ol { list-style: none; } @@ -76,7 +91,7 @@ li { } -// general +/* general */ :root { font-size: 16px; scroll-behavior: smooth; @@ -112,6 +127,17 @@ h1 { h2, h3 { color: white; } +/* Override for specific sections that need dark text */ +.static-events h2, +.static-events h3, +.static-events p, +.static-events li, +.static-events a { + color: #333 !important; +} +.static-events a:hover { + color: #667eea !important; +} h1::after { position: absolute; content: ''; @@ -129,6 +155,11 @@ p { font-size: 1.4rem; color: white; } +/* Override for sections that need dark text */ +.static-events p, +.static-events li { + color: #333 !important; +} a { color: white; } diff --git a/static/icons/heart.svg b/static/icons/heart.svg new file mode 100644 index 00000000..c73a3d24 --- /dev/null +++ b/static/icons/heart.svg @@ -0,0 +1,4 @@ + + + + From 9044bf58adb138854390eacd8136b4c033c7080e Mon Sep 17 00:00:00 2001 From: Eric Date: Sat, 9 Aug 2025 10:25:52 +0200 Subject: [PATCH 2/8] Changed agenda's text color --- src/lib/components/calendar/Calendar.svelte | 37 ++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/lib/components/calendar/Calendar.svelte b/src/lib/components/calendar/Calendar.svelte index fed9f6e8..105697d6 100644 --- a/src/lib/components/calendar/Calendar.svelte +++ b/src/lib/components/calendar/Calendar.svelte @@ -90,7 +90,7 @@ timeGridDay: lang === 'de' ? 'Tag' : 'Day', listMonth: lang === 'de' ? 'Agenda' : 'Agenda' }, - height: 'auto', + height: '600px', eventColor: '#667eea', eventTextColor: '#fff', dayMaxEvents: 3, @@ -334,6 +334,28 @@ border-radius: 8px; padding: 1rem; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + max-height: 650px; + overflow-y: auto; + overflow-x: hidden; + } + + /* Custom scrollbar styling */ + .calendar-wrapper::-webkit-scrollbar { + width: 8px; + } + + .calendar-wrapper::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 4px; + } + + .calendar-wrapper::-webkit-scrollbar-thumb { + background: #667eea; + border-radius: 4px; + } + + .calendar-wrapper::-webkit-scrollbar-thumb:hover { + background: #5a6fd8; } .event-stats { @@ -409,6 +431,19 @@ --ec-event-border-color: #27ae60; } + /* List/Agenda view styling */ + :global(.ec-list .ec-event) { + color: white !important; + } + + :global(.ec-list .ec-event-title) { + color: white !important; + } + + :global(.ec-list .ec-event-time) { + color: white !important; + } + @media (max-width: 768px) { section { padding: 1rem; From 0d71221c2bc73b2cf3749098ac14309adb1352e0 Mon Sep 17 00:00:00 2001 From: Eric Date: Sat, 9 Aug 2025 10:37:43 +0200 Subject: [PATCH 3/8] Fixies #3: Added more groups --- src/lib/models/GroupsData.js | 468 +++++++++++++++++++++++++++++++++++ 1 file changed, 468 insertions(+) diff --git a/src/lib/models/GroupsData.js b/src/lib/models/GroupsData.js index 98900be0..7140c051 100644 --- a/src/lib/models/GroupsData.js +++ b/src/lib/models/GroupsData.js @@ -166,5 +166,473 @@ export const GroupsData = [ img: "fire-community.webp", type: "other", link: "https://forum.mustachianpost.com/t/meetup-in-bern-for-coffee-beer-and-chat-about-fi-re-plans/8673/" + }, + // Unko-Märkte (Non-commercial Marketplaces) + { + name: { + de: "Bern - Hauptgruppe (Unko-Markt)", + en: "Bern - Main Group (Non-commercial Market)" + }, + slug: "unko-bern-main", + desc: { + de: "Hauptgruppe für den unkommerziellen Marktplatz in Bern.", + en: "Main group for the non-commercial marketplace in Bern." + }, + img: "marktplatz.webp", + type: "telegram", + link: "https://t.me/+j6oiWwlyYiw5MjM0" + }, + { + name: { + de: "Bümpliz und Bethlehem (Unko-Markt)", + en: "Bümpliz and Bethlehem (Non-commercial Market)" + }, + slug: "unko-buempliz-bethlehem", + desc: { + de: "Unkommerzieller Marktplatz für Bümpliz und Bethlehem.", + en: "Non-commercial marketplace for Bümpliz and Bethlehem districts." + }, + img: "telegramgruppen.webp", + type: "telegram", + link: "https://tiny.cc/unkomarktbernbuempliz" + }, + { + name: { + de: "Fischermätteli, Mattenhof, Sulgenau & Weissenbühl (Unko-Markt)", + en: "Fischermätteli, Mattenhof, Sulgenau & Weissenbühl (Non-commercial Market)" + }, + slug: "unko-fischermatteli-area", + desc: { + de: "Unkommerzieller Marktplatz für die Quartiere Fischermätteli, Mattenhof, Sulgenau und Weissenbühl.", + en: "Non-commercial marketplace for Fischermätteli, Mattenhof, Sulgenau and Weissenbühl districts." + }, + img: "connect-bern.webp", + type: "telegram", + link: "https://t.me/joinchat/V1agD1T8E7ZiOWY0" + }, + { + name: { + de: "Zollikofen (Unko-Markt)", + en: "Zollikofen (Non-commercial Market)" + }, + slug: "unko-zollikofen", + desc: { + de: "Unkommerzieller Marktplatz für Zollikofen.", + en: "Non-commercial marketplace for Zollikofen." + }, + img: "lets-bern.webp", + type: "telegram", + link: "https://tiny.cc/zusammenzollikofentg" + }, + { + name: { + de: "Konolfingen (Unko-Markt)", + en: "Konolfingen (Non-commercial Market)" + }, + slug: "unko-konolfingen", + desc: { + de: "Unkommerzieller Marktplatz für Konolfingen.", + en: "Non-commercial marketplace for Konolfingen." + }, + img: "whats-up-bern.webp", + type: "telegram", + link: "https://t.me/+0d0e2-SaejQxZTc0" + }, + { + name: { + de: "Worb (Unko-Markt)", + en: "Worb (Non-commercial Market)" + }, + slug: "unko-worb", + desc: { + de: "Unkommerzieller Marktplatz für Worb.", + en: "Non-commercial marketplace for Worb." + }, + img: "israelis-jews-friends.webp", + type: "telegram", + link: "https://t.me/+qRhXsX8PJws1MDk0" + }, + { + name: { + de: "Gürbetal (Unko-Markt)", + en: "Gürbetal (Non-commercial Market)" + }, + slug: "unko-guerbetal", + desc: { + de: "Unkommerzieller Marktplatz für das Gürbetal.", + en: "Non-commercial marketplace for Gürbetal valley." + }, + img: "berndeutsch.webp", + type: "telegram", + link: "https://t.me/+OYMZhEs90tQ1NjU0" + }, + { + name: { + de: "Region Gantrisch (Unko-Markt)", + en: "Gantrisch Region (Non-commercial Market)" + }, + slug: "unko-gantrisch", + desc: { + de: "Unkommerzieller Marktplatz für die Region Gantrisch.", + en: "Non-commercial marketplace for Gantrisch region." + }, + img: "deutschkurs.webp", + type: "telegram", + link: "https://t.me/+JXMdN-Go9UY2NDM0" + }, + { + name: { + de: "Wittigkofen-Quartier (Unko-Markt)", + en: "Wittigkofen District (Non-commercial Market)" + }, + slug: "unko-wittigkofen", + desc: { + de: "Unkommerzieller Marktplatz für das Wittigkofen-Quartier.", + en: "Non-commercial marketplace for Wittigkofen district." + }, + img: "fire-community.webp", + type: "telegram", + link: "http://tiny.cc/wittiunko" + }, + // Specialized Trading Groups + { + name: { + de: "Kindersachen Bern", + en: "Children's Items Bern" + }, + slug: "kindersachen-bern", + desc: { + de: "Gruppe zum Tauschen und Verschenken von Kindersachen.", + en: "Group for trading and gifting children's items." + }, + img: "connect-bern.webp", + type: "telegram", + link: "https://t.me/BEKindersachen" + }, + { + name: { + de: "Foodsharing Bern", + en: "Foodsharing Bern" + }, + slug: "foodsharing-bern", + desc: { + de: "Gruppe für das Teilen von Lebensmitteln gegen Verschwendung.", + en: "Group for sharing food to prevent waste." + }, + img: "vegan.webp", + type: "telegram", + link: "https://t.me/foodsharingbe" + }, + { + name: { + de: "Kleidertausch Bern", + en: "Clothing Exchange Bern" + }, + slug: "kleidertausch-bern", + desc: { + de: "Gruppe zum Tauschen von Kleidung.", + en: "Group for exchanging clothes." + }, + img: "whats-up-bern.webp", + type: "telegram", + link: "https://t.me/kleidertauschbern" + }, + { + name: { + de: "Pflanzentausch Bern", + en: "Plant Exchange Bern" + }, + slug: "pflanzentausch-bern", + desc: { + de: "Gruppe zum Tauschen von Pflanzen und Samen.", + en: "Group for exchanging plants and seeds." + }, + img: "lets-bern.webp", + type: "telegram", + link: "https://t.me/pflanzentauschen1" + }, + { + name: { + de: "Musik-Instrumente Tausch Bern", + en: "Music Instruments Exchange Bern" + }, + slug: "musik-instrumente-bern", + desc: { + de: "Gruppe zum Tauschen und Verkaufen von Musikinstrumenten.", + en: "Group for exchanging and selling musical instruments." + }, + img: "events-and-friends.webp", + type: "telegram", + link: "https://t.me/MusikInstrumente_Tausch_Bern" + }, + { + name: { + de: "Musiker*innen/Bands Bern", + en: "Musicians/Bands Bern" + }, + slug: "musikernetz-bern", + desc: { + de: "Netzwerk für Musiker*innen und Bands in Bern.", + en: "Network for musicians and bands in Bern." + }, + img: "spielegruppe.webp", + type: "telegram", + link: "https://t.me/musikernetzbern" + }, + // Events Groups + { + name: { + de: "Bern Unko Agenda (Events)", + en: "Bern Unko Agenda (Events)" + }, + slug: "bern-unko-agenda", + desc: { + de: "Hauptgruppe für Events und Veranstaltungen in Bern.", + en: "Main group for events and activities in Bern." + }, + img: "events-and-friends.webp", + type: "telegram", + link: "https://t.me/bernunkoagenda" + }, + { + name: { + de: "Event Veranstalter*innen Chat", + en: "Event Organizers Chat" + }, + slug: "event-organizers-chat", + desc: { + de: "Chat-Gruppe für Event-Veranstalter*innen.", + en: "Chat group for event organizers." + }, + img: "spielegruppe.webp", + type: "telegram", + link: "https://t.me/+UOrn5kOXNfeKYWHX" + }, + { + name: { + de: "Events in und um Bern", + en: "Events in and around Bern" + }, + slug: "events-around-bern", + desc: { + de: "Gruppe für Events in und um Bern.", + en: "Group for events in and around Bern." + }, + img: "lets-bern.webp", + type: "telegram", + link: "https://t.me/eventsbern" + }, + // Social and Community Groups + { + name: { + de: "Unko-Care", + en: "Unko-Care" + }, + slug: "unko-care", + desc: { + de: "Gruppe für gegenseitige Unterstützung und Fürsorge.", + en: "Group for mutual support and care." + }, + img: "berndeutsch.webp", + type: "telegram", + link: "https://t.me/+Hr1XrvM2JZplZmZk" + }, + { + name: { + de: "Sippe von Bern", + en: "Tribe of Bern" + }, + slug: "sippe-von-bern", + desc: { + de: "Gemeinschaftsgruppe für Menschen in Bern.", + en: "Community group for people in Bern." + }, + img: "deutschkurs.webp", + type: "telegram", + link: "https://t.me/menschbern" + }, + { + name: { + de: "Allerlei Menschliches", + en: "All Things Human" + }, + slug: "allerlei-menschliches", + desc: { + de: "Gruppe für allgemeine menschliche Themen und Austausch.", + en: "Group for general human topics and exchange." + }, + img: "fire-community.webp", + type: "telegram", + link: "https://t.me/+kAkkzvPqKidlYWU0" + }, + { + name: { + de: "Connect Bern (Telegram)", + en: "Connect Bern (Telegram)" + }, + slug: "connect-bern-telegram", + desc: { + de: "Die Telegram-Version der Connect Bern Hauptgruppe.", + en: "The Telegram version of the main Connect Bern group." + }, + img: "connect-bern.webp", + type: "telegram", + link: "https://t.me/connectbern" + }, + { + name: { + de: "Kritische Männlichkeiten", + en: "Critical Masculinities" + }, + slug: "kritische-maennlichkeiten", + desc: { + de: "Gruppe für Diskussionen über kritische Männlichkeiten.", + en: "Group for discussions about critical masculinities." + }, + img: "israelis-jews-friends.webp", + type: "telegram", + link: "https://t.me/+2lFNnfMSru4wMWY0" + }, + { + name: { + de: "Vegan Bern & Agglo (Telegram)", + en: "Vegan Bern & Surroundings (Telegram)" + }, + slug: "vegan-bern-telegram", + desc: { + de: "Die Telegram-Version der veganen Gruppe für Bern und Umgebung.", + en: "The Telegram version of the vegan group for Bern and surroundings." + }, + img: "vegan.webp", + type: "telegram", + link: "https://t.me/bernvegan" + }, + // Support and Services + { + name: { + de: "Tipps für Therapie, Beratung, Yoga", + en: "Tips for Therapy, Counseling, Yoga" + }, + slug: "therapy-counseling-yoga", + desc: { + de: "Gruppe für Empfehlungen zu Therapie, Beratung und Yoga.", + en: "Group for recommendations on therapy, counseling and yoga." + }, + img: "berndeutsch.webp", + type: "telegram", + link: "https://t.me/joinchat/fQAk9XDEkiM4NTJk" + }, + { + name: { + de: "Wohnen - WG Suche", + en: "Housing - Shared Apartment Search" + }, + slug: "housing-wg-search", + desc: { + de: "Gruppe für die Suche nach Wohngemeinschaften und Wohnungen.", + en: "Group for searching shared apartments and housing." + }, + img: "deutschkurs.webp", + type: "telegram", + link: "https://t.me/joinchat/LIezUBJgr4IRDyv8jYTWkg" + }, + { + name: { + de: "Mitfahrgelegenheit Bern", + en: "Ridesharing Bern" + }, + slug: "mitfahrgelegenheit-bern", + desc: { + de: "Gruppe für Mitfahrgelegenheiten in und um Bern.", + en: "Group for ridesharing in and around Bern." + }, + img: "whats-up-bern.webp", + type: "telegram", + link: "https://tiny.cc/mitfahrenbern" + }, + { + name: { + de: "Vorwärts links", + en: "Forward Left" + }, + slug: "vorwaerts-links", + desc: { + de: "Politische Gruppe mit linker Ausrichtung.", + en: "Political group with left-wing orientation." + }, + img: "fire-community.webp", + type: "telegram", + link: "https://t.me/joinchat/E2kynkdsZXd1x7lXB6wdJw" + }, + { + name: { + de: "Kombucha SCOBYs gratis", + en: "Kombucha SCOBYs for Free" + }, + slug: "kombucha-scobys", + desc: { + de: "Gruppe zum kostenlosen Teilen von Kombucha SCOBYs.", + en: "Group for sharing Kombucha SCOBYs for free." + }, + img: "vegan.webp", + type: "telegram", + link: "https://t.me/scobysch" + }, + // Other Cities + { + name: { + de: "Bienne/Biel Unko-Markt", + en: "Bienne/Biel Non-commercial Market" + }, + slug: "biel-bienne-unko", + desc: { + de: "Unkommerzieller Marktplatz für Biel/Bienne.", + en: "Non-commercial marketplace for Biel/Bienne." + }, + img: "telegramgruppen.webp", + type: "telegram", + link: "https://t.me/uncommercial_bielbienne" + }, + { + name: { + de: "Wohnen Biel/Bienne", + en: "Housing Biel/Bienne" + }, + slug: "housing-biel-bienne", + desc: { + de: "Gruppe für Wohnungssuche in Biel/Bienne.", + en: "Group for housing search in Biel/Bienne." + }, + img: "israelis-jews-friends.webp", + type: "telegram", + link: "https://t.me/joinchat/n-50O24IUIxmMWY0" + }, + { + name: { + de: "Mobienne", + en: "Mobienne" + }, + slug: "mobienne", + desc: { + de: "Community-Gruppe für Biel/Bienne.", + en: "Community group for Biel/Bienne." + }, + img: "spielegruppe.webp", + type: "telegram", + link: "https://t.me/mobienne" + }, + { + name: { + de: "Thun Unko-Markt", + en: "Thun Non-commercial Market" + }, + slug: "thun-unko", + desc: { + de: "Unkommerzieller Marktplatz für Thun.", + en: "Non-commercial marketplace for Thun." + }, + img: "marktplatz.webp", + type: "telegram", + link: "https://t.me/joinchat/CaUxwxSJYNG2JxN3wpTJgg" } ] \ No newline at end of file From 4fa1828112c4dbf4d3b88153d029e92f76cddd1d Mon Sep 17 00:00:00 2001 From: Eric Date: Sat, 9 Aug 2025 16:34:51 +0200 Subject: [PATCH 4/8] Caledar from 0 --- src/lib/models/GroupsData.js | 468 +++++++++++++++++++++++++++++++++++ 1 file changed, 468 insertions(+) diff --git a/src/lib/models/GroupsData.js b/src/lib/models/GroupsData.js index 98900be0..7140c051 100644 --- a/src/lib/models/GroupsData.js +++ b/src/lib/models/GroupsData.js @@ -166,5 +166,473 @@ export const GroupsData = [ img: "fire-community.webp", type: "other", link: "https://forum.mustachianpost.com/t/meetup-in-bern-for-coffee-beer-and-chat-about-fi-re-plans/8673/" + }, + // Unko-Märkte (Non-commercial Marketplaces) + { + name: { + de: "Bern - Hauptgruppe (Unko-Markt)", + en: "Bern - Main Group (Non-commercial Market)" + }, + slug: "unko-bern-main", + desc: { + de: "Hauptgruppe für den unkommerziellen Marktplatz in Bern.", + en: "Main group for the non-commercial marketplace in Bern." + }, + img: "marktplatz.webp", + type: "telegram", + link: "https://t.me/+j6oiWwlyYiw5MjM0" + }, + { + name: { + de: "Bümpliz und Bethlehem (Unko-Markt)", + en: "Bümpliz and Bethlehem (Non-commercial Market)" + }, + slug: "unko-buempliz-bethlehem", + desc: { + de: "Unkommerzieller Marktplatz für Bümpliz und Bethlehem.", + en: "Non-commercial marketplace for Bümpliz and Bethlehem districts." + }, + img: "telegramgruppen.webp", + type: "telegram", + link: "https://tiny.cc/unkomarktbernbuempliz" + }, + { + name: { + de: "Fischermätteli, Mattenhof, Sulgenau & Weissenbühl (Unko-Markt)", + en: "Fischermätteli, Mattenhof, Sulgenau & Weissenbühl (Non-commercial Market)" + }, + slug: "unko-fischermatteli-area", + desc: { + de: "Unkommerzieller Marktplatz für die Quartiere Fischermätteli, Mattenhof, Sulgenau und Weissenbühl.", + en: "Non-commercial marketplace for Fischermätteli, Mattenhof, Sulgenau and Weissenbühl districts." + }, + img: "connect-bern.webp", + type: "telegram", + link: "https://t.me/joinchat/V1agD1T8E7ZiOWY0" + }, + { + name: { + de: "Zollikofen (Unko-Markt)", + en: "Zollikofen (Non-commercial Market)" + }, + slug: "unko-zollikofen", + desc: { + de: "Unkommerzieller Marktplatz für Zollikofen.", + en: "Non-commercial marketplace for Zollikofen." + }, + img: "lets-bern.webp", + type: "telegram", + link: "https://tiny.cc/zusammenzollikofentg" + }, + { + name: { + de: "Konolfingen (Unko-Markt)", + en: "Konolfingen (Non-commercial Market)" + }, + slug: "unko-konolfingen", + desc: { + de: "Unkommerzieller Marktplatz für Konolfingen.", + en: "Non-commercial marketplace for Konolfingen." + }, + img: "whats-up-bern.webp", + type: "telegram", + link: "https://t.me/+0d0e2-SaejQxZTc0" + }, + { + name: { + de: "Worb (Unko-Markt)", + en: "Worb (Non-commercial Market)" + }, + slug: "unko-worb", + desc: { + de: "Unkommerzieller Marktplatz für Worb.", + en: "Non-commercial marketplace for Worb." + }, + img: "israelis-jews-friends.webp", + type: "telegram", + link: "https://t.me/+qRhXsX8PJws1MDk0" + }, + { + name: { + de: "Gürbetal (Unko-Markt)", + en: "Gürbetal (Non-commercial Market)" + }, + slug: "unko-guerbetal", + desc: { + de: "Unkommerzieller Marktplatz für das Gürbetal.", + en: "Non-commercial marketplace for Gürbetal valley." + }, + img: "berndeutsch.webp", + type: "telegram", + link: "https://t.me/+OYMZhEs90tQ1NjU0" + }, + { + name: { + de: "Region Gantrisch (Unko-Markt)", + en: "Gantrisch Region (Non-commercial Market)" + }, + slug: "unko-gantrisch", + desc: { + de: "Unkommerzieller Marktplatz für die Region Gantrisch.", + en: "Non-commercial marketplace for Gantrisch region." + }, + img: "deutschkurs.webp", + type: "telegram", + link: "https://t.me/+JXMdN-Go9UY2NDM0" + }, + { + name: { + de: "Wittigkofen-Quartier (Unko-Markt)", + en: "Wittigkofen District (Non-commercial Market)" + }, + slug: "unko-wittigkofen", + desc: { + de: "Unkommerzieller Marktplatz für das Wittigkofen-Quartier.", + en: "Non-commercial marketplace for Wittigkofen district." + }, + img: "fire-community.webp", + type: "telegram", + link: "http://tiny.cc/wittiunko" + }, + // Specialized Trading Groups + { + name: { + de: "Kindersachen Bern", + en: "Children's Items Bern" + }, + slug: "kindersachen-bern", + desc: { + de: "Gruppe zum Tauschen und Verschenken von Kindersachen.", + en: "Group for trading and gifting children's items." + }, + img: "connect-bern.webp", + type: "telegram", + link: "https://t.me/BEKindersachen" + }, + { + name: { + de: "Foodsharing Bern", + en: "Foodsharing Bern" + }, + slug: "foodsharing-bern", + desc: { + de: "Gruppe für das Teilen von Lebensmitteln gegen Verschwendung.", + en: "Group for sharing food to prevent waste." + }, + img: "vegan.webp", + type: "telegram", + link: "https://t.me/foodsharingbe" + }, + { + name: { + de: "Kleidertausch Bern", + en: "Clothing Exchange Bern" + }, + slug: "kleidertausch-bern", + desc: { + de: "Gruppe zum Tauschen von Kleidung.", + en: "Group for exchanging clothes." + }, + img: "whats-up-bern.webp", + type: "telegram", + link: "https://t.me/kleidertauschbern" + }, + { + name: { + de: "Pflanzentausch Bern", + en: "Plant Exchange Bern" + }, + slug: "pflanzentausch-bern", + desc: { + de: "Gruppe zum Tauschen von Pflanzen und Samen.", + en: "Group for exchanging plants and seeds." + }, + img: "lets-bern.webp", + type: "telegram", + link: "https://t.me/pflanzentauschen1" + }, + { + name: { + de: "Musik-Instrumente Tausch Bern", + en: "Music Instruments Exchange Bern" + }, + slug: "musik-instrumente-bern", + desc: { + de: "Gruppe zum Tauschen und Verkaufen von Musikinstrumenten.", + en: "Group for exchanging and selling musical instruments." + }, + img: "events-and-friends.webp", + type: "telegram", + link: "https://t.me/MusikInstrumente_Tausch_Bern" + }, + { + name: { + de: "Musiker*innen/Bands Bern", + en: "Musicians/Bands Bern" + }, + slug: "musikernetz-bern", + desc: { + de: "Netzwerk für Musiker*innen und Bands in Bern.", + en: "Network for musicians and bands in Bern." + }, + img: "spielegruppe.webp", + type: "telegram", + link: "https://t.me/musikernetzbern" + }, + // Events Groups + { + name: { + de: "Bern Unko Agenda (Events)", + en: "Bern Unko Agenda (Events)" + }, + slug: "bern-unko-agenda", + desc: { + de: "Hauptgruppe für Events und Veranstaltungen in Bern.", + en: "Main group for events and activities in Bern." + }, + img: "events-and-friends.webp", + type: "telegram", + link: "https://t.me/bernunkoagenda" + }, + { + name: { + de: "Event Veranstalter*innen Chat", + en: "Event Organizers Chat" + }, + slug: "event-organizers-chat", + desc: { + de: "Chat-Gruppe für Event-Veranstalter*innen.", + en: "Chat group for event organizers." + }, + img: "spielegruppe.webp", + type: "telegram", + link: "https://t.me/+UOrn5kOXNfeKYWHX" + }, + { + name: { + de: "Events in und um Bern", + en: "Events in and around Bern" + }, + slug: "events-around-bern", + desc: { + de: "Gruppe für Events in und um Bern.", + en: "Group for events in and around Bern." + }, + img: "lets-bern.webp", + type: "telegram", + link: "https://t.me/eventsbern" + }, + // Social and Community Groups + { + name: { + de: "Unko-Care", + en: "Unko-Care" + }, + slug: "unko-care", + desc: { + de: "Gruppe für gegenseitige Unterstützung und Fürsorge.", + en: "Group for mutual support and care." + }, + img: "berndeutsch.webp", + type: "telegram", + link: "https://t.me/+Hr1XrvM2JZplZmZk" + }, + { + name: { + de: "Sippe von Bern", + en: "Tribe of Bern" + }, + slug: "sippe-von-bern", + desc: { + de: "Gemeinschaftsgruppe für Menschen in Bern.", + en: "Community group for people in Bern." + }, + img: "deutschkurs.webp", + type: "telegram", + link: "https://t.me/menschbern" + }, + { + name: { + de: "Allerlei Menschliches", + en: "All Things Human" + }, + slug: "allerlei-menschliches", + desc: { + de: "Gruppe für allgemeine menschliche Themen und Austausch.", + en: "Group for general human topics and exchange." + }, + img: "fire-community.webp", + type: "telegram", + link: "https://t.me/+kAkkzvPqKidlYWU0" + }, + { + name: { + de: "Connect Bern (Telegram)", + en: "Connect Bern (Telegram)" + }, + slug: "connect-bern-telegram", + desc: { + de: "Die Telegram-Version der Connect Bern Hauptgruppe.", + en: "The Telegram version of the main Connect Bern group." + }, + img: "connect-bern.webp", + type: "telegram", + link: "https://t.me/connectbern" + }, + { + name: { + de: "Kritische Männlichkeiten", + en: "Critical Masculinities" + }, + slug: "kritische-maennlichkeiten", + desc: { + de: "Gruppe für Diskussionen über kritische Männlichkeiten.", + en: "Group for discussions about critical masculinities." + }, + img: "israelis-jews-friends.webp", + type: "telegram", + link: "https://t.me/+2lFNnfMSru4wMWY0" + }, + { + name: { + de: "Vegan Bern & Agglo (Telegram)", + en: "Vegan Bern & Surroundings (Telegram)" + }, + slug: "vegan-bern-telegram", + desc: { + de: "Die Telegram-Version der veganen Gruppe für Bern und Umgebung.", + en: "The Telegram version of the vegan group for Bern and surroundings." + }, + img: "vegan.webp", + type: "telegram", + link: "https://t.me/bernvegan" + }, + // Support and Services + { + name: { + de: "Tipps für Therapie, Beratung, Yoga", + en: "Tips for Therapy, Counseling, Yoga" + }, + slug: "therapy-counseling-yoga", + desc: { + de: "Gruppe für Empfehlungen zu Therapie, Beratung und Yoga.", + en: "Group for recommendations on therapy, counseling and yoga." + }, + img: "berndeutsch.webp", + type: "telegram", + link: "https://t.me/joinchat/fQAk9XDEkiM4NTJk" + }, + { + name: { + de: "Wohnen - WG Suche", + en: "Housing - Shared Apartment Search" + }, + slug: "housing-wg-search", + desc: { + de: "Gruppe für die Suche nach Wohngemeinschaften und Wohnungen.", + en: "Group for searching shared apartments and housing." + }, + img: "deutschkurs.webp", + type: "telegram", + link: "https://t.me/joinchat/LIezUBJgr4IRDyv8jYTWkg" + }, + { + name: { + de: "Mitfahrgelegenheit Bern", + en: "Ridesharing Bern" + }, + slug: "mitfahrgelegenheit-bern", + desc: { + de: "Gruppe für Mitfahrgelegenheiten in und um Bern.", + en: "Group for ridesharing in and around Bern." + }, + img: "whats-up-bern.webp", + type: "telegram", + link: "https://tiny.cc/mitfahrenbern" + }, + { + name: { + de: "Vorwärts links", + en: "Forward Left" + }, + slug: "vorwaerts-links", + desc: { + de: "Politische Gruppe mit linker Ausrichtung.", + en: "Political group with left-wing orientation." + }, + img: "fire-community.webp", + type: "telegram", + link: "https://t.me/joinchat/E2kynkdsZXd1x7lXB6wdJw" + }, + { + name: { + de: "Kombucha SCOBYs gratis", + en: "Kombucha SCOBYs for Free" + }, + slug: "kombucha-scobys", + desc: { + de: "Gruppe zum kostenlosen Teilen von Kombucha SCOBYs.", + en: "Group for sharing Kombucha SCOBYs for free." + }, + img: "vegan.webp", + type: "telegram", + link: "https://t.me/scobysch" + }, + // Other Cities + { + name: { + de: "Bienne/Biel Unko-Markt", + en: "Bienne/Biel Non-commercial Market" + }, + slug: "biel-bienne-unko", + desc: { + de: "Unkommerzieller Marktplatz für Biel/Bienne.", + en: "Non-commercial marketplace for Biel/Bienne." + }, + img: "telegramgruppen.webp", + type: "telegram", + link: "https://t.me/uncommercial_bielbienne" + }, + { + name: { + de: "Wohnen Biel/Bienne", + en: "Housing Biel/Bienne" + }, + slug: "housing-biel-bienne", + desc: { + de: "Gruppe für Wohnungssuche in Biel/Bienne.", + en: "Group for housing search in Biel/Bienne." + }, + img: "israelis-jews-friends.webp", + type: "telegram", + link: "https://t.me/joinchat/n-50O24IUIxmMWY0" + }, + { + name: { + de: "Mobienne", + en: "Mobienne" + }, + slug: "mobienne", + desc: { + de: "Community-Gruppe für Biel/Bienne.", + en: "Community group for Biel/Bienne." + }, + img: "spielegruppe.webp", + type: "telegram", + link: "https://t.me/mobienne" + }, + { + name: { + de: "Thun Unko-Markt", + en: "Thun Non-commercial Market" + }, + slug: "thun-unko", + desc: { + de: "Unkommerzieller Marktplatz für Thun.", + en: "Non-commercial marketplace for Thun." + }, + img: "marktplatz.webp", + type: "telegram", + link: "https://t.me/joinchat/CaUxwxSJYNG2JxN3wpTJgg" } ] \ No newline at end of file From f03b5968b7886b2d3444e302e786ffe87d842a80 Mon Sep 17 00:00:00 2001 From: Eric Date: Sat, 9 Aug 2025 16:53:26 +0200 Subject: [PATCH 5/8] Second version of calender --- src/routes/events/+page.svelte | 314 +++++++++++++++++++++------------ 1 file changed, 205 insertions(+), 109 deletions(-) diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index 1f5bcda8..8fb36d12 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -1,12 +1,10 @@ - Events • Connect Bern + Events • Connect Bern - @@ -19,128 +17,226 @@

    -
      -
    • - Check for events on Facebook on the 'local' tab: - - Link - -
    • -
    • - On Meetup.com and - - Gemeinsam Erleben - -
    • - -
    • - On Pusterum's website. -
    • - -
    • - On the Reitschule - and Heitere Fahne websites. -
    • -
    • - Impact Hub Bern -
    • -
    • - Check the Bern Subreddit to meet people -
    • - -
    • - Monday: +
      +
      +

      Where to Find Events

      -
    • - -
    • - Tuesday: - -
    • - - - -
    • - Wednesday: -
      • - Once a month posterum for games night - second Wednesday of the month usually. + Community Spaces: + Impact Hub Bern
      • - After work - JYoB, every first Wednesday of the month -
      • -
      • - Social get together of effective altruism group. + Reddit Community: + r/bern subreddit
      -
    • - + -
    • - Thursday: -
        -
      • - English club (Englishclub.ch) -
      • -
      • - Once a month Polyamorous meetup on the first Thursday of the month usually. -
      • -
      • - Chess club -
      • -
      • - German language exchange meetup (usually gut gelaunt or grosse Schanze check MeetUp) -
      • -
      • - Erupt games night -
      • -
      -
    • +
      +

      Weekly Recurring Events

      -
    • - Friday: -
        -
      • - English speaking club (Englishclub.ch) -
      • -
      -
    • +
      +

      Monday

      + +
      -
    • - Saturday: -
        -
      • - Karaoke night at DELFINO -
      • -
      • - Once a month from 17.00 to 23.00 https://patt.be -
      • -
      -
    • -
    +
    +

    Tuesday

    +
      +
    • + Beer on Tuesday (Every 3rd Tuesday)
      + Hackers and infosec professionals meetup with drinks. Free entry except for special events.
      + beerontuesday.ch +
    • +
    • + International Meetup - Blabla language exchange +
    • +
    • + CCC Weekly Meeting +
    • +
    +
    + +
    +

    Wednesday

    +
      +
    • + Games Night at Posterum (2nd Wednesday of the month) +
    • +
    • + After Work - JYoB (1st Wednesday of the month) +
    • +
    • + Effective Altruism - Social gathering +
    • +
    +
    + +
    +

    Thursday

    +
      +
    • + English Club - englishclub.ch +
    • +
    • + Polyamorous Meetup (1st Thursday of the month) +
    • +
    • + Chess Club +
    • +
    • + German Language Exchange - Usually at Gut Gelaunt or Grosse Schanze (check Meetup) +
    • +
    • + Erupt Games Night +
    • +
    +
    + +
    +

    Friday

    + +
    + +
    +

    Saturday

    +
      +
    • + Karaoke Night at DELFINO +
    • +
    • + Monthly Event - 17:00 to 23:00
      + patt.be +
    • +
    +
    + + +
    +

    Event Calendar

    + +
    +
    -
    - -
    + From d52433434e6f67ca6e74ee871f4b10812247ac69 Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 10 Aug 2025 16:42:43 +0200 Subject: [PATCH 6/8] Added a button to add a new event --- src/routes/events/+page.svelte | 124 ++++++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/src/routes/events/+page.svelte b/src/routes/events/+page.svelte index 8fb36d12..43af8168 100644 --- a/src/routes/events/+page.svelte +++ b/src/routes/events/+page.svelte @@ -7,6 +7,25 @@ import { currentLanguage } from '$lib/stores/languageStore'; $: lang = $currentLanguage; + + // Event submission template + const eventTemplate = encodeURIComponent(`🎉 NEW EVENT SUBMISSION + +📅 Date: +⏰ Time: +📍 Location: +🎯 Event Name: + +📝 Description: + +💰 Cost: +🗣️ Language: +👥 Target audience: + +📞 Contact: +🔗 Link:`); + + const whatsappEventUrl = `https://wa.me/41783166727?text=${eventTemplate}`;
    @@ -152,10 +171,103 @@ title="Events Calendar"> + + +
    +

    Submit Your Event

    +
    +

    Have an event to share with the Bern community? Submit it directly via WhatsApp!

    + + + + + Submit Event via WhatsApp + +
    +
    From fff7df4faf2261dbc77d4e0850314196a2e60660 Mon Sep 17 00:00:00 2001 From: Eric Date: Sun, 10 Aug 2025 17:22:14 +0200 Subject: [PATCH 7/8] Fixes #5: choose both filters for the groups --- src/lib/components/GroupsSection.svelte | 131 +++++++++++++++++++----- src/lib/models/GroupsData.js | 36 +++---- src/lib/services/groupsManager.js | 42 ++++++++ 3 files changed, 167 insertions(+), 42 deletions(-) diff --git a/src/lib/components/GroupsSection.svelte b/src/lib/components/GroupsSection.svelte index d0b83463..0b950a04 100644 --- a/src/lib/components/GroupsSection.svelte +++ b/src/lib/components/GroupsSection.svelte @@ -1,6 +1,6 @@ @@ -38,21 +59,20 @@
    -
    - - handlePlatformToggle(platform)} + /> + {platform} + {/each} - +
    + + + @@ -265,4 +273,39 @@ justify-content: center; align-items: center; } + + .github-footer { + margin-top: 3rem; + text-align: center; + padding: 2rem 1rem; + border-top: 1px solid rgba(255, 255, 255, 0.2); + } + + .github-link { + display: inline-flex; + align-items: center; + gap: 0.5rem; + color: rgba(255, 255, 255, 0.8); + text-decoration: none; + font-size: 0.9rem; + padding: 0.5rem 1rem; + border-radius: 6px; + background: rgba(255, 255, 255, 0.05); + transition: all 0.2s ease; + } + + .github-link:hover { + color: white; + background: rgba(255, 255, 255, 0.1); + transform: translateY(-2px); + } + + .github-icon { + width: 18px; + height: 18px; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='white' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z'/%3E%3C/svg%3E"); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + } \ No newline at end of file