new version

This commit is contained in:
silas
2022-02-23 21:21:34 +01:00
parent ee9d010f6e
commit 232c034560
148 changed files with 170682 additions and 12808 deletions

View File

@@ -3,23 +3,25 @@
<h1>Geschenkeliste</h1>
<p>
Ihr macht uns die größte Freude, wenn ihr mit uns feiert und den Tag verbringt. Wenn ihr uns gerne etwas
schenken möchtet, haben wir eine Liste zusammengestellt, worüber wir uns für den Start ins gemeinsame Leben
sehr freuen. Außerdem lieben wir es zu reisen und freuen uns immer über Geld für unsere Reisekasse. Falls
ihr euch unten in der Liste etwas ausgesucht habt, dann setzt dort gerne einen Haken. Wenn ihr auf ein Bild
klickt, öffnet sich direkt der passende Link dazu.
schenken möchtet, haben wir eine Liste zusammengestellt, worüber wir uns sehr freuen. Außerdem lieben wir es
zu reisen und freuen uns immer über Geld für unsere Reisekasse. Falls ihr euch unten in der Liste etwas
ausgesucht habt, dann setzt dort gerne einen Haken. Wenn ihr auf ein Bild klickt, öffnet sich direkt der
passende Link dazu.
</p>
<!-- <p>-->
<!-- Diese Liste wird sich in den nächsten Wochen noch füllen. Schaut gerne noch mal vorbei!-->
<!-- </p>-->
<!-- <p>-->
<!-- Diese Liste wird sich in den nächsten Wochen noch füllen. Schaut gerne noch mal vorbei!-->
<!-- </p>-->
<div id="present-container">
<a id="present-template" class="flex-container present" target="_blank">
<div class="present-checkbox">
<div></div>
</div>
<img class="present-image">
<div class="grow">
<div class="present-name"></div>
<div class="present-description"></div>
<div class="grow present-info">
<div>
<div class="present-name"></div>
<div class="present-description"></div>
</div>
</div>
</a>
</div>

View File

@@ -1,13 +1,12 @@
<div class="site-content grid-container">
<h1>Herzlich Willkommen</h1>
<p>Wir heiraten! Und das möchten wir mit euch gemeinsam in Aachen feiern.
Leider müssen wir jedoch wegen der Corona Pandemie unsere kirchliche
Hochzeit um ein Jahr auf den <b>07.05.22</b> verschieben. Standesamtlich haben wir natürlich
trotzdem am 24. April in Betzdorf (Sieg) geheiratet und sind glücklich darüber
gemeinsam in die Ehe zu starten. Wir freuen uns schon sehr darauf, nächstes Jahr
unseren Hochzeitsgottesdienst und eine große Party mit euch am 07.05.22 zu feiern.
</p>
<p>Der Termin für unsere kirchliche Hochzeit steht fest. <b>Wir feiern am 07. Mai '22!</b></p>
<p>Falls ihr Fragen habt, meldet euch gerne unter <a href = 'mailto:hochzeit-js@gmx.net'>hochzeit-js@gmx.net</a></p>
<p>Wir freuen uns, mit Euch unsere Hochzeit in Aachen zu feiern! Nach unserer wunderschönen standesamtlichen Trauung
am 24. April letztes Jahr, freuen wir uns auf unsere kirchliche Hochzeit am 7. Mai dieses Jahr. Bitte sagt uns
doch bis zum 15. März, ob ihr dabei sein könnt! Schreibt uns dazu gerne eine Mail an <a
href='mailto:hochzeit-js@gmx.net'>hochzeit-js@gmx.net</a>.
</p>
<p>Nach den neusten Lockerungen sind wir sehr zuversichtlich, dass unsere Hochzeit dieses Jahr trotz Corona
stattfinden kann. Wir gehen davon aus, dass wir unter 2G- oder 2G-plus-Regeln feiern werden, aber mit genaueren
Infos dazu melden wir uns nochmal rechtzeitig vorher.</p>
<p>Falls ihr Fragen habt, meldet euch gerne bei uns :)</p>
</div>

View File

@@ -0,0 +1,6 @@
<div class="site-content grid-container">
<h1>Standesamtliche Trauung</h1>
<p>Hier findet ihr ein paar Impressionen zu unserer standesamtlichen Trauung letztes Jahr. Wir haben trotz Start des
bundesweiten Lockdowns einen wunderschönen Tag im kleinen Familienkreis verbracht.</p><br/>
<div id="gallery"></div>
</div>

View File

@@ -1,6 +1,7 @@
<div class="flex-container fill-height-medium-up">
<div class="height-100" id="info-image-container" data-state="godi">
<img src="../img/tagesablauf.jpg" class="height-100">
<img src="../img/tagesablauf_neu.jpg" class="height-100">
<img src="../img/einkreiser.png" class="circler visible">
<img src="../img/einkreiser.png" class="circler godi" data-state="godi">
<img src="../img/einkreiser.png" class="circler fingerfood" data-state="fingerfood">
<img src="../img/einkreiser.png" class="circler foto" data-state="foto">
@@ -13,50 +14,53 @@
<div class="anchor" data-state="godi">
<h1>Traugottesdienst</h1>
<p>
Um 14:00 Uhr möchten wir gemeinsam mit euch unseren Traugottesdienst in der Annakirche feiern
(Annastraße
35, 52062 Aachen). Wenn ihr mit dem Auto anreist könnt ihr im Parkhaus am Dom (Jesuitenstraße 12, 52062
Aachen) parken, das ist direkt neben der Kirche.
Um 12:00 Uhr möchten wir gemeinsam mit euch unseren Traugottesdienst in der Annakirche feiern
(Annastraße 35, 52062 Aachen). Wenn ihr mit dem Auto anreist könnt ihr im Parkhaus am Dom
(Jesuitenstraße 12, 52062 Aachen) parken, das ist direkt neben der Kirche. <br/>Kleiner fun fact: Es
lohnt
sich auf der obersten Etage zu parken, dort gibt es eine tolle Aussicht auf den Dom und da haben wir uns
verlobt.
</p>
</div>
<div class="anchor" data-state="fingerfood">
<h1>Fingerfood</h1>
<p>
Nach dem Gottesdienst gehen wir zusammen zu Fuß ins Aachener Fenster (Buchkremerstraße 2). Dort gibt es
dann
süßes und salziges Fingerfood und ganz viel Zeit zum Gratulieren. Wenn ihr etwas zum Buffet beisteuern
möchtet, dann meldet euch gerne bei <a href='mailto:sinah.stinner@googlemail.com'>Sinah Stinner
Nach dem Gottesdienst gibt es süßes und salziges Fingerfood und ganz viel Zeit zum Gratulieren. Wenn ihr
etwas zum Buffet beisteuern möchtet, dann meldet euch gerne bei <a
href='mailto:sinah.stinner@googlemail.com'>Sinah Stinner
(sinah.stinner@googlemail.com)</a>.
</p></div>
</p>
</div>
<div class="anchor" data-state="foto">
<h1>Gruppenfotos</h1>
<p>
Um ganz viele wundervolle Erinnerungen an unsere Hochzeit, die wir mit euch feiern, zu haben, gehen wir
um
17:00 Uhr auf den Katschhof und machen dort Gruppenfotos.
</p></div>
Um ganz viele wundervolle Erinnerungen an den besonderen Tag zu haben, gehen wir gegen 15:30 Uhr auf den
Katschhof, zwischen dem Aachener Dom und Rathaus, und machen dort Gruppenfotos.
</p>
</div>
<div class="anchor" data-state="sekt">
<h1>Sektempfang</h1>
<p>
Wir feiern unsere Hochzeit im Forum M über der Aachener Mayerschen mit einem wundervollen Blick über die
Aachener Innenstadt. Nach den Fotos werden wir dort gemeinsam anstoßen.
</p></div>
Aachener Innenstadt. Gegen 17h wollen wir dort gemeinsam anstoßen.
</p>
</div>
<div class="anchor" data-state="essen">
<h1>Festessen</h1>
<p>
Nach vielen wundervollen Bildern, freuen wir uns alle auf unser leckeres Hochzeitsbuffet, das es um halb
acht gibt.
</p></div>
Um halb acht starten wir den Abend mit dem leckeren Hochzeitsbuffet.
</p>
</div>
<div class="anchor" data-state="spiel">
<h1>Spiel und Spass</h1>
<p>
Wir freuen uns auf richtige viele einzigartige, lustige und spaßige Programmbeiträge von euch. Wenn ihr
es
schon gar nicht erwarten könnt uns eine Freude zu machen und einen Beiträg beizusteuern, dann meldet
euch
gerne bei <a href = 'mailto:seitz-miriam@web.de'>Miriam Seitz (seitz.miriam@web.de)</a>. Und keine Sorge, Miriam behält alle Beiträge und
Wir freuen uns auf viele einzigartige, lustige und spaßige Programmbeiträge von euch. Wenn ihr es schon
gar nicht erwarten könnt uns eine Freude zu machen und einen Beitrag beizusteuern, dann meldet euch
gerne bei <a
href='mailto:seitz-miriam@web.de'>Miriam Seitz (seitz-miriam@web.de)</a>. Und keine Sorge, Miriam behält alle Beiträge und
Überraschungen für sich, aber sagt ihr bitte bei allem Bescheid, was ihr planen wollt.
</p></div>
</p>
</div>
<div class="anchor" data-state="dance">
<h1>Let's Dance</h1>
<p>
@@ -65,4 +69,4 @@
</div>
</div>
</div>
<div id = "modal"></div>
<div id="modal"></div>

View File

@@ -1,7 +1,4 @@
<div class="flex-container fill-height-medium-up">
<!-- <div class="height-100 show-for-small-only">-->
<!-- <img src="../img/unterkunft.jpg">-->
<!-- </div>-->
<div class="grow height-100 overflow-auto site-content hide-scrollbar">
<h1>Unterkunft</h1>
<p>
@@ -9,19 +6,13 @@
verbringen!
</p>
<p>
Unten stehend findet ihr Vorschläge für Übernachtungsmöglichkeiten in Aachen. Wahrscheinlich macht es auf
Grund der aktuellen Corona-Lage noch keinen Sinn, dass ihr etwas bucht, weil wir erst abwarten müssen,
inwiefern wir unsere Hochzeit feiern können.
</p>
<p>
Das B&B Hotel Aachen City (Großkölnstraße 57-63) ist fußläufig von unserer Location in fünf Minuten zu
erreichen. Da wir von der Kirche zu Fuß ins Forum M gehen können, könnt ihr das Auto im Parkhaus am Dom über
Nacht stehen lassen.
Untenstehend findet ihr Vorschläge für Übernachtungsmöglichkeiten in Aachen. Das B&B Hotel Aachen City
(Großkölnstraße 57-63) ist fußläufig von unserer Location in fünf Minuten zu erreichen. Da wir von der
Kirche zu Fuß ins Forum M gehen können, könnt ihr das Auto im Parkhaus am Dom über Nacht stehen lassen.
</p>
<p>
Alle, die eher eine studentische Übernachtungsmöglichkeit suchen, können sich gerne bei uns melden. Ihr
werdet
dann bei Freunden aus Aachen in WGs mituntergebracht. Sagt uns da bitte bis spätestens zum 15.April
werdet dann bei Freunden von uns in WGs übernachten. Sagt uns da bitte auch spätestens bis zum 15. März
Bescheid.
</p>
@@ -33,12 +24,13 @@
</a>
</div>
<div class="small-8">
<!-- <iframe id="map_unterkunft" src="https://maps.google.com/maps?width=520&amp;height=395&amp;hl=de&amp;q=IBIS%20budget%20Hotel+Schumacherstr%2012%20Aachen&amp;t=&amp;z=14&amp;ie=UTF8&amp;iwloc=B&amp;output=embed"></iframe>-->
<iframe id="map_unterkunft" src="https://maps.google.com/maps?width=520&amp;height=395&amp;hl=de&amp;q=B%26B+Hotel+Aachen-City,+Großkölnstraße+57-63,+52062+Aachen&amp;t=&amp;z=14&amp;ie=UTF8&amp;iwloc=B&amp;output=embed"></iframe>
<!-- <iframe id="map_unterkunft" src="https://maps.google.com/maps?width=520&amp;height=395&amp;hl=de&amp;q=IBIS%20budget%20Hotel+Schumacherstr%2012%20Aachen&amp;t=&amp;z=14&amp;ie=UTF8&amp;iwloc=B&amp;output=embed"></iframe>-->
<iframe id="map_unterkunft"
src="https://maps.google.com/maps?width=520&amp;height=395&amp;hl=de&amp;q=B%26B+Hotel+Aachen-City,+Großkölnstraße+57-63,+52062+Aachen&amp;t=&amp;z=14&amp;ie=UTF8&amp;iwloc=B&amp;output=embed"></iframe>
</div>
</div>
</div>
<div class="height-100 hide-for-small-only img-column">
<img src="../img/unterkunft.jpg" class="height-100">
</div>
</div>
</div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 985 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 789 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

View File

@@ -29,7 +29,7 @@
<li data-site="tagesablauf"><a>Tagesablauf</a></li>
<li data-site="unterkunft"><a>Unterkunft</a></li>
<li data-site="geschenke"><a>Geschenke</a></li>
<!-- <li><a href="#">Galerie</a></li>-->
<li data-site="standesamt"><a>Standesamt</a></li>
</ul>
<ul class="menu align-center-middle medium-horizontal hide-for-small-only">
<li><img class="logo-img" src="img/logo.png" alt="J&S"></li>
@@ -37,7 +37,7 @@
<li data-site="tagesablauf"><a>Tagesablauf</a></li>
<li data-site="unterkunft"><a>Unterkunft</a></li>
<li data-site="geschenke"><a>Geschenke</a></li>
<!-- <li><a href="#">Galerie</a></li>-->
<li data-site="standesamt"><a>Standesamt</a></li>
</ul>
</div>
<div class="top-bar-right">
@@ -67,4 +67,4 @@
</div>
</div>
</body>
</html>
</html>

View File

@@ -0,0 +1,133 @@
import React, { useState, useLayoutEffect, useRef, useMemo } from 'react';
import PropTypes from 'prop-types';
import ResizeObserver from 'resize-observer-polyfill';
import Photo, { photoPropType } from './Photo';
import { computeColumnLayout } from './layouts/columns';
import { computeRowLayout } from './layouts/justified';
import { findIdealNodeSearch } from './utils/findIdealNodeSearch';
const Gallery = React.memo(function Gallery({
photos,
onClick,
direction,
margin,
limitNodeSearch,
targetRowHeight,
columns,
renderImage,
}) {
const [containerWidth, setContainerWidth] = useState(0);
const galleryEl = useRef(null);
useLayoutEffect(() => {
let animationFrameID = null;
const observer = new ResizeObserver(entries => {
// only do something if width changes
const newWidth = entries[0].contentRect.width;
if (containerWidth !== newWidth) {
// put in an animation frame to stop "benign errors" from
// ResizObserver https://stackoverflow.com/questions/49384120/resizeobserver-loop-limit-exceeded
animationFrameID = window.requestAnimationFrame(() => {
setContainerWidth(Math.floor(newWidth));
});
}
});
observer.observe(galleryEl.current);
return () => {
observer.disconnect();
window.cancelAnimationFrame(animationFrameID);
};
});
const handleClick = (event, { index }) => {
onClick(event, {
index,
photo: photos[index],
previous: photos[index - 1] || null,
next: photos[index + 1] || null,
});
};
// no containerWidth until after first render with refs, skip calculations and render nothing
if (!containerWidth) return <div ref={galleryEl}>&nbsp;</div>;
// subtract 1 pixel because the browser may round up a pixel
const width = containerWidth - 1;
let galleryStyle, thumbs;
if (direction === 'row') {
// allow user to calculate limitNodeSearch from containerWidth
if (typeof limitNodeSearch === 'function') {
limitNodeSearch = limitNodeSearch(containerWidth);
}
if (typeof targetRowHeight === 'function') {
targetRowHeight = targetRowHeight(containerWidth);
}
// set how many neighboring nodes the graph will visit
if (limitNodeSearch === undefined) {
limitNodeSearch = 2;
if (containerWidth >= 450) {
limitNodeSearch = findIdealNodeSearch({ containerWidth, targetRowHeight });
}
}
galleryStyle = { display: 'flex', flexWrap: 'wrap', flexDirection: 'row' };
thumbs = computeRowLayout({ containerWidth: width, limitNodeSearch, targetRowHeight, margin, photos });
}
if (direction === 'column') {
// allow user to calculate columns from containerWidth
if (typeof columns === 'function') {
columns = columns(containerWidth);
}
// set default breakpoints if user doesn't specify columns prop
if (columns === undefined) {
columns = 1;
if (containerWidth >= 500) columns = 2;
if (containerWidth >= 900) columns = 3;
if (containerWidth >= 1500) columns = 4;
}
galleryStyle = { position: 'relative' };
thumbs = computeColumnLayout({ containerWidth: width, columns, margin, photos });
galleryStyle.height = thumbs[thumbs.length - 1].containerHeight;
}
const renderComponent = renderImage || Photo;
return (
<div className="react-photo-gallery--gallery">
<div ref={galleryEl} style={galleryStyle}>
{thumbs.map((thumb, index) => {
const { left, top, containerHeight, ...photo } = thumb;
return renderComponent({
left,
top,
key: thumb.key || thumb.src,
containerHeight,
index,
margin,
direction,
onClick: onClick ? handleClick : null,
photo,
});
})}
</div>
</div>
);
});
Gallery.propTypes = {
photos: PropTypes.arrayOf(photoPropType).isRequired,
direction: PropTypes.string,
onClick: PropTypes.func,
columns: PropTypes.oneOfType([PropTypes.func, PropTypes.number]),
targetRowHeight: PropTypes.oneOfType([PropTypes.func, PropTypes.number]),
limitNodeSearch: PropTypes.oneOfType([PropTypes.func, PropTypes.number]),
margin: PropTypes.number,
renderImage: PropTypes.func,
};
Gallery.defaultProps = {
margin: 2,
direction: 'row',
targetRowHeight: 300,
};
export { Photo };
export default Gallery;

View File

@@ -0,0 +1,59 @@
import React from 'react';
import PropTypes from 'prop-types';
const imgWithClick = { cursor: 'pointer' };
const Photo = ({ index, onClick, photo, margin, direction, top, left, key }) => {
const imgStyle = { margin: margin, display: 'block' };
imgStyle.width = photo.width+"px";
imgStyle.height=photo.height+"px";
if (direction === 'column') {
imgStyle.position = 'absolute';
imgStyle.left = left;
imgStyle.top = top;
}
const handleClick = event => {
onClick(event, { photo, index });
};
return (
<img
key={key}
style={onClick ? { ...imgStyle, ...imgWithClick } : imgStyle}
{...photo}
onClick={onClick ? handleClick : null}
/>
);
};
export const photoPropType = PropTypes.shape({
key: PropTypes.string,
src: PropTypes.string.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
alt: PropTypes.string,
title: PropTypes.string,
srcSet: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
sizes: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
});
Photo.propTypes = {
index: PropTypes.number.isRequired,
onClick: PropTypes.func,
photo: photoPropType.isRequired,
margin: PropTypes.number,
top: props => {
if (props.direction === 'column' && typeof props.top !== 'number') {
return new Error('top is a required number when direction is set to `column`');
}
},
left: props => {
if (props.direction === 'column' && typeof props.left !== 'number') {
return new Error('left is a required number when direction is set to `column`');
}
},
direction: PropTypes.string,
};
export default Photo;

View File

@@ -0,0 +1,49 @@
import { round } from '../utils/round';
// compute sizes for column directed layouts
export const computeColumnLayout = ({ photos, columns, containerWidth, margin }) => {
// calculate each colWidth based on total width and column amount
let colWidth = (containerWidth - margin * 2 * columns) / columns;
// map through each photo to assign adjusted height and width based on colWidth
const photosWithSizes = photos.map(photo => {
const newHeight = photo.height / photo.width * colWidth;
return {
...photo,
width: round(colWidth, 1),
height: round(newHeight, 1),
};
});
// store all possible left positions
// and current top positions for each column
const colLeftPositions = [];
const colCurrTopPositions = [];
for (var i = 0; i < columns; i++) {
colLeftPositions[i] = round(i * (colWidth + margin * 2), 1);
colCurrTopPositions[i] = 0;
}
// map through each photo, then reduce thru each "column"
// find column with the smallest height and assign to photo's 'top'
// update that column's height with this photo's height
const photosPositioned = photosWithSizes.map(photo => {
const smallestCol = colCurrTopPositions.reduce((acc, item, i) => {
acc = item < colCurrTopPositions[acc] ? i : acc;
return acc;
}, 0);
photo.top = colCurrTopPositions[smallestCol];
photo.left = colLeftPositions[smallestCol];
colCurrTopPositions[smallestCol] = colCurrTopPositions[smallestCol] + photo.height + margin * 2;
// store the tallest col to use for gallery height because of abs positioned elements
const tallestCol = colCurrTopPositions.reduce((acc, item, i) => {
acc = item > colCurrTopPositions[acc] ? i : acc;
return acc;
}, 0);
photo.containerHeight = colCurrTopPositions[tallestCol];
return photo;
});
return photosPositioned;
};

View File

@@ -0,0 +1,49 @@
import { ratio } from '../utils/ratio';
import { round } from '../utils/round';
import { findShortestPath } from '../utils/dijkstra';
// compute sizes by creating a graph with rows as edges and photo to break on as nodes
// to calculate the single best layout using Dijkstra's findShortestPat
// get the height for a set of photos in a potential row
const getCommonHeight = (row, containerWidth, margin) => {
const rowWidth = containerWidth - row.length * (margin * 2);
const totalAspectRatio = row.reduce((acc, photo) => acc + ratio(photo), 0);
return rowWidth / totalAspectRatio;
};
// calculate the cost of breaking at this node (edge weight)
const cost = (photos, i, j, width, targetHeight, margin) => {
const row = photos.slice(i, j);
const commonHeight = getCommonHeight(row, width, margin);
return Math.pow(Math.abs(commonHeight - targetHeight), 2);
};
// return function that gets the neighboring nodes of node and returns costs
const makeGetNeighbors = (targetHeight, containerWidth, photos, limitNodeSearch, margin) => start => {
const results = {};
start = +start;
results[+start] = 0;
for (let i = start + 1; i < photos.length + 1; ++i) {
if (i - start > limitNodeSearch) break;
results[i.toString()] = cost(photos, start, i, containerWidth, targetHeight, margin);
}
return results;
};
export const computeRowLayout = ({ containerWidth, limitNodeSearch, targetRowHeight, margin, photos }) => {
// const t = +new Date();
const getNeighbors = makeGetNeighbors(targetRowHeight, containerWidth, photos, limitNodeSearch, margin);
let path = findShortestPath(getNeighbors, '0', photos.length);
path = path.map(node => +node);
// console.log(`time to find the shortest path: ${(+new Date() - t)} ms`);
for (let i = 1; i < path.length; ++i) {
const row = photos.slice(path[i - 1], path[i]);
const height = getCommonHeight(row, containerWidth, margin);
for (let j = path[i - 1]; j < path[i]; ++j) {
photos[j].width = round(height * ratio(photos[j]), 1);
photos[j].height = height;
}
}
return photos;
};

View File

@@ -0,0 +1,123 @@
/*
Copyright 2007-2013 Marijn Haverbeke frin "Eloquent Javascript, 1st Edition"
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
export function BinaryHeap(scoreFunction) {
this.content = [];
this.scoreFunction = scoreFunction;
}
BinaryHeap.prototype = {
push: function(element) {
// Add the new element to the end of the array.
this.content.push(element);
// Allow it to bubble up.
this.bubbleUp(this.content.length - 1);
},
pop: function() {
// Store the first element so we can return it later.
var result = this.content[0];
// Get the element at the end of the array.
var end = this.content.pop();
// If there are any elements left, put the end element at the
// start, and let it sink down.
if (this.content.length > 0) {
this.content[0] = end;
this.sinkDown(0);
}
return result;
},
remove: function(node) {
var length = this.content.length;
// To remove a value, we must search through the array to find
// it.
for (var i = 0; i < length; i++) {
if (this.content[i] != node) continue;
// When it is found, the process seen in 'pop' is repeated
// to fill up the hole.
var end = this.content.pop();
// If the element we popped was the one we needed to remove,
// we're done.
if (i == length - 1) break;
// Otherwise, we replace the removed element with the popped
// one, and allow it to float up or sink down as appropriate.
this.content[i] = end;
this.bubbleUp(i);
this.sinkDown(i);
break;
}
},
size: function() {
return this.content.length;
},
bubbleUp: function(n) {
// Fetch the element that has to be moved.
var element = this.content[n],
score = this.scoreFunction(element);
// When at 0, an element can not go up any further.
while (n > 0) {
// Compute the parent element's index, and fetch it.
var parentN = Math.floor((n + 1) / 2) - 1,
parent = this.content[parentN];
// If the parent has a lesser score, things are in order and we
// are done.
if (score >= this.scoreFunction(parent)) break;
// Otherwise, swap the parent with the current element and
// continue.
this.content[parentN] = element;
this.content[n] = parent;
n = parentN;
}
},
sinkDown: function(n) {
// Look up the target element and its score.
var length = this.content.length,
element = this.content[n],
elemScore = this.scoreFunction(element);
while (true) {
// Compute the indices of the child elements.
var child2N = (n + 1) * 2,
child1N = child2N - 1;
// This is used to store the new position of the element,
// if any.
var swap = null;
// If the first child exists (is inside the array)...
if (child1N < length) {
// Look it up and compute its score.
var child1 = this.content[child1N],
child1Score = this.scoreFunction(child1);
// If the score is less than our element's, we need to swap.
if (child1Score < elemScore) swap = child1N;
}
// Do the same checks for the other child.
if (child2N < length) {
var child2 = this.content[child2N],
child2Score = this.scoreFunction(child2);
if (child2Score < (swap == null ? elemScore : child1Score)) swap = child2N;
}
// No need to swap further, we are done.
if (swap == null) break;
// Otherwise, swap and continue.
this.content[n] = this.content[swap];
this.content[swap] = element;
n = swap;
}
},
};
export default BinaryHeap;

View File

@@ -0,0 +1,74 @@
import { BinaryHeap } from './binary-heap';
const buildPrecedentsMap = (graph, startNode, endNode) => {
// store the previous vertex of the shortest path of arrival
const precedentsMap = {};
// store nodes already visited
const visited = {};
// store/update only the shortest edge weights measured
// the purpose of this is object is constant time lookup vs. binary heap lookup O(n)
const storedShortestPaths = {};
storedShortestPaths[startNode] = 0;
// priority queue of ALL nodes and storedShortestPaths
// don't bother to delete them because it's faster to look at visited?
const pQueue = new BinaryHeap(function(n) {
return n.weight;
});
pQueue.push({ id: startNode, weight: 0 });
while (pQueue.size()) {
// pop node with shortest total weight from start node
const shortestNode = pQueue.pop();
const shortestNodeId = shortestNode.id;
// if already visited, continue
if (visited[shortestNodeId]) continue;
// visit neighboring nodes
const neighboringNodes = graph(shortestNodeId) || {};
visited[shortestNodeId] = 1;
// meet the neighbors, looking for shorter paths
for (let neighbor in neighboringNodes) {
// weight of path from startNode to this neighbor
const newTotalWeight = shortestNode.weight + neighboringNodes[neighbor];
// if this is the first time meeting the neighbor OR if the new total weight from
// start node to this neighbor node is greater than the old weight path, update it,
// and update precedent node
if (typeof storedShortestPaths[neighbor] === 'undefined' || storedShortestPaths[neighbor] > newTotalWeight) {
storedShortestPaths[neighbor] = newTotalWeight;
pQueue.push({ id: neighbor, weight: newTotalWeight });
precedentsMap[neighbor] = shortestNodeId;
}
}
}
if (typeof storedShortestPaths[endNode] === 'undefined') {
throw new Error(`There is no path from ${startNode} to ${endNode}`);
}
return precedentsMap;
};
// build the route from precedent node vertices
const getPathFromPrecedentsMap = (precedentsMap, endNode) => {
const nodes = [];
let n = endNode;
let precedent;
while (n) {
nodes.push(n);
precedent = precedentsMap[n];
n = precedentsMap[n];
}
return nodes.reverse();
};
// build the precedentsMap and find the shortest path from it
export const findShortestPath = (graph, startNode, endNode) => {
const precedentsMap = buildPrecedentsMap(graph, startNode, endNode);
return getPathFromPrecedentsMap(precedentsMap, endNode);
};

View File

@@ -0,0 +1,9 @@
import { round } from './round';
// guesstimate how many neighboring nodes should be searched based on
// the aspect ratio of the container with images having an avg AR of 1.5
// as the minimum amount of photos per row, plus some nodes
export const findIdealNodeSearch = ({ targetRowHeight, containerWidth }) => {
const rowAR = containerWidth / targetRowHeight;
return round(rowAR / 1.5) + 8;
};

View File

@@ -0,0 +1,4 @@
import { round } from './round';
// return two decimal places rounded number
export const ratio = ({ width, height }) => round(width / height, 2);

View File

@@ -0,0 +1,4 @@
export const round = (value, decimals) => {
if (!decimals) decimals = 0;
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
};

View File

@@ -0,0 +1,47 @@
import * as React from 'react';
import Carousel, {Modal, ModalGateway} from "react-images";
import {useCallback, useState} from "react";
import {photos} from "./photos";
import Gallery from "./Gallery/Gallery";
export type ImageGalleryProps = {};
function ImageGallery({}: ImageGalleryProps) {
const [currentImage, setCurrentImage] = useState(0);
const [viewerIsOpen, setViewerIsOpen] = useState(false);
const openLightbox = useCallback((event, {photo, index}) => {
setCurrentImage(index);
setViewerIsOpen(true);
}, []);
const closeLightbox = () => {
setCurrentImage(0);
setViewerIsOpen(false);
};
return <div>
{/* @ts-ignore*/}
<Gallery photos={photos} onClick={openLightbox}></Gallery>
<ModalGateway>
{viewerIsOpen ? (
<Modal onClose={closeLightbox}>
<Carousel
currentIndex={currentImage}
views={photos.map(x => ({
...x,
source: x.src
// srcset: x.srcSet,
// caption: x.title
}))}
/>
</Modal>
) : null}
</ModalGateway>
</div>;
}
// Need ImageGalleryMemo for autocompletion of phpstorm
const ImageGalleryMemo = React.memo(ImageGallery) as typeof ImageGallery;
export {ImageGalleryMemo as ImageGallery}

View File

@@ -0,0 +1,82 @@
export const photos = [
{
src: require("../../img/standesamt/1.jpg").default,
width: 3024,
height: 4032
},
{
src: require("../../img/standesamt/2.jpg").default,
width: 4928,
height: 3264
},
{
src: require("../../img/standesamt/3.jpg").default,
width: 4928,
height: 3264
},
{
src: require("../../img/standesamt/4.jpg").default,
width: 3264,
height: 4928
},
{
src: require("../../img/standesamt/5.jpg").default,
width: 3264,
height: 4928
},
{
src: require("../../img/standesamt/6.jpg").default,
width: 4928,
height: 3264
},
{
src: require("../../img/standesamt/7.jpg").default,
width: 3264,
height: 4928
},
{
src: require("../../img/standesamt/8.jpg").default,
width: 4928,
height: 3264
},
{
src: require("../../img/standesamt/9.jpg").default,
width: 4928,
height: 3264
},
{
src: require("../../img/standesamt/10.jpg").default,
width: 4928,
height: 3264
},
{
src: require("../../img/standesamt/11.jpg").default,
width: 3299,
height: 2209
},
{
src: require("../../img/standesamt/12.jpg").default,
width: 2592,
height: 3872
},
{
src: require("../../img/standesamt/13.jpg").default,
width: 3872,
height: 2592
},
{
src: require("../../img/standesamt/14.jpg").default,
width: 3872,
height: 2592
},
{
src: require("../../img/standesamt/15.jpg").default,
width: 3872,
height: 2592
},
{
src: require("../../img/standesamt/16.jpg").default,
width: 3872,
height: 2592
},
]

View File

@@ -2,11 +2,15 @@ import * as $ from "jquery";
import "foundation-sites/dist/js/foundation.es6";
import {PresentsHandler} from "./PresentsHandler";
import "../sass/index.scss"
import {setupImageGallery} from "./setupImageGallery";
const templates = {
home: require("../html/home.html"),
unterkunft: require("../html/unterkunft.html"),
tagesablauf: require("../html/tagesablauf.html"),
geschenke: require("../html/geschenke.html"),
standesamt: require("../html/standesamt.html"),
}
const images = {
@@ -14,6 +18,7 @@ const images = {
unterkunft: require("../img/unterkunft.jpg").default,
tagesablauf: null,
geschenke: require("../img/geschenke.jpg").default,
standesamt: null,
}
const callbacks = {
@@ -87,6 +92,7 @@ const callbacks = {
});
},
geschenke: async () => await new PresentsHandler().showPresents(),
standesamt: setupImageGallery
}
$(document).foundation();
@@ -134,4 +140,4 @@ $(function () {
document.querySelector("li[data-site='home']").dispatchEvent(new Event("click"));
})
})
});
});

View File

@@ -1,26 +1,29 @@
export default [{
id: 1,
isBought: false,
image: require("../img/geschenke/Quicheform.png").default,
name: "Quicheform",
description: "Eine Keramik-Quicheform mit Haltegriffen, die spülmaschinengeeigent ist (wie im Link oder ähnlich)",
link: "https://www.zwilling.com/de/zwilling-kuchenform-28-cm-keramik-40202-028-0/40202-028-0.html",
version: 0,
}, {
id: 2,
isBought: false,
image: require("../img/geschenke/Sodastream.png").default,
name: "2 Sodastream Flaschen",
description: "Zwei Glaskaraffen für den Sodastream Crystal",
link: "https://sodastream.de/products/glaskaraffe-duo-pack-0-8l",
version: 0,
}, {
export default [
// {
// id: 1,
// isBought: false,
// image: require("../img/geschenke/Quicheform.png").default,
// name: "Quicheform",
// description: "Eine Keramik-Quicheform mit Haltegriffen, die spülmaschinengeeigent ist (wie im Link oder ähnlich)",
// link: "https://www.zwilling.com/de/zwilling-kuchenform-28-cm-keramik-40202-028-0/40202-028-0.html",
// version: 0,
// },
// {
// id: 2,
// isBought: false,
// image: require("../img/geschenke/Sodastream.png").default,
// name: "2 Sodastream Flaschen",
// description: "Zwei Glaskaraffen für den Sodastream Crystal",
// link: "https://sodastream.de/products/glaskaraffe-duo-pack-0-8l",
// version: 0,
// },
{
id: 3,
isBought: false,
image: require("../img/geschenke/GoPro.png").default,
name: "Go Pro Hero 7 black",
description: "Eine Go Pro Hero 7 Actioncam in schwarz",
link: "https://gopro.com/de/de/shop/hero7-black/tech-specs?pid=CHDHX-701-master",
name: "Go Pro Hero 9 black",
description: "Eine Go Pro Hero 9 Action Cam in schwarz",
link: "https://gopro.com/de/de/shop/cameras/hero9-black/CHDHX-901-master.html",
version: 0,
}, {
id: 4,
@@ -28,58 +31,64 @@ export default [{
image: require("../img/geschenke/AdventureKit_GoPro.png").default,
name: "Go Pro Zubehör",
description: "Go Pro Abenteuer Kit mit schwimmendem Handgriff, Kopfgurt, QuickClip und Tasche",
link: "https://gopro.com/de/de/shop/mounts-accessories/abenteuer-kit/AKTES-002.html",
link: "https://gopro.com/de/de/shop/mounts-accessories/adventure-kit/AKTES-002.html",
version: 0,
}, {
id: 5,
isBought: false,
image: require("../img/geschenke/Messerblock.png").default,
name: "Messerblock",
description: "ZWILLING Messerblock, 8-tlg., Bambusblock, 6 Messer und eine Schere aus rostfreiem Spezialstahl",
link: "https://www.amazon.de/Zwilling-32434-002-0-Bambus-Style-8-tlg/dp/B00AO2TRUI/",
description: "ZWILLING Selbstschärfender Messerblock, 7-tlg. In schwarz",
link: "https://www.otto.de/p/zwilling-messerblock-gourmet-selbstschaerfend-7-tlg-weiss-selbstschaerfend-scharfe-messer-eisgehaertete-klinge-C1197649235/#variationId=1197649236",
version: 0,
}, {
id: 6,
isBought: false,
image: require("../img/geschenke/Brettspiele.jpg").default,
name: "Brettspiele",
// description: "Wir freuen uns immer über ein neues, spannendes Brettspiel. Hier eine Liste von Spielen, die wir schon haben:<ul><li>Die Siedler inklusive Seefahrer Erweiterung</li><li>Dominion</li><li>Kingdom Builder</li><li>Keltis</li><li> Das verrückte Labyrinth</li><li> Trivial Pursuit</li><li> Dog</li><li> Outburst</li><li>eine Spielesammlung</li></ul>",
description: "Wir freuen uns immer über ein neues, spannendes Brettspiel. Falls ihr sichergehen wollt, welche Spiele wir schon haben, fragt doch unsere Trauzeugen Sinah oder Miriam.",
link: "",
version: 0,
}, {
id: 7,
isBought: false,
image: require("../img/geschenke/Zahnbürste.png").default,
name: "Elektrische Pärchenzahn-bürste",
description: "Nachhaltige elektrische Zahnbürste von happy brush, SCHALL VIBE 3 Partner Bundle",
link: "https://www.happybrush.de/starterkit-vibe-3-schall-zahnbuerste-bundle-mix/",
version: 0,
}, {
id: 8,
isBought: false,
image: require("../img/geschenke/Kappsäge.png").default,
name: "Kappsäge",
description: "Einhell Kapp-/Gehrungssäge TC-MS 2112 (1600 W, Sägeblatt Ø 210 mm, Schnittbreite 120 mm, schwenkbarer Sägekopf)",
link: "https://www.amazon.de/dp/B00DEXXFMK",
version: 0,
}, {
id: 9,
isBought: false,
image: require("../img/geschenke/Akkuschrauber.png").default,
name: "Akku-schrauber",
description: "LUX Akku-Bohrschrauber-Set inkl. Akku (wie im Link oder ähnlich)",
link: "https://www.obi.de/akkuschrauber/lux-akku-bohrschrauber-set-1-powersystem-a-bs-20/p/9543208",
version: 0,
}, {
id: 10,
isBought: false,
image: require("../img/geschenke/BodumBrotbox.jpg").default,
name: "Bodum Brotbox",
description: "Bodum bistroBrotkasten mit Bambus-Schneidebrett, 23.81 x 37.15 x 14.29 cm; 1.11 Kilogramm",
link: "https://www.amazon.de/Bodum-bistroBrotkasten-Bambus-Schneidebrett-BPA-freier-Kunststoff/dp/B00MAPNVCW/",
version: 0,
}, {
},
// {
// id: 6,
// isBought: false,
// image: require("../img/geschenke/Brettspiele.jpg").default,
// name: "Brettspiele",
// // description: "Wir freuen uns immer über ein neues, spannendes Brettspiel. Hier eine Liste von Spielen, die wir schon haben:<ul><li>Die Siedler inklusive Seefahrer Erweiterung</li><li>Dominion</li><li>Kingdom Builder</li><li>Keltis</li><li> Das verrückte Labyrinth</li><li> Trivial Pursuit</li><li> Dog</li><li> Outburst</li><li>eine Spielesammlung</li></ul>",
// description: "Wir freuen uns immer über ein neues, spannendes Brettspiel. Falls ihr sichergehen wollt, welche Spiele wir schon haben, fragt doch unsere Trauzeugen Sinah oder Miriam.",
// link: "",
// version: 0,
// },
// {
// id: 7,
// isBought: false,
// image: require("../img/geschenke/Zahnbürste.png").default,
// name: "Elektrische Pärchenzahn-bürste",
// description: "Nachhaltige elektrische Zahnbürste von happy brush, SCHALL VIBE 3 Partner Bundle",
// link: "https://www.happybrush.de/starterkit-vibe-3-schall-zahnbuerste-bundle-mix/",
// version: 0,
// },
// {
// id: 8,
// isBought: false,
// image: require("../img/geschenke/Kappsäge.png").default,
// name: "Kappsäge",
// description: "Einhell Kapp-/Gehrungssäge TC-MS 2112 (1600 W, Sägeblatt Ø 210 mm, Schnittbreite 120 mm, schwenkbarer Sägekopf)",
// link: "https://www.amazon.de/dp/B00DEXXFMK",
// version: 0,
// },
// {
// id: 9,
// isBought: false,
// image: require("../img/geschenke/Akkuschrauber.png").default,
// name: "Akku-schrauber",
// description: "LUX Akku-Bohrschrauber-Set inkl. Akku (wie im Link oder ähnlich)",
// link: "https://www.obi.de/akkuschrauber/lux-akku-bohrschrauber-set-1-powersystem-a-bs-20/p/9543208",
// version: 0,
// },
// {
// id: 10,
// isBought: false,
// image: require("../img/geschenke/BodumBrotbox.jpg").default,
// name: "Bodum Brotbox",
// description: "Bodum bistroBrotkasten mit Bambus-Schneidebrett, 23.81 x 37.15 x 14.29 cm; 1.11 Kilogramm",
// link: "https://www.amazon.de/Bodum-bistroBrotkasten-Bambus-Schneidebrett-BPA-freier-Kunststoff/dp/B00MAPNVCW/",
// version: 0,
// },
{
id: 11,
isBought: false,
image: require("../img/geschenke/großer_Topf.png").default,
@@ -105,53 +114,185 @@ export default [{
description: "MacArthur Studienbibel mit Schlachter 2000 Übersetzung",
link: "https://www.scm-shop.de/macarthur-studienbibel-schlachter-2000-7485697.html",
version: 0,
}, {
id: 14,
},
// {
// id: 14,
// isBought: false,
// image: require("../img/geschenke/nudelholz.png").default,
// name: "Nudelholz",
// description: "Eine Teigrolle aus Holz (wie im Link oder ähnlich)",
// link: "https://shop.oetker.at/dr-oetker-teigroller-holz",
// version: 0,
// },
// {
// id: 15,
// isBought: false,
// image: require("../img/geschenke/suppenkelle.png").default,
// name: "Suppenkelle mit Ausguss",
// description: "Eine Suppenkelle/ Schöpflöffel mit Ausguss",
// link: "https://www.fackelmann.de/fackelmann-ovalgriff-schoepfloeffel-29cm",
// version: 0,
// },
// {
// id: 16,
// isBought: false,
// image: require("../img/geschenke/pizzaschneider.png").default,
// name: "Pizzaschneider",
// description: "Ein Fahrrad Pizzaschneider",
// link: "https://www.amazon.de/s?k=Fahrrad+Pizzaschneider&i=kitchen&__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91",
// version: 0,
// },
// {
// id: 17,
// isBought: false,
// image: require("../img/geschenke/teekasten.png").default,
// name: "Teebox",
// description: "Eine Teebox mit genügend Platz für viele Teebeutel (wie im Link oder ähnlich)",
// link: "https://www.amazon.de/dp/B002P9JK4Q?tag=teebox-best-21",
// version: 0,
// },
// {
// id: 18,
// isBought: false,
// image: require("../img/geschenke/backblech.png").default,
// name: "Backblech mit Kuchenhaube",
// description: "Ein Backblech mit passender Kuchenhaube (wie im Link oder ähnlich)",
// link: "https://www.real.de/product/309417147/",
// version: 0,
// },
// {
// id: 19,
// isBought: false,
// image: require("../img/geschenke/zimmerpflanze.png").default,
// name: "Zimmerpflanze Strelitzia nicolai",
// description: "Strelitzie mit einer Höhe von 100 - 110 cm, Topf-Ø 24 cm, Paradiesvogelblume (wie im Link oder ähnlich)",
// link: "https://www.obi.de/weitere-gruenpflanzen/strelitzie-hoehe-100-110-cm-topf-24-cm-paradiesvogelblume-strelitzia-nicolai/p/9625096",
// version: 0,
// },
{
id: 20,
isBought: false,
image: require("../img/geschenke/nudelholz.png").default,
name: "Nudelholz",
description: "Eine Teigrolle aus Holz (wie im Link oder ähnlich)",
link: "https://shop.oetker.at/dr-oetker-teigroller-holz",
image: require("../img/geschenke/Bang.png").default,
name: "Bang! The Bullet",
description: "Das Bang! Grundspiel mit Erweiterungen",
link: "https://www.thalia.de/shop/home/artikeldetails/A1017416573",
version: 0,
}, {
id: 15,
},
{
id: 21,
isBought: false,
image: require("../img/geschenke/suppenkelle.png").default,
name: "Suppenkelle mit Ausguss",
description: "Eine Suppenkelle/ Schöpflöffel mit Ausguss",
link: "https://www.fackelmann.de/fackelmann-ovalgriff-schoepfloeffel-29cm",
image: require("../img/geschenke/Codenames.png").default,
name: "Codenames XXL",
description: "Condenames XXL mit extra großen Bildkarten",
link: "https://www.thalia.de/shop/home/artikeldetails/A1052674361",
version: 0,
}, {
id: 16,
},
{
id: 23,
isBought: false,
image: require("../img/geschenke/pizzaschneider.png").default,
name: "Pizzaschneider",
description: "Ein Fahrrad Pizzaschneider",
link: "https://www.amazon.de/s?k=Fahrrad+Pizzaschneider&i=kitchen&__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91",
image: require("../img/geschenke/Staubsaugerroboter.png").default,
name: "Staubsaugerroboter mit Wischfunktion",
description: "Staubsaugerroboter Roborock S5 Max mit Wischfunktion in schwarz",
link: "https://www.idealo.de/preisvergleich/OffersOfProduct/200074714_-s5-max-schwarz-roborock.html",
version: 0,
}, {
id: 17,
},
{
id: 24,
isBought: false,
image: require("../img/geschenke/teekasten.png").default,
name: "Teebox",
description: "Eine Teebox mit genügend Platz für viele Teebeutel (wie im Link oder ähnlich)",
link: "https://www.amazon.de/dp/B002P9JK4Q?tag=teebox-best-21",
image: require("../img/geschenke/Weltkarte.jpg").default,
name: "Weltkarte",
description: "Weltkarte als Poster (197 x 116,5 cm)",
link: "https://www.amazon.de/Weltkarte-Klassische-Vorderseite-laminiert-118/dp/B014FW44H8/ref=sr_1_14?keywords=weltkarte%2Bposter&qid=1642886702&sr=8-14&th=1",
version: 0,
}, {
id: 18,
},
{
id: 25,
isBought: false,
image: require("../img/geschenke/backblech.png").default,
name: "Backblech mit Kuchenhaube",
description: "Ein Backblech mit passender Kuchenhaube (wie im Link oder ähnlich)",
link: "https://www.real.de/product/309417147/",
image: require("../img/geschenke/Korkplatte.png").default,
name: "4 Korkplatten für die Weltkarte",
description: "Vier Korkplatten 60x 100 cm, als Unterlage zur Weltkarte",
link: "https://www.amazon.de/Schadstofffrei-Antistatisch-Bastel-Unterlage-Trittschalld%C3%A4mmung-Wandverkleidung/dp/B079ND27TG/ref=pb_allspark_purchase_sims_desktop_2/258-0765775-0428551",
version: 0,
}, {
id: 19,
},
{
id: 26,
isBought: false,
image: require("../img/geschenke/zimmerpflanze.png").default,
name: "Zimmerpflanze Strelitzia nicolai",
description: "Strelitzie mit einer Höhe von 100 - 110 cm, Topf-Ø 24 cm, Paradiesvogelblume (wie im Link oder ähnlich)",
link: "https://www.obi.de/weitere-gruenpflanzen/strelitzie-hoehe-100-110-cm-topf-24-cm-paradiesvogelblume-strelitzia-nicolai/p/9625096",
image: require("../img/geschenke/Sitzkissen.png").default,
name: "4 Sitzkissen",
description: "4 Sitzkissen für unsere Wohnzimmerstühle",
link: "https://jysk.de/wohnaccessoires/sitzkissen/sitzkissen-kejserlind-o34-lammfell-weiss",
version: 0,
},
{
id: 27,
isBought: false,
image: require("../img/geschenke/Stoffservietten.png").default,
name: "12 Stoffservieten",
description: "12 weiße Stoffservietten aus 100% Bio-Baumwolle",
link: "https://www.bewusstgruen.de/12-stoffservietten-aus-100-bio-baumwolle/",
version: 0,
},
{
id: 28,
isBought: false,
image: require("../img/geschenke/Nudelzange.png").default,
name: "WMF Nudelzange",
description: "Nudelzange von WMF",
link: "https://www.wmf.com/de/nudelzange-bistro.html",
version: 0,
},
{
id: 29,
isBought: false,
image: require("../img/geschenke/Eisportionierer.png").default,
name: "Eisportionierer",
description: "Eisportionierer mit Kugel-Auswurf Funktion (wie im Link oder ähnlich)",
link: "https://www.fackelmann.de/fackelmann-eisportionierer-mit-kugel-auswurf-funktion-oe5cm",
version: 0,
},
{
id: 30,
isBought: false,
image: require("../img/geschenke/Gießkanne.png").default,
name: "Blechgießkanne",
description: "Eine Blechgießkann mit max. 2l Füllvolumen zum Blumengießen in der Wohnung",
link: "https://www.bauhaus.info/giesskannen/zimmergiesskanne/p/16640093",
version: 0,
},
{
id: 31,
isBought: false,
image: require("../img/geschenke/Saftpresse.png").default,
name: "Saftpresse Thermomix",
description: "Saftpressen-Aufsatz für den Thermomix",
link: "https://www.wundermix.de/thermomix-zubehoer/zubereiten-aufbewahren/1372/saftpresse-fuer-thermomix-tm6/tm5?",
version: 0,
},
{
id: 32,
isBought: false,
image: require("../img/geschenke/Buch.jpeg").default,
name: "Buch „Du+Ich in Ewigkeit“",
description: "Buch „Du + Ich in Ewigkeit“",
link: "https://www.thalia.de/shop/home/artikeldetails/A1038260264",
version: 0,
},
{
id: 33,
isBought: false,
image: require("../img/geschenke/Backpapier.png").default,
name: "Mehrfachverwendbares Backpapier",
description: "Spülmaschinenfestes, mehrfachverwendbares Backpapier",
link: "https://www.amazon.de/Pritogo-Dauerbackfolie-Backunterlage-sp%C3%BClmaschinenfest-antihaftbeschichtet/dp/B07GNVHQKQ/ref=pd_sbs_3/259-2377249-7131115",
version: 0,
},
{
id: 34,
isBought: false,
image: require("../img/geschenke/Bienenwachstuch.jpeg").default,
name: "Großes Bienenwachstuch",
description: "Ein großes Bienenwachstuch (mind. 50x40cm) zum Abdecken unserer Auflaufform (Link als Beispiel)",
link: "https://pachamama-laden.de/de/item/wildwax-xl-50x40cm-bienenwachstucher-versch-designs",
version: 0,
},
]

View File

@@ -0,0 +1,7 @@
import React from "react";
import ReactDOM from "react-dom";
import {ImageGallery} from "./ImageGallery/ImageGallery";
export function setupImageGallery(){
ReactDOM.render(<ImageGallery/>, document.getElementById("gallery"));
}

View File

@@ -58,4 +58,11 @@
.present-name {
font-weight: bold;
}
}
.present-info{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
}

View File

@@ -0,0 +1,3 @@
#gallery img {
height: initial;
}

View File

@@ -3,6 +3,51 @@
$opacityVisible: 0.7;
$states: godi fingerfood foto sekt essen spiel dance;
$positions: (
godi: (
top: 9.5%,
left: 47%,
width: initial,
height: 12%
),
fingerfood: (
left: 2%,
top: 20%,
width: 41%,
height: 20%,
),
foto: (
left: 54%,
top: 36%,
width: 33%,
height: 12%
),
sekt: (
left: 7%,
top: 50%,
width: 35%,
height: 12%
),
essen: (
left: 54%,
top: 62.5%,
width: 33%,
height: 12%
),
spiel: (
left: 4%,
top: 74.5%,
width: 37%,
height: 12%
),
dance: (
left: 54%,
top: 86%,
width: 35%,
height: 12%
)
);
#info-image-container {
position: relative;
@@ -13,61 +58,74 @@ $states: godi fingerfood foto sekt essen spiel dance;
}
img.circler {
transition: all 0.2s;
position: absolute;
height: 12%;
opacity: 0;
cursor: pointer;
&.visible {
opacity: 1;
}
//left: 0;
&.godi {
top: 1.5%;
left: 51%;
top: 9.5%;
left: 47%;
}
&.fingerfood {
left: 5%;
top: 12.5%;
width: 38%;
left: 2%;
top: 20%;
width: 41%;
height: 20%;
}
&.foto {
left: 55%;
top: 32%;
left: 54%;
top: 36%;
width: 33%;
}
&.sekt {
left: 7%;
top: 46.5%;
top: 50%;
width: 35%;
}
&.essen {
left: 55%;
top: 60%;
width: 32%;
left: 54%;
top: 62.5%;
width: 33%;
}
&.spiel {
left: 8%;
top: 72.5%;
width: 34%;
left: 4%;
top: 74.5%;
width: 37%;
}
&.dance {
left: 55%;
left: 54%;
top: 86%;
width: 32%;
width: 35%;
}
}
@each $state in $states {
&[data-state='#{$state}'] .#{$state} {
opacity: $opacityVisible;
$data: map-get($positions, $state);
&[data-state='#{$state}'] .circler.visible {
//opacity: $opacityVisible;
top: map-get($data, "top");
left: map-get($data, "left");
width: map-get($data, "width");
height: map-get($data, "height");
}
}
}
.anchor {
@@ -86,7 +144,8 @@ $states: godi fingerfood foto sekt essen spiel dance;
&.show-in-dialog {
position: fixed;
}
&:last-child{
&:last-child {
height: calc(100vh - 8rem - 1px);
@include breakpoint(medium down) {
height: calc(100vh - 7rem - 1px);
@@ -121,4 +180,4 @@ $states: godi fingerfood foto sekt essen spiel dance;
height: initial;
}
}
}
}

View File

@@ -1,4 +1,4 @@
@import "../../../node_modules/foundation-sites/scss/foundation";
@import "node_modules/foundation-sites/scss/foundation";
@import "settings";
@@ -9,6 +9,7 @@
@import "unterkunft";
@import "geschenke";
@import "tagesablauf";
@import "standesamt";
@font-face {
font-family: "WinterSunrise";
@@ -184,4 +185,4 @@ img.full-screen-width {
&::-webkit-scrollbar{
display: none;
}
}
}