Merge branch 'main' into feature/slides

This commit is contained in:
Prof. Dr. Matthias Jung DL9MJ
2025-06-24 22:07:23 +02:00
committed by Tim Grelka
11 changed files with 422 additions and 27 deletions
+5 -4
View File
@@ -4,8 +4,9 @@ import requests
class DirectusAPI: class DirectusAPI:
def __init__(self, config): def __init__(self, base_url, access_token):
self.config = config self.base_url = base_url
self.access_token = access_token
def __get_raw(self, endpoint, params = None): def __get_raw(self, endpoint, params = None):
if params is None: if params is None:
@@ -13,12 +14,12 @@ class DirectusAPI:
for k in params.keys(): for k in params.keys():
if type(params[k]) is dict: if type(params[k]) is dict:
params[k] = json.dumps(params[k]) params[k] = json.dumps(params[k])
url = self.config.base_url + endpoint url = self.base_url + endpoint
result = requests.get( result = requests.get(
url, url,
params = params, params = params,
headers = { headers = {
"Authorization": f"Bearer {self.config.access_token}", "Authorization": f"Bearer {self.access_token}",
"Cache-Control": "no-store" "Cache-Control": "no-store"
} }
) )
+7 -5
View File
@@ -4,8 +4,9 @@ import src.config as config
import src.download as download import src.download as download
conf = config.Config() conf = config.Config()
api = directus.DirectusAPI(conf) api = directus.DirectusAPI(conf.question_base_url, conf.question_access_token)
dl = download.Download(api, conf) content_api = directus.DirectusAPI(conf.content_base_url, conf.content_access_token)
dl = download.Download(api, content_api, conf)
bd = build.Build() bd = build.Build()
# Download the text files: # Download the text files:
@@ -15,9 +16,10 @@ dl.download_edition("N")
dl.download_question_metadata() dl.download_question_metadata()
dl.download_pictures() dl.download_pictures()
dl.download_photos() dl.download_photos()
dl.download_snippets()
dl.download_content()
# Build edition: # Build Everything:
bd.build_website()
bd.build_edition("N") bd.build_edition("N")
# Build assets:
bd.build_assets() bd.build_assets()
+4 -1
View File
@@ -1,4 +1,7 @@
{ {
"directus_base_url" : "https://fragenkatalog.darc.de/", "directus_question_base_url" : "https://fragenkatalog.darc.de/",
"directus_question_api_key" : "",
"directus_content_base_url" : "https://redaktion.50ohm.de/",
"directus_content_api_key" : "",
"no_latex": true "no_latex": true
} }
+88 -9
View File
@@ -3,7 +3,6 @@ import os
import random import random
import shutil import shutil
from bs4 import BeautifulSoup
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
from joblib import Memory from joblib import Memory
from mistletoe import Document from mistletoe import Document
@@ -98,9 +97,13 @@ class Build:
return self.__build_question(input, template_file="slide/question.html") return self.__build_question(input, template_file="slide/question.html")
# cached # cached
def __build_page(self, content) : def __build_page(self, content, course_wrapper=False, sidebar=None) :
page_template = self.env.get_template("html/page.html") page_template = self.env.get_template("html/page.html")
return page_template.render(content=content) return page_template.render(
content=content,
course_wrapper=course_wrapper,
sidebar=sidebar
)
def __picture_handler(self, id): def __picture_handler(self, id):
os.makedirs("build/pictures", exist_ok=True) os.makedirs("build/pictures", exist_ok=True)
@@ -132,8 +135,7 @@ class Build:
title=next_chapter["title"], title=next_chapter["title"],
) )
result = self.__build_page(result) result = self.__build_page(result, course_wrapper=True)
result = BeautifulSoup(result, "html.parser").prettify()
file.write(result) file.write(result)
# cached # cached
@@ -169,8 +171,34 @@ class Build:
title=next_chapter["title"], title=next_chapter["title"],
) )
result = self.__build_page(result) result = self.__build_page(result, course_wrapper=True)
result = BeautifulSoup(result, "html.parser").prettify() file.write(result)
def __build_chapter_slidedeck(self, edition, chapter, sections, next_chapter):
with open(f'build/{edition}_slide_{chapter["ident"]}.html', 'w') as file:
slide_template = self.env.get_template("slide/slide.html")
help_template = self.env.get_template("slide/help.html")
next_template = self.env.get_template("slide/next.html")
with FiftyOhmHtmlSlideRenderer(
question_renderer=self.__build_question_slide,
picture_handler=self.__picture_handler,
photo_handler=self.__photo_handler
) as renderer:
result = "<section>\n"
result += f'<section data-background="#DAEEFA">\n<h1>{chapter["title"]}</h1>\n</section>\n'
result += help_template.render()
result += "</section>\n"
for section in sections:
tmp = f'<section data-background="#DAEEFA">\n<h1>{section["title"]}</h1>\n</section>\n'
tmp += renderer.render_wrapper(section["slide"])
result += f"<section>{tmp}</section>\n"
result += next_template.render(
edition=edition,
next_chapter=next_chapter,
chapter=chapter,
)
result = slide_template.render(content=result)
file.write(result) file.write(result)
def __build_chapter_slidedeck(self, edition, chapter, sections, next_chapter): def __build_chapter_slidedeck(self, edition, chapter, sections, next_chapter):
@@ -219,7 +247,6 @@ class Build:
book=book, book=book,
) )
result = self.__build_page(result) result = self.__build_page(result)
result = BeautifulSoup(result, "html.parser").prettify()
file.write(result) file.write(result)
def __build_slide_index(self, book): def __build_slide_index(self, book):
@@ -229,7 +256,6 @@ class Build:
book=book, book=book,
) )
result = self.__build_page(result) result = self.__build_page(result)
result = BeautifulSoup(result, "html.parser").prettify()
file.write(result) file.write(result)
def build_edition(self, edition): def build_edition(self, edition):
@@ -252,3 +278,56 @@ class Build:
def build_assets(self): def build_assets(self):
shutil.copytree("assets", "build/assets", dirs_exist_ok=True) shutil.copytree("assets", "build/assets", dirs_exist_ok=True)
def __parse_snippets(self):
with open("data/snippets.json") as f:
snippets = json.load(f)
with FiftyOhmHtmlRenderer(self.__build_question, self.__picture_handler, self.__photo_handler) as renderer:
for key, value in snippets.items():
snippets[key] = renderer.render_inner(Document(value))
# Remove leading <p> and trailing </p>:
snippets[key] = snippets[key][3:-4]
return snippets
def __parse_contents(self):
with open("data/content.json") as f:
contents = json.load(f)
return contents
def __build_index(self, snippets):
template = self.env.get_template("index.html")
result = template.render({"snippets": snippets})
with open("build/index.html", "w") as file:
result = self.__build_page(result)
file.write(result)
def __build_course_page(self, snippets, template, page):
template = self.env.get_template(f"{template}.html")
result=template.render({"snippets": snippets})
with open(f"build/{page}.html", "w") as file:
result = self.__build_page(result)
file.write(result)
def __build_html_page(self, contents, page):
for content in contents:
if content["url_part"] == page:
with open(f"build/{page}.html", "w") as file:
result = self.__build_page(
content=content["content"],
sidebar=content["sidebar"]
)
file.write(result)
def build_website(self):
snippets = self.__parse_snippets()
contents = self.__parse_contents()
self.__build_index(snippets)
self.__build_course_page(snippets, "kurse-karte", "kurse_vor_ort_karte")
self.__build_course_page(snippets, "kurse-liste", "kurse_vor_ort_liste")
self.__build_course_page(snippets, "patenkarte", "patenkarte")
self.__build_html_page(contents, "pruefung")
self.__build_html_page(contents, "infos")
+4 -2
View File
@@ -13,8 +13,10 @@ class Config:
with open("config/config.json") as file: with open("config/config.json") as file:
self.config = json.load(file) self.config = json.load(file)
self.access_token = self.get_config_value("directus_api_key") self.question_access_token = self.get_config_value("directus_question_api_key")
self.base_url = self.get_config_value("directus_api_url", "https://fragenkatalog.darc.de/") self.question_base_url = self.get_config_value("directus_question_base_url", "https://fragenkatalog.darc.de/")
self.content_access_token = self.get_config_value("directus_content_api_key")
self.content_base_url = self.get_config_value("directus_content_base_url", "https://redaktion.50ohm.de/")
self.no_latex = self.get_config_value("no_latex", False) self.no_latex = self.get_config_value("no_latex", False)
def get_config_value(self, key: str, default=None): def get_config_value(self, key: str, default=None):
+23 -1
View File
@@ -8,9 +8,10 @@ from tqdm import tqdm
class Download: class Download:
def __init__(self, api, config): def __init__(self, api, content_api, config):
self.api = api self.api = api
self.config = config self.config = config
self.content_api = content_api
def download_edition(self, edition): def download_edition(self, edition):
in_edition = self.api.get_one("items/edition", {"filter": {"ident": {"_eq": edition}}}) in_edition = self.api.get_one("items/edition", {"filter": {"ident": {"_eq": edition}}})
@@ -131,3 +132,24 @@ class Download:
Parallel(n_jobs=multiprocessing.cpu_count())( Parallel(n_jobs=multiprocessing.cpu_count())(
delayed(build_picture)(picture) for picture in tqdm(pictures, desc="Build All Pictures") delayed(build_picture)(picture) for picture in tqdm(pictures, desc="Build All Pictures")
) )
def download_snippets(self):
snippets = {}
for snippet in tqdm(self.content_api.get("items/snippet"), desc="Downloading snippets"):
snippets[snippet["ident"]] = snippet["content"]
with open("data/snippets.json", "w", encoding="utf-8") as file:
json.dump(snippets, file, ensure_ascii=False, indent=4)
def download_content(self):
contents = []
for content in self.content_api.get("items/content"): #tqdm(self.content_api.get("items/content"), desc="Downloading content"):
contents.append(
{
"url_part": content["url_part"],
"content": content["content"],
"sidebar": content["sidebar"],
}
)
with open("data/content.json", "w", encoding="utf-8") as file:
json.dump(contents, file, ensure_ascii=False, indent=4)
+184
View File
@@ -0,0 +1,184 @@
<div class="fiftyohm-content-index">
<div>
<h1>{{ snippets.index_title }}</h1>
<p>
{{ snippets.index_teaser }}
</p>
<div class="d-grid gap-3 d-md-block my-5">
<a href="#lernen" class="btn btn-primary btn-lg">{{ snippets.index_btn_start }}</a>
<a href="infos.html" class="btn btn-outline-secondary btn-lg">{{ snippets.index_btn_was_ist_afu }}</a>
</div>
<p>
<div class="alert alert-primary" role="alert">
{{ snippets.index_content }}
</div>
</p>
</div>
<div>
<div id="carouselExampleControls" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="assets/images/hero/hero06.jpg" class="d-block w-100" alt="...">
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
<p class="p-2 m-0 text-end">Foto: DK5WP df0alz.de</p>
</div>
</div>
<div class="carousel-item">
<img src="assets/images/hero/hero02.jpg" class="d-block w-100" alt="...">
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
<p class="p-2 m-0 text-end">Foto: DK5WP df0alz.de</p>
</div>
</div>
<div class="carousel-item">
<img src="assets/images/hero/hero03.jpg" class="d-block w-100" alt="...">
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
<p class="p-2 m-0 text-end">Foto: DK4HAA draussenfunker.de</p>
</div>
</div>
<div class="carousel-item">
<img src="assets/images/hero/hero01.jpg" class="d-block w-100" alt="...">
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
<p class="p-2 m-0 text-end">Foto: DB8KN bei DL0JMU</p>
</div>
</div>
<div class="carousel-item">
<img src="assets/images/hero/hero04.jpg" class="d-block w-100" alt="...">
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
<p class="p-2 m-0 text-end">Foto: DK4HAA draussenfunker.de</p>
</div>
</div>
<div class="carousel-item">
<img src="assets/images/hero/hero05.jpg" class="d-block w-100" alt="...">
<div class="position-absolute bottom-0 text-light w-100" style="background-color: rgba(0, 0, 0, 0.5)">
<p class="p-2 m-0 text-end">Foto: DO3OI</p>
</div>
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleControls" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#carouselExampleControls" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
</div>
</div>
<a name="lernen"></a>
<div class="row g-5 pt-5 mt-2 row-cols-1">
<div class="col col-lg-4">
<div class="feature col">
<div class="feature-icon bg-primary bg-gradient">
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48"><path d="M480-60q-72-68-165-104t-195-36v-440q101 0 194 36.5T480-498q73-69 166-105.5T840-640v440q-103 0-195.5 36T480-60Zm0-104q63-47 134-75t146-37v-276q-73 13-143.5 52.5T480-394q-66-66-136.5-105.5T200-552v276q75 9 146 37t134 75Zm0-436q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T560-760q0-33-23.5-56.5T480-840q-33 0-56.5 23.5T400-760q0 33 23.5 56.5T480-680Zm0-80Zm0 366Z"/></svg>
</div>
<h2>Online lernen</h2>
<p>Bringe dir das nötige Wissen für die Amateurfunkprüfung einfach selber bei. Unser Lernmaterial hilft dir auf deinem Weg! Es gibt die drei <a href="infos.html">Klassen N, E und A</a>, die aufeinander aufbauen.</p>
<h5>Gesamtkurse</h5>
<p>Diese Kurse richten sich an alle, die noch kein Amateurfunkzeugnis haben.</p>
<div class="row row-cols-lg-3 g-2">
<div class="col"><a href="N_course_index.html" class="btn btn-outline-dark w-100">N<br><small>Neueinsteiger</small></a></div>
<div class="col"><a href="NE_course_index.html" class="btn btn-outline-dark w-100">N + E<br><small>Erweitert</small></a></div>
<div class="col"><a href="NEA_course_index.html" class="btn btn-outline-dark w-100">N + E + A<br><small>Alles</small></a></div>
</div>
<br>
<h5>Aufbaukurse</h5>
<p>Für alle, die schon über ein Amateurfunkzeugnis der Klasse N oder E verfügen, gibt es folgende Aufbaukurse:</p>
<div class="row row-cols-lg-3 g-2">
<div class="col"><a href="E_course_index.html" class="btn btn-outline-dark w-100">N -> E</a></div>
<div class="col"><a href="EA_course_index.html" class="btn btn-outline-dark w-100">N -> A</a></div>
<div class="col"><a href="A_course_index.html" class="btn btn-outline-dark w-100">E -> A</a></div>
</div>
<br>
<h5>Fragestunden</h5>
<p>Tauchen beim Selbststudium Fragen auf? Unsere ehrenamtlichen Helfer bieten für DARC-Mitglieder eine Fragestunde auf dem DARC-Videokonferenzserver an.</p>
<div class="row row-cols-lg-2">
<div class="col"><a href="https://treff.darc.de/d/#/teilnehmer/964LmqHw" class="btn btn-outline-dark w-100">Mittwochs 19:00</a></div>
<div class="col"><a href="https://treff.darc.de/d/#/teilnehmer/964LmqHw" class="btn btn-outline-dark w-100">Sonntags 18:00</a></div>
</div>
<br>
<h5>DARC Chat</h5>
<p>Der DARC e. V. betreibt eine eigene Matrix-Instanz. Dort gibt es Räume, in denen du deine Fragen stellen kannst (🌍 öffentlich, d. h. auch von anderen Matrix-Servern erreichbar, und 🔐 nur für Mitglieder):</p>
<div class="row row-cols-lg-3">
<div class="col"><a href="https://matrix.to/#/#ausbildung:darc.de" class="btn btn-outline-dark w-100">🌍 Ausbildung</a></div>
<div class="col"><a href="https://matrix.to/#/#Fragen_Technik:darc.de" class="btn btn-outline-dark w-100">🔐 Fragen T</a></div>
<div class="col"><a href="https://matrix.to/#/#Fragen_BV:darc.de" class="btn btn-outline-dark w-100">🔐 Fragen B+V</a></div>
</div>
<br>
<h5>Mitglied werden</h5>
<p>Der <a href="https://darc.de">DARC e. V.</a> unterstützt Dich auf deinem Weg zum Amateurfunkzeugnis und ist die größte Interessensvertretung der Funkamateure in Deutschland.</p>
<div class="row row-cols-lg-2">
<div class="col"><a href="https://www.darc.de/mitgliedschaft/mitglied-werden/" class="btn btn-outline-dark w-100">Mitglied Werden</a></div>
<div class="col"><a href="https://www.darc.de/mitgliedschaft/mitglied-werden/#c154065" class="btn btn-outline-dark w-100">Gastmitgliedschaft</a></div>
</div>
</div>
</div>
<div class="col col-lg-8 row g-5 pb-5 m-0 row-cols-1 row-cols-lg-2">
<div class="feature col">
<div class="feature-icon bg-primary bg-gradient">
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 -960 960 960" width="48" fill="#5f6368"><path d="m380-300 280-180-280-180v360ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h640v-480H160v480Zm0 0v-480 480Z"/></svg>
</div>
<h2>Videokurs Klasse N</h2>
<p>In Zusammenarbeit mit DL2YMR ist ein Videokurs für die Klasse N entstanden, der auf seinem YouTube-Kanal abrufbar ist.</p>
<div class="d-grid gap-2 d-md-block mb-5">
<a href="https://www.youtube.com/playlist?list=PLDpWnjHk5ERbcgpLPUaU0iTsD-wrmfENk" class="btn btn-primary">Zum Videokurs</a>
</div>
</div>
<div class="feature col">
<img style="float: right; width: 33%;" src="assets/images/darc-amateurfunklehrgang-klasse-n.jpg">
<div class="feature-icon bg-primary bg-gradient">
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 448 512" width="48"><path d="M96 0C43 0 0 43 0 96L0 416c0 53 43 96 96 96l288 0 32 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l0-64c17.7 0 32-14.3 32-32l0-320c0-17.7-14.3-32-32-32L384 0 96 0zm0 384l256 0 0 64L96 448c-17.7 0-32-14.3-32-32s14.3-32 32-32zm32-240c0-8.8 7.2-16 16-16l192 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-192 0c-8.8 0-16-7.2-16-16zm16 48l192 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-192 0c-8.8 0-16-7.2-16-16s7.2-16 16-16z"/></svg>
</div>
<h2>Buch Klasse N</h2>
<p>Die Lernhinhalte für die Klasse N gibt es auch als gedrucktes Buch. Es ist passend zum Online-Kurs ausgelegt.</p>
<div class="d-grid gap-2 d-md-block mb-5">
<a href="https://darcverlag.de/DARC-Amateurfunklehrgang-Klasse-N" class="btn btn-primary">Beim DARC-Verlag kaufen</a>
</div>
</div>
<div class="feature col">
<div class="feature-icon bg-primary bg-gradient">
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 640 512" width="48"><path d="M337.8 5.4C327-1.8 313-1.8 302.2 5.4L166.3 96 48 96C21.5 96 0 117.5 0 144L0 464c0 26.5 21.5 48 48 48l208 0 0-96c0-35.3 28.7-64 64-64s64 28.7 64 64l0 96 208 0c26.5 0 48-21.5 48-48l0-320c0-26.5-21.5-48-48-48L473.7 96 337.8 5.4zM96 192l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64c0-8.8 7.2-16 16-16zm400 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64zM96 320l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64c0-8.8 7.2-16 16-16zm400 16c0-8.8 7.2-16 16-16l32 0c8.8 0 16 7.2 16 16l0 64c0 8.8-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16l0-64zM232 176a88 88 0 1 1 176 0 88 88 0 1 1 -176 0zm88-48c-8.8 0-16 7.2-16 16l0 32c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-16 0 0-16c0-8.8-7.2-16-16-16z"/></svg>
</div>
<h2>Kurse vor Ort</h2>
<p>Einige unserer Ortsverbände bieten Präsenz- oder Onlinekurse mit erfahrenen Ausbildern an. Finde heraus, ob es einen für dich passenden Kurs bei dir in der Nähe gibt!</p>
<div class="d-grid gap-2 d-md-block mb-5">
<a href="kurse_vor_ort_karte.html" class="btn btn-primary">Präsenz</a>
<a href="kurse_vor_ort_liste.html" class="btn btn-primary">Online</a>
</div>
</div>
<div class="feature col">
<div class="feature-icon bg-primary bg-gradient">
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 448 512" width="48"><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512l388.6 0c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304l-91.4 0z"/></svg>
</div>
<h2>Ausbildungs&shy;paten</h2>
<p>Unsere Ausbildungspaten sind erfahrene Funkamateure, die dich gerne unterstützen. Sie können mit dir auch praktischen üben und nützliche Tipps für die Praxis geben.</p>
<div class="d-grid gap-2 d-md-block mb-5">
<a href="patenkarte.html" class="btn btn-primary">Zur Patenkarte</a>
</div>
</div>
<div class="feature col">
<div class="feature-icon bg-primary bg-gradient">
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 384 512" width="48"><path d="M192 0c-41.8 0-77.4 26.7-90.5 64L64 64C28.7 64 0 92.7 0 128L0 448c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64l-37.5 0C269.4 26.7 233.8 0 192 0zm0 64a32 32 0 1 1 0 64 32 32 0 1 1 0-64zM105.8 229.3c7.9-22.3 29.1-37.3 52.8-37.3l58.3 0c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L216 328.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24l0-13.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1l-58.3 0c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM160 416a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/></svg>
</div>
<h2>Fragenkatalog</h2>
<p>Den Fragenkatalog mit den amtlichen Prüfungsfragen gibt es digital bei der <a href="https://50ohm.de/fk">Bundesnetzagentur</a>. Beim DARC-Verlag kann man auch eine gedruckte Version bestellen.</p>
<div class="d-grid gap-2 d-md-block mb-5">
<a href="https://darcverlag.de/Fragenkatalog-Klasse-N" class="btn btn-primary">Beim DARC-Verlag kaufen</a>
</div>
</div>
<div class="feature col">
<div class="feature-icon bg-primary bg-gradient">
<svg xmlns="http://www.w3.org/2000/svg" height="48" viewBox="0 0 384 512" width="48"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M16 64C16 28.7 44.7 0 80 0L304 0c35.3 0 64 28.7 64 64l0 384c0 35.3-28.7 64-64 64L80 512c-35.3 0-64-28.7-64-64L16 64zM224 448a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zM304 64L80 64l0 320 224 0 0-320z"/></svg>
</div>
<h2>Trainings App</h2>
<p>Zum Trainieren der Fragen gibt es die 50Ohm App. Sie ist passend zum Online-Kurs ausgelegt.</p>
<div class="d-grid gap-2 d-md-block mb-5">
<a href="https://play.google.com/store/apps/details?id=de.darc.fuenfizigohm" class="btn btn-primary">Android</a>
<a href="https://apps.apple.com/de/app/50ohm/id6474642114" class="btn btn-primary">iOS</a>
</div>
</div>
</div>
</div>
<a rel="me" href="https://social.darc.de/@AJW"></a>
+53
View File
@@ -0,0 +1,53 @@
<div class="row flex-lg-row-reverse align-items-top g-5">
<div class="col-lg-7">
<iframe src="https://ajw.darc.de/lehrgangskarte/" width="100%" height="800px"></iframe>
</div>
<div class="col-lg-5">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="index.html">Home</a></li>
<li class="breadcrumb-item"><a href="lernen.html">Lernen</a></li>
<li class="breadcrumb-item active" aria-current="page">Kurse vor Ort</li>
</ol>
</nav>
<h1>Kurse vor Ort</h1>
<p>Erfahrene Ausbilder halten &ndash; meist einmal in der Woche abends &ndash; Lektionen. Zwischen den Treffen solltest du selbständig den Lernstoff vertiefen und üben.</p>
<a class="btn btn-outline-secondary btn-sm px-4 gap-3" href="kurse_vor_ort_liste.html">Online-Kurse</a>
<hr class="col-md-12 mb-3">
<div><b>Ausbildungskurs</b></div>
<div class="d-grid gap-4 d-sm-flex mb-2 align-items-center">
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
<img src="https://ajw.darc.de/lehrgangskarte/img/Lehrgang-neu.png">
neu
</div>
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
<img src="https://ajw.darc.de/lehrgangskarte/img/Lehrgang-begonnen.png">
läuft
</div>
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
<img src="https://ajw.darc.de/lehrgangskarte/img/Lehrgang-jederzeit.png">
auf Anfrage
</div>
</div>
<div><b>Online-Kurs mit Präsenzanteil</b></div>
<div class="d-grid gap-4 d-sm-flex mb-2 align-items-center">
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
<img src="https://ajw.darc.de/lehrgangskarte/img/Online-neu.png">
neu
</div>
<div class="d-grid gap-2 d-sm-flex mb-2 align-items-center">
<img src="https://ajw.darc.de/lehrgangskarte/img/Online-begonnen.png">
läuft
</div>
</div>
</div>
</div>
+19
View File
@@ -0,0 +1,19 @@
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="index.html">Home</a></li>
<li class="breadcrumb-item"><a href="lernen.html">Lernen</a></li>
<li class="breadcrumb-item active" aria-current="page">Kurse vor Ort</li>
</ol>
</nav>
<h1>Kurse vor Ort</h1>
<p>Erfahrene Ausbilder halten &ndash; meist einmal in der Woche abends &ndash; Lektionen. Zwischen den Treffen solltest du selbständig den Lernstoff vertiefen und üben.</p>
<a class="btn btn-outline-secondary btn-sm px-4 gap-3" href="kurse_vor_ort_karte.html">Kartenansicht</a>
<hr class="col-md-12 mb-3">
<script src="https://darc.de/fileadmin/config/Resources/Public/JavaScript/tx_t3jquery/jquery-1.8.x-1.9.x-1.2.x.js?1619439474" type="text/javascript"></script>
<script id="onlinekurse" type="text/javascript" src="https://ajw.darc.de/lehrgangskarte/onlinelehrgaenge.js"></script>
+14 -3
View File
@@ -104,9 +104,20 @@
</div> </div>
{% endif %} {% endif %}
<div class="course"> {% if sidebar == None %}
{{ content }} {% if course_wrapper == True %}
</div> <div class="course">
{{ content }}
</div>
{% else %}
{{ content }}
{% endif %}
{% else %}
<div class="fiftyohm-content-2cols">
<div>{{ content }}</div>
<div>{{ sidebar }}</div>
</div>
{% endif %}
<footer class="text-lg-start border-top border-dark mt-5 pt-3"> <footer class="text-lg-start border-top border-dark mt-5 pt-3">
<div class="d-flex flex-wrap justify-content-between gap-5 mb-5"> <div class="d-flex flex-wrap justify-content-between gap-5 mb-5">
+19
View File
@@ -0,0 +1,19 @@
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="index.html">Home</a></li>
<li class="breadcrumb-item"><a href="lernen.html">Lernen</a></li>
<li class="breadcrumb-item active" aria-current="page">Ausbildungspaten</li>
</ol>
</nav>
<div class="row flex-lg-row-reverse align-items-top g-5 py-1">
<div class="col-lg-7">
<iframe src="https://ajw.darc.de/patenkarte/" width="100%" height="800px"></iframe>
</div>
<div class="col-lg-5">
<h1>Ausbildungspaten</h1>
<p>Die DARC-Ausbildungspaten sind erfahrene Funkamateure und helfen dir gerne beim Einstieg in den Amateurfunk. Sie beantworten Fragen, Helfen beim Lernen und können mit dir praktischen Ausbildungsfunk machen.</p>
</div>
</div>