Compare commits
No commits in common. "main" and "gatsby-archive" have entirely different histories.
main
...
gatsby-arc
|
@ -0,0 +1,6 @@
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
public/
|
||||||
|
.git/
|
||||||
|
.cache/
|
|
@ -0,0 +1,34 @@
|
||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Unix-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# Matches multiple files with brace expansion notation
|
||||||
|
# Set default charset
|
||||||
|
[*.{js,py}]
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
# 4 space indentation
|
||||||
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
# Tab indentation (no size specified)
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
# Indentation override for all JS under lib directory
|
||||||
|
[lib/**.js]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Matches the exact files either package.json or .travis.yml
|
||||||
|
[{package.json,.travis.yml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es6": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"standard",
|
||||||
|
"plugin:react/recommended"
|
||||||
|
],
|
||||||
|
"globals": {
|
||||||
|
"Atomics": "readonly",
|
||||||
|
"SharedArrayBuffer": "readonly"
|
||||||
|
},
|
||||||
|
"parser": "babel-eslint",
|
||||||
|
"plugins": [
|
||||||
|
"babel",
|
||||||
|
"react"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
name: Build website container
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build image
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container: git.namesny.com/cluster/act-runner:v1
|
|
||||||
env:
|
|
||||||
IMAGE_NAME: namesny-com
|
|
||||||
REGISTRY: git.namesny.com
|
|
||||||
REPO_OWNER: mathis
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: git.namesny.com
|
|
||||||
username: ${{ gitea.actor }}
|
|
||||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
||||||
- name: Build and push
|
|
||||||
run: |
|
|
||||||
TODAY=$(date +'%Y-%m-%d')
|
|
||||||
docker build -t ${REGISTRY}/${REPO_OWNER}/${IMAGE_NAME}:${TODAY} -t ${REGISTRY}/${REPO_OWNER}/${IMAGE_NAME}:latest .
|
|
||||||
docker push ${REGISTRY}/${REPO_OWNER}/${IMAGE_NAME}:${TODAY}
|
|
||||||
docker push ${REGISTRY}/${REPO_OWNER}/${IMAGE_NAME}:latest
|
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: '16 19 * * 1'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'javascript' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||||
|
# Learn more:
|
||||||
|
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
|
@ -1,13 +1,72 @@
|
||||||
# Generated files by hugo
|
# Logs
|
||||||
/public/
|
logs
|
||||||
/resources/_gen/
|
*.log
|
||||||
/assets/jsconfig.json
|
npm-debug.log*
|
||||||
hugo_stats.json
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
# Executable may be added to repository
|
# Runtime data
|
||||||
hugo.exe
|
pids
|
||||||
hugo.darwin
|
*.pid
|
||||||
hugo.linux
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
# Temporary lock file while building
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
/.hugo_build.lock
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Typescript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# gatsby files
|
||||||
|
.cache/
|
||||||
|
public
|
||||||
|
|
||||||
|
# Mac files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Yarn
|
||||||
|
yarn-error.log
|
||||||
|
.pnp/
|
||||||
|
.pnp.js
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# Custom
|
||||||
|
/content
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
.cache
|
||||||
|
package.json
|
||||||
|
package-lock.json
|
||||||
|
public
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"semi": false
|
||||||
|
}
|
27
Dockerfile
27
Dockerfile
|
@ -1,27 +0,0 @@
|
||||||
FROM golang:1.21-bookworm as build
|
|
||||||
|
|
||||||
ARG DART_SASS_VERSION=1.70.0
|
|
||||||
ARG HUGO_VERSION=0.122.0
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Install Dart Sass
|
|
||||||
RUN curl -LJO https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz && \
|
|
||||||
tar -xf dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz && \
|
|
||||||
cp -r dart-sass/* /usr/local/bin && \
|
|
||||||
rm -rf dart-sass*
|
|
||||||
|
|
||||||
# Install Hugo
|
|
||||||
RUN curl -LJO https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb && \
|
|
||||||
apt install -y ./hugo_extended_${HUGO_VERSION}_linux-amd64.deb && \
|
|
||||||
rm hugo_extended_${HUGO_VERSION}_linux-amd64.deb
|
|
||||||
|
|
||||||
COPY . /app
|
|
||||||
|
|
||||||
RUN hugo mod get -u && \
|
|
||||||
hugo --gc --minify
|
|
||||||
|
|
||||||
FROM nginx:stable-alpine
|
|
||||||
|
|
||||||
COPY --from=build /app/public /usr/share/nginx/html/
|
|
||||||
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
The BSD Zero Clause License (0BSD)
|
||||||
|
|
||||||
|
Copyright (c) 2020 Gatsby Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Personal Website
|
||||||
|
|
||||||
|
This is a source code for my personal website. It's implemented using Gatsby.js
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
* Light theme
|
||||||
|
* Remove Google Fonts CDN
|
|
@ -1,6 +0,0 @@
|
||||||
---
|
|
||||||
title: "{{ replace .Name "-" " " | title }}"
|
|
||||||
date: {{ .Date }}
|
|
||||||
draft: true
|
|
||||||
---
|
|
||||||
|
|
50
config.toml
50
config.toml
|
@ -1,50 +0,0 @@
|
||||||
baseURL = 'https://namesny.com/'
|
|
||||||
languageCode = 'en-us'
|
|
||||||
|
|
||||||
[module]
|
|
||||||
[[module.imports]]
|
|
||||||
path = "github.com/LordMathis/hugo-theme-nightfall"
|
|
||||||
|
|
||||||
[menu]
|
|
||||||
[[menu.header]]
|
|
||||||
name = "blog"
|
|
||||||
weight = 0
|
|
||||||
url = "blog"
|
|
||||||
[[menu.header]]
|
|
||||||
name = "about"
|
|
||||||
weight = 1
|
|
||||||
url = "about"
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
user = "hello"
|
|
||||||
hostname = "namesny.com"
|
|
||||||
|
|
||||||
[params.author]
|
|
||||||
name = "Matúš Námešný"
|
|
||||||
|
|
||||||
[[params.social]]
|
|
||||||
key = 0
|
|
||||||
name = "github"
|
|
||||||
url = "https://github.com/LordMathis"
|
|
||||||
|
|
||||||
[[params.social]]
|
|
||||||
key = 1
|
|
||||||
name = "gitea"
|
|
||||||
url = "https://git.namesny.com/Mathis"
|
|
||||||
|
|
||||||
[[params.social]]
|
|
||||||
key = 2
|
|
||||||
name = "linkedin"
|
|
||||||
url = "https://www.linkedin.com/in/matus-namesny/"
|
|
||||||
|
|
||||||
[[params.social]]
|
|
||||||
key = 3
|
|
||||||
name = "mastodon"
|
|
||||||
url = "https://toot.io/@mathis"
|
|
||||||
rel = "me"
|
|
||||||
|
|
||||||
[[params.social]]
|
|
||||||
key = 4
|
|
||||||
name = "email"
|
|
||||||
url = "mailto:matus@namesny.com"
|
|
|
@ -1,24 +0,0 @@
|
||||||
---
|
|
||||||
title: 'About Me'
|
|
||||||
showMetadata: false
|
|
||||||
---
|
|
||||||
|
|
||||||
Hello there.
|
|
||||||
|
|
||||||
I am Matúš [ˈmatuːʃ]. I am a Machine Learning Engineer based in Darmstadt, Germany. I focus on MLOps bridging the gap between Data Science, DevOps and Software Engineering. I am interested in broad range of topics including Machine Learning, Cloud, DevOps, Linux and open source.
|
|
||||||
|
|
||||||
After graduating in Artificial Intelligence and Natural Language Processing I joined Konica Minolta in Brno, Czechia, where I worked as an R&D Engineer developing a Python application that provides a unified approach for production ML model deployment. I was also deploying ML applications and MLOps tools to the cloud with Docker and Kubernetes which sparked my interest in DevOps and Cloud.
|
|
||||||
|
|
||||||
Currently, I work at Telespazio Germany as a Software Engineer. I participated in the development of a Kubeflow based Machine Learning Platform for Spacecraft Operational datasets. Nowadays I am working on a question-answering Chatbot the helps users explain complex documentation.
|
|
||||||
|
|
||||||
Here are some interesting projects that I'm working on in my free time:
|
|
||||||
|
|
||||||
* [k3s-configs](https://git.namesny.com/Cluster/k3s-configs) - Kustomize manifests for my self-hosted cluster.
|
|
||||||
* [neural-nets](https://github.com/LordMathis/neural-nets) - Small neural network library written in C from scratch.
|
|
||||||
* [GitEcho](https://github.com/LordMathis/GitEcho) - Backup tool for git repositories.
|
|
||||||
* [CUDANet](https://github.com/LordMathis/CUDANet) - Convolutional neural network library with CUDA support.
|
|
||||||
|
|
||||||
I also maintain two themes for [Hugo](https://gohugo.io), a static site generator:
|
|
||||||
|
|
||||||
* [Nix](https://github.com/LordMathis/hugo-theme-nix)
|
|
||||||
* [Nightfall](https://github.com/LordMathis/hugo-theme-nightfall)
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
title: "Blog"
|
|
||||||
---
|
|
|
@ -1,47 +0,0 @@
|
||||||
---
|
|
||||||
title: "Back to Hugo"
|
|
||||||
date: "2023-08-13"
|
|
||||||
tags:
|
|
||||||
- gatsby
|
|
||||||
- hugo
|
|
||||||
---
|
|
||||||
|
|
||||||
Over the years, this website was running on WordPress, Hugo, a custom React SPA, server-side rendered React, Gatsby, and now I'm back to Hugo.
|
|
||||||
|
|
||||||
<!--more-->
|
|
||||||
|
|
||||||
## First Hugo Website
|
|
||||||
|
|
||||||
I created my first Hugo website in 2016 while still in University studying Computer Science. I started looking for internships and thought that having a personal website would enhance my appeal. I created the [Nix theme](https://github.com/LordMathis/hugo-theme-nix), a minimalistic theme inspired by Unix and the terminal. Looking back at the code, it's actually not that bad considering I had zero experience with web development. But I think it speaks more about the simplicity of Hugo and Bootstrap rather than my skills.
|
|
||||||
|
|
||||||
If I were to rewrite this theme from scratch, I would implement many things differently. However, many people use the theme, so I continue to maintain it.
|
|
||||||
|
|
||||||
## Here Comes React
|
|
||||||
|
|
||||||
Hugo was working perfectly fine for my needs, but for some reason, I wanted something more. Since I was already learning React and Node.js, I decided to build my website using React. Initially, I started building the website as a standard React app. I created all the components that I thought I might need, and the website quickly grew.
|
|
||||||
|
|
||||||
Then I learned about universal (isomorphic) rendering and decided to give it a try. This part of development took me the longest. My challenge with implementing universal rendering was a distinct lack of up-to-date tutorials. They all used outdated versions of Webpack or React Router, or didn't utilize React Router at all. Another issue was that some tutorials were using babel-node in production, which is not recommended.
|
|
||||||
|
|
||||||
After finally implementing universal rendering, the next issue to solve was how to deliver content. A simpler approach would be to create a new React component for each blog post and "hard code" the content. However, that's not very React-like. Instead, I implemented a simple API in Express.
|
|
||||||
|
|
||||||
There are many more aspects that I didn't mention, things I spent hours working on, only to change my mind after implementation. An honorable mention goes to the CSS and the overall style of the website, which underwent several changes. I also reinvented the wheel multiple times, opting to build features from scratch rather than using existing modules.
|
|
||||||
|
|
||||||
So now, I had a new website that was much more complex but had fewer features than my initial Hugo website.
|
|
||||||
|
|
||||||
## The Great Gatsby
|
|
||||||
|
|
||||||
My React-based website wasn't fully server-side rendered. The only server-rendered element was the page layout, while the content was served via an API and rendered on the client side. Thus, I found myself running a Node.js app at all times for a relatively simple website with minimal visitors and content. Instead of embarking on creating my own server-side renderer, I got sidetracked by a captivating newcomer: Gatsby.
|
|
||||||
|
|
||||||
Migrating to Gatsby wasn't overly challenging since I already had all my styles and components ready. I just needed to grasp how to write GraphQL queries to fetch content and assemble a set of Gatsby plugins for website building. The initial implementation of the Gatsby website was enjoyable, but ongoing maintenance proved to be a hassle.
|
|
||||||
|
|
||||||
## Move Fast and Break Things
|
|
||||||
|
|
||||||
The JavaScript landscape evolves at breakneck speed. Libraries that emerged yesterday risk deprecation tomorrow. Not to mention the ceaseless discovery of vulnerabilities every day. To mitigate this, I established dependabot security alerts for my website's GitHub repository. At one point, dependabot became the primary contributor.
|
|
||||||
|
|
||||||
While the detected vulnerabilities didn't directly threaten my server, as the website generated static HTML files and was served by nginx, a chain of vulnerabilities encompassing Gatsby, nginx, and Docker would be necessary for a genuine threat. Nevertheless, uncertainty lingered.
|
|
||||||
|
|
||||||
In the end, I opted to return to Hugo. You can still explore the archived React/Gatsby source code [here](https://git.namesny.com/Mathis/namesny-com-gatsby-archive).
|
|
||||||
|
|
||||||
## Full Circle
|
|
||||||
|
|
||||||
Instead of revisiting my old Nix theme, I chose to create a new theme: [Nightfall](https://github.com/LordMathis/hugo-theme-nightfall), based on the layout of my Gatsby website. Migrating to Hugo was relatively straightforward, thanks to React components. I only needed to replace JSX tags with appropriate HTML tags and integrate Hugo partials. I welcome all contributions to both the Nix and Nightfall themes.
|
|
|
@ -1,24 +0,0 @@
|
||||||
---
|
|
||||||
title: "Coding style"
|
|
||||||
draft: true
|
|
||||||
---
|
|
||||||
|
|
||||||
I had a few interviews where I was asked about my coding style. I wasn't sure how to respond. I'm not following dogmatically any one coding principle such as Clean Code or TDD. Coding standards are hard, thats why there are so many books about it. I pick and choose the ideas and try to follow those in my code.
|
|
||||||
|
|
||||||
I would be surprised if I follow the same ideas in 5 years. The style is evolving and my opinions change.
|
|
||||||
|
|
||||||
Here are ideas that I currently follow:
|
|
||||||
|
|
||||||
- never nesting
|
|
||||||
- early return
|
|
||||||
- fight abstractions
|
|
||||||
- grugg brained dev
|
|
||||||
- don't repeat yourself thrice
|
|
||||||
|
|
||||||
Sources:
|
|
||||||
|
|
||||||
- https://www.youtube.com/watch?v=tD5NrevFtbU
|
|
||||||
- https://www.youtube.com/watch?v=CFRhGnuXG-4
|
|
||||||
- https://grugbrain.dev/
|
|
||||||
- https://testing.googleblog.com/2023/09/else-nuances.html
|
|
||||||
- https://www.youtube.com/watch?v=bJQj1uKtnus
|
|
|
@ -1,29 +0,0 @@
|
||||||
---
|
|
||||||
title: Writing a Convolutional Neural Network library with CUDA Support
|
|
||||||
draft: true
|
|
||||||
---
|
|
||||||
|
|
||||||
Straightforward project, learned a lot more than I expected.
|
|
||||||
|
|
||||||
"Just use cuBLAS, it'll be easier. You don't have to implement custom CUDA kernels.", they said. Actually, noone said that. I just thought that because I didn't do enough research.
|
|
||||||
|
|
||||||
Why not combine multiple challenging things into 1 (C++, cmake, CUDA, CNN)
|
|
||||||
|
|
||||||
Quickly discovering that without writing custom kernels, you can't really progress
|
|
||||||
|
|
||||||
- cuBLAS column major layout, macro
|
|
||||||
- cmake woes (findCUDA)
|
|
||||||
- google test
|
|
||||||
- padding kernel
|
|
||||||
- column major / row major headache
|
|
||||||
- removing cuBLAS -> just row major representation
|
|
||||||
- naive conv2d
|
|
||||||
- learning 3D memory representation
|
|
||||||
- optimizing conv2d
|
|
||||||
- softmax sum reduce
|
|
||||||
- softmax numerical stability - max reduce
|
|
||||||
- custom binary weights file - (safetensors - json parser vs csv) values overwritten by header
|
|
||||||
- tests passing -> implement AlexNet
|
|
||||||
- AlexNet cmake, opencv
|
|
||||||
- AlexNet crashing -> add cuda error checking to tests -> test crashing
|
|
||||||
- compute-sanitizer memecheck
|
|
|
@ -1,88 +0,0 @@
|
||||||
---
|
|
||||||
title: "Building a Docker Container with Gitea Actions on K3s"
|
|
||||||
date: "2023-12-28"
|
|
||||||
tags:
|
|
||||||
- gitea
|
|
||||||
- k3s
|
|
||||||
- cicd
|
|
||||||
---
|
|
||||||
|
|
||||||
Building a Docker image and pushing it to the registry with GitHub Actions is incredibily easy. Since Gitea Actions are designed to be compatible with GitHub Actions, this should be easy, right?
|
|
||||||
|
|
||||||
<!--more-->
|
|
||||||
|
|
||||||
## Gitea Actions
|
|
||||||
|
|
||||||
Gitea Actions is a CI/CD solution tightly coupled with Gitea. They have been available since Gitea 1.19 and are designed to be mostly compatible with GitHub Actions. They are based on the [act](https://github.com/nektos/act), which allows you to run GitHub workflows locally. Gitea has soft forked it to create [act_runner](https://gitea.com/gitea/act_runner).
|
|
||||||
|
|
||||||
To use Gitea Actions on you instance, you need to first allow them in `app.ini`. Then create a token and deploy the runner. Once the runner is deployed and registered, you will also need to enable Actions for each repository separately. The Actions runner is a self-contained system - a docker container that, for each job, launches a new container inside which the action steps are run. For a full guide on setting up Actions, check the official [Gitea docs](https://docs.gitea.com/usage/actions/quickstart).
|
|
||||||
|
|
||||||
## Building and Pushing Docker Image with GitHub Actions
|
|
||||||
|
|
||||||
With GitHub Actions, you can make use of thousands of actions available in [GitHub Marketplace](https://github.com/marketplace?type=actions). If you want to build a Docker image on GitHub, you can just use the official Docker [build-and-push](https://github.com/marketplace/actions/build-and-push-docker-images) action. Just copy one of the examples and you are good to go.
|
|
||||||
|
|
||||||
## Building with Gitea
|
|
||||||
|
|
||||||
In order to enable Gitea Actions, you nedd to first deploy the Actions runner. I followed the Kubernetes example from [gitea/act_runner](https://gitea.com/gitea/act_runner/src/commit/f17cad1bbe0d4a84308a37fb4a5e64211ada7e8a/examples/kubernetes/rootless-docker.yaml) repository. The deployment is simple. The runner will register itself with your Gitea instance, and after you enable Actions globally and for each repository, you'll be able to try Actions.
|
|
||||||
|
|
||||||
The first thing I tried was the same workflow that I used on Github. That didn't work. The first step to fail was docker login action. It complained that it couldn't find the `docker` command. It turns out that the default container image in which the Actions runner runs the commands did not contain docker. I tried manually installing it, but a simpler solution was to just specify a different container by [catthehacker](https://github.com/catthehacker/docker_images), which already has docker preinstalled. After switch to the new container, the logging in worked fine.
|
|
||||||
|
|
||||||
The next problem was with setting up the docker buildx action. It couldn't connect to Docker daemon at `unix:///var/run/docker.sock`. After much debugging, trying different things, and searching the internet, I found out that because the docker-in-docker runner container is rootless, the Docker socket is at `unix:///var/run/user/1000/docker.sock` instead. I just needed to change the `DOCKER_HOST` environment variables. I also removed `DOCKER_TLS_VERIFY` and `DOCKER_CERT_PATH` environment variables since they weren't necessary.
|
|
||||||
|
|
||||||
Okay, so now, everything should work fine, right? Not so fast. Apparently the Docker buildx action makea some assumtions about the system, which work well in a well-defined environment of GitHub Actions but don't necessarily hold true for self-hosted K3s deployments. It complained that it couldn't mount `sysfs` to `rootfs` at `/sys` due to operation not permitted. The solution was to run docker commands directly instead of using `buildx` action.
|
|
||||||
|
|
||||||
The last hurdle was to pass the login secrets to the action. Gitea does not yet support an equivalent to `GITHUB_TOKEN`, so instead, I needed to manually create a token and add it to action secrets as `REGISTRY_TOKEN`.
|
|
||||||
|
|
||||||
This is a very condensed summary of many hours spent debugging, searching, and trying to make Gitea Actions build a Docker image on K3s. I've skiped a few different attempts that lead to nowhere, such as using RedHat's Buildah instead of Docker. In the end the actual solution was much simpler than any of my attempts.
|
|
||||||
|
|
||||||
## TL;DR
|
|
||||||
|
|
||||||
To build a Docker image using Gitea Actions on K3s deploy the dind-rootless Actions runner with these environment variables:
|
|
||||||
|
|
||||||
{{< highlight yaml >}}
|
|
||||||
env:
|
|
||||||
- name: DOCKER_HOST
|
|
||||||
value: unix:///var/run/user/1000/docker.sock
|
|
||||||
- name: GITEA_INSTANCE_URL
|
|
||||||
value: http://gitea-http.gitea.svc.cluster.local:3000
|
|
||||||
- name: GITEA_RUNNER_REGISTRATION_TOKEN
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: runner-secret
|
|
||||||
key: token
|
|
||||||
{{< / highlight >}}
|
|
||||||
|
|
||||||
Create `release.yaml` file in `.gitea/workflows` folder. For building and pushing the image, use `docker` commands directly. For example:
|
|
||||||
|
|
||||||
{{< highlight yaml >}}
|
|
||||||
name: Build docker container
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build image
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container: ghcr.io/catthehacker/ubuntu:act-latest
|
|
||||||
env:
|
|
||||||
IMAGE_NAME: example-image
|
|
||||||
REGISTRY: example.com
|
|
||||||
REPO_OWNER: test
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: example.com
|
|
||||||
username: ${{ gitea.actor }}
|
|
||||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
||||||
- name: Build and push
|
|
||||||
run: |
|
|
||||||
TODAY=$(date +'%Y-%m-%d')
|
|
||||||
docker build -t ${REGISTRY}/${REPO_OWNER}/${IMAGE_NAME}:${TODAY} -t ${REGISTRY}/${REPO_OWNER}/${IMAGE_NAME}:latest .
|
|
||||||
docker push ${REGISTRY}/${REPO_OWNER}/${IMAGE_NAME}:${TODAY}
|
|
||||||
docker push ${REGISTRY}/${REPO_OWNER}/${IMAGE_NAME}:latest
|
|
||||||
{{< / highlight >}}
|
|
|
@ -1,84 +0,0 @@
|
||||||
---
|
|
||||||
title: "Replicating Gitea Docker SSH Passthrough on K3s"
|
|
||||||
date: "2023-02-12"
|
|
||||||
tags:
|
|
||||||
- gitea
|
|
||||||
- k3s
|
|
||||||
---
|
|
||||||
|
|
||||||
If you are selfhosting Gitea on a single node Kubernetes cluster and want to enable git through SSH while keeping SSH connection to the cluster, this guide is for you.
|
|
||||||
|
|
||||||
<!--more-->
|
|
||||||
|
|
||||||
**Update**
|
|
||||||
|
|
||||||
As of Gitea Helm Chart v9.0.0, Gitea is not a StatefulSet but a Deployment instead. In order to make this work you have to replace pod pod name `gitea-0` with:
|
|
||||||
|
|
||||||
{{< highlight bash >}}
|
|
||||||
$(kubectl get po -n gitea -l app=gitea -o name --no-headers=true)
|
|
||||||
{{< / highlight >}}
|
|
||||||
|
|
||||||
|
|
||||||
Command substitution does not work in `AuthorizedKeysCommand` so I suggest creating a separate script along the lines of `/usr/local/bin/gitea-shell`
|
|
||||||
|
|
||||||
|
|
||||||
## Background
|
|
||||||
|
|
||||||
I am currently in the process of migrating my selfhosted applications from docker-compose to Kubernetes. One of my most used selfhosted app is Gitea. I use it to host my projects, dotfiles and config files where I don't expect any contributions or I simply want to keep it more private. In my docker-compose setup I used SSH Container Passthrough from [Gitea docs](https://docs.gitea.io/en-us/install-with-docker/#SSH-container-passthrough) but when I moved Gitea to k3s I couldn't find any guides on how to achieve the same thing.
|
|
||||||
|
|
||||||
I installed Gitea using the official [Helm Chart](https://gitea.com/gitea/helm-chart/). The documentation says this about enabling SSH:
|
|
||||||
|
|
||||||
> If you're using ingress and want to use SSH, keep in mind, that ingress is not able to forward SSH Ports. You will need a LoadBalancer like metallb and a setting in your SSH service annotations.
|
|
||||||
|
|
||||||
However using this method will route all incoming SSH connections to the Gitea container, essentialy disabling SSH connection to the host. Therefore we need a way to pass SSH connections to user `git` to our Gite container running on Kubernetes and at the same time allow SSH connections to host for some other user(s)
|
|
||||||
|
|
||||||
## Kubernetes Setup
|
|
||||||
|
|
||||||
Create user git on your host and deploy Gitea to Kubernetes (e.g. using Helm). You don't need to expose port 22 using a service.
|
|
||||||
|
|
||||||
First we are going to create a new login shell for user git. Create file `/usr/local/bin/gitea-shell` with content:
|
|
||||||
|
|
||||||
{{< highlight bash >}}
|
|
||||||
#!/bin/sh
|
|
||||||
/usr/local/bin/kubectl exec -i -n gitea gitea-0 -c gitea -- env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" /bin/sh "$@"
|
|
||||||
{{< / highlight >}}
|
|
||||||
|
|
||||||
Your namespace might be different.
|
|
||||||
|
|
||||||
Then run as root (or sudo):
|
|
||||||
|
|
||||||
{{< highlight bash >}}
|
|
||||||
chmod +x /usr/local/bin/gitea-shell
|
|
||||||
usermod -s /usr/local/bin/gitea-shell git
|
|
||||||
{{< / highlight >}}
|
|
||||||
|
|
||||||
Now everytime the user git logs in (i.e. using git via SSH) `/usr/local/bin/gitea-shell` gets executed which means our original SSH command will be executed in the gitea container.
|
|
||||||
|
|
||||||
Finally we need to make sure that the SSH keys we add through Gitea interface allow us to 'login' as git user.
|
|
||||||
|
|
||||||
Edit `/etc/SSH/SSHd_config` and add the following:
|
|
||||||
|
|
||||||
{{< highlight yaml>}}
|
|
||||||
Match User git
|
|
||||||
AuthorizedKeysCommandUser git
|
|
||||||
AuthorizedKeysCommand /usr/local/bin/kubectl exec -i -n gitea gitea-0 -c gitea -- /usr/local/bin/gitea keys -e git -u %u -t %t -k %k
|
|
||||||
{{< / highlight >}}
|
|
||||||
|
|
||||||
If you are using `AllowUsers` directive don't forget to add user git
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
Open Gitea in web browser and add you SSH key. Then try to SSH into the Gitea container.
|
|
||||||
|
|
||||||
{{< highlight bash >}}
|
|
||||||
ssh git@<your gitea url>
|
|
||||||
{{< / highlight >}}
|
|
||||||
|
|
||||||
You should get a message like this:
|
|
||||||
|
|
||||||
> PTY allocation request failed on channel 0
|
|
||||||
> Hi there, test! You've successfully authenticated with the key named <your ssh key>, but Gitea does not provide shell access.
|
|
||||||
> If this is unexpected, please log in with password and setup Gitea under another user.
|
|
||||||
> Connection to <your gitea url> closed.
|
|
||||||
|
|
||||||
Now you can create a repo and you should be able to clone and push via SSH.
|
|
|
@ -1,64 +0,0 @@
|
||||||
---
|
|
||||||
title: "Building My Resume with GitHub Actions"
|
|
||||||
date: "2023-10-02"
|
|
||||||
tags:
|
|
||||||
- cicd
|
|
||||||
---
|
|
||||||
|
|
||||||
Even if you are not actively looking for a new job, it is a good idea to have an up to date resume. I'm using Overleaf's GitHub integration and GitHub Actions to build PDF from my LaTeX resume and release it on GitHub
|
|
||||||
|
|
||||||
<!--more-->
|
|
||||||
|
|
||||||
|
|
||||||
## LaTeX
|
|
||||||
|
|
||||||
LaTeX is a typesetting system and document preparation tool known for its professional-quality typography and precise formatting capabilities. Widely used in academia, it's popular for creating resumes and academic documents due to its superior handling of complex formatting, mathematical equations, and citations. One of the benefits of using LaTeX is that it separates the content and formatting of a document, which makes it easier to focus on the content without worrying about the layout.
|
|
||||||
|
|
||||||
TeXLive is a comprehensive distribution of the LaTeX typesetting system, providing a wide range of packages, fonts, and utilities for users. It includes everything needed to create LaTeX documents, making it a go-to choice for many LaTeX users.
|
|
||||||
|
|
||||||
## Compiling PDF on Overleaf
|
|
||||||
|
|
||||||
I have been using [Overleaf](https://www.overleaf.com/) to edit, update and build my resume. Overleaf is a cloud-based LaTeX editor with countless templates for resumes, theses, presentations, cover letters, scientific papers and more. Overleaf uses TeXLive distribution, enabling their compile servers to provide a real-time preview of the typeset PDFs. This makes editing LaTeX on Overleaf very convenient since it is not necessary to understand the intricacies of document processing. Overleaf handles the complexities of LaTeX compilation, allowing you to concentrate on creating a standout resume. However, replicating the same results outside of Overleaf's environment requires deeper knowledge of the compilation process.
|
|
||||||
|
|
||||||
Overleaf uses [latexmk](https://ctan.org/pkg/latexmk?lang=en) package to automate the compilation. The package uses a system-wide configuration, which can be customized by a user-level configuration on a document-by-document basis. This customization might include adjusting the sequence of commands, specifying which files to include or exclude, defining custom dependencies, or setting up personalized error-handling procedures. You can access the `latexmk` configuration file used by Overleaf to typeset your document by compiling [this project](https://www.overleaf.com/learn/how-to/How_does_Overleaf_compile_my_project%3F#How_to_access_a_copy_of_Overleaf%E2%80%99s_LatexMk_file).
|
|
||||||
|
|
||||||
Because the template of my resume is quite simple it was not necessary to get the exact `latexmk` config file or to customize it in any way.
|
|
||||||
|
|
||||||
## Compiling and Releasing with GitHub Actions
|
|
||||||
|
|
||||||
Leveraging the power of GitHub Actions has streamlined my document compilation and release process significantly. Within the GitHub Actions Marketplace, there's a wealth of workflows tailored for various tasks, including LaTeX compilation. I've opted for [xu-cheng/latex-action](https://github.com/xu-cheng/latex-action) which utilizes the TeXLive environment and `latexmk` compiler, mirroring the setup used on Overleaf. And indeed without any configuration changes, my resume compiled to PDF correctly.
|
|
||||||
|
|
||||||
But automation doesn't stop there. To simplify the release procedure, I've incorporated [softprops/action-gh-release](https://github.com/softprops/action-gh-release). This action automates the creation of new tags, and releases, and even handles file attachments seamlessly. I've configured it to generate new releases marked with the current date, effortlessly adding the compiled `resume.pdf`. This automated process not only saves valuable time but also streamlines the release workflow, eliminating the need for manual login to Overleaf, recompilation, and downloading. It ensures that each new version of my resume is promptly available to the public.
|
|
||||||
|
|
||||||
You can check the full repository [here](https://github.com/LordMathis/resume). Alternatively here's just the workflow file:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: Release Compiled PDF
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_latex:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: Get current date
|
|
||||||
id: date
|
|
||||||
run: echo "NOW=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up Git repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Compile
|
|
||||||
uses: xu-cheng/latex-action@v2
|
|
||||||
with:
|
|
||||||
root_file: resume.tex
|
|
||||||
|
|
||||||
- name: Release
|
|
||||||
uses: softprops/action-gh-release@v1
|
|
||||||
with:
|
|
||||||
tag_name: ${{ env.NOW }}
|
|
||||||
files: ./resume.pdf
|
|
||||||
```
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
FROM node:16-alpine as front
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./ /app/
|
||||||
|
|
||||||
|
RUN yarn install
|
||||||
|
RUN yarn run build
|
||||||
|
|
||||||
|
FROM nginx:1.17.8-alpine
|
||||||
|
RUN rm -rf /usr/share/nginx/html
|
||||||
|
COPY --from=front /app/public/ /usr/share/nginx/html
|
||||||
|
COPY ./docker/default.conf /etc/nginx/conf.d/default.conf
|
|
@ -0,0 +1,21 @@
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
|
||||||
|
index index.html;
|
||||||
|
autoindex off;
|
||||||
|
charset urtf-8;
|
||||||
|
|
||||||
|
error_page 404 /404.html;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log;
|
||||||
|
|
||||||
|
location ~* \.(html)$ {
|
||||||
|
add_header Cache-Control "no-store";
|
||||||
|
expires off;
|
||||||
|
}
|
||||||
|
|
||||||
|
rewrite ^([^.\?]*[^/])$ $1/ permanent;
|
||||||
|
|
||||||
|
try_files $uri $uri/ $uri/index.html =404;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
/**
|
||||||
|
* Implement Gatsby's Browser APIs in this file.
|
||||||
|
*
|
||||||
|
* See: https://www.gatsbyjs.org/docs/browser-apis/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// You can delete this file if you're not using it
|
|
@ -0,0 +1,72 @@
|
||||||
|
module.exports = {
|
||||||
|
siteMetadata: {
|
||||||
|
author: `Matúš Námešný`,
|
||||||
|
user: "hello",
|
||||||
|
hostname: "namesny.com",
|
||||||
|
email: "matus@namesny.com",
|
||||||
|
social: [
|
||||||
|
{
|
||||||
|
name: "github",
|
||||||
|
link: "https://github.com/LordMathis",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "linkedin",
|
||||||
|
link: "https://www.linkedin.com/in/mat%C3%BA%C5%A1-n%C3%A1me%C5%A1n%C3%BD-3903b6128/",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
resolve: `gatsby-source-filesystem`,
|
||||||
|
options: {
|
||||||
|
name: `pages`,
|
||||||
|
path: `${__dirname}/content/pages`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resolve: `gatsby-transformer-remark`,
|
||||||
|
options: {
|
||||||
|
filter: node => node.sourceInstanceName === `pages`,
|
||||||
|
type: `MarkdownPage`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resolve: `gatsby-source-filesystem`,
|
||||||
|
options: {
|
||||||
|
name: `posts`,
|
||||||
|
path: `${__dirname}/content/posts/`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resolve: `gatsby-transformer-remark`,
|
||||||
|
options: {
|
||||||
|
filter: node => node.sourceInstanceName === `posts`,
|
||||||
|
excerpt_separator: `<!-- end -->`,
|
||||||
|
type: `BlogPost`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resolve: `gatsby-source-filesystem`,
|
||||||
|
options: {
|
||||||
|
name: `images`,
|
||||||
|
path: `${__dirname}/src/images`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
`gatsby-transformer-sharp`,
|
||||||
|
`gatsby-plugin-sharp`,
|
||||||
|
`gatsby-plugin-react-helmet`,
|
||||||
|
{
|
||||||
|
resolve: `gatsby-plugin-manifest`,
|
||||||
|
options: {
|
||||||
|
name: `gatsby-starter-default`,
|
||||||
|
short_name: `starter`,
|
||||||
|
start_url: `/`,
|
||||||
|
background_color: `#663399`,
|
||||||
|
theme_color: `#663399`,
|
||||||
|
display: `minimal-ui`,
|
||||||
|
icon: `src/images/favicon-32x32.png`, // This path is relative to the root of the site.
|
||||||
|
},
|
||||||
|
},
|
||||||
|
`gatsby-plugin-sass`,
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
const path = require(`path`)
|
||||||
|
const { createFilePath } = require(`gatsby-source-filesystem`)
|
||||||
|
|
||||||
|
exports.onCreateNode = ({ node, getNode, actions }) => {
|
||||||
|
const { createNodeField } = actions
|
||||||
|
if (node.internal.type === `MarkdownRemark`) {
|
||||||
|
const slug = createFilePath({ node, getNode, basePath: `pages` })
|
||||||
|
const parent = getNode(node.parent)
|
||||||
|
createNodeField({
|
||||||
|
node,
|
||||||
|
name: `slug`,
|
||||||
|
value: slug,
|
||||||
|
})
|
||||||
|
createNodeField({
|
||||||
|
node,
|
||||||
|
name: 'collection',
|
||||||
|
value: parent.sourceInstanceName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createPages = async ({ graphql, actions, reporter }) => {
|
||||||
|
const { createPage } = actions
|
||||||
|
|
||||||
|
// Posts query
|
||||||
|
const posts = await graphql(
|
||||||
|
`
|
||||||
|
{
|
||||||
|
allMarkdownRemark(filter:{frontmatter: {draft: {ne: true}}, fields: {collection: {eq: "posts"}}}) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
fields {
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
|
if (posts.errors) {
|
||||||
|
reporter.panicOnBuild(`Error while running GraphQL query.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create pages for each markdown file.
|
||||||
|
const blogPostTemplate = path.resolve(`src/templates/blog-post.js`)
|
||||||
|
posts.data.allMarkdownRemark.edges.forEach(({ node }) => {
|
||||||
|
createPage({
|
||||||
|
path: `/posts${node.fields.slug}`,
|
||||||
|
component: blogPostTemplate,
|
||||||
|
context: {
|
||||||
|
slug: node.fields.slug,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const pages = await graphql(
|
||||||
|
`
|
||||||
|
{
|
||||||
|
allMarkdownRemark(filter: {fields: {collection: {eq: "pages"}}}) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
fields {
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handle errors
|
||||||
|
if (pages.errors) {
|
||||||
|
reporter.panicOnBuild(`Error while running GraphQL query.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create pages for each markdown file.
|
||||||
|
const pageTemplate = path.resolve(`src/templates/page.js`)
|
||||||
|
pages.data.allMarkdownRemark.edges.forEach(({ node }) => {
|
||||||
|
createPage({
|
||||||
|
path: node.fields.slug,
|
||||||
|
component: pageTemplate,
|
||||||
|
context: {
|
||||||
|
slug: node.fields.slug,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
/**
|
||||||
|
* Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
|
||||||
|
*
|
||||||
|
* See: https://www.gatsbyjs.org/docs/ssr-apis/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// You can delete this file if you're not using it
|
5
go.mod
5
go.mod
|
@ -1,5 +0,0 @@
|
||||||
module git.namesny.com/Mathis/namesny.com
|
|
||||||
|
|
||||||
go 1.20
|
|
||||||
|
|
||||||
require github.com/LordMathis/hugo-theme-nightfall v0.7.0 // indirect
|
|
10
go.sum
10
go.sum
|
@ -1,10 +0,0 @@
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.0.0-20230212210243-f116fbf0bdbb h1:31cDOpojmeNh9kpnwdPSe+Umzc1UaMc9vFM5N/7e5Yc=
|
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.0.0-20230212210243-f116fbf0bdbb/go.mod h1:0tCPxAeg5+tWhv17517Q8Lti/TPh0KNyON/uferEU30=
|
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.5.1 h1:xeycc74MTnikZ7tv+V8Lhuu9zrqRpVkaNjqw9eQYVNc=
|
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.5.1/go.mod h1:0tCPxAeg5+tWhv17517Q8Lti/TPh0KNyON/uferEU30=
|
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.6.0 h1:AmJFH2tQ66ZboBJ44RVwtt37Nhi6Qv29k6I/ouPxxRc=
|
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.6.0/go.mod h1:0tCPxAeg5+tWhv17517Q8Lti/TPh0KNyON/uferEU30=
|
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.6.1 h1:O9MXJpRv8A6Gxn2xUQHZJ2PVq4ryORlht6d4miUXrvI=
|
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.6.1/go.mod h1:0tCPxAeg5+tWhv17517Q8Lti/TPh0KNyON/uferEU30=
|
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.7.0 h1:aKN7W6wx1l2alvesLwA4rsoi7w/9wR0A+pKBWysiDCI=
|
|
||||||
github.com/LordMathis/hugo-theme-nightfall v0.7.0/go.mod h1:0tCPxAeg5+tWhv17517Q8Lti/TPh0KNyON/uferEU30=
|
|
17
nginx.conf
17
nginx.conf
|
@ -1,17 +0,0 @@
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
listen [::]:80;
|
|
||||||
server_name localhost;
|
|
||||||
|
|
||||||
access_log /var/log/nginx/access.log main;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
index index.html index.htm;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_page 500 502 503 504 /50x.html;
|
|
||||||
location = /50x.html {
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "namesny.com",
|
||||||
|
"private": true,
|
||||||
|
"description": "Personal website",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"author": "Matus Namesny <matus@namesny.com>",
|
||||||
|
"dependencies": {
|
||||||
|
"@fontsource/fira-mono": "^4.5.0",
|
||||||
|
"@fontsource/open-sans": "^4.5.2",
|
||||||
|
"gatsby": "^4.5.4",
|
||||||
|
"gatsby-image": "^3.11.0",
|
||||||
|
"gatsby-plugin-manifest": "^4.5.2",
|
||||||
|
"gatsby-plugin-offline": "^5.5.2",
|
||||||
|
"gatsby-plugin-react-helmet": "^5.5.0",
|
||||||
|
"gatsby-plugin-sass": "^5.5.0",
|
||||||
|
"gatsby-plugin-sharp": "^4.5.2",
|
||||||
|
"gatsby-source-filesystem": "^4.5.2",
|
||||||
|
"gatsby-transformer-remark": "^5.25.1",
|
||||||
|
"gatsby-transformer-sharp": "^4.5.0",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react": "^17.0.2",
|
||||||
|
"react-dom": "^17.0.2",
|
||||||
|
"react-helmet": "^6.1.0",
|
||||||
|
"sass": "^1.49.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "^2.5.1"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"gatsby",
|
||||||
|
"blog",
|
||||||
|
"portfolio"
|
||||||
|
],
|
||||||
|
"license": "0BSD",
|
||||||
|
"scripts": {
|
||||||
|
"build": "gatsby build",
|
||||||
|
"develop": "gatsby develop",
|
||||||
|
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
|
||||||
|
"start": "npm run develop",
|
||||||
|
"serve": "gatsby serve",
|
||||||
|
"clean": "gatsby clean",
|
||||||
|
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/gatsbyjs/gatsby-starter-default"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/gatsbyjs/gatsby/issues"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from "react"
|
||||||
|
import PostLink from "./post-link"
|
||||||
|
import {header} from "../styles/blog.module.scss"
|
||||||
|
|
||||||
|
const Blog = ({ edges }) => {
|
||||||
|
const Posts = edges
|
||||||
|
.map(edge => <PostLink key={edge.node.id} post={edge.node} />)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={header}>
|
||||||
|
<h1>Blog</h1>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{Posts}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Blog
|
|
@ -0,0 +1,12 @@
|
||||||
|
import React from "react"
|
||||||
|
import { footer, link } from '../styles/footer.module.scss'
|
||||||
|
|
||||||
|
const Footer = ({authorName}) => (
|
||||||
|
<footer className={footer}>
|
||||||
|
© {new Date().getFullYear()} {authorName}, Built with
|
||||||
|
{` `}
|
||||||
|
<a href="https://www.gatsbyjs.org" className={link}>Gatsby</a>
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Footer
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { Link } from "gatsby"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import React from "react"
|
||||||
|
import { header, headerWrapper, terminal, links } from "../styles/header.module.scss"
|
||||||
|
|
||||||
|
const Header = ({ user, hostname }) => (
|
||||||
|
<header className={headerWrapper}>
|
||||||
|
<div className={header}>
|
||||||
|
<div>
|
||||||
|
<Link to="/" className={terminal}>{user}@{hostname} ~ $</Link>
|
||||||
|
</div>
|
||||||
|
<nav className={links}>
|
||||||
|
<ul>
|
||||||
|
<li key="about">
|
||||||
|
<a href='/about'>
|
||||||
|
<span>~/about</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li key="blog">
|
||||||
|
<a href='/blog'>
|
||||||
|
<span>~/blog</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
|
||||||
|
Header.propTypes = {
|
||||||
|
user: PropTypes.string.isRequired,
|
||||||
|
hostname: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Header
|
|
@ -0,0 +1,32 @@
|
||||||
|
import React from "react"
|
||||||
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
import Img from "gatsby-image"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This component is built using `gatsby-image` to automatically serve optimized
|
||||||
|
* images with lazy loading and reduced file sizes. The image is loaded using a
|
||||||
|
* `useStaticQuery`, which allows us to load the image from directly within this
|
||||||
|
* component, rather than having to pass the image data down from pages.
|
||||||
|
*
|
||||||
|
* For more information, see the docs:
|
||||||
|
* - `gatsby-image`: https://gatsby.dev/gatsby-image
|
||||||
|
* - `useStaticQuery`: https://www.gatsbyjs.org/docs/use-static-query/
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Image = () => {
|
||||||
|
const data = useStaticQuery(graphql`
|
||||||
|
query {
|
||||||
|
placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
|
||||||
|
childImageSharp {
|
||||||
|
fluid(maxWidth: 300) {
|
||||||
|
...GatsbyImageSharpFluid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Image
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { Link } from "gatsby"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import React from "react"
|
||||||
|
import { indexWrapper, header } from "../styles/index.module.scss"
|
||||||
|
import Social from "./social"
|
||||||
|
|
||||||
|
const Index = ({ author, social, email }) => (
|
||||||
|
<div className={indexWrapper}>
|
||||||
|
<div>
|
||||||
|
<h1 className={header}>{ author }</h1>
|
||||||
|
</div>
|
||||||
|
<Social social={social} email={email}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
Index.propTypes = {
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Index
|
|
@ -0,0 +1,49 @@
|
||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
|
import Header from "./header"
|
||||||
|
import Footer from "./footer"
|
||||||
|
import { Helmet } from "react-helmet"
|
||||||
|
import '../styles/global.scss';
|
||||||
|
import { main, content, vertical, flexWrapper } from "../styles/layout.module.scss"
|
||||||
|
|
||||||
|
const Layout = ({ children, title, verticalLayout}) => {
|
||||||
|
|
||||||
|
const data = useStaticQuery(graphql`
|
||||||
|
query SiteTitleQuery {
|
||||||
|
site {
|
||||||
|
siteMetadata {
|
||||||
|
author
|
||||||
|
user
|
||||||
|
hostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
const classes = verticalLayout ? `${content} ${vertical}` : content
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={flexWrapper}>
|
||||||
|
<Helmet
|
||||||
|
titleTemplate={`%s | ${data.site.siteMetadata.author}`}>
|
||||||
|
<html lang="en" amp />
|
||||||
|
<title>{title}</title>
|
||||||
|
</Helmet>
|
||||||
|
<Header
|
||||||
|
user={data.site.siteMetadata.user}
|
||||||
|
hostname={data.site.siteMetadata.hostname} />
|
||||||
|
<div className={classes}>
|
||||||
|
<main className={main}>{children}</main>
|
||||||
|
</div>
|
||||||
|
<Footer authorName={data.site.siteMetadata.author}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
vertical: PropTypes.bool
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layout
|
|
@ -0,0 +1,28 @@
|
||||||
|
import React from "react"
|
||||||
|
import { Link } from "gatsby"
|
||||||
|
import { postTitle, postDate, postHeader, postListItem, postExcerpt } from '../styles/post-link.module.scss'
|
||||||
|
|
||||||
|
const PostLink = ({ post }) => {
|
||||||
|
|
||||||
|
const date = new Date(post.frontmatter.date)
|
||||||
|
const options = { year: 'numeric', month: 'long', day: 'numeric' };
|
||||||
|
const postDateString = date.toLocaleDateString('en', options);
|
||||||
|
const postUrl = "/posts" + post.fields.slug
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link to={postUrl}>
|
||||||
|
<div className={postListItem} role="listitem">
|
||||||
|
<div className={postHeader} >
|
||||||
|
<span className={postTitle}>{post.frontmatter.title}</span>
|
||||||
|
<span className={postDate}>{postDateString}</span>
|
||||||
|
</div>
|
||||||
|
<div className={postExcerpt}>
|
||||||
|
<p>{post.excerpt}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PostLink
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { socialNavbar } from '../styles/social.module.scss'
|
||||||
|
|
||||||
|
export default class Social extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
social: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
email: PropTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
let key = 0
|
||||||
|
|
||||||
|
const socialLinks = this.props.social.map((val) => {
|
||||||
|
const link = (
|
||||||
|
<li key={key}>
|
||||||
|
<a href={val.link} role="link">
|
||||||
|
{val.name}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
key += 1
|
||||||
|
return link
|
||||||
|
})
|
||||||
|
|
||||||
|
socialLinks.push(
|
||||||
|
<li key={key}>
|
||||||
|
<a href={`mailto:${this.props.email}`} role="link">
|
||||||
|
e-mail
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={socialNavbar} role="list">
|
||||||
|
<ul>
|
||||||
|
{socialLinks}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 433 B After Width: | Height: | Size: 433 B |
Before Width: | Height: | Size: 887 B After Width: | Height: | Size: 887 B |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,10 @@
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
const NotFoundPage = () => (
|
||||||
|
<Layout title="404: Not found" >
|
||||||
|
<h1>NOT FOUND</h1>
|
||||||
|
<p>You just hit a route that doesn't exist... the sadness.</p>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default NotFoundPage
|
|
@ -0,0 +1,39 @@
|
||||||
|
import React from "react"
|
||||||
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
|
import Layout from "../components/layout"
|
||||||
|
import Blog from "../components/blog"
|
||||||
|
|
||||||
|
const IndexPage = () => {
|
||||||
|
|
||||||
|
const data = useStaticQuery(graphql`
|
||||||
|
query {
|
||||||
|
allMarkdownRemark(
|
||||||
|
sort: { order: DESC, fields: [frontmatter___date] }
|
||||||
|
filter: {frontmatter: {draft: {ne: true}}, fields: {collection: {eq: "posts"}}}
|
||||||
|
) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
excerpt
|
||||||
|
frontmatter {
|
||||||
|
date
|
||||||
|
title
|
||||||
|
}
|
||||||
|
fields {
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout title="Blog">
|
||||||
|
<Blog edges={data.allMarkdownRemark.edges}/>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IndexPage
|
|
@ -0,0 +1,31 @@
|
||||||
|
import React from "react"
|
||||||
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
|
import Layout from "../components/layout"
|
||||||
|
import Index from "../components"
|
||||||
|
|
||||||
|
const IndexPage = () => {
|
||||||
|
|
||||||
|
const data = useStaticQuery(graphql`
|
||||||
|
query SiteDataQuery {
|
||||||
|
site {
|
||||||
|
siteMetadata {
|
||||||
|
author
|
||||||
|
email
|
||||||
|
social {
|
||||||
|
name
|
||||||
|
link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout title="Home" vertical={true} >
|
||||||
|
<Index author={data.site.siteMetadata.author} social={data.site.siteMetadata.social} email={data.site.siteMetadata.email}/>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IndexPage
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import "./variables.scss";
|
||||||
|
|
||||||
|
.blogPostWrapper {
|
||||||
|
text-align: left;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import "./variables.scss";
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: left;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
@import "./variables.scss";
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
padding: 15px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: $backgroundDarker;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
color: $white;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
@import "./variables.scss";
|
||||||
|
|
||||||
|
body, html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: $fontParagraph;
|
||||||
|
color: $white;
|
||||||
|
background-color: $backgroundDark;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@for $i from 1 through 6 {
|
||||||
|
h#{$i} {
|
||||||
|
font-family: $fontHeader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-ms-viewport{
|
||||||
|
width: device-width;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
@import "./variables.scss";
|
||||||
|
|
||||||
|
.header {
|
||||||
|
font-family: $fontHeader;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
@media only screen and (min-width: $breakLarge) {
|
||||||
|
width: $width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerWrapper {
|
||||||
|
overflow: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: $backgroundDarker;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
li {
|
||||||
|
display: inline;
|
||||||
|
margin: 5px;
|
||||||
|
a {
|
||||||
|
color: $white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.terminal {
|
||||||
|
color: $white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
.indexWrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
@import "./variables.scss";
|
||||||
|
|
||||||
|
.content {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 auto;
|
||||||
|
flex: 1 auto;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
@media only screen and (min-width: $breakLarge) {
|
||||||
|
display: flex;
|
||||||
|
width: $width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flexWrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import "./variables.scss";
|
||||||
|
|
||||||
|
.pageWrapper {
|
||||||
|
text-align: left;
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
@import "./variables.scss";
|
||||||
|
|
||||||
|
.postDate {
|
||||||
|
float: right;
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postTitle {
|
||||||
|
color: $blue;
|
||||||
|
text-decoration: none;
|
||||||
|
text-transform: capitalize;
|
||||||
|
font-family: $fontHeader;
|
||||||
|
font-size: 1.2em;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postHeader {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postsList {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postListItem {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: $black;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postExcerpt {
|
||||||
|
text-align: initial;
|
||||||
|
text-decoration: none;
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerContainer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noDecoration {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
a:link,
|
||||||
|
a:visited,
|
||||||
|
a:hover,
|
||||||
|
a:active{
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
@import "./variables.scss";
|
||||||
|
|
||||||
|
|
||||||
|
.socialNavbar {
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: $white;
|
||||||
|
text-shadow: $black 0px 0px 2px;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Colors
|
||||||
|
$darkGrey: #323232;
|
||||||
|
$white: #f8f8ff;
|
||||||
|
$black: #2f2f2f;
|
||||||
|
$blue: #0f52bf;
|
||||||
|
|
||||||
|
$backgroundDarker: #252627;
|
||||||
|
$backgroundDark: #292a2d;
|
||||||
|
|
||||||
|
//Fonts
|
||||||
|
@import "~@fontsource/fira-mono/500.css";
|
||||||
|
@import "~@fontsource/open-sans/index.css"; // Weight 400.
|
||||||
|
$fontHeader: 'Fira Mono', monospace;
|
||||||
|
$fontParagraph: 'Open Sans', sans-serif;
|
||||||
|
|
||||||
|
// Content
|
||||||
|
$breakLarge: 992px;
|
||||||
|
$width: 760px;
|
|
@ -0,0 +1,27 @@
|
||||||
|
import React from "react"
|
||||||
|
import { graphql } from "gatsby"
|
||||||
|
import Layout from "../components/layout"
|
||||||
|
import { blogPostWrapper } from "../styles/blog-post.module.scss"
|
||||||
|
|
||||||
|
export default function BlogPost({ data }) {
|
||||||
|
const post = data.markdownRemark
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<div className={blogPostWrapper}>
|
||||||
|
<h1>{post.frontmatter.title}</h1>
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: post.html }} />
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const query = graphql`
|
||||||
|
query($slug: String!) {
|
||||||
|
markdownRemark(fields: { slug: { eq: $slug } }) {
|
||||||
|
html
|
||||||
|
frontmatter {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,27 @@
|
||||||
|
import React from "react"
|
||||||
|
import { graphql } from "gatsby"
|
||||||
|
import Layout from "../components/layout"
|
||||||
|
import {pageWrapper} from "../styles/page.module.scss"
|
||||||
|
|
||||||
|
export default function Page({ data }) {
|
||||||
|
const page = data.markdownRemark
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<div className={pageWrapper}>
|
||||||
|
<h1>{page.frontmatter.title}</h1>
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: page.html }} />
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const query = graphql`
|
||||||
|
query($slug: String!) {
|
||||||
|
markdownRemark(fields: { slug: { eq: $slug } }) {
|
||||||
|
html
|
||||||
|
frontmatter {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
Loading…
Reference in New Issue