Compare commits
8 Commits
c227c291c9
...
f880e9f10c
Author | SHA1 | Date | |
---|---|---|---|
f880e9f10c | |||
b179541532 | |||
5098d27ae9 | |||
d8fb9ea2fd | |||
5dbe7816cd | |||
1657a10dec | |||
7d22a32cb4 | |||
ed4941b403 |
66
docs/docs.go
66
docs/docs.go
@ -15,6 +15,33 @@ const docTemplate = `{
|
|||||||
"host": "{{.Host}}",
|
"host": "{{.Host}}",
|
||||||
"basePath": "{{.BasePath}}",
|
"basePath": "{{.BasePath}}",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
"/cards": {
|
||||||
|
"post": {
|
||||||
|
"description": "Generate cards based on the provided data",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/pdf"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"cards"
|
||||||
|
],
|
||||||
|
"summary": "Generate runner cards",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Card data",
|
||||||
|
"name": "data",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.CardRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/contracts": {
|
"/contracts": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "Generate a contract based on the provided data",
|
"description": "Generate a contract based on the provided data",
|
||||||
@ -35,7 +62,7 @@ const docTemplate = `{
|
|||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/models.Contract"
|
"$ref": "#/definitions/models.ContractRequest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -44,7 +71,42 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"models.Contract": {
|
"models.Card": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"$ref": "#/definitions/models.Runner"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"models.CardRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"card": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/models.Card"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"locale": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"en",
|
||||||
|
"de"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"models.ContractRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"locale": {
|
"locale": {
|
||||||
|
@ -6,6 +6,33 @@
|
|||||||
"contact": {}
|
"contact": {}
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
|
"/cards": {
|
||||||
|
"post": {
|
||||||
|
"description": "Generate cards based on the provided data",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/pdf"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"cards"
|
||||||
|
],
|
||||||
|
"summary": "Generate runner cards",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Card data",
|
||||||
|
"name": "data",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.CardRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/contracts": {
|
"/contracts": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "Generate a contract based on the provided data",
|
"description": "Generate a contract based on the provided data",
|
||||||
@ -26,7 +53,7 @@
|
|||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/models.Contract"
|
"$ref": "#/definitions/models.ContractRequest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -35,7 +62,42 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"models.Contract": {
|
"models.Card": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"$ref": "#/definitions/models.Runner"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"models.CardRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"card": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/models.Card"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"locale": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"en",
|
||||||
|
"de"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"models.ContractRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"locale": {
|
"locale": {
|
||||||
|
@ -1,5 +1,28 @@
|
|||||||
definitions:
|
definitions:
|
||||||
models.Contract:
|
models.Card:
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
runner:
|
||||||
|
$ref: '#/definitions/models.Runner'
|
||||||
|
type: object
|
||||||
|
models.CardRequest:
|
||||||
|
properties:
|
||||||
|
card:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/models.Card'
|
||||||
|
type: array
|
||||||
|
locale:
|
||||||
|
enum:
|
||||||
|
- en
|
||||||
|
- de
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
models.ContractRequest:
|
||||||
properties:
|
properties:
|
||||||
locale:
|
locale:
|
||||||
enum:
|
enum:
|
||||||
@ -39,6 +62,24 @@ info:
|
|||||||
for pdf generation.
|
for pdf generation.
|
||||||
title: LfK Document Server API
|
title: LfK Document Server API
|
||||||
paths:
|
paths:
|
||||||
|
/cards:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Generate cards based on the provided data
|
||||||
|
parameters:
|
||||||
|
- description: Card data
|
||||||
|
in: body
|
||||||
|
name: data
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.CardRequest'
|
||||||
|
produces:
|
||||||
|
- application/pdf
|
||||||
|
responses: {}
|
||||||
|
summary: Generate runner cards
|
||||||
|
tags:
|
||||||
|
- cards
|
||||||
/contracts:
|
/contracts:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
@ -50,7 +91,7 @@ paths:
|
|||||||
name: data
|
name: data
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/models.Contract'
|
$ref: '#/definitions/models.ContractRequest'
|
||||||
produces:
|
produces:
|
||||||
- application/pdf
|
- application/pdf
|
||||||
responses: {}
|
responses: {}
|
||||||
|
110
handlers/card.go
Normal file
110
handlers/card.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"git.odit.services/lfk/document-server/models"
|
||||||
|
"git.odit.services/lfk/document-server/services"
|
||||||
|
"git.odit.services/lfk/document-server/templates"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenerateCard godoc
|
||||||
|
// @Summary Generate runner cards
|
||||||
|
// @Description Generate cards based on the provided data
|
||||||
|
// @Tags cards
|
||||||
|
// @Accept json
|
||||||
|
// @Param data body models.CardRequest true "Card data"
|
||||||
|
// @Produce application/pdf
|
||||||
|
// @Router /cards [post]
|
||||||
|
func GenerateCard(c *fiber.Ctx) error {
|
||||||
|
cardRequest := new(models.CardRequest)
|
||||||
|
if err := c.BodyParser(cardRequest); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !slices.Contains([]string{"en", "de"}, cardRequest.Locale) {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"error": "Invalid locale",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
generator := services.DefaultTemplater{}
|
||||||
|
templateString, err := templates.GetTemplate(cardRequest.Locale, "card")
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"error": "Template not found",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
template, err := generator.StringToTemplate(templateString)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
genConfig := &models.CardTemplateOptions{
|
||||||
|
CardSegments: splitCardSegments(cardRequest.Cards),
|
||||||
|
EventName: "Event name",
|
||||||
|
CardSubtitle: "Card subtitle",
|
||||||
|
BarcodeFormat: "ean13",
|
||||||
|
BarcodePrefix: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := generator.Execute(template, genConfig)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
c.Set(fiber.HeaderContentType, "text/html")
|
||||||
|
converter := services.GotenbergConverter{BaseUrl: "http://localhost:3001"}
|
||||||
|
pdf, err := converter.ToPdf(result, "a4", false)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Set(fiber.HeaderContentType, "application/pdf")
|
||||||
|
return c.Send(pdf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func invertCardArrayItemPairs(cards []models.Card) []models.Card {
|
||||||
|
inverted := make([]models.Card, 0)
|
||||||
|
for i := 0; i < len(cards); i += 2 {
|
||||||
|
if i+1 < len(cards) {
|
||||||
|
inverted = append(inverted, cards[i+1])
|
||||||
|
}
|
||||||
|
inverted = append(inverted, cards[i])
|
||||||
|
}
|
||||||
|
return inverted
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitCardSegments(cards []models.Card) []models.CardTemplateSegment {
|
||||||
|
cardSegments := make([]models.CardTemplateSegment, 0)
|
||||||
|
const currentCards = 0
|
||||||
|
for i := 0; i < len(cards); i += 10 {
|
||||||
|
segmentLength := 10
|
||||||
|
if len(cards)-i < 10 {
|
||||||
|
segmentLength = len(cards) - i
|
||||||
|
}
|
||||||
|
segment := cards[i : i+segmentLength]
|
||||||
|
if segmentLength%2 != 0 {
|
||||||
|
segment = append(segment, models.Card{
|
||||||
|
ID: 0,
|
||||||
|
Enabled: false,
|
||||||
|
Runner: models.Runner{},
|
||||||
|
Code: "",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
cardSegments = append(cardSegments, models.CardTemplateSegment{
|
||||||
|
Cards: segment,
|
||||||
|
CardsSwapped: invertCardArrayItemPairs(segment),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return cardSegments
|
||||||
|
}
|
@ -59,7 +59,7 @@ func GenerateContract(c *fiber.Ctx) error {
|
|||||||
BarcodePrefix: "1",
|
BarcodePrefix: "1",
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := generator.Execute(template)
|
result, err := generator.Execute(template, genConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
@ -78,9 +78,9 @@ func GenerateContract(c *fiber.Ctx) error {
|
|||||||
return c.Send(pdf)
|
return c.Send(pdf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func repeatRunnerArrayItems(runners []Runner, duplicates int) []Runner {
|
func repeatRunnerArrayItems(runners []models.Runner, duplicates int) []models.Runner {
|
||||||
var duplicatedRunners []models.Runner
|
var duplicatedRunners []models.Runner
|
||||||
for _, runner := range contract.Runners {
|
for _, runner := range runners {
|
||||||
for i := 0; i < duplicates; i++ {
|
for i := 0; i < duplicates; i++ {
|
||||||
duplicatedRunners = append(duplicatedRunners, runner)
|
duplicatedRunners = append(duplicatedRunners, runner)
|
||||||
}
|
}
|
||||||
|
1
main.go
1
main.go
@ -35,6 +35,7 @@ func main() {
|
|||||||
return c.SendString("Hello, World!")
|
return c.SendString("Hello, World!")
|
||||||
})
|
})
|
||||||
v1.Post("/contracts", handlers.GenerateContract)
|
v1.Post("/contracts", handlers.GenerateContract)
|
||||||
|
v1.Post("/cards", handlers.GenerateCard)
|
||||||
|
|
||||||
app.Use(handlers.NotFoundHandler)
|
app.Use(handlers.NotFoundHandler)
|
||||||
docs.SwaggerInfo.BasePath = "/"
|
docs.SwaggerInfo.BasePath = "/"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
type CardRequest struct {
|
type CardRequest struct {
|
||||||
Cards []Card `json:"card"`
|
Cards []Card `json:"cards"`
|
||||||
Locale string `json:"locale" enums:"en,de"`
|
Locale string `json:"locale" enums:"en,de"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,10 +12,15 @@ type Card struct {
|
|||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContractTemplateOptions struct {
|
type CardTemplateOptions struct {
|
||||||
Cards []Card `json:"cards"`
|
CardSegments []CardTemplateSegment `json:"card_segments"`
|
||||||
EventName string `json:"event_name"`
|
EventName string `json:"event_name"`
|
||||||
CardSubtitle string `json:"card_subtitle"`
|
CardSubtitle string `json:"card_subtitle"`
|
||||||
BarcodeFormat string `json:"barcode_format"`
|
BarcodeFormat string `json:"barcode_format"`
|
||||||
BarcodePrefix string `json:"barcode_prefix"`
|
BarcodePrefix string `json:"barcode_prefix"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CardTemplateSegment struct {
|
||||||
|
Cards []Card `json:"cards"`
|
||||||
|
CardsSwapped []Card `json:"cards_swapped"`
|
||||||
|
}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"html/template"
|
"html/template"
|
||||||
"image/png"
|
"image/png"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/boombuler/barcode"
|
"github.com/boombuler/barcode"
|
||||||
"github.com/boombuler/barcode/code128"
|
"github.com/boombuler/barcode/code128"
|
||||||
@ -22,22 +21,20 @@ type Templater interface {
|
|||||||
type DefaultTemplater struct {
|
type DefaultTemplater struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func idToEan13(id int, prefix string) (string, error) {
|
func idToEan13(id string, prefix string) (string, error) {
|
||||||
idStr := strconv.Itoa(id)
|
if len(id) > 12 {
|
||||||
|
|
||||||
if len(idStr) > 12 {
|
|
||||||
return "", errors.New("id too long")
|
return "", errors.New("id too long")
|
||||||
}
|
}
|
||||||
|
|
||||||
for len(idStr) < 11 {
|
for len(id) < 11 {
|
||||||
idStr = "0" + idStr
|
id = "0" + id
|
||||||
}
|
}
|
||||||
idStr = prefix + idStr
|
id = prefix + id
|
||||||
|
|
||||||
return idStr, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *DefaultTemplater) GenerateBarcode(code int, format string, prefix string) (string, error) {
|
func (t *DefaultTemplater) GenerateBarcode(code string, format string, prefix string) (string, error) {
|
||||||
var generatedCode barcode.Barcode
|
var generatedCode barcode.Barcode
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -53,13 +50,13 @@ func (t *DefaultTemplater) GenerateBarcode(code int, format string, prefix strin
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "code128":
|
case "code128":
|
||||||
generatedCode, err = code128.Encode(prefix + strconv.Itoa(code))
|
generatedCode, err = code128.Encode(prefix + code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case "qr":
|
case "qr":
|
||||||
generatedCode, err = qr.Encode(prefix+strconv.Itoa(code), qr.M, qr.Numeric)
|
generatedCode, err = qr.Encode(prefix+code, qr.M, qr.AlphaNumeric)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -85,6 +82,7 @@ func (t *DefaultTemplater) GenerateBarcode(code int, format string, prefix strin
|
|||||||
func (t *DefaultTemplater) StringToTemplate(templateString string) (*template.Template, error) {
|
func (t *DefaultTemplater) StringToTemplate(templateString string) (*template.Template, error) {
|
||||||
return template.New("template").Funcs(template.FuncMap{
|
return template.New("template").Funcs(template.FuncMap{
|
||||||
"barcode": t.GenerateBarcode,
|
"barcode": t.GenerateBarcode,
|
||||||
|
"sponsorLogo": func(id int) string { return "a" },
|
||||||
}).Parse(templateString)
|
}).Parse(templateString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,10 +28,12 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="A4 landscape">
|
<body class="A4 landscape">
|
||||||
|
{{ range .CardSegments }}
|
||||||
<div class="sheet">
|
<div class="sheet">
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
{{ range .cards }}
|
{{ range .Cards }}
|
||||||
<div class="column is-half runnercard">
|
<div class="column is-half runnercard">
|
||||||
|
{{ if ne .Code "" }}
|
||||||
<p class="title is-5" style="text-align: center; padding-bottom: 0; margin-top: -0.75rem;">{{ $.EventName }}</p>
|
<p class="title is-5" style="text-align: center; padding-bottom: 0; margin-top: -0.75rem;">{{ $.EventName }}</p>
|
||||||
<p style="text-align: center; margin-top: -1.5rem; font-size: small;">{{ $.CardSubtitle }}</p>
|
<p style="text-align: center; margin-top: -1.5rem; font-size: small;">{{ $.CardSubtitle }}</p>
|
||||||
<p style="font-size: small;">Mit Unterstützung von:</p>
|
<p style="font-size: small;">Mit Unterstützung von:</p>
|
||||||
@ -43,29 +45,36 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="column is-half">
|
<div class="column is-half">
|
||||||
<!--BARCODE HERE-->
|
<!--BARCODE HERE-->
|
||||||
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 5rem;"
|
||||||
src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
||||||
|
<p style="font-size: 0.6rem; text-align: center; margin: 0; padding: 0;">{{ .Code }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{ .Runner.LastName }}, {{ .Runner.FirstName }} {{ .Runner.MiddleName }}</p>
|
<p>{{ .Runner.LastName }}, {{ .Runner.FirstName }} {{ .Runner.MiddleName }}</p>
|
||||||
<p>{{ .Runner.Group.Name }}</p>
|
<p>{{ .Runner.Group.Name }}</p>
|
||||||
|
{{ end}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sheet">
|
<div class="sheet">
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
{{#each cards_swapped}}
|
{{ range .CardsSwapped }}
|
||||||
<div class="column is-half runnercard" style="justify-content: center; align-items: center; text-align: center;">
|
<div class="column is-half runnercard" style="justify-content: center; align-items: center; text-align: center;">
|
||||||
|
{{ if ne .Code "" }}
|
||||||
<!--SPONSOR LOGO FIRST-->
|
<!--SPONSOR LOGO FIRST-->
|
||||||
<div style="height: 2cm; padding: 0 0 2.25cm 0">
|
<div style="height: 2cm; padding: 0 0 1cm 0">
|
||||||
<img style="object-fit: cover; max-height: 2cm;" src="data:image/png;base64,{{ sponsorLogo .ID }}" />
|
<img style="object-fit: cover; max-height: 2cm;" src="data:image/png;base64,{{ sponsorLogo .ID }}" />
|
||||||
</div>
|
</div>
|
||||||
<img style="object-fit: cover; max-height: 2.5cm; position: relative;" src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
<img style="object-fit: cover; max-height: 6rem; position: relative;"
|
||||||
|
src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
||||||
|
<p style="font-size: 1rem; text-align: center; margin: 0; padding: 0;">{{ .Code }}</p>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end}}
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -28,9 +28,10 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="A4 landscape">
|
<body class="A4 landscape">
|
||||||
|
{{ range .CardSegments }}
|
||||||
<div class="sheet">
|
<div class="sheet">
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
{{#each cards}}
|
{{ range .Cards }}
|
||||||
<div class="column is-half runnercard">
|
<div class="column is-half runnercard">
|
||||||
<p class="title is-5" style="text-align: center; padding-bottom: 0; margin-top: -0.75rem;">{{ $.EventName }}</p>
|
<p class="title is-5" style="text-align: center; padding-bottom: 0; margin-top: -0.75rem;">{{ $.EventName }}</p>
|
||||||
<p style="text-align: center; margin-top: -1.5rem; font-size: small;">{{ $.CardSubtitle }}</p>
|
<p style="text-align: center; margin-top: -1.5rem; font-size: small;">{{ $.CardSubtitle }}</p>
|
||||||
@ -43,29 +44,32 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="column is-half">
|
<div class="column is-half">
|
||||||
<!--BARCODE HERE-->
|
<!--BARCODE HERE-->
|
||||||
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 5rem;"
|
||||||
src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
||||||
|
<p style="font-size: 0.6rem; text-align: center; margin: 0; padding: 0;">{{ .Code }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{ .Runner.LastName }}, {{ .Runner.FirstName }} {{ .Runner.MiddleName }}</p>
|
<p>{{ .Runner.LastName }}, {{ .Runner.FirstName }} {{ .Runner.MiddleName }}</p>
|
||||||
<p>{{ .Runner.Group.Name }}</p>
|
<p>{{ .Runner.Group.Name }}</p>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sheet">
|
<div class="sheet">
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
{{#each cards_swapped}}
|
{{ range .CardsSwapped }}
|
||||||
<div class="column is-half runnercard" style="justify-content: center; align-items: center; text-align: center;">
|
<div class="column is-half runnercard" style="justify-content: center; align-items: center; text-align: center;">
|
||||||
<!--SPONSOR LOGO FIRST-->
|
<!--SPONSOR LOGO FIRST-->
|
||||||
<div style="height: 2cm; padding: 0 0 2.25cm 0">
|
<div style="height: 2cm; padding: 0 0 1cm 0">
|
||||||
<img style="object-fit: cover; max-height: 2cm;" src="data:image/png;base64,{{ sponsorLogo .ID }}" />
|
<img style="object-fit: cover; max-height: 2cm;" src="data:image/png;base64,{{ sponsorLogo .ID }}" />
|
||||||
</div>
|
</div>
|
||||||
<img style="object-fit: cover; max-height: 2.5cm; position: relative;" src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
<img style="object-fit: cover; max-height: 6rem; position: relative;" src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
||||||
|
<p style="font-size: 1rem; text-align: center; margin: 0; padding: 0;">{{ .Code }}</p>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end}}
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -56,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
||||||
src="data:image/png;base64,{{ barcode .ID $.BarcodeFormat $.BarcodePrefix }}" />
|
src="data:image/png;base64,{{ barcode (printf "%d" .ID) $.BarcodeFormat $.BarcodePrefix }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns" style="padding-top: 1rem;">
|
<div class="columns" style="padding-top: 1rem;">
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
||||||
src="data:image/png;base64,{{ barcode .ID $.BarcodeFormat $.BarcodePrefix }}"/>
|
src="data:image/png;base64,{{ barcode (printf "%d" .ID) $.BarcodeFormat $.BarcodePrefix }}"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns" style="padding-top: 1rem;">
|
<div class="columns" style="padding-top: 1rem;">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user