commit d52db343dbe68fcefda9b8b4e8837de65a5ec9a1 Author: Jannik Menzel Date: Sat Feb 1 13:10:04 2025 +0100 Initial commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/iFSR-Sharepicgenerator.iml b/.idea/iFSR-Sharepicgenerator.iml new file mode 100644 index 0000000..9a5cfce --- /dev/null +++ b/.idea/iFSR-Sharepicgenerator.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..639900d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9792f93 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/assets/favicon.svg b/assets/favicon.svg new file mode 100644 index 0000000..e4fa5bc --- /dev/null +++ b/assets/favicon.svg @@ -0,0 +1,16 @@ + + + + LogoStandard + Created with Sketch. + + + + + + + + + + + diff --git a/assets/icons/discord.svg b/assets/icons/discord.svg new file mode 100644 index 0000000..d675e69 --- /dev/null +++ b/assets/icons/discord.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/assets/icons/github.svg b/assets/icons/github.svg new file mode 100644 index 0000000..3548561 --- /dev/null +++ b/assets/icons/github.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/assets/icons/icon.png b/assets/icons/icon.png new file mode 100644 index 0000000..94aebdb Binary files /dev/null and b/assets/icons/icon.png differ diff --git a/assets/icons/instagram.svg b/assets/icons/instagram.svg new file mode 100644 index 0000000..b7b9792 --- /dev/null +++ b/assets/icons/instagram.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/icons/mastodon.svg b/assets/icons/mastodon.svg new file mode 100644 index 0000000..fa33f74 --- /dev/null +++ b/assets/icons/mastodon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/assets/icons/telegram.svg b/assets/icons/telegram.svg new file mode 100644 index 0000000..b892f17 --- /dev/null +++ b/assets/icons/telegram.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/defaultBackground.jpg b/assets/images/defaultBackground.jpg new file mode 100644 index 0000000..d433b78 Binary files /dev/null and b/assets/images/defaultBackground.jpg differ diff --git a/assets/images/defaultLogo.svg b/assets/images/defaultLogo.svg new file mode 100644 index 0000000..a7cc113 --- /dev/null +++ b/assets/images/defaultLogo.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..9bcc6c5 --- /dev/null +++ b/css/styles.css @@ -0,0 +1,246 @@ +/* ======================== + Allgemeines Styling + ======================== */ +html { + background-color: #212528; +} + +body { + display: flex; + flex-direction: column; + font-family: Arial, sans-serif; + color: #333; + background-color: #fefefe; + min-height: 100vh; + margin: 0; + font-size: 1rem; + line-height: 1.6; +} + +/* ======================== + Navigation + ======================== */ +.navbar { + padding: 1rem; + background-color: #354f52; + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; +} + +.navbar img { + height: 40px; + max-width: 100%; + object-fit: contain; +} + +/* ======================== + Hero Section + ======================== */ +.hero-section { + position: relative; + height: 60vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + color: #333; + padding: 0 20px; + background-color: #f8f9fa; + overflow: hidden; +} + +.hero-section h1 { + font-family: 'Montserrat', sans-serif; + font-weight: 600; + font-size: 4rem; + margin: 0; + color: #333; +} + +.hero-section p { + font-family: 'Montserrat', sans-serif; + font-weight: 200; + font-size: 1.4rem; + margin-top: 5px; + color: #333; +} + +/* ======================== + Generator Section + ======================== */ +.form { + display: flex; + flex-direction: column; + gap: 20px; + padding: 20px; + background-color: #fff; + border-radius: 8px; + margin: auto; + width: 100%; + max-width: 500px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); +} + +label { + font-size: 16px; + color: #333; + font-weight: 600; +} + +textarea, input[type="file"], input[type="range"], input[type="checkbox"] { + padding: 12px 16px; + font-size: 16px; + border: 1px solid #ddd; + border-radius: 6px; + background-color: #f9f9f9; + width: 100%; + box-sizing: border-box; + margin-bottom: 15px; +} + +textarea { + resize: vertical; + min-height: 100px; +} + +input[type="range"] { + -webkit-appearance: none; + height: 6px; + border-radius: 4px; +} + +input[type="range"]:focus { + outline: none; + background: #ccc; +} + +.checkbox-container { + display: flex; + align-items: center; + gap: 10px; +} + +input[type="checkbox"] { + width: 20px; + height: 20px; + cursor: pointer; +} + +.container-generator { + display: flex; + gap: 30px; + justify-content: space-between; + flex-wrap: wrap; +} + +.preview { + flex: 1; + display: flex; + align-items: center; + padding: 20px; + background-color: #fff; + border-radius: 8px; + min-height: 500px; +} + +#canvas { + max-width: 100%; + max-height: 100%; + border: 1px solid #ddd; + border-radius: 8px; +} + +/* ======================== + Button Styling + ======================== */ +button { + padding: 12px 20px; + font-size: 16px; + font-weight: bold; + border: none; + border-radius: 6px; + background-color: #6a994e99; + color: #fff; + cursor: pointer; + transition: background-color 0.3s ease, transform 0.2s ease; + outline: none; +} + +button:hover { + background-color: #6a994ecc; + transform: translateY(-2px); +} + +button:active { + transform: translateY(0); +} + +button:disabled { + background-color: #c6c6c6; + cursor: not-allowed; +} + +/* ======================== + Footer + ======================== */ +footer { + background-color: #2f3e46; + color: #bbb; + text-align: center; + padding: 20px; + margin-top: auto; + font-size: 0.9rem; +} + +/* ======================== + Responsives Design + ======================== */ +@media (max-width: 1200px) { + .hero-section h1 { + font-size: 3.7rem; + } + + .hero-section p { + font-size: 1.3rem; + } + + .container-generator { + flex-direction: column; + } + + .preview { + order: -1; + min-height: 400px; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + max-width: 800px; + margin: 0 auto; + } + + #canvas { + width: 100%; + height: auto; + max-width: 100%; + object-fit: contain; + transition: width 0.3s ease-in-out, height 0.3s ease-in-out; + } +} + +@media (max-width: 700px) { + .hero-section { + padding: 30px 0; + } + + .hero-section h1 { + font-size: 2.5rem; + } + + .hero-section p { + font-size: 1.0rem; + } +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..df74762 --- /dev/null +++ b/index.html @@ -0,0 +1,109 @@ + + + + + + iFSR Sharepicgenerator + + + + + + + + + + + +
+
+

iFSR Sharepicgenerator

+

Der Sharepicgenerator des FSR Informatik.

+ + + +
+
+ + +
+
+ +
+ +
+ + +
+
+ + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + + +
+
+
+
+ + +
+
+

Hinweis

+

Für das Hochladen von Bildern und Logos gilt, dass ausschließlich Material hochgeladen werden darf, für das du die entsprechenden Rechte besitzt. Falls du keine eigenen Bilder oder Logos verwenden möchtest, kannst du auf Plattformen wie Unsplash, Pexels und Pixabay zurückgreifen, die lizenzfreie oder copyrightfreie Fotos anbieten.

+
+
+ + + + + + + + \ No newline at end of file diff --git a/js/script.js b/js/script.js new file mode 100644 index 0000000..e5dcff8 --- /dev/null +++ b/js/script.js @@ -0,0 +1,215 @@ +// Variablen für hochgeladene Bilder und deren Position +let uploadedImage = null; +let uploadedLogo = null; +let imageOffsetX = 0; +let imageOffsetY = 0; +let isDragging = false; +let dragStartX = 0; +let dragStartY = 0; + +// Standardwerte für Bild, Logo und Texte +const defaultImage = 'assets/images/defaultBackground.jpg'; +const defaultLogo = 'assets/images/defaultLogo.svg'; +const defaultHeadline = 'iFSR sharepic Headline'; +const defaultSubline = 'Hier könnte ein unfassbar fesselnder Werbetext des Fachschaftsrats Informatik stehen.'; + +// Initialisierung beim Laden der Seite +window.onload = function () { + document.getElementById('headline').value = defaultHeadline; + document.getElementById('subline').value = defaultSubline; + + loadDefaultImage(); + loadDefaultLogo(); + generateSharepic(); +}; + +// Lädt das Standardhintergrundbild +function loadDefaultImage() { + uploadedImage = new Image(); + uploadedImage.onload = drawCanvas; + uploadedImage.src = defaultImage; +} + +// Lädt das Standardlogo +function loadDefaultLogo() { + uploadedLogo = new Image(); + uploadedLogo.onload = drawCanvas; + uploadedLogo.src = defaultLogo; +} + +// Event-Listener für Datei-Uploads und Eingaben +document.getElementById('imageUpload').addEventListener('change', handleImageUpload); +document.getElementById('logoUpload').addEventListener('change', handleLogoUpload); +document.getElementById('headline').addEventListener('input', generateSharepic); +document.getElementById('subline').addEventListener('input', generateSharepic); +document.getElementById('fontSize').addEventListener('input', generateSharepic); +document.getElementById('boxHeight').addEventListener('input', generateSharepic); +document.getElementById('logoSize').addEventListener('input', generateSharepic); +document.getElementById('logoLeft').addEventListener('change', generateSharepic); + +// Verarbeitet den Upload eines neuen Hintergrundbildes +function handleImageUpload(event) { + const file = event.target.files[0]; + if (file) { + const imageUrl = URL.createObjectURL(file); + uploadedImage = new Image(); + uploadedImage.onload = function () { + imageOffsetX = 0; + imageOffsetY = 0; + drawCanvas(); + }; + uploadedImage.src = imageUrl; + } +} + +// Verarbeitet den Upload eines neuen Logos +function handleLogoUpload(event) { + const file = event.target.files[0]; + if (file) { + const logoUrl = URL.createObjectURL(file); + uploadedLogo = new Image(); + uploadedLogo.onload = drawCanvas; + uploadedLogo.src = logoUrl; + } +} + +// Generiert das Sharepic neu +function generateSharepic() { + drawCanvas(); +} + +// Berechnet die Bildgröße passend zur Canvas-Größe +function calculateImageDimensions(image, canvas) { + let imageWidth, imageHeight; + + if (image.width > image.height) { + imageHeight = canvas.height; + imageWidth = image.width * (imageHeight / image.height); + } else { + imageWidth = canvas.width; + imageHeight = image.height * (imageWidth / image.width); + } + + return { width: imageWidth, height: imageHeight }; +} + +// Zeichnet das Canvas mit Bild, Logo und Text +function drawCanvas() { + const canvas = document.getElementById('canvas'); + const ctx = canvas.getContext('2d'); + + canvas.width = 1080; + canvas.height = 1080; + + // Zeichnet das hochgeladene Hintergrundbild + if (uploadedImage) { + const { width, height } = calculateImageDimensions(uploadedImage, canvas); + ctx.drawImage(uploadedImage, imageOffsetX, imageOffsetY, width, height); + } + + // Zeichnet das weiße Textfeld + const boxHeight = parseInt(document.getElementById('boxHeight').value); + const boxPadding = 20; + ctx.fillStyle = 'white'; + ctx.fillRect(boxPadding, canvas.height - boxHeight - boxPadding, canvas.width - 2 * boxPadding, boxHeight); + + // Holt die Texteingaben + const headline = document.getElementById('headline').value; + const subline = document.getElementById('subline').value; + const fontSize = parseInt(document.getElementById('fontSize').value); + + // Setzt Schriftfarbe + ctx.fillStyle = 'black'; + + const headlineFont = `bold ${fontSize * 1.2}px 'Cairo', sans-serif`; + const sublineFont = `${fontSize}px 'Cairo', sans-serif`; + const maxWidth = canvas.width - 2 * boxPadding - 40; + + // Funktion zum Umbruch langer Texte + function wrapText(ctx, text, x, y, maxWidth, font) { + ctx.font = font; + const lineHeight = parseInt(font.match(/\d+/)[0]) * 1.2; + + const words = text.split(' '); + let line = ''; + let lines = []; + + for (let n = 0; n < words.length; n++) { + let testLine = line + words[n] + ' '; + let testWidth = ctx.measureText(testLine).width; + + if (testWidth > maxWidth && n > 0) { + lines.push(line); + line = words[n] + ' '; + } else { + line = testLine; + } + } + lines.push(line); + + lines.forEach((line, i) => ctx.fillText(line, x, y + i * lineHeight)); + } + + // Zeichnet Headline und Subline ins Canvas + wrapText(ctx, headline, boxPadding + 20, canvas.height - boxHeight - boxPadding + 80, maxWidth, headlineFont); + wrapText(ctx, subline, boxPadding + 20, canvas.height - boxHeight - boxPadding + 150, maxWidth, sublineFont); + + // Zeichnet das Logo + if (uploadedLogo) { + const logoSize = parseInt(document.getElementById('logoSize').value); + const logoRatio = uploadedLogo.width / uploadedLogo.height; + let logoWidth = logoSize * logoRatio; + let logoHeight = logoSize; + + if (logoWidth > canvas.width - 40) { + logoWidth = canvas.width - 40; + logoHeight = logoWidth / logoRatio; + } + + const logoLeft = document.getElementById('logoLeft').checked; + const logoX = logoLeft ? 20 : canvas.width - logoWidth - 20; + + ctx.drawImage(uploadedLogo, logoX, 20, logoWidth, logoHeight); + } +} + +// Bild-Drag-Funktionalität +const canvas = document.getElementById('canvas'); +canvas.addEventListener('mousedown', function (e) { + if (uploadedImage) { + isDragging = true; + dragStartX = e.offsetX - imageOffsetX; + dragStartY = e.offsetY - imageOffsetY; + } +}); + +canvas.addEventListener('mousemove', function (e) { + if (isDragging && uploadedImage) { + const { width, height } = calculateImageDimensions(uploadedImage, canvas); + + if (uploadedImage.width > uploadedImage.height) { + imageOffsetX = e.offsetX - dragStartX; + imageOffsetX = Math.min(0, Math.max(imageOffsetX, canvas.width - width)); + } else { + imageOffsetY = e.offsetY - dragStartY; + imageOffsetY = Math.min(0, Math.max(imageOffsetY, canvas.height - height)); + } + drawCanvas(); + } +}); + +canvas.addEventListener('mouseup', () => isDragging = false); +canvas.addEventListener('mouseout', () => isDragging = false); + +// Download-Button für das Sharepic +document.getElementById('downloadBtn').addEventListener('click', function (event) { + event.preventDefault(); + + const dataUrl = canvas.toDataURL('image/png'); + const a = document.createElement('a'); + a.href = dataUrl; + a.download = 'sharepic.png'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); +}); \ No newline at end of file