Compare commits
4 Commits
74269c4fbb
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
331e6e70a9 | ||
|
|
9b42f824f9 | ||
|
|
c40fe447b0 | ||
|
|
82deb5ac15 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -11,14 +11,15 @@
|
||||
*.pdf
|
||||
*.bak
|
||||
|
||||
# Real participant data (copy to "Export Brevetkarte.csv" and fill in)
|
||||
Export Brevetkarte.csv
|
||||
# Real participant data (copy export_brevetcard.csv.example and fill in)
|
||||
export_brevetcard.csv
|
||||
|
||||
# Real event data (copy event.yml.example to event.yml and fill in)
|
||||
event.yml
|
||||
|
||||
# Generated files
|
||||
brevetkarte-personalized.tex
|
||||
brevetkarte-rueckseite.tex
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
10
Dockerfile
10
Dockerfile
@@ -7,12 +7,4 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
make \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
# Copy project files
|
||||
COPY brevetkarte.tex .
|
||||
COPY cyclist-logo.png .
|
||||
|
||||
# Default command
|
||||
CMD ["pdflatex", "-interaction=nonstopmode", "brevetkarte.tex"]
|
||||
WORKDIR /workspace
|
||||
33
Makefile
33
Makefile
@@ -1,37 +1,23 @@
|
||||
# Makefile for building Brevet card PDF in Docker
|
||||
|
||||
IMAGE_NAME := brevetcard-builder
|
||||
TEX_FILE_FRONT := brevetkarte.tex
|
||||
TEX_FILE_BACK := brevetkarte-rueckseite.tex
|
||||
TEX_FILE_PERSONALIZED := brevetkarte-personalized.tex
|
||||
PDF_FILE_FRONT := brevetkarte.pdf
|
||||
PDF_FILE_BACK := brevetkarte-rueckseite.pdf
|
||||
TEX_FILE_BACK := brevetkarte-rueckseite.tex
|
||||
PDF_FILE_PERSONALIZED := brevetkarte-personalized.pdf
|
||||
CSV_FILE := Export Brevetkarte.csv
|
||||
PDF_FILE_BACK := brevetkarte-rueckseite.pdf
|
||||
CSV_FILE := export_brevetcard.csv
|
||||
|
||||
.PHONY: all build clean build-image build-front build-back generate build-personalized run shell help
|
||||
.PHONY: all build clean build-image build-back generate build-personalized run shell help
|
||||
|
||||
# Default target
|
||||
all: build
|
||||
|
||||
# Build static demo front side (builds image if needed)
|
||||
build: build-image build-front
|
||||
all: build-personalized
|
||||
|
||||
# Build Docker image
|
||||
build-image:
|
||||
@echo "Building Docker image..."
|
||||
docker build -t $(IMAGE_NAME) .
|
||||
|
||||
# Compile static demo front side PDF
|
||||
build-front:
|
||||
@echo "Compiling front side LaTeX to PDF..."
|
||||
docker run --rm \
|
||||
-v $(PWD):/workspace \
|
||||
$(IMAGE_NAME) \
|
||||
pdflatex -interaction=nonstopmode $(TEX_FILE_FRONT)
|
||||
@echo "PDF generated: $(PDF_FILE_FRONT)"
|
||||
|
||||
# Compile back side PDF (always generated from event.yml via generate)
|
||||
# Compile back side PDF (after generate)
|
||||
build-back: build-image
|
||||
@echo "Compiling back side LaTeX to PDF..."
|
||||
docker run --rm \
|
||||
@@ -89,19 +75,18 @@ clean-all: clean
|
||||
docker rmi $(IMAGE_NAME) 2>/dev/null || true
|
||||
|
||||
# Rebuild from scratch
|
||||
rebuild: clean-all build
|
||||
rebuild: clean-all build-personalized
|
||||
|
||||
# Show help
|
||||
help:
|
||||
@echo "Brevet Card PDF Builder"
|
||||
@echo ""
|
||||
@echo "Available targets:"
|
||||
@echo " make build - Build Docker image and compile static front side (default)"
|
||||
@echo " make - Generate and compile front + back side PDFs (default)"
|
||||
@echo " make build-image - Build Docker image only"
|
||||
@echo " make build-front - Compile static demo front side PDF"
|
||||
@echo " make generate - Generate tex files from CSV + event.yml"
|
||||
@echo " make build-personalized - Generate and compile front + back side PDFs"
|
||||
@echo " make build-back - Compile back side PDF (after generate)"
|
||||
@echo " make build-back - Compile back side PDF only (after generate)"
|
||||
@echo " make shell - Open interactive shell in container"
|
||||
@echo " make clean - Remove generated files (aux, log, pdf)"
|
||||
@echo " make clean-all - Remove all files and Docker image"
|
||||
|
||||
12
README.md
12
README.md
@@ -13,7 +13,7 @@ LaTeX-basierter Generator für Audax Randonneurs Allemagne Brevetkarten mit Vord
|
||||
Vor dem ersten Build zwei Dateien aus den Beispielen anlegen und befüllen:
|
||||
|
||||
```bash
|
||||
cp "Export Brevetkarte.csv.example" "Export Brevetkarte.csv"
|
||||
cp export_brevetcard.csv.example export_brevetcard.csv
|
||||
cp event.yml.example event.yml
|
||||
```
|
||||
|
||||
@@ -52,7 +52,7 @@ Teilnehmerdaten im Format:
|
||||
Startnr, Nachname, Vorname, Straße, PLZ, Ort, Land, Medaille
|
||||
```
|
||||
|
||||
Siehe `Export Brevetkarte.csv.example` für das vollständige Format.
|
||||
Siehe `export_brevetcard.csv.example` für das vollständige Format.
|
||||
|
||||
## Verwendung
|
||||
|
||||
@@ -76,9 +76,6 @@ make generate
|
||||
|
||||
# Nur Rückseite kompilieren (nach generate)
|
||||
make build-back
|
||||
|
||||
# Statische Demo-Vorderseite bauen (ohne CSV, für Tests)
|
||||
make build-front
|
||||
```
|
||||
|
||||
### Weitere Befehle
|
||||
@@ -96,11 +93,10 @@ make help # Alle Befehle anzeigen
|
||||
| Datei | Beschreibung |
|
||||
|---|---|
|
||||
| `event.yml.example` | Vorlage für Veranstaltungsdaten (→ als `event.yml` kopieren) |
|
||||
| `Export Brevetkarte.csv.example` | Vorlage für Teilnehmerdaten (→ als `Export Brevetkarte.csv` kopieren) |
|
||||
| `export_brevetcard.csv.example` | Vorlage für Teilnehmerdaten (→ als `export_brevetcard.csv` kopieren) |
|
||||
| `brevetkarte-template.tex` | Vorlage Vorderseite (Platzhalter aus CSV + event.yml) |
|
||||
| `brevetkarte-rueckseite-template.tex` | Vorlage Rückseite (Zellplatzhalter aus event.yml) |
|
||||
| `brevetkarte.tex` | Statische Demo-Vorderseite (ohne Personalisierung) |
|
||||
| `generate_cards.py` | Generiert personalisierte .tex-Dateien |
|
||||
| `generate_cards.py` | Generiert .tex-Dateien aus Templates + Konfiguration |
|
||||
| `cyclist-logo.png` | Audax Randonneurs Logo |
|
||||
| `Dockerfile` | Docker-Image-Definition (debian:bookworm-slim + TeX Live) |
|
||||
| `Makefile` | Build-Automatisierung |
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
\documentclass[a4paper,10pt,landscape]{article}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage[landscape,top=0.8cm,bottom=0.8cm,left=0.8cm,right=0.8cm]{geometry}
|
||||
\usepackage{array}
|
||||
\usepackage{helvet}
|
||||
|
||||
% Set sans-serif font as default
|
||||
\renewcommand{\familydefault}{\sfdefault}
|
||||
|
||||
\setlength{\parindent}{0pt}
|
||||
\setlength{\tabcolsep}{3pt}
|
||||
\pagestyle{empty}
|
||||
|
||||
\newcommand{\rowheight}{2.833cm}
|
||||
|
||||
\begin{document}
|
||||
|
||||
% Upper card table (rows 1-3)
|
||||
\noindent
|
||||
\begin{tabular}{|p{6.6cm}|p{6.6cm}|p{6.6cm}|p{6.6cm}|}
|
||||
\hline
|
||||
% Row 1
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 1:} Km 0 -- Unisport\\
|
||||
Nachtigallenweg 86, Bonn\\
|
||||
\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 7:30\\
|
||||
bis: 8:30}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 4:} Km 165 -- Mahlberg Ecke K50,\\
|
||||
Breitestraße\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 13:21\\
|
||||
bis: 19:30}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Kontrollfrage:}\\
|
||||
Wann wurde das Kriegerdenkmal\\
|
||||
eingerichtet?}
|
||||
\\
|
||||
\hline
|
||||
|
||||
% Row 2
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 2:} Km 57 -- ,,Nationalpark-Tor`` im\\
|
||||
alten Bahnhofsgebäude, Heimbach\\
|
||||
\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 9:11\\
|
||||
bis: 12:21}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 5:} Km 205 -- Unisport\\
|
||||
Nachtigallenweg 86, Bonn\\
|
||||
\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 13:23\\
|
||||
bis: 21:00}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
\\
|
||||
\hline
|
||||
|
||||
% Row 3
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 3:} Km 100 -- Friterie ,,Au Petit\\
|
||||
Creux`` oder Total-Tankstelle, Ecke Rue\\
|
||||
de Botrange/Rue de Charmilles, Waimes\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 11:26\\
|
||||
bis: 15:10}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
\\
|
||||
\hline
|
||||
\end{tabular}
|
||||
|
||||
\vspace{1.8cm}
|
||||
|
||||
% Lower card table (rows 1-3, identical)
|
||||
\noindent
|
||||
\begin{tabular}{|p{6.6cm}|p{6.6cm}|p{6.6cm}|p{6.6cm}|}
|
||||
\hline
|
||||
% Row 1
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 1:} Km 0 -- Unisport\\
|
||||
Nachtigallenweg 86, Bonn\\
|
||||
\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 7:30\\
|
||||
bis: 8:30}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 4:} Km 165 -- Mahlberg Ecke K50,\\
|
||||
Breitestraße\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 13:21\\
|
||||
bis: 19:30}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Kontrollfrage:}\\
|
||||
Wann wurde das Kriegerdenkmal\\
|
||||
eingerichtet?}
|
||||
\\
|
||||
\hline
|
||||
|
||||
% Row 2
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 2:} Km 57 -- ,,Nationalpark-Tor`` im\\
|
||||
alten Bahnhofsgebäude, Heimbach\\
|
||||
\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 9:11\\
|
||||
bis: 12:21}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 5:} Km 205 -- Unisport\\
|
||||
Nachtigallenweg 86, Bonn\\
|
||||
\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 13:23\\
|
||||
bis: 21:00}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
\\
|
||||
\hline
|
||||
|
||||
% Row 3
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
\vspace{2mm}
|
||||
\textbf{Nr. 3:} Km 100 -- Friterie ,,Au Petit\\
|
||||
Creux`` oder Total-Tankstelle, Ecke Rue\\
|
||||
de Botrange/Rue de Charmilles, Waimes\\
|
||||
\textbf{Kontrollzeit}\\
|
||||
von: 11:26\\
|
||||
bis: 15:10}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
&
|
||||
\parbox[c][\rowheight][t]{6.5cm}{%
|
||||
}
|
||||
\\
|
||||
\hline
|
||||
\end{tabular}
|
||||
|
||||
\end{document}
|
||||
139
brevetkarte.tex
139
brevetkarte.tex
@@ -1,139 +0,0 @@
|
||||
\documentclass[a4paper,10pt,landscape]{article}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage[landscape,top=0.8cm,bottom=0.8cm,left=0.8cm,right=0.8cm]{geometry}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{tikz}
|
||||
\usepackage{helvet}
|
||||
\usepackage{hyperref}
|
||||
|
||||
% Set sans-serif font as default
|
||||
\renewcommand{\familydefault}{\sfdefault}
|
||||
|
||||
% Define colors
|
||||
\definecolor{headerblack}{RGB}{0,0,0}
|
||||
|
||||
% Configure hyperlinks to be black
|
||||
\hypersetup{
|
||||
colorlinks=true,
|
||||
linkcolor=black,
|
||||
urlcolor=black,
|
||||
citecolor=black
|
||||
}
|
||||
|
||||
\setlength{\parindent}{0pt}
|
||||
\pagestyle{empty}
|
||||
|
||||
% Command to create one brevet card
|
||||
\newcommand{\brevetcard}{%
|
||||
\noindent
|
||||
\begin{tikzpicture}[x=1cm,y=1cm]
|
||||
|
||||
% Black vertical separator lines (drawn first, extend through headers)
|
||||
\draw[black,line width=0.5pt] (6.9,-7.2) -- (6.9,1.3);
|
||||
\draw[black,line width=0.5pt] (13.8,-7.2) -- (13.8,1.3);
|
||||
\draw[black,line width=0.5pt] (20.7,-7.2) -- (20.7,1.3);
|
||||
|
||||
% Black header boxes (drawn on top)
|
||||
\fill[headerblack] (0,0) rectangle (6.9,1.3);
|
||||
\node[white,align=center,font=\tiny,text width=6.6cm] at (3.45,0.65) {
|
||||
Jeder Teilnehmer muss diese Brevetkarte zu jeder Zeit\\
|
||||
mit sich führen und an den Kontrollen abstempeln lassen\\
|
||||
bzw. Fotos erstellen.\\
|
||||
\textbf{Ohne Kontrollzeiten und Zielzeit keine Wertung!}
|
||||
};
|
||||
|
||||
\fill[headerblack] (6.9,0) rectangle (13.8,1.3);
|
||||
\node[white,font=\Large] at (10.35,0.65) {HOMOLOGATION};
|
||||
|
||||
\fill[headerblack] (13.8,0) rectangle (20.7,1.3);
|
||||
\node[white,font=\Large] at (17.25,0.65) {TEILNEHMER/-IN};
|
||||
|
||||
\fill[headerblack] (20.7,0) rectangle (27.6,1.3);
|
||||
\node[white,align=center,font=\normalsize] at (24.15,0.75) {BREVET DES RANDONNEURS};
|
||||
\node[white,font=\Large] at (24.15,0.35) {MONDIAUX};
|
||||
|
||||
% Column 1 - Rules (left section)
|
||||
\node[anchor=north west,text width=6.6cm,font=\small,align=left] at (0.2,-0.3) {
|
||||
\textbf{Es gelten die Regeln von}\\
|
||||
\textbf{Randonneur Mondiaux}\\
|
||||
\textbf{insbesondere:}
|
||||
{\setlength{\leftmargini}{0.4cm}%
|
||||
\begin{itemize}%
|
||||
\setlength{\itemsep}{1pt}\setlength{\topsep}{2pt}\setlength{\parsep}{0pt}
|
||||
\item Einhaltung der StVO
|
||||
\item Beleuchtung und Sicherheitsweste/-Gurt
|
||||
\item keine Abkürzungen
|
||||
\item keine Begleitfahrzeuge
|
||||
\item Rücksicht auf Teilnehmer und Umwelt
|
||||
\item Rücksicht in den Kontrollen
|
||||
\end{itemize}}
|
||||
\hspace{0.3cm}$\Rightarrow$ \textbf{\underline{Bei Verstoß keine Wertung!}}\\[0.3cm]
|
||||
-
|
||||
};
|
||||
|
||||
\node[anchor=south west,text width=6.6cm,font=\small,align=left] at (0.2,-7.0) {
|
||||
\textbf{AUDAX RANDONNEURS ALLEMAGNE E.V.}\\
|
||||
\href{http://www.audax-randonneure.de}{www.audax-randonneure.de}\\
|
||||
- gegründet 1992 in Hamburg -
|
||||
};
|
||||
|
||||
% Column 2 - Homologation (middle-left section)
|
||||
\node[anchor=north,text width=6.6cm,font=\small,align=center] at (10.35,-0.5) {
|
||||
Der Randonnée wurde beendet in:\\[0.6cm]
|
||||
\makebox[2cm]{\dotfill}h\makebox[2cm]{\dotfill}min
|
||||
};
|
||||
|
||||
\node[anchor=center,font=\Large] at (10.35,-4.0) {
|
||||
HOMOLOGATION
|
||||
};
|
||||
|
||||
\node[anchor=south,text width=6.6cm,font=\small,align=center] at (10.35,-6.8) {
|
||||
Brevet N° \makebox[5cm]{\dotfill}
|
||||
};
|
||||
|
||||
% Column 3 - Participant Info (middle-right section)
|
||||
\node[anchor=north west,text width=6.6cm,font=\small,align=left] at (14.0,-0.5) {
|
||||
Name:\\[0.4cm]
|
||||
Straße:\\[0.4cm]
|
||||
PLZ/Ort:\\[0.4cm]
|
||||
Land:\\[0.4cm]
|
||||
Medaille:\\[0.6cm]
|
||||
Startzeit: 8:30
|
||||
};
|
||||
|
||||
% Column 4 - Event Info (right section)
|
||||
\node[anchor=north,text width=6.6cm,align=center] at (24.15,-0.4) {
|
||||
\includegraphics[width=5.5cm]{cyclist-logo.png}
|
||||
};
|
||||
|
||||
\node[anchor=north,text width=6.6cm,font=\small,align=center] at (24.15,-2.2) {
|
||||
\textbf{Auf eine Pommes nach Belgien}\\
|
||||
Randonnée über \textbf{200} km\\
|
||||
am \textbf{20. September 2025}\\
|
||||
mit Start in \textbf{Bonn, Uni-Sportgelände}\\
|
||||
von \textbf{ARA Rheinland}\\
|
||||
N° ACP du Club \textbf{111011}
|
||||
};
|
||||
|
||||
\node[anchor=south,text width=6.6cm,font=\scriptsize,align=center] at (24.15,-7.0) {
|
||||
CONTRÔLÉE ET HOMOLOGUÉE EXCLUSIVEMENT PAR\\
|
||||
\href{http://www.audax-club-parisien.com}{www.audax-club-parisien.com}\\
|
||||
- Société fondée en 1904 -
|
||||
};
|
||||
|
||||
\end{tikzpicture}
|
||||
}
|
||||
|
||||
\begin{document}
|
||||
|
||||
% First brevet card
|
||||
\brevetcard
|
||||
|
||||
\vspace{0.8cm}
|
||||
|
||||
% Second brevet card (identical)
|
||||
\brevetcard
|
||||
|
||||
\end{document}
|
||||
@@ -93,7 +93,7 @@ def generate_card_from_template(template, data):
|
||||
|
||||
|
||||
def main():
|
||||
csv_file = Path("Export Brevetkarte.csv")
|
||||
csv_file = Path("export_brevetcard.csv")
|
||||
template_file = Path("brevetkarte-template.tex")
|
||||
backside_template_file = Path("brevetkarte-rueckseite-template.tex")
|
||||
event_config_file = Path("event.yml")
|
||||
|
||||
Reference in New Issue
Block a user