diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..987e834 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,44 @@ +kind: pipeline +type: docker +name: default + +steps: + - name: build + image: node + commands: + - npm install + - npm run build + - name: deploy-dev + image: alpine + environment: + FTP_HOST: + from_secret: FTP_HOST + FTP_USERNAME: + from_secret: FTP_USERNAME + FTP_PASSWORD: + from_secret: FTP_PASSWORD + commands: + - which lftp || ( apk --update add lftp ) + - lftp -e "set ftp:ssl-force true; set ssl:verify-certificate no; mirror -R ./dist/ dev.sp-codes.de/; bye" -u $FTP_USERNAME,$FTP_PASSWORD $FTP_HOST + when: + branch: + - develop + event: + - push + - name: deploy + image: alpine + environment: + FTP_HOST: + from_secret: FTP_HOST + FTP_USERNAME: + from_secret: FTP_USERNAME + FTP_PASSWORD: + from_secret: FTP_PASSWORD + commands: + - which lftp || ( apk --update add lftp ) + - lftp -e "set ftp:ssl-force true; set ssl:verify-certificate no; mirror -R ./dist/ sp-codes.de/; bye" -u $FTP_USERNAME,$FTP_PASSWORD $FTP_HOST + when: + branch: + - main + event: + - push diff --git a/.eleventy.js b/.eleventy.js index 2287334..9a02e4b 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -1,84 +1,22 @@ -const pluginRev = require("eleventy-plugin-rev"); -const pluginSass = require("eleventy-sass"); -const pluginTinyHtml = require("@sardine/eleventy-plugin-tinyhtml"); -const pluginNavigation = require("@11ty/eleventy-navigation"); +const eleventyNavigationPlugin = require("@11ty/eleventy-navigation"); -module.exports = function (eleventyConfig) { - eleventyConfig.addPlugin(pluginRev); - eleventyConfig.addPlugin(pluginTinyHtml); - eleventyConfig.addPlugin(pluginSass, { - sass: { - loadPaths: ["node_modules"], - style: "compressed", - sourceMap: false, - }, - compileOptions: { - permalink: function (contents, inputPath) { - return (data) => { - return data.page.filePathStem.replace(/^\/scss\//, "/css/") + ".css"; - }; - } - }, - rev: true - }); - eleventyConfig.addPlugin(pluginNavigation); +module.exports = function(eleventyConfig) { + eleventyConfig.addWatchTarget("./src/scss/"); + eleventyConfig.addPlugin(eleventyNavigationPlugin); eleventyConfig.setUseGitIgnore(false); eleventyConfig.addPassthroughCopy({ "src/img": "img", "src/font": "font", - "src/favicon.*": "", - }); - eleventyConfig.addShortcode("translatedUrl", function (currentLocale, newLocale) { - return this.page.url.replace(new RegExp(`\/${currentLocale}\/`), `/${newLocale}/`); - }); - - eleventyConfig.addFilter('year', function (value) { - return value * 12; - }); - - eleventyConfig.addFilter("sum", function (value) { - return value.map(d => d.amount).reduce((a, b) => a + b, 0); - }); - - eleventyConfig.addFilter("amount", function (value) { - // TODO update language dynamically - return value.toLocaleString('de', {minimumFractionDigits: 2}); - }); - - eleventyConfig.addFilter("banktransfers", function (donations) { - return donations - .flatMap(y => y.donations) - .filter(d => d.via === 'banktransfer') - .filter(d => d.first) - .length; - }); - - eleventyConfig.addFilter("cash", function (donations) { - return donations - .flatMap(y => y.donations) - .filter(d => d.via === 'cash') - .filter(d => d.first) - .length; - }); - - eleventyConfig.addFilter('getServiceById', (services, serviceId) => { - return services.find(s => s.id === serviceId); + "node_modules/@fortawesome/fontawesome-free/webfonts/": "font", + "node_modules/flag-icon-css/flags/4x3/(de|us)*": "flags" }); return { - // Pre-process *.md files with: (default: `liquid`) - markdownTemplateEngine: "njk", - // Pre-process *.html files with: (default: `liquid`) - htmlTemplateEngine: "njk", - // Opt-out of pre-processing global data JSON files: (default: `liquid`) - dataTemplateEngine: false, - dir: { input: "src", includes: "_includes", layouts: "_includes/layouts", - data: "_data", output: "dist" } }; diff --git a/.forgejo/workflows/build-deploy.yml b/.forgejo/workflows/build-deploy.yml deleted file mode 100644 index b153732..0000000 --- a/.forgejo/workflows/build-deploy.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Build and Deploy Website - -on: [push] - -jobs: - build: - name: Build Website - runs-on: docker - container: - image: node:lts - steps: - - uses: actions/checkout@v3 - - name: Install Dependencies - run: npm install - - name: Build Website - run: npm run build - - uses: actions/upload-artifact@v3 - with: - name: build - path: dist/ - deploy-dev: - name: Deploy Dev Website - runs-on: docker - container: - image: node:lts-alpine - needs: [build] - if: github.ref == 'refs/heads/develop' - steps: - - uses: actions/download-artifact@v3 - - name: Install Dependencies - run: which lftp || ( apk --update add lftp ) - - name: Deploy Website - run: lftp -e "set ftp:ssl-force true; set ssl:verify-certificate no; mirror -R ./build/ dev.sp-codes.de/; bye" -u $FTP_USERNAME,$FTP_PASSWORD $FTP_HOST - env: - FTP_HOST: ${{ secrets.FTP_HOST }} - FTP_USERNAME: ${{ secrets.FTP_USERNAME }} - FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }} - deploy: - name: Deploy Website - runs-on: docker - container: - image: node:lts-alpine - needs: [build] - if: github.ref == 'refs/heads/main' - steps: - - uses: actions/download-artifact@v3 - - name: Install Dependencies - run: which lftp || ( apk --update add lftp ) - - name: Deploy Website - run: lftp -e "set ftp:ssl-force true; set ssl:verify-certificate no; mirror -R ./build/ sp-codes.de/; bye" -u $FTP_USERNAME,$FTP_PASSWORD $FTP_HOST - env: - FTP_HOST: ${{ secrets.FTP_HOST }} - FTP_USERNAME: ${{ secrets.FTP_USERNAME }} - FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }} diff --git a/README.md b/README.md index d8ff99d..7eed4db 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # sp-codes.de -[](https://ci.sp-codes.de/samuel-p/sp-codes.de) +[](https://ci.sp-codes.de/samuel-p/sp-codes.de) Website for [sp-codes.de](https://sp-codes.de) @@ -9,7 +9,7 @@ Website for [sp-codes.de](https://sp-codes.de) The following Parameters are set directly on the Web-Server. ``` -Content-Security-Policy: default-src 'none'; script-src 'self' https://umami.sp-codes.de; object-src 'none'; style-src 'self'; img-src 'self' https://status.sp-codes.de https://shields.sp-codes.de; media-src 'none'; frame-src 'none'; font-src 'self'; connect-src 'self' https://umami.sp-codes.de +Content-Security-Policy: default-src 'none'; script-src 'self' https://plausible.sp-codes.de; object-src 'none'; style-src 'self'; img-src 'self' https://shields.sp-codes.de; media-src 'none'; frame-src 'none'; font-src 'self'; connect-src 'self' https://plausible.sp-codes.de Referrer-Policy: strict-origin-when-cross-origin Feature-Policy: sync-xhr 'self' Strict-Transport-Security: max-age=31536000; includeSubDomains; preload diff --git a/package.json b/package.json index 0b9272e..0780854 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,11 @@ "version": "1.0.0", "description": "website for sp-codes.de", "scripts": { - "minify-css": "uncss -n -H dist/ -o dist/css/main-*.css dist/**/*.html dist/**/**/*.html dist/**/**/**/*.html dist/**/**/**/**/*.html dist/**/**/**/**/**/*.html", - "start": "eleventy --serve --watch", - "build": "eleventy && npm run move-index && npm run minify-css", + "compile-sass": "node-sass --output-style compressed --importer=node_modules/node-sass-tilde-importer src/scss/main.scss dist/css/main.css", + "watch:eleventy": "eleventy --serve", + "watch:sass": "npm run compile-sass -- --watch", + "start": "npm-run-all compile-sass --parallel watch:*", + "build": "npm run compile-sass && eleventy && npm run move-index", "move-index": "cpx dist/de/index.html dist/" }, "author": "samuel-p", @@ -14,25 +16,19 @@ "url": "https://git.sp-codes.de/samuel-p/sp-codes.de" }, "optionalDependencies": { - "browser-sync": "^2.29.3" + "browser-sync": "^2.26.14" }, "devDependencies": { - "@11ty/eleventy": "^2.0.1", - "@11ty/eleventy-navigation": "^0.3.5", - "@node-minify/core": "^8.0.6", - "@node-minify/crass": "^8.0.6", - "@node-minify/html-minifier": "^8.0.6", - "@sardine/eleventy-plugin-tinyhtml": "^0.2.0", + "@11ty/eleventy": "^0.12.1", + "@11ty/eleventy-navigation": "^0.1.6", "cpx": "^1.5.0", - "eleventy-plugin-rev": "^2.0.0", - "eleventy-sass": "^2.2.4", - "glob": "^10.3.10", - "minify": "^10.5.2", - "postcss": "^8.4.32", - "sass": "^1.69.5", - "uncss": "^0.17.3" + "node-sass": "^5.0.0", + "node-sass-tilde-importer": "^1.0.2", + "npm-run-all": "^4.1.5" }, "dependencies": { - "bootstrap": "^5.3.2" + "@fortawesome/fontawesome-free": "^5.15.3", + "bootstrap": "^4.6.0", + "flag-icon-css": "^3.5.0" } } diff --git a/src/_data/donations.json b/src/_data/donations.json index 30cff4e..87a2ddf 100644 --- a/src/_data/donations.json +++ b/src/_data/donations.json @@ -1,281 +1,10 @@ -[ - { - "year": 2023, - "donations": [ - { - "date": "16.11.2023", - "amount": 25, - "via": "banktransfer", - "from": null, - "first": false - }, - { - "date": "26.10.2023", - "amount": 20, - "via": "banktransfer", - "from": "ub1x", - "first": false - }, - { - "date": "26.10.2023", - "amount": 20, - "via": "banktransfer", - "from": "ub1x", - "first": false - }, - { - "date": "17.07.2023", - "amount": 20, - "via": "banktransfer", - "from": "ub1x", - "first": false - }, - { - "date": "27.02.2023", - "amount": 40, - "via": "banktransfer", - "from": "xhoff637", - "first": true - }, - { - "date": "20.02.2023", - "amount": 50, - "via": "banktransfer", - "from": null, - "first": false - }, - { - "date": "16.01.2023", - "amount": 12, - "via": "banktransfer", - "from": null, - "first": true - } - ] +{ + "banktransfer": { + "number": 3, + "color": "success" }, - { - "year": 2022, - "donations": [ - { - "date": "15.12.2022", - "amount": 20, - "via": "banktransfer", - "from": "ub1x", - "first": false - }, - { - "date": "16.11.2022", - "amount": 25, - "via": "banktransfer", - "from": null, - "first": false - }, - { - "date": "02.11.2022", - "amount": 30, - "via": "banktransfer", - "from": null, - "first": false - }, - { - "date": "11.08.2022", - "amount": 10, - "via": "banktransfer", - "from": "TeomaHK", - "first": false - }, - { - "date": "11.07.2022", - "amount": 10, - "via": "banktransfer", - "from": "TeomaHK", - "first": false - }, - { - "date": "03.06.2022", - "amount": 10, - "via": "banktransfer", - "from": "TeomaHK", - "first": false - }, - { - "date": "11.05.2022", - "amount": 20, - "via": "banktransfer", - "from": "ub1x", - "first": true - }, - { - "date": "03.05.2022", - "amount": 10, - "via": "banktransfer", - "from": "TeomaHK", - "first": false - }, - { - "date": "04.04.2022", - "amount": 10, - "via": "banktransfer", - "from": "TeomaHK", - "first": false - }, - { - "date": "15.03.2022", - "amount": 1, - "via": "banktransfer", - "from": "Jonathan Klatt", - "first": false - }, - { - "date": "10.03.2022", - "amount": 1.42, - "via": "banktransfer", - "from": "Jonathan Klatt", - "first": false - }, - { - "date": "03.03.2022", - "amount": 10, - "via": "banktransfer", - "from": "TeomaHK", - "first": false - }, - { - "date": "14.02.2022", - "amount": 10, - "via": "banktransfer", - "from": "TeomaHK", - "first": false - }, - { - "date": "17.01.2022", - "amount": 1, - "via": "banktransfer", - "from": "Jonathan Klatt", - "first": true - }, - { - "date": "03.01.2022", - "amount": 10, - "via": "banktransfer", - "from": "TeomaHK", - "first": true - } - ] - }, - { - "year": 2021, - "donations": [ - { - "date": "30.11.2021", - "amount": 5, - "via": "banktransfer", - "from": "Rumo", - "first": false - }, - { - "date": "16.11.2021", - "amount": 120, - "via": "banktransfer", - "from": "poetaster", - "first": true - }, - { - "date": "16.11.2021", - "amount": 25, - "via": "banktransfer", - "from": null, - "first": true - }, - { - "date": "20.09.2021", - "amount": 20, - "via": "banktransfer", - "from": "Clemi", - "first": true - }, - { - "date": "26.08.2021", - "amount": 18.27, - "via": "opencollective", - "from": "Skoop", - "first": true - }, - { - "date": "18.08.2021", - "amount": 30, - "via": "banktransfer", - "from": null, - "first": true - }, - { - "date": "02.08.2021", - "amount": 10, - "via": "banktransfer", - "from": null, - "first": false - }, - { - "date": "01.06.2021", - "amount": 20, - "via": "banktransfer", - "from": "Rumo", - "first": true - }, - { - "date": "26.04.2021", - "amount": 8.96, - "via": "banktransfer", - "from": null, - "first": false - }, - { - "date": "23.03.2021", - "amount": 30, - "via": "banktransfer", - "from": null, - "first": true - }, - { - "date": "19.02.2021", - "amount": 20, - "via": "banktransfer", - "from": null, - "first": true - }, - { - "date": "02.02.2021", - "amount": 9.01, - "via": "opencollective", - "from": "Dennis H.", - "first": true - }, - { - "date": "20.01.2021", - "amount": 10, - "via": "banktransfer", - "from": null, - "first": true - }, - { - "date": "17.01.2021", - "amount": 4.41, - "via": "opencollective", - "from": "Michael Haak", - "first": true - } - ] - }, - { - "year": 2020, - "donations": [ - { - "date": "04.12.2020", - "amount": 10, - "via": "banktransfer", - "from": null, - "first": true - } - ] + "cash": { + "number": 0, + "color": "inactive" } -] +} diff --git a/src/_data/expenses.json b/src/_data/expenses.json deleted file mode 100644 index 0d30bc9..0000000 --- a/src/_data/expenses.json +++ /dev/null @@ -1,33 +0,0 @@ -[ - { - "name": "Services", - "type": "Dedicated Server", - "provider": "Hetzner", - "location": "Falkenstein", - "amount": 75.8 - }, - { - "name": "Monitoring", - "type": "Cloud Server", - "provider": "Hetzner", - "location": "Nürnberg", - "amount": 4.51 - }, - { - "name": "Backup", - "type": "Storage Box", - "provider": "Hetzner", - "location": "Helsinki", - "amount": 12.97 - }, - { - "name": { - "en": "Websites", - "de": "Webseiten" - }, - "type": "Webhosting", - "provider": "netcup", - "location": "Nürnberg", - "amount": 2.17 - } -] diff --git a/src/_data/services.json b/src/_data/services.json index a7b6c30..2f3272a 100644 --- a/src/_data/services.json +++ b/src/_data/services.json @@ -1,119 +1,111 @@ [ + { + "id": "searx", + "name": "Searx", + "icon": "fas fa-search", + "url": "https://searx.sp-codes.de", + "status": "https://searx.sp-codes.de", + "summary": { + "de": "Eine privatsphären-respektierende, hackbare Metasuchmaschine.", + "en": "A privacy-respecting, hackable metasearch engine." + } + }, { "id": "matrix", "name": "Matrix", - "icon": "i-comments", + "icon": "fas fa-comments", "url": "https://chat.sp-codes.de", - "status": "1", + "status": "https://matrix.sp-codes.de/_matrix/static/", "summary": { - "de": "Die offene Plattform für sichere und dezentrale Kommunikation.", - "en": "The open platform for secure and decentralized communication." - }, - "ossrox": { - "url": "https://ossrox.org/store/matrix", - "description": { - "de": "Wenn du einen eigenen Matrix-Server für dich, deine Familie oder deine Firma betreiben willst, unterstütze ich dich gerne mit meiner Firma Ossrox damit. Schau dir gerne unser Angebot dazu auf unserer Webseite an oder schreib mir eine Nachricht dazu.", - "en": "If you want to have your own matrix server for you, your family or your company, I would be happy to support you with my company Ossrox. Please have a look at our services on our website or send me a message." - } + "de": "Ein offenes Netzwerk für sichere, dezentralisierte Kommunikation.", + "en": "An open network for secure, decentralized communication." } }, { "id": "jitsi", "name": "Jitsi Meet", - "icon": "i-users", + "icon": "fas fa-users", "url": "https://jitsi.sp-codes.de", - "status": "2", + "status": "https://jitsi.sp-codes.de", "summary": { - "de": "Einfache Videokonferenzen mit Leichtigkeit.", - "en": "Easy video conferencing with ease." + "de": "Eine sichere, einfache und skalierbare Plattform für Videokonferenzen.", + "en": "A secure, simple and scalable platform for video conferencing." } }, { - "id": "mastodon", - "name": "Mastodon", - "icon": "i-mastodon", - "url": "https://social.sp-codes.de", - "status": "7", - "summary": { - "de": "Das soziale Netzwerk für dezentrale und sichere Interaktion.", - "en": "The social network for decentralized and secure interaction." - } - }, - { - "id": "peertube", - "name": "PeerTube", - "icon": "i-peertube", - "url": "https://tube.sp-codes.de", - "status": "9", - "summary": { - "de": "Die freie und dezentrale Plattform für gemeinsames Video-Streaming.", - "en": "The free and decentralized platform for collaborative video streaming." - } - }, - { - "id": "pixelfed", - "name": "Pixelfed", - "icon": "i-pixelfed", - "url": "https://pixel.sp-codes.de", - "status": "11", - "beta": true, - "summary": { - "de": "Das soziale Netzwerk für den Austausch von Bildern und Fotografie.", - "en": "The social network for sharing images and photography." - } - }, - { - "id": "forgejo", - "name": "Forgejo", - "icon": "i-git", + "id": "gitea", + "name": "Gitea", + "icon": "fas fa-code", "url": "https://git.sp-codes.de", - "status": "13", + "status": "https://git.sp-codes.de", "summary": { - "de": "Die Plattform für einfaches und sicheres Code-Hosting.", - "en": "The platform for easy and secure code hosting." + "de": "Eine leichtgewichtige Code-Hosting-Plattform für git.", + "en": "A lightweight code hosting platform for git." } }, { "id": "connectivitycheck", "name": "Captive Portal Check", - "icon": "i-wifi", - "status": "19", + "icon": "fas fa-wifi", + "status": "https://connectivitycheck.sp-codes.de/generate204", "summary": { - "de": "Überprüfung der Verfügbarkeit von Internetzugang.", - "en": "Verification of Internet access availability." + "de": "Eine datenschutzfreundliches Tool, um Anmeldeseiten in WLAN-Netzwerken zu erkennen.", + "en": "A privacy friendly Service to detect captive portals in WIFI networks." } }, { - "id": "ntfy", - "name": "ntfy", - "icon": "i-cloud-download", - "url": "https://ntfy.sp-codes.de", - "status": "18", + "id": "firefox-sync", + "name": "Firefox Sync", + "icon": "fab fa-firefox-browser", + "status": "https://sync.firefox.sp-codes.de/token/", "summary": { - "de": "Echtzeitbenachrichtigungen mit UnifiedPush-Unterstützung.", - "en": "Real-time notifications with UnifiedPush support." - } - }, - { - "id": "etherpad", - "name": "Etherpad", - "icon": "i-pencil-square", - "url": "https://pad.sp-codes.de", - "status": "17", - "summary": { - "de": "Gemeinsame Echtzeit-Textbearbeitung für effektive Zusammenarbeit.", - "en": "Collaborative real-time text editing for effective collaboration." + "de": "Ein Service um Firefox Einstellungen, Lesezeichen, offene Tabs und vieles mehr über verschiedene Geräte zu synchronisieren.", + "en": "A service to sync Firefox settings, bookmarks, open tabs and much more between multiple devices." } }, { "id": "shields", "name": "Shields", - "icon": "i-tags", + "icon": "fas fa-tags", "url": "https://shields.sp-codes.de", - "status": "20", + "status": "https://shields.sp-codes.de", "summary": { - "de": "Visuelle Badges zur Anzeige von Projektinformationen und Status.", - "en": "Visual badges for displaying project information and status." + "de": "Prägnante, konsistente und lesbare Badges im SVG- und Rasterformat.", + "en": "Concise, consistent, and legible badges in SVG and raster format." + } + }, + { + "id": "invidious", + "name": "Invidious", + "icon": "fab fa-youtube", + "url": "https://invidious.sp-codes.de", + "status": "https://invidious.sp-codes.de", + "summary": { + "de": "Ein alternatives YouTube-Frontend.", + "en": "An alternative YouTube-Frontend." + } + }, + { + "id": "nitter", + "name": "Nitter", + "icon": "fab fa-twitter", + "url": "https://nitter.sp-codes.de", + "status": "https://nitter.sp-codes.de", + "summary": { + "de": "Ein alternatives Twitter-Frontend.", + "en": "An alternative Twitter-Frontend." + } + }, + { + "id": "yotter", + "name": "Yotter", + "icon": "fas fa-desktop", + "url": "https://yotter.sp-codes.de", + "status": "https://yotter.sp-codes.de", + "beta": true, + "summary": { + "de": "Ein alternatives Twitter- und YouTube-Frontend.", + "en": "An alternative Twitter- and YouTube-Frontend." } } ] diff --git a/src/_data/strings.json b/src/_data/strings.json index 2fe4cff..5748020 100644 --- a/src/_data/strings.json +++ b/src/_data/strings.json @@ -32,59 +32,11 @@ "en": "Online" }, "outage": { - "de": "Ausfall", - "en": "Outage" + "de": "Fehler", + "en": "Error" }, "maintenance": { "de": "Wartung", "en": "Maintenance" - }, - "date": { - "de": "Datum", - "en": "Date" - }, - "amount": { - "de": "Betrag", - "en": "Amount" - }, - "via": { - "de": "Via", - "en": "Via" - }, - "from": { - "de": "Von", - "en": "Form" - }, - "banktransfer": { - "de": "Überweisung", - "en": "Bank transfer" - }, - "total": { - "de": "Gesamt", - "en": "Total" - }, - "name": { - "de": "Name", - "en": "Name" - }, - "type": { - "de": "Typ", - "en": "Type" - }, - "provider": { - "de": "Anbieter", - "en": "Provider" - }, - "location": { - "de": "Standort", - "en": "Location" - }, - "month": { - "de": "Monat", - "en": "Month" - }, - "year": { - "de": "Jahr", - "en": "Year" } } diff --git a/src/_includes/donations-current.html b/src/_includes/donations-current.html deleted file mode 100644 index 16e3174..0000000 --- a/src/_includes/donations-current.html +++ /dev/null @@ -1,36 +0,0 @@ -
{{strings.date[locale]}} | -{{strings.via[locale]}} | -{{strings.from[locale]}} | -{{strings.amount[locale]}} | -||
---|---|---|---|---|---|
{{donation.date}} | - {% if donation.via == 'opencollective' %} -Open Collective | - {% else %} -{{strings[donation.via][locale]}} | - {% endif %} - {% if donation.from %} -{{donation.from}} | - {% else %} -*** | - {% endif %} -{{donation.amount | amount}} € | -
{{strings.total[locale]}} | -{{donations[0].donations | sum | amount}} € | -
{{strings.date[locale]}} | -{{strings.via[locale]}} | -{{strings.from[locale]}} | -{{strings.amount[locale]}} | -||
---|---|---|---|---|---|
{{donation.date}} | - {% if donation.via == 'opencollective' %} -Open Collective | - {% else %} -{{strings[donation.via][locale]}} | - {% endif %} - {% if donation.from %} -{{donation.from}} | - {% else %} -*** | - {% endif %} -{{donation.amount | amount}} € | -
{{strings.total[locale]}} | -{{year.donations | sum | amount}} € | -
{{strings.name[locale]}} | -{{strings.type[locale]}} | -{{strings.provider[locale]}} | -{{strings.location[locale]}} | -{{strings.amount[locale]}} / {{strings.month[locale]}} | -{{strings.amount[locale]}} / {{strings.year[locale]}} | -|
---|---|---|---|---|---|---|
{{expense.name[locale]}} | - {% else %} -{{expense.name}} | - {% endif %} -{{expense.type}} | -{{expense.provider}} | -{{expense.location}} | -{{expense.amount | amount}} € | -{{expense.amount | year | amount}} € | -
{{strings.total[locale]}} | -{{expenses | sum | amount}} € | -{{expenses | sum | year | amount}} € | -
- Komm gerne in der Matrix-Gruppe vorbei und lass uns diskutieren. Ich freue mich auf dein Feedback! -
- #sp-codes:matrix.sp-codes.de -- Mein Name ist Samuel Philipp und ich bin ein Software Engineer aus Magdeburg. In meiner Freizeit - hoste ich verschiedene freie Dienste. Hier schreibe ich Artikel rund um - Sicherheit und Datenschutz. -
- Mehr erfahren -