diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d83fbc1..970babe 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,6 +24,16 @@ repos: - id: ruff args: ["--fix", "--show-fixes"] +- repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.36.0 + hooks: + - id: check-jsonschema + name: Validate jobs YAML (schema) + args: + - "--schemafile" + - "data/jobs/schema.json" + files: "^data/jobs/.*\\.ya?ml$" + exclude: "^data/jobs/_TEMPLATE\\.ya?ml$" # Spelling errors and typos - repo: https://github.com/codespell-project/codespell diff --git a/assets/css/overrides.css b/assets/css/overrides.css index e2ae56a..bf2e17e 100644 --- a/assets/css/overrides.css +++ b/assets/css/overrides.css @@ -44,3 +44,48 @@ content-container class */ .news-container, .hero-container { width: 100%; } + +/* Admonitions: minor accessibility tweaks */ +.adm { opacity: 1; } +.adm a { text-decoration: underline; } + +@media (prefers-color-scheme: dark) { + /* prefer specificity over !important to avoid fighting the theme */ + .article .adm, .article .adm *, + .content .adm, .content .adm *, + .markdown .adm, .markdown .adm * { + color: var(--text, #f1f5f9); + } + .adm a { color: var(--primary, #9ae6b4); } + .adm { background: var(--surface-2, rgba(255,255,255,0.06)); } +} + +/* Jobs board styles, scoped */ +.jobs-board .job-card { + border: 1px solid var(--border, rgba(0,0,0,0.15)); + padding: 1rem; + border-radius: 6px; + margin: 1rem 0; + background: var(--surface, transparent); +} +.jobs-board .job-card__header { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; } +.jobs-board .job-card__title { margin: 0; font-size: 1.15rem; } +.jobs-board .job-card__entity { color: var(--text-muted, inherit); font-weight: 600; } +.jobs-board .job-card__meta, .jobs-board .job-card__dates { display: flex; flex-wrap: wrap; gap: .5rem .5rem; margin: .5rem 0; } +.jobs-board .job-badge { + display: inline-flex; + align-items: center; + background: var(--surface-2, rgba(0,0,0,0.04)); + border: 1px solid var(--border, rgba(0,0,0,0.15)); + padding: .15rem .4rem; + border-radius: 999px; + font-size: .85rem; + color: var(--text, inherit); + margin-right: .5rem; + margin-bottom: .5rem; +} +.jobs-board .job-card__dates span { margin-right: .75rem; } +.jobs-board .job-card__description { margin: .5rem 0; color: inherit; line-height: 1.55; } +.jobs-board .job-card__description ul, .jobs-board .job-card__description ol { margin: .5rem 0 .5rem 1.25rem; } +.jobs-board .job-card__apply .button { display: inline-block; } +.jobs-board .job-card--archived { opacity: .85; } diff --git a/config.yaml b/config.yaml index aa8a39d..7b59da8 100644 --- a/config.yaml +++ b/config.yaml @@ -4,10 +4,11 @@ title: "PyBaMM" # site title theme: scientific-python-hugo-theme relativeURLs: true DefaultContentLanguage: en -disableKinds: ["term", "taxonomy"] +disableKinds: ["term", "taxonomy", "404"] enableEmoji: true enableInlineShortcodes: true + markup: highlight: noClasses: true diff --git a/content/jobs.md b/content/jobs.md index 2f1ffbe..e920bd9 100644 --- a/content/jobs.md +++ b/content/jobs.md @@ -4,34 +4,13 @@ shortcutDepth: 0 summary: "Current job openings related to PyBaMM and battery modeling" --- -Welcome to the PyBaMM Jobs Board! Here you can find current job openings related to PyBaMM and battery modeling. If you're interested in contributing to the future of battery simulation and modeling, check out the opportunities below. +Welcome to the PyBaMM Jobs Board! Here you can find current job openings related to PyBaMM and battery modeling. -### Ionworks Open Position - -**Location:** Remote (US- or UK-based) -
-**Type:** Full-time - -Ionworks is always interested in connecting with talented individuals in the field of battery modeling and simulation. While we may not have specific positions open at the moment, we welcome expressions of interest from potential candidates who are passionate about advancing battery technology. - -**Areas of Interest:** - -- Battery modeling and simulation -- Software development for scientific applications - -**Ideal Background:** - -- Advanced degree (Masters or higher) in a relevant field (e.g., Chemical Engineering, Applied Mathematics, Physics) -- Experience with battery modeling software, preferably including PyBaMM -- Proficiency in Python programming -- Strong analytical and problem-solving skills -- Excellent communication and collaboration abilities - -If you're excited about the prospect of contributing to cutting-edge battery simulation projects and shaping the future of energy storage technology, we encourage you to reach out. Your expression of interest will be kept on file for future opportunities that may arise. +{{< admonition tip >}} +To post a job, open a PR adding a file under data/jobs/ using the template at data/jobs/_TEMPLATE.yaml. See instructions below. +{{< /admonition >}} -
- Express Interest -
+{{< jobs-list >}} --- @@ -48,13 +27,11 @@ Do you have an open position in battery modeling or simulation? By posting in th - Increase visibility within the PyBaMM community and broader battery modeling ecosystem - Support the open-source PyBaMM project and its community -Jobs can be posted by companies, research institutions, or individuals looking to hire for positions related to battery modeling and simulation. All fees collected for job postings will be used to support the development and maintenance of PyBaMM. +Jobs can be posted by companies, research institutions, or individuals looking to hire for positions related to battery modeling and simulation. ### How to Post a Job -1. [Email us](mailto:pybamm@pybamm.org) the job description (preferably as an editable document) or open a pull request adding your post. -2. Make the payment through [this link](https://app.hubspot.com/payments/purchase/hscs_lIGxEAJy1ZF1nSDuOswBBtgYJ2lqdM7yi40DttGAC8TMh9c8BUIptnqJAYMmllfq). -3. Optionally, add a **suggested donation** to further support PyBaMM’s mission. +To propose a listing, open a pull request adding a YAML file under data/jobs/ using data/jobs/_TEMPLATE.yaml. Submissions are validated automatically. {{< admonition important >}} For details, please review our [Terms & Conditions](/jobs-t-and-c/). diff --git a/data/jobs/_TEMPLATE.yaml b/data/jobs/_TEMPLATE.yaml new file mode 100644 index 0000000..825eef3 --- /dev/null +++ b/data/jobs/_TEMPLATE.yaml @@ -0,0 +1,28 @@ +# Job posting template for the PyBaMM jobs board. +# Copy this file to a new name (e.g. acme-battery-modeler-20250315.yaml) and fill it in. +# Required keys: entity, title, url, percentTime, percentOSS, deadline, expires, location, description +# Notes: dates = YYYY-MM-DD; url starts with http(s); percentTime 1–100; percentOSS 0–100. + +entity: Your Organisation +title: Battery Modeling Engineer (PyBaMM) +url: https://www.example.com/careers/battery-modeling-engineer +percentTime: 100 +percentOSS: 50 +deadline: 2026-01-31 +expires: 2026-02-28 +location: Remote (UTC±2 preferred) +tags: [full-time, PyBaMM, Python] +# author_date: 2025-12-01 + +description: | + One or two short paragraphs describing the role and team. + + Responsibilities: + - Build, validate, and maintain physics-based battery models with PyBaMM + - Parameterise models, run studies, and analyse results + - Collaborate with the open-source community where appropriate + + Requirements: + - Strong Python and numerical methods + - Experience with physics-based battery modeling or electrochemistry + - Clear communication and collaboration diff --git a/data/jobs/example-company-battery-modeler-20251222.yaml b/data/jobs/example-company-battery-modeler-20251222.yaml new file mode 100644 index 0000000..5e41bee --- /dev/null +++ b/data/jobs/example-company-battery-modeler-20251222.yaml @@ -0,0 +1,22 @@ +entity: Ionworks +title: Battery Modeling Engineer (PyBaMM) +url: https://www.ionworks.com/ +percentTime: 100 +percentOSS: 50 +deadline: 2026-01-31 +expires: 2026-02-28 +location: Remote (UK/EU time zones preferred) +tags: [full-time, modeling, PyBaMM, Python] +description: | + Ionworks is looking for a Battery Modeling Engineer to build and deploy + physics-based battery models using PyBaMM for clients across industry and academia. + + Responsibilities: + - Develop, validate, and maintain battery models using PyBaMM + - Parameterise models, run simulations, and analyse results for production use + - Collaborate with open-source maintainers and contribute improvements back to PyBaMM where appropriate + + Requirements: + - Strong Python experience and familiarity with numerical methods + - Experience with physics-based battery modelling and scientific computing + - Excellent communication and collaboration skills diff --git a/data/jobs/schema.json b/data/jobs/schema.json new file mode 100644 index 0000000..1b86246 --- /dev/null +++ b/data/jobs/schema.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "PyBaMM Jobs Board Posting", + "type": "object", + "additionalProperties": false, + "required": [ + "entity", + "title", + "url", + "percentTime", + "percentOSS", + "deadline", + "expires", + "location", + "description" + ], + "properties": { + "entity": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "url": { + "type": "string", + "minLength": 1, + "pattern": "^https?://" + }, + "percentTime": { + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "percentOSS": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "deadline": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" + }, + "expires": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" + }, + "author_date": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" + }, + "location": { + "type": "string", + "minLength": 1 + }, + "tags": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + }, + "description": { + "type": "string", + "minLength": 1 + } + } +} diff --git a/layouts/partials/jobs/card.html b/layouts/partials/jobs/card.html new file mode 100644 index 0000000..87c6692 --- /dev/null +++ b/layouts/partials/jobs/card.html @@ -0,0 +1,54 @@ +{{/* Renders a single job using theme shortcodes (card, badge, button). Expects dict with keys: job, now */}} +{{- $job := .job -}} +{{- $now := .now -}} +{{- $open := or (not $job.expires) (ge (time $job.expires) $now) -}} + +{{- $scratch := newScratch -}} + +{{/* Build badges using theme badge shortcode */}} +{{- with $job.location -}} + {{- $scratch.Add "badges" (printf "{{< badge secondary >}}%s{{< /badge >}} " .) -}} +{{- end -}} +{{- with $job.percentTime -}} + {{- $scratch.Add "badges" (printf "{{< badge primary >}}%d%% time{{< /badge >}} " .) -}} +{{- end -}} +{{- with $job.percentOSS -}} + {{- $scratch.Add "badges" (printf "{{< badge success >}}%d%% OSS{{< /badge >}} " .) -}} +{{- end -}} +{{- with $job.tags -}} + {{- range . -}} + {{- $scratch.Add "badges" (printf "{{< badge muted >}}%s{{< /badge >}} " .) -}} + {{- end -}} +{{- end -}} +{{- $badges := $scratch.Get "badges" | default "" -}} + +{{/* Dates summary */}} +{{- $dates := "" -}} +{{- with $job.deadline -}} + {{- $dates = printf "%s\n- Deadline: %s" $dates . -}} +{{- end -}} +{{- with $job.expires -}} + {{- $dates = printf "%s\n- Visible until: %s" $dates . -}} +{{- end -}} + +{{/* Optional apply button */}} +{{- $apply := "" -}} +{{- with $job.url -}} + {{- $apply = printf "\n\n{{< button style=\"primary\" label=\"Apply / Learn more\" link=\"%s\" >}}" . -}} +{{- end -}} + +{{/* Card class for archived */}} +{{- $classcard := "" -}} +{{- if not $open -}} + {{- $classcard = "sd-opacity-75" -}} +{{- end -}} + +{{- $body := printf "%s\n\n%s\n\n%s%s" ($job.entity | default "") $badges ($job.description | default "") $apply -}} +{{- $card := printf "{{< card >}}\n%s\n%s\n%s\n%s\n{{< /card >}}" + (printf "title = '%s'" ($job.title | default "")) + (cond (ne $classcard "") (printf "classcard = '%s'" $classcard) "") + (printf "body = '''\n%s\n%s\n'''" ($body | replaceRE "'" "\\'")) + (cond (and $job.url (ne $job.url "")) (printf "link = '%s'" $job.url) "") +-}} + +{{ .Page.RenderString $card }} diff --git a/layouts/partials/jobs/list.html b/layouts/partials/jobs/list.html new file mode 100644 index 0000000..a990be7 --- /dev/null +++ b/layouts/partials/jobs/list.html @@ -0,0 +1,56 @@ +{{/* +Lists jobs from data/jobs. Splits into open and archived by expires date. +Sorts open by deadline asc; archived by expires desc. +*/}} +{{- $now := now -}} +{{- $jobs := slice -}} + +{{/* Load YAML job postings directly from data/jobs */}} +{{- range (readDir "data/jobs") -}} + {{- if and (not .IsDir) (or (hasSuffix .Name ".yaml") (hasSuffix .Name ".yml")) (ne .Name "_TEMPLATE.yaml") (ne .Name "schema.json") -}} + {{- $path := printf "data/jobs/%s" .Name -}} + {{- $data := (readFile $path | transform.Unmarshal) -}} + {{- $key := replaceRE "\\.(yaml|yml)$" "" .Name -}} + {{- $job := (dict "key" $key) | merge $data -}} + {{- $jobs = $jobs | append $job -}} + {{- end -}} +{{- end -}} + +{{/* partition */}} +{{- $open := slice -}} +{{- $archived := slice -}} +{{- range $jobs -}} + {{- $exp := .expires -}} + {{- if or (not $exp) (ge (time $exp) $now) -}} + {{- $open = $open | append . -}} + {{- else -}} + {{- $archived = $archived | append . -}} + {{- end -}} +{{- end -}} + +{{- $sortedOpen := sort $open "deadline" "asc" -}} + +

Open roles

+{{- if gt (len $sortedOpen) 0 -}} + {{- range $sortedOpen -}} + {{ partial "jobs/card.html" (dict "job" . "now" $now) }} + {{- end -}} +{{- else -}} +

No open roles at the moment.

+{{- end -}} + +
+ +{{- $sortedArchived := sort $archived "expires" "desc" -}} +{{- $body := "" -}} +{{- if gt (len $sortedArchived) 0 -}} + {{- $scratch := newScratch -}} + {{- range $sortedArchived -}} + {{- $scratch.Add "html" (partial "jobs/card.html" (dict "job" . "now" $now)) -}} + {{- end -}} + {{- $body = $scratch.Get "html" -}} +{{- else -}} + {{- $body = "

No archived roles yet.

" -}} +{{- end -}} +{{- $md := printf "{{< details \"%s\" >}}\n%s\n{{< /details >}}" "Archived roles" $body -}} +{{ .Page.RenderString $md }} diff --git a/layouts/shortcodes/jobs-list.html b/layouts/shortcodes/jobs-list.html new file mode 100644 index 0000000..305214f --- /dev/null +++ b/layouts/shortcodes/jobs-list.html @@ -0,0 +1,4 @@ +{{/* Shortcode to render the jobs list from data/jobs */}} +
+ {{ partial "jobs/list.html" . }} +