From 2be144c37876b63e78c0a1b666ca24c5ce258144 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Thu, 30 Jan 2025 20:05:16 -0800 Subject: [PATCH 01/12] Initial outline with some page content --- __main__.py | 49 ++++++++++++++++++++++++++++++++++++ page_content/404.md | 1 + page_content/bio.md | 1 + page_content/home.md | 19 ++++++++++++++ page_content/portfolio.md | 32 ++++++++++++++++++++++++ page_content/resume.md | 52 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 154 insertions(+) create mode 100644 __main__.py create mode 100644 page_content/404.md create mode 100644 page_content/bio.md create mode 100644 page_content/home.md create mode 100644 page_content/portfolio.md create mode 100644 page_content/resume.md diff --git a/__main__.py b/__main__.py new file mode 100644 index 0000000..0fd2605 --- /dev/null +++ b/__main__.py @@ -0,0 +1,49 @@ +from os.path import abspath, isfile + +from nicegui import ui + +_tab_to_content = { + "Home": "page_content/home.md", + "Portfolio": "page_content/portfolio.md", + "Resume": "page_content/resume.md", + "Bio": "page_content/bio.md" +} + +_error_page = "page_content/404.md" + +def _get_content_from_file(file_name: str) -> str: + """ + Take a file name/path and return its contents + :param file_name: Relative or absolute path to a file + """ + if not isfile(abspath(file_name)): + file_name = _error_page + with open(abspath(file_name), 'r') as f: + return f.read() + +def render_tab(tab_name: str): + file_name = _tab_to_content.get(tab_name, _error_page) + ui.markdown(_get_content_from_file(file_name)) + + +def render_header() -> ui.tab_panels: + """ + Render sticky page header with navigation + """ + tab_names = _tab_to_content.keys() + with ui.tabs().classes('w-full') as tabs: + tab_list = [ui.tab(name) for name in tab_names] + with ui.tab_panels(tabs).classes('w-full') as header: + for t in tab_list: + with ui.tab_panel(t): + render_tab(t._props['name']) + return header + +def main(): + header = render_header() + header.set_value(list(_tab_to_content.keys())[0]) + ui.run(dark=None) + + +if __name__ in ("__main__", "__mp_main__"): + main() diff --git a/page_content/404.md b/page_content/404.md new file mode 100644 index 0000000..debde83 --- /dev/null +++ b/page_content/404.md @@ -0,0 +1 @@ +Oops. This content hasn't been written yet... \ No newline at end of file diff --git a/page_content/bio.md b/page_content/bio.md new file mode 100644 index 0000000..f7aa4fc --- /dev/null +++ b/page_content/bio.md @@ -0,0 +1 @@ +## Hi! diff --git a/page_content/home.md b/page_content/home.md new file mode 100644 index 0000000..75c009f --- /dev/null +++ b/page_content/home.md @@ -0,0 +1,19 @@ +# McKnight Technology Services + +Hi! This is some text + +## h2 Title +Lorem ipsum... + +> This is a quote + +### Shell +```shell +ls / +``` + +### Python +```python +for i in range(42): + print(i) +``` diff --git a/page_content/portfolio.md b/page_content/portfolio.md new file mode 100644 index 0000000..344cf9c --- /dev/null +++ b/page_content/portfolio.md @@ -0,0 +1,32 @@ +# Project Portfolio +I have developed and contributed to hundreds of open source repositories on GitHub (as well as some Private ones that +I cannot share here). This is just a selection of some of my favorite projects and what I like about them. + +## `neon-data-models` +This repository contains barely any functional code, but it was an exercise in careful planning. +It is structured into a logical hierarchy with documentation and unit tests. +This project was not fully integrated to the extent I planned, but it proved invaluable in defining/validating +messages sent between modules. The use of Pydantic also means that validator methods can be used to adapt an old-style +input into a new one when an API changes. + +## `neon-users-service` +This project defines a service for managing a user database with a flexible backend; initially, it supports SQLite for +a standalone system (and easy development/testing) and MongoDb, which is what we used for production at NeonGecko. +I implemented a very simple CRUD (Create/Read/Update/Delete) design, with RBAC (Role-Based Access Controls) to enable +easy integration with applications. The design enables the service to be easily adapted to any user database and to +allow other services to easily operate on user entries (with the proper permissions, of course). + +## `neon-hana` +This is primarily a RESTful API used to access other services. This is one of the more complex FastAPI applications +I have written; it implements JWT authentication and Pydantic models to validate requests/responses. + +## `neon-diana` +This isn't the prettiest project, but it is my first foray into writing Helm charts. The module provides some +developer-oriented CLI tools for generating Helm charts to deploy the same services NeonGecko uses in production +systems. + +## `neon-docs` +Just what it says, this is all documentation. + +## This Site +I fully defined this site using [nicegui](https://nicegui.io/)! diff --git a/page_content/resume.md b/page_content/resume.md new file mode 100644 index 0000000..21219bf --- /dev/null +++ b/page_content/resume.md @@ -0,0 +1,52 @@ +## Work Experience +### Neon Gecko Inc. +Software Developer, Developer Relations Manager, Lead Hardware Developer + +December 2017 – Present. Responsibilities Include: +- Managing multiple projects and work from individual contributors, one-off contractors, and long-term contract workers +- Working with management and developers to develop roadmaps, set timelines, and spec projects +- Extensive Python programming +- Extensive GitOps and workflow design, automation, and management +- Being fluent in voice assistant concepts and technologies +- Having a strong understanding of LLM technologies and model fine-tuning +- Deploying and maintaining infrastructure with Kubernetes, XCP-ng, and various cloud providers +- Kotlin for Android app development and Google Play Store publication +### Best Buy/Geek Squad +Consultation Agent, Sales Associate + +November 2015 - December 2017 +- Experience with Windows and Mac system administration, troubleshooting, and repair + +## Projects +- Professional open-source work can be found at: https://github.com/neondaniel +- Documentation I wrote for much of my professional work: https://neongeckocom.github.io/neon-docs/ +- A selection of small projects are documented on my blog: https://blog.mcknight.tech/ + +## Technologies +### Languages +- Python +- SQL +- MongoDb +- Kotlin +### Frameworks +- Git and GitHub +- FastAPI +- SocketIO +- Sentry +- Kubernetes + +## Education +### University of Washington +Bachelor of Science in Physics, June 2018 + +Secretary, Physics Club at UW Bothell + +### Bellevue College +Associate of Science in Engineering, June 2016 + +Member, Phi Theta Kappa Honors Society + +### Mercer Island High School +High School Diploma, June 2012 + +Recipient, Washington State Honors Award -- 2.45.2 From 53895b6f65e8bdb912ddaf6d283c7d86ad5646d2 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Thu, 30 Jan 2025 21:15:57 -0800 Subject: [PATCH 02/12] Refactor into module Add Dockerfile with kluges Update portfolio --- Dockerfile | 9 +++++++++ requirements.txt | 1 + site_mcknight_tech/__init__.py | 0 __main__.py => site_mcknight_tech/__main__.py | 17 +++++++++-------- .../page_content}/404.md | 0 .../page_content}/bio.md | 0 .../page_content}/home.md | 0 .../page_content}/portfolio.md | 18 ++++++++++++++++++ .../page_content}/resume.md | 0 9 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 Dockerfile create mode 100644 requirements.txt create mode 100644 site_mcknight_tech/__init__.py rename __main__.py => site_mcknight_tech/__main__.py (74%) mode change 100644 => 100755 rename {page_content => site_mcknight_tech/page_content}/404.md (100%) rename {page_content => site_mcknight_tech/page_content}/bio.md (100%) rename {page_content => site_mcknight_tech/page_content}/home.md (100%) rename {page_content => site_mcknight_tech/page_content}/portfolio.md (61%) rename {page_content => site_mcknight_tech/page_content}/resume.md (100%) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8cd58c4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.12-bookworm + +EXPOSE 8080 + +COPY site_mcknight_tech /site +COPY requirements.txt /tmp/requirements.txt +RUN pip install -r /tmp/requirements.txt + +ENTRYPOINT [ "python3", "/site/__main__.py" ] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..0d3d37e --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +nicegui~=2.10 \ No newline at end of file diff --git a/site_mcknight_tech/__init__.py b/site_mcknight_tech/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/__main__.py b/site_mcknight_tech/__main__.py old mode 100644 new mode 100755 similarity index 74% rename from __main__.py rename to site_mcknight_tech/__main__.py index 0fd2605..c223fd7 --- a/__main__.py +++ b/site_mcknight_tech/__main__.py @@ -1,5 +1,6 @@ -from os.path import abspath, isfile +# Copyright (C) 2025 Daniel McKnight - All Rights Reserved +from os.path import isfile, join, dirname from nicegui import ui _tab_to_content = { @@ -16,9 +17,10 @@ def _get_content_from_file(file_name: str) -> str: Take a file name/path and return its contents :param file_name: Relative or absolute path to a file """ - if not isfile(abspath(file_name)): + file_name = join(dirname(__file__), file_name) + if not isfile(file_name): file_name = _error_page - with open(abspath(file_name), 'r') as f: + with open(file_name, 'r') as f: return f.read() def render_tab(tab_name: str): @@ -32,11 +34,11 @@ def render_header() -> ui.tab_panels: """ tab_names = _tab_to_content.keys() with ui.tabs().classes('w-full') as tabs: - tab_list = [ui.tab(name) for name in tab_names] + tab_list = {name: ui.tab(name) for name in tab_names} with ui.tab_panels(tabs).classes('w-full') as header: - for t in tab_list: + for name, t in tab_list.items(): with ui.tab_panel(t): - render_tab(t._props['name']) + render_tab(name) return header def main(): @@ -45,5 +47,4 @@ def main(): ui.run(dark=None) -if __name__ in ("__main__", "__mp_main__"): - main() +main() diff --git a/page_content/404.md b/site_mcknight_tech/page_content/404.md similarity index 100% rename from page_content/404.md rename to site_mcknight_tech/page_content/404.md diff --git a/page_content/bio.md b/site_mcknight_tech/page_content/bio.md similarity index 100% rename from page_content/bio.md rename to site_mcknight_tech/page_content/bio.md diff --git a/page_content/home.md b/site_mcknight_tech/page_content/home.md similarity index 100% rename from page_content/home.md rename to site_mcknight_tech/page_content/home.md diff --git a/page_content/portfolio.md b/site_mcknight_tech/page_content/portfolio.md similarity index 61% rename from page_content/portfolio.md rename to site_mcknight_tech/page_content/portfolio.md index 344cf9c..4e37062 100644 --- a/page_content/portfolio.md +++ b/site_mcknight_tech/page_content/portfolio.md @@ -2,6 +2,13 @@ I have developed and contributed to hundreds of open source repositories on GitHub (as well as some Private ones that I cannot share here). This is just a selection of some of my favorite projects and what I like about them. +## Neon Core +This is the primary project I contributed to as part of my work at NeonGecko. It started as work with the (now defunct) +open source Mycroft AI project, turned into a proprietary fork, and then we ended up open sourcing that fork. Working on +this project, I learned a lot about contributing to open source and managing open source projects. At the start, I learned +how to be a helpful individual contributor, and later I was on the other side, learning how to interface with the community +to balance internal goals with community feedback. + ## `neon-data-models` This repository contains barely any functional code, but it was an exercise in careful planning. It is structured into a logical hierarchy with documentation and unit tests. @@ -25,6 +32,17 @@ This isn't the prettiest project, but it is my first foray into writing Helm cha developer-oriented CLI tools for generating Helm charts to deploy the same services NeonGecko uses in production systems. +## `neon-debos` +This project was my first foray into Go templates. It started as a fork of another similar project which I adapted to +our needs. As part of this project, I used squashfs/overlayfs to enable safe OS updates with methods to roll-back or +reset an installation in case of any errors. To support this, I compiled custom kernels and implemented a customized +initramfs. + +## `.github` +This repository contains a number of shared GitHub Actions, in addition to the standard issue templates and other special +files GitHub supports here. Creating this repository was part of an effort to consolidate code and make sprawling +repositories more manageable. + ## `neon-docs` Just what it says, this is all documentation. diff --git a/page_content/resume.md b/site_mcknight_tech/page_content/resume.md similarity index 100% rename from page_content/resume.md rename to site_mcknight_tech/page_content/resume.md -- 2.45.2 From 8ccdde5cb127a5cb2261c205860248f46198e2a6 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Thu, 30 Jan 2025 21:34:55 -0800 Subject: [PATCH 03/12] Fix list formatting --- site_mcknight_tech/__main__.py | 2 +- site_mcknight_tech/page_content/resume.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/site_mcknight_tech/__main__.py b/site_mcknight_tech/__main__.py index c223fd7..6a76388 100755 --- a/site_mcknight_tech/__main__.py +++ b/site_mcknight_tech/__main__.py @@ -25,7 +25,7 @@ def _get_content_from_file(file_name: str) -> str: def render_tab(tab_name: str): file_name = _tab_to_content.get(tab_name, _error_page) - ui.markdown(_get_content_from_file(file_name)) + ui.markdown(_get_content_from_file(file_name), extras=['cuddled-lists', 'fenced-code-blocks', 'tables']) def render_header() -> ui.tab_panels: diff --git a/site_mcknight_tech/page_content/resume.md b/site_mcknight_tech/page_content/resume.md index 21219bf..d03694f 100644 --- a/site_mcknight_tech/page_content/resume.md +++ b/site_mcknight_tech/page_content/resume.md @@ -3,6 +3,7 @@ Software Developer, Developer Relations Manager, Lead Hardware Developer December 2017 – Present. Responsibilities Include: + - Managing multiple projects and work from individual contributors, one-off contractors, and long-term contract workers - Working with management and developers to develop roadmaps, set timelines, and spec projects - Extensive Python programming @@ -11,10 +12,12 @@ December 2017 – Present. Responsibilities Include: - Having a strong understanding of LLM technologies and model fine-tuning - Deploying and maintaining infrastructure with Kubernetes, XCP-ng, and various cloud providers - Kotlin for Android app development and Google Play Store publication + ### Best Buy/Geek Squad Consultation Agent, Sales Associate November 2015 - December 2017 + - Experience with Windows and Mac system administration, troubleshooting, and repair ## Projects @@ -28,6 +31,7 @@ November 2015 - December 2017 - SQL - MongoDb - Kotlin + ### Frameworks - Git and GitHub - FastAPI -- 2.45.2 From b8d712e19d0ff9e9fd671157838b98fa2e2a8d98 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Fri, 31 Jan 2025 21:26:45 -0800 Subject: [PATCH 04/12] Implement setup.py Update entrypoints --- Dockerfile | 7 +++---- setup.py | 27 +++++++++++++++++++++++++++ site_mcknight_tech/__main__.py | 5 +---- 3 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 setup.py diff --git a/Dockerfile b/Dockerfile index 8cd58c4..9bc1645 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,8 +2,7 @@ FROM python:3.12-bookworm EXPOSE 8080 -COPY site_mcknight_tech /site -COPY requirements.txt /tmp/requirements.txt -RUN pip install -r /tmp/requirements.txt +COPY . /site +RUN pip install /site -ENTRYPOINT [ "python3", "/site/__main__.py" ] +ENTRYPOINT [ "launch-site" ] diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..fa54a3f --- /dev/null +++ b/setup.py @@ -0,0 +1,27 @@ +# Copyright (C) 2025 Daniel McKnight - All Rights Reserved +from os.path import join, dirname + +from setuptools import setup, find_packages + + +def get_requirements(requirements_filename: str): + requirements_file = join(dirname(__file__), requirements_filename) + with open(requirements_file, 'r', encoding='utf-8') as r: + requirements = r.readlines() + requirements = [r.strip() for r in requirements if r.strip() + and not r.strip().startswith("#")] + return requirements + +setup( + name="site-mcknight-tech", + author="Daniel McKnight", + author_email="daniel@mcknight.tech", + description="McKnight Tech Website", + packages=find_packages(), + include_package_data=True, + package_data={"site_mcknight_tech": ["page_content/*"]}, + install_requires=get_requirements("requirements.txt"), + entry_points={ + "console_scripts": ['launch-site=site_mcknight_tech.__main__:main'] + } +) \ No newline at end of file diff --git a/site_mcknight_tech/__main__.py b/site_mcknight_tech/__main__.py index 6a76388..61c1675 100755 --- a/site_mcknight_tech/__main__.py +++ b/site_mcknight_tech/__main__.py @@ -44,7 +44,4 @@ def render_header() -> ui.tab_panels: def main(): header = render_header() header.set_value(list(_tab_to_content.keys())[0]) - ui.run(dark=None) - - -main() + ui.run(dark=None, reload=False) -- 2.45.2 From f4aaf13c17228ab204301cb8bc4ea603b2ca184e Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Fri, 31 Jan 2025 22:28:45 -0800 Subject: [PATCH 05/12] Update title and content --- site_mcknight_tech/__main__.py | 2 +- site_mcknight_tech/page_content/home.md | 21 +++----------------- site_mcknight_tech/page_content/portfolio.md | 6 +++--- site_mcknight_tech/page_content/resume.md | 5 ----- 4 files changed, 7 insertions(+), 27 deletions(-) diff --git a/site_mcknight_tech/__main__.py b/site_mcknight_tech/__main__.py index 61c1675..85c85fe 100755 --- a/site_mcknight_tech/__main__.py +++ b/site_mcknight_tech/__main__.py @@ -44,4 +44,4 @@ def render_header() -> ui.tab_panels: def main(): header = render_header() header.set_value(list(_tab_to_content.keys())[0]) - ui.run(dark=None, reload=False) + ui.run(dark=None, reload=False, title="Daniel McKnight") diff --git a/site_mcknight_tech/page_content/home.md b/site_mcknight_tech/page_content/home.md index 75c009f..2a6e145 100644 --- a/site_mcknight_tech/page_content/home.md +++ b/site_mcknight_tech/page_content/home.md @@ -1,19 +1,4 @@ -# McKnight Technology Services +# Daniel McKnight +## Coder, Sysadmin, Manager -Hi! This is some text - -## h2 Title -Lorem ipsum... - -> This is a quote - -### Shell -```shell -ls / -``` - -### Python -```python -for i in range(42): - print(i) -``` +I work in the design and implementation of voice assistants, LLMs, infrastructure, and plenty more. diff --git a/site_mcknight_tech/page_content/portfolio.md b/site_mcknight_tech/page_content/portfolio.md index 4e37062..5a42ab8 100644 --- a/site_mcknight_tech/page_content/portfolio.md +++ b/site_mcknight_tech/page_content/portfolio.md @@ -3,7 +3,7 @@ I have developed and contributed to hundreds of open source repositories on GitH I cannot share here). This is just a selection of some of my favorite projects and what I like about them. ## Neon Core -This is the primary project I contributed to as part of my work at NeonGecko. It started as work with the (now defunct) +This is the primary project I contribute to as part of my work at NeonGecko. It started as work with the (now defunct) open source Mycroft AI project, turned into a proprietary fork, and then we ended up open sourcing that fork. Working on this project, I learned a lot about contributing to open source and managing open source projects. At the start, I learned how to be a helpful individual contributor, and later I was on the other side, learning how to interface with the community @@ -33,8 +33,8 @@ developer-oriented CLI tools for generating Helm charts to deploy the same servi systems. ## `neon-debos` -This project was my first foray into Go templates. It started as a fork of another similar project which I adapted to -our needs. As part of this project, I used squashfs/overlayfs to enable safe OS updates with methods to roll-back or +This project was my first exposure to Go templates. It started as a fork of another similar project which I adapted to +our needs. As part of this project, I used squashfs/overlayfs to enable safe OS updates with methods to roll back or reset an installation in case of any errors. To support this, I compiled custom kernels and implemented a customized initramfs. diff --git a/site_mcknight_tech/page_content/resume.md b/site_mcknight_tech/page_content/resume.md index d03694f..bf1f847 100644 --- a/site_mcknight_tech/page_content/resume.md +++ b/site_mcknight_tech/page_content/resume.md @@ -20,11 +20,6 @@ November 2015 - December 2017 - Experience with Windows and Mac system administration, troubleshooting, and repair -## Projects -- Professional open-source work can be found at: https://github.com/neondaniel -- Documentation I wrote for much of my professional work: https://neongeckocom.github.io/neon-docs/ -- A selection of small projects are documented on my blog: https://blog.mcknight.tech/ - ## Technologies ### Languages - Python -- 2.45.2 From ccaf5492ef13dc9a9fb6a35c506e44c386ad5c98 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Mon, 3 Feb 2025 20:23:30 -0800 Subject: [PATCH 06/12] Add links to project portfolio Add links to homepage --- site_mcknight_tech/page_content/home.md | 2 ++ site_mcknight_tech/page_content/portfolio.md | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/site_mcknight_tech/page_content/home.md b/site_mcknight_tech/page_content/home.md index 2a6e145..da71a32 100644 --- a/site_mcknight_tech/page_content/home.md +++ b/site_mcknight_tech/page_content/home.md @@ -2,3 +2,5 @@ ## Coder, Sysadmin, Manager I work in the design and implementation of voice assistants, LLMs, infrastructure, and plenty more. +I built this site using [NiceGUI](https://nicegui.io/), with the source code available +[on Forgejo](https://forge.mcknight.tech/d_mcknight/website-mcknight-tech). diff --git a/site_mcknight_tech/page_content/portfolio.md b/site_mcknight_tech/page_content/portfolio.md index 5a42ab8..9c5c828 100644 --- a/site_mcknight_tech/page_content/portfolio.md +++ b/site_mcknight_tech/page_content/portfolio.md @@ -2,49 +2,49 @@ I have developed and contributed to hundreds of open source repositories on GitHub (as well as some Private ones that I cannot share here). This is just a selection of some of my favorite projects and what I like about them. -## Neon Core +## [Neon Core](https://github.com/neongeckocom/NeonCore) This is the primary project I contribute to as part of my work at NeonGecko. It started as work with the (now defunct) open source Mycroft AI project, turned into a proprietary fork, and then we ended up open sourcing that fork. Working on this project, I learned a lot about contributing to open source and managing open source projects. At the start, I learned how to be a helpful individual contributor, and later I was on the other side, learning how to interface with the community to balance internal goals with community feedback. -## `neon-data-models` +## [`neon-data-models`](https://github.com/neongeckocom/neon-data-models) This repository contains barely any functional code, but it was an exercise in careful planning. It is structured into a logical hierarchy with documentation and unit tests. This project was not fully integrated to the extent I planned, but it proved invaluable in defining/validating messages sent between modules. The use of Pydantic also means that validator methods can be used to adapt an old-style input into a new one when an API changes. -## `neon-users-service` +## [`neon-users-service`](https://github.com/neongeckocom/neon-users-service) This project defines a service for managing a user database with a flexible backend; initially, it supports SQLite for a standalone system (and easy development/testing) and MongoDb, which is what we used for production at NeonGecko. I implemented a very simple CRUD (Create/Read/Update/Delete) design, with RBAC (Role-Based Access Controls) to enable easy integration with applications. The design enables the service to be easily adapted to any user database and to allow other services to easily operate on user entries (with the proper permissions, of course). -## `neon-hana` +## [`neon-hana`](https://github.com/neongeckocom/neon-hana) This is primarily a RESTful API used to access other services. This is one of the more complex FastAPI applications I have written; it implements JWT authentication and Pydantic models to validate requests/responses. -## `neon-diana` +## [`neon-diana`](https://github.com/neongeckocom/neon-diana-utils) This isn't the prettiest project, but it is my first foray into writing Helm charts. The module provides some developer-oriented CLI tools for generating Helm charts to deploy the same services NeonGecko uses in production systems. -## `neon-debos` +## [`neon-debos`](https://github.com/neongeckocom/neon_debos) This project was my first exposure to Go templates. It started as a fork of another similar project which I adapted to our needs. As part of this project, I used squashfs/overlayfs to enable safe OS updates with methods to roll back or reset an installation in case of any errors. To support this, I compiled custom kernels and implemented a customized initramfs. -## `.github` +## [`.github`](https://github.com/neongeckocom/.github) This repository contains a number of shared GitHub Actions, in addition to the standard issue templates and other special files GitHub supports here. Creating this repository was part of an effort to consolidate code and make sprawling repositories more manageable. -## `neon-docs` +## [`neon-docs`](https://neongeckocom.github.io/neon-docs/) Just what it says, this is all documentation. -## This Site -I fully defined this site using [nicegui](https://nicegui.io/)! +## [This Site](https://forge.mcknight.tech/d_mcknight/website-mcknight-tech) +I built this site using [nicegui](https://nicegui.io/)! -- 2.45.2 From 553b7bbc5f9c38d2d76bbce29f2da185376bca0b Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Mon, 3 Feb 2025 20:24:24 -0800 Subject: [PATCH 07/12] Define footer and update main content to fill height --- site_mcknight_tech/__main__.py | 18 ++++++++++++++---- site_mcknight_tech/page_content/footer.html | 3 +++ 2 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 site_mcknight_tech/page_content/footer.html diff --git a/site_mcknight_tech/__main__.py b/site_mcknight_tech/__main__.py index 85c85fe..cc51e6f 100755 --- a/site_mcknight_tech/__main__.py +++ b/site_mcknight_tech/__main__.py @@ -3,6 +3,7 @@ from os.path import isfile, join, dirname from nicegui import ui +# TODO: Read from configuration _tab_to_content = { "Home": "page_content/home.md", "Portfolio": "page_content/portfolio.md", @@ -11,6 +12,8 @@ _tab_to_content = { } _error_page = "page_content/404.md" +_footer_block = "page_content/footer.html" + def _get_content_from_file(file_name: str) -> str: """ @@ -25,23 +28,30 @@ def _get_content_from_file(file_name: str) -> str: def render_tab(tab_name: str): file_name = _tab_to_content.get(tab_name, _error_page) - ui.markdown(_get_content_from_file(file_name), extras=['cuddled-lists', 'fenced-code-blocks', 'tables']) + with ui.scroll_area().classes('w-full h-screen no-wrap'): + ui.markdown(_get_content_from_file(file_name), extras=['cuddled-lists', 'fenced-code-blocks', 'tables']) -def render_header() -> ui.tab_panels: +def render_main() -> ui.tab_panels: """ Render sticky page header with navigation """ tab_names = _tab_to_content.keys() with ui.tabs().classes('w-full') as tabs: tab_list = {name: ui.tab(name) for name in tab_names} - with ui.tab_panels(tabs).classes('w-full') as header: + with ui.tab_panels(tabs).classes('w-full h-screen no-wrap') as header: for name, t in tab_list.items(): with ui.tab_panel(t): render_tab(name) return header def main(): - header = render_header() + header = render_main() header.set_value(list(_tab_to_content.keys())[0]) + ui.query('.nicegui-content').classes('h-screen no-wrap') + ui.html(_get_content_from_file(_footer_block), tag="footer").classes("rounded-lg shadow-sm m-4 w-full text-center") ui.run(dark=None, reload=False, title="Daniel McKnight") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/site_mcknight_tech/page_content/footer.html b/site_mcknight_tech/page_content/footer.html new file mode 100644 index 0000000..e091239 --- /dev/null +++ b/site_mcknight_tech/page_content/footer.html @@ -0,0 +1,3 @@ + + © 2025 Daniel McKnight. All Rights Reserved. + -- 2.45.2 From 409ec5bd1d5d7829e5d13ba9532b9daba20d7e73 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 4 Feb 2025 20:41:41 -0800 Subject: [PATCH 08/12] Add social links to footer with CSS --- site_mcknight_tech/__main__.py | 16 ++++++- site_mcknight_tech/page_content/footer.html | 50 +++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/site_mcknight_tech/__main__.py b/site_mcknight_tech/__main__.py index cc51e6f..e67858f 100755 --- a/site_mcknight_tech/__main__.py +++ b/site_mcknight_tech/__main__.py @@ -26,10 +26,16 @@ def _get_content_from_file(file_name: str) -> str: with open(file_name, 'r') as f: return f.read() + def render_tab(tab_name: str): + """ + Render a simple webpage tab from a single file + :param tab_name: Tab name to render + """ file_name = _tab_to_content.get(tab_name, _error_page) with ui.scroll_area().classes('w-full h-screen no-wrap'): - ui.markdown(_get_content_from_file(file_name), extras=['cuddled-lists', 'fenced-code-blocks', 'tables']) + ui.markdown(_get_content_from_file(file_name), + extras=['cuddled-lists', 'fenced-code-blocks', 'tables']) def render_main() -> ui.tab_panels: @@ -50,6 +56,14 @@ def main(): header.set_value(list(_tab_to_content.keys())[0]) ui.query('.nicegui-content').classes('h-screen no-wrap') ui.html(_get_content_from_file(_footer_block), tag="footer").classes("rounded-lg shadow-sm m-4 w-full text-center") + ui.add_css(""" + .fa { + font-size: 30px; + text-decoration: none; + margin: 10px 5px; + vertical-align: bottom; + } + """) ui.run(dark=None, reload=False, title="Daniel McKnight") diff --git a/site_mcknight_tech/page_content/footer.html b/site_mcknight_tech/page_content/footer.html index e091239..57cd5d9 100644 --- a/site_mcknight_tech/page_content/footer.html +++ b/site_mcknight_tech/page_content/footer.html @@ -1,3 +1,47 @@ - - © 2025 Daniel McKnight. All Rights Reserved. - + + + +
+ + © 2025 Daniel McKnight. All Rights Reserved. + +
+ -- 2.45.2 From 0f6e0e574147fe509be8858e43bd86770d21eb3d Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 4 Feb 2025 21:36:08 -0800 Subject: [PATCH 09/12] Limit content width --- site_mcknight_tech/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site_mcknight_tech/__main__.py b/site_mcknight_tech/__main__.py index e67858f..e6fe40c 100755 --- a/site_mcknight_tech/__main__.py +++ b/site_mcknight_tech/__main__.py @@ -45,7 +45,7 @@ def render_main() -> ui.tab_panels: tab_names = _tab_to_content.keys() with ui.tabs().classes('w-full') as tabs: tab_list = {name: ui.tab(name) for name in tab_names} - with ui.tab_panels(tabs).classes('w-full h-screen no-wrap') as header: + with ui.tab_panels(tabs).classes('w-full mx-auto h-screen').style('max-width: 1200px') as header: for name, t in tab_list.items(): with ui.tab_panel(t): render_tab(name) -- 2.45.2 From 7a61545a4763f2f88538bd3b10217546e43ad84e Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Wed, 12 Feb 2025 19:50:43 -0800 Subject: [PATCH 10/12] Minor adjustment to footer icons --- site_mcknight_tech/page_content/footer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site_mcknight_tech/page_content/footer.html b/site_mcknight_tech/page_content/footer.html index 57cd5d9..26bd77f 100644 --- a/site_mcknight_tech/page_content/footer.html +++ b/site_mcknight_tech/page_content/footer.html @@ -30,7 +30,7 @@ - + -- 2.45.2 From 50931665592e79c2a034cd2ec014711ca46aa0f3 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Wed, 12 Feb 2025 19:50:57 -0800 Subject: [PATCH 11/12] Add bio first draft --- site_mcknight_tech/page_content/bio.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/site_mcknight_tech/page_content/bio.md b/site_mcknight_tech/page_content/bio.md index f7aa4fc..dfd72d1 100644 --- a/site_mcknight_tech/page_content/bio.md +++ b/site_mcknight_tech/page_content/bio.md @@ -1 +1,15 @@ -## Hi! +## About Me +I'm a software engineer with a passion for conversational AI, and open source development. With a background in physics +and a range of interests that extend from software development to 3D printing, woodworking, and circuit design, +I am constantly finding new projects to apply my skills to. + +At Neon AI, I have found the perfect environment to pursue my interests in tech. With a range of projects, my work at +Neon AI aligns with my commitment to responsible software development. All the projects I've worked on respect user +privacy, and many are run on user-owned hardware, ensuring that users maintain control over their data and their systems. + +I have also had the pleasure of working with a large software stack, including voice technologies, +model training and customization (LLMs, Speech Synthesis, and Intent Determination), data organization, system +architecture and design, code and workflow optimization, documentation, and infrastructure management. I've called out a +few projects that highlight my work in these areas in my Portfolio. + +Yes, an LLM helped me write this 😉. -- 2.45.2 From 3ac9aaed047eca12a9d1c8972a214ccf691dbf27 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Tue, 25 Feb 2025 21:03:16 -0800 Subject: [PATCH 12/12] Update homepage content Add path router to allow URL navigation to specific pages --- site_mcknight_tech/__main__.py | 39 ++++++++++++++++++++----- site_mcknight_tech/page_content/home.md | 4 ++- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/site_mcknight_tech/__main__.py b/site_mcknight_tech/__main__.py index e6fe40c..098aaa0 100755 --- a/site_mcknight_tech/__main__.py +++ b/site_mcknight_tech/__main__.py @@ -1,20 +1,32 @@ # Copyright (C) 2025 Daniel McKnight - All Rights Reserved from os.path import isfile, join, dirname +from typing import Optional + +from fastapi.openapi.models import RequestBody from nicegui import ui +from fastapi.requests import Request # TODO: Read from configuration _tab_to_content = { - "Home": "page_content/home.md", - "Portfolio": "page_content/portfolio.md", - "Resume": "page_content/resume.md", - "Bio": "page_content/bio.md" + "home": "page_content/home.md", + "portfolio": "page_content/portfolio.md", + "resume": "page_content/resume.md", + "bio": "page_content/bio.md" } _error_page = "page_content/404.md" _footer_block = "page_content/footer.html" +@ui.page("/{name}") +def _render_path(name: str): + """ + Parse a path element to render a page + :param name: path element of the request + """ + render_site(name) + def _get_content_from_file(file_name: str) -> str: """ Take a file name/path and return its contents @@ -38,7 +50,7 @@ def render_tab(tab_name: str): extras=['cuddled-lists', 'fenced-code-blocks', 'tables']) -def render_main() -> ui.tab_panels: +def render_header() -> ui.tab_panels: """ Render sticky page header with navigation """ @@ -51,9 +63,17 @@ def render_main() -> ui.tab_panels: render_tab(name) return header -def main(): - header = render_main() - header.set_value(list(_tab_to_content.keys())[0]) + +def render_site(page_name: Optional[str] = None): + """ + Renders the site with the requested page active + :param page_name: Page to render. If `None` or invalid, `Home` will be rendered + """ + header = render_header() + if page_name and page_name in _tab_to_content.keys(): + header.set_value(page_name) + else: + header.set_value(list(_tab_to_content.keys())[0]) ui.query('.nicegui-content').classes('h-screen no-wrap') ui.html(_get_content_from_file(_footer_block), tag="footer").classes("rounded-lg shadow-sm m-4 w-full text-center") ui.add_css(""" @@ -64,6 +84,9 @@ def main(): vertical-align: bottom; } """) + +def main(): + render_site() ui.run(dark=None, reload=False, title="Daniel McKnight") diff --git a/site_mcknight_tech/page_content/home.md b/site_mcknight_tech/page_content/home.md index da71a32..b5fa04c 100644 --- a/site_mcknight_tech/page_content/home.md +++ b/site_mcknight_tech/page_content/home.md @@ -1,6 +1,8 @@ # Daniel McKnight ## Coder, Sysadmin, Manager -I work in the design and implementation of voice assistants, LLMs, infrastructure, and plenty more. +I work in the design and implementation of voice assistants, LLMs, infrastructure, and plenty more. Check out a selection +of my work [in my portfolio](https://www.mcknight.tech/portfolio) or learn some more about me and my experience +[in my bio](https://www.mcknight.tech/bio) and [resume](https://www.mcknight.tech/resume), respectively. I built this site using [NiceGUI](https://nicegui.io/), with the source code available [on Forgejo](https://forge.mcknight.tech/d_mcknight/website-mcknight-tech). -- 2.45.2