Compare commits
31 Commits
3e8a34ae35
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
4aa64a880d
|
|||
|
614a32e0d4
|
|||
|
59525cbde5
|
|||
|
264fe63e9b
|
|||
|
7d4c8e6cb1
|
|||
|
924af6e200
|
|||
|
62339b4f33
|
|||
|
d9d87daf7e
|
|||
|
320035c828
|
|||
|
92ca1f6feb
|
|||
|
bfd53b66ec
|
|||
|
d6aea329fe
|
|||
|
d5eef87740
|
|||
|
6eb4334691
|
|||
|
4ce0421e95
|
|||
|
91c8a825be
|
|||
|
e5ab74ebfb
|
|||
|
3e7c1d7ad3
|
|||
|
2b988b9be9
|
|||
|
276b8401ef
|
|||
|
ef12d4883c
|
|||
|
1c04a8c2a4
|
|||
|
7f75cd533e
|
|||
|
8ceb0839cf
|
|||
|
64d4ecaf55
|
|||
|
09bd36514c
|
|||
|
e38ad1530d
|
|||
|
5c252e8ff1
|
|||
|
6d86744166
|
|||
|
0b2a69a523
|
|||
|
23d72ebc39
|
11
.cspell.yaml
@@ -1,9 +1,20 @@
|
|||||||
|
# yamllint disable-line rule:line-length
|
||||||
|
# yaml-language-server: $schema=https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
|
||||||
---
|
---
|
||||||
version: "0.2"
|
version: "0.2"
|
||||||
import:
|
import:
|
||||||
- "@cspell/dict-de-de/cspell-ext.json"
|
- "@cspell/dict-de-de/cspell-ext.json"
|
||||||
language: en,de
|
language: en,de
|
||||||
|
ignorePaths:
|
||||||
|
- /pnpm-lock.yaml
|
||||||
words:
|
words:
|
||||||
|
- dockervolumes
|
||||||
|
- github
|
||||||
|
- gitlab
|
||||||
|
- grayscale
|
||||||
|
- keyoxide
|
||||||
- kmoschcau
|
- kmoschcau
|
||||||
- markuplint
|
- markuplint
|
||||||
- moschcau
|
- moschcau
|
||||||
|
- tailwindcss
|
||||||
|
- tsconfigs
|
||||||
|
|||||||
@@ -2,5 +2,8 @@
|
|||||||
"extends": ["markuplint:recommended-static-html"],
|
"extends": ["markuplint:recommended-static-html"],
|
||||||
"parser": {
|
"parser": {
|
||||||
".astro$": "@markuplint/astro-parser"
|
".astro$": "@markuplint/astro-parser"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"use-list": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
.prettierignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/.astro/
|
||||||
|
/dist/
|
||||||
|
/pnpm-lock.yaml
|
||||||
@@ -1,7 +1,18 @@
|
|||||||
# vim: filetype=gitignore
|
# vim: filetype=gitignore
|
||||||
|
|
||||||
|
/dist/
|
||||||
|
|
||||||
|
*.html
|
||||||
*.ico
|
*.ico
|
||||||
|
*.jpg
|
||||||
|
*.js
|
||||||
*.json
|
*.json
|
||||||
*.md
|
*.md
|
||||||
*.mjs
|
*.mjs
|
||||||
|
*.mts
|
||||||
|
*.png
|
||||||
*.svg
|
*.svg
|
||||||
|
*.ts
|
||||||
|
*.vim
|
||||||
|
*.webp
|
||||||
*.yaml
|
*.yaml
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ Any static assets, like images, can be placed in the `public/` directory.
|
|||||||
|
|
||||||
All commands are run from the root of the project, from a terminal:
|
All commands are run from the root of the project, from a terminal:
|
||||||
|
|
||||||
| Command | Action |
|
| Command | Action |
|
||||||
| :------------------------ | :----------------------------------------------- |
|
| :--------------------- | :----------------------------------------------- |
|
||||||
| `pnpm install` | Installs dependencies |
|
| `pnpm install` | Installs dependencies |
|
||||||
| `pnpm dev` | Starts local dev server at `localhost:4321` |
|
| `pnpm dev` | Starts local dev server at `localhost:4321` |
|
||||||
| `pnpm build` | Build your production site to `./dist/` |
|
| `pnpm build` | Build your production site to `./dist/` |
|
||||||
| `pnpm preview` | Preview your build locally, before deploying |
|
| `pnpm preview` | Preview your build locally, before deploying |
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
import { defineConfig } from "astro/config";
|
|
||||||
import tailwindcss from "@tailwindcss/vite";
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
|
import { defineConfig } from "astro/config";
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
|||||||
@@ -1,21 +1,27 @@
|
|||||||
import js from "@eslint/js";
|
import js from "@eslint/js";
|
||||||
import eslintPluginAstro from "eslint-plugin-astro";
|
import eslintPluginAstro from "eslint-plugin-astro";
|
||||||
|
import jsxA11y from "eslint-plugin-jsx-a11y";
|
||||||
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
|
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
|
||||||
import { defineConfig } from "eslint/config";
|
import { defineConfig } from "eslint/config";
|
||||||
import jsxA11y from "eslint-plugin-jsx-a11y";
|
|
||||||
|
|
||||||
export default defineConfig([
|
export default defineConfig([
|
||||||
|
{
|
||||||
|
ignores: ["./dist/", "**/*.html"],
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
files: ["**/*.{js,mjs}"],
|
files: ["**/*.{js,mjs}"],
|
||||||
plugins: { js },
|
plugins: { js },
|
||||||
extends: ["js/recommended"],
|
extends: ["js/recommended"],
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
files: ["**/*.{astro,html}"],
|
files: ["**/*.{astro,html}"],
|
||||||
plugins: {
|
plugins: {
|
||||||
"jsx-a11y": jsxA11y,
|
"jsx-a11y": jsxA11y,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
...eslintPluginAstro.configs.recommended,
|
...eslintPluginAstro.configs.recommended,
|
||||||
eslintPluginPrettierRecommended,
|
eslintPluginPrettierRecommended,
|
||||||
]);
|
]);
|
||||||
|
|||||||
23
package.json
@@ -7,24 +7,28 @@
|
|||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"astro": "astro",
|
"astro": "astro",
|
||||||
|
"format": "prettier --write .",
|
||||||
|
"format:check": "prettier --check .",
|
||||||
"lint:eslint": "eslint",
|
"lint:eslint": "eslint",
|
||||||
"lint:markuplint": "markuplint '**/*.{astro,html}'",
|
"lint:markuplint": "markuplint './{public,src}/**/*.{astro,html}'",
|
||||||
"lint:stylelint": "stylelint ."
|
"lint:stylelint": "stylelint .",
|
||||||
|
"deploy": "astro build && scp -r dist/* vds:~/dockervolumes/kmoschcau_website/web/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/vite": "^4.2.1",
|
"@tailwindcss/vite": "^4.2.2",
|
||||||
"astro": "^5.17.1",
|
"astro": "^6.1.2",
|
||||||
"tailwindcss": "^4.2.1"
|
"tailwindcss": "^4.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/ts-plugin": "^1.10.6",
|
"@astrojs/ts-plugin": "^1.10.7",
|
||||||
"@cspell/dict-de-de": "^4.1.2",
|
"@cspell/dict-de-de": "^4.1.2",
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@markuplint/astro-parser": "^4.6.23",
|
"@markuplint/astro-parser": "^4.6.23",
|
||||||
"@markuplint/ml-config": "^4.8.15",
|
"@markuplint/ml-config": "^4.8.15",
|
||||||
"@typescript-eslint/parser": "^8.56.1",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
|
"@typescript-eslint/parser": "^8.57.2",
|
||||||
"cspell": "^9.7.0",
|
"cspell": "^9.7.0",
|
||||||
"eslint": "^10.0.2",
|
"eslint": "^10.1.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-astro": "^1.6.0",
|
"eslint-plugin-astro": "^1.6.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
@@ -33,9 +37,10 @@
|
|||||||
"postcss-html": "^1.8.1",
|
"postcss-html": "^1.8.1",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"prettier-plugin-astro": "^0.14.1",
|
"prettier-plugin-astro": "^0.14.1",
|
||||||
|
"prettier-plugin-organize-imports": "^4.3.0",
|
||||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"stylelint": "^17.4.0",
|
"stylelint": "^17.5.0",
|
||||||
"stylelint-config-html": "^1.1.0",
|
"stylelint-config-html": "^1.1.0",
|
||||||
"stylelint-config-recommended": "^18.0.0",
|
"stylelint-config-recommended": "^18.0.0",
|
||||||
"stylelint-config-standard": "^40.0.0",
|
"stylelint-config-standard": "^40.0.0",
|
||||||
|
|||||||
2150
pnpm-lock.yaml
generated
3
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
overrides:
|
||||||
|
minimatch@10.1.2: 10.2.3
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
/** @type {import("prettier").Config} */
|
/** @type {import("prettier").Config} */
|
||||||
export default {
|
export default {
|
||||||
plugins: ["prettier-plugin-astro", "prettier-plugin-tailwindcss"],
|
plugins: [
|
||||||
|
"prettier-plugin-astro",
|
||||||
|
"prettier-plugin-organize-imports",
|
||||||
|
"prettier-plugin-tailwindcss",
|
||||||
|
],
|
||||||
|
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
|
|||||||
21
src/components/button-link.astro
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
import type { HTMLAttributes } from "astro/types";
|
||||||
|
import { getRel } from "../link-utils";
|
||||||
|
|
||||||
|
interface Props extends HTMLAttributes<"a"> {
|
||||||
|
/** Whether this link should use defaults for external links. */
|
||||||
|
external?: boolean | "me" | null | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { class: className, external, target, rel, ...rest } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<a
|
||||||
|
class:list={[
|
||||||
|
className,
|
||||||
|
"flex min-w-full items-center justify-center gap-4 rounded px-6 py-2 text-lg outline-offset-2 sm:px-24",
|
||||||
|
]}
|
||||||
|
target={target ?? (external ? "_blank" : undefined)}
|
||||||
|
rel={rel ?? getRel(external)}
|
||||||
|
{...rest}><slot name="logo" /><slot /></a
|
||||||
|
>
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
import type { HTMLAttributes } from "astro/types";
|
|
||||||
|
|
||||||
interface Props extends HTMLAttributes<"a"> {
|
|
||||||
cssClass: string;
|
|
||||||
href: string;
|
|
||||||
title: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { cssClass, href, title } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<a
|
|
||||||
class:list={[
|
|
||||||
cssClass,
|
|
||||||
"flex min-w-full items-center justify-center gap-4 rounded px-6 py-2 text-lg sm:px-24",
|
|
||||||
]}
|
|
||||||
{href}
|
|
||||||
{title}
|
|
||||||
target="_blank"
|
|
||||||
rel="external me noreferrer"><slot name="logo" /><slot /></a
|
|
||||||
>
|
|
||||||
24
src/components/inline-link.astro
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
import type { HTMLAttributes } from "astro/types";
|
||||||
|
import ExternalIcon from "../icons/arrow-top-right-on-square.svg";
|
||||||
|
import InlineSvg from "./inline-svg.astro";
|
||||||
|
import { getRel } from "../link-utils";
|
||||||
|
|
||||||
|
interface Props extends HTMLAttributes<"a"> {
|
||||||
|
/** Whether this link should use defaults for external links. */
|
||||||
|
external?: boolean | "me" | null | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { external, target, rel, ...rest } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<a
|
||||||
|
target={target ?? (external ? "_blank" : undefined)}
|
||||||
|
rel={rel ?? getRel(external)}
|
||||||
|
{...rest}
|
||||||
|
><slot />{
|
||||||
|
external ? (
|
||||||
|
<InlineSvg SvgComponent={ExternalIcon} class="ms-1" />
|
||||||
|
) : undefined
|
||||||
|
}</a
|
||||||
|
>
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
---
|
---
|
||||||
import type { SvgComponent } from "astro/types";
|
import type { HTMLAttributes, SvgComponent } from "astro/types";
|
||||||
|
|
||||||
interface Props {
|
interface Props extends HTMLAttributes<"svg"> {
|
||||||
SvgComponent: SvgComponent;
|
SvgComponent: SvgComponent;
|
||||||
size?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { size = 24, SvgComponent } = Astro.props;
|
const {
|
||||||
|
SvgComponent,
|
||||||
|
class: className,
|
||||||
|
role = "presentation",
|
||||||
|
...rest
|
||||||
|
} = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<SvgComponent
|
<SvgComponent class:list={[className, "inline h-[1em]"]} {role} {...rest} />
|
||||||
height={size}
|
|
||||||
width={size}
|
|
||||||
fill="currentColor"
|
|
||||||
role="presentation"
|
|
||||||
/>
|
|
||||||
|
|||||||
11
src/duration-utils.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const UNIX_EPOCH_YEAR = 1970;
|
||||||
|
|
||||||
|
export function getDurationInYearsBetween(start: Date, end: Date): number {
|
||||||
|
return (
|
||||||
|
new Date(end.getTime() - start.getTime()).getUTCFullYear() - UNIX_EPOCH_YEAR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDurationInYearsFrom(from: Date): number {
|
||||||
|
return getDurationInYearsBetween(from, new Date());
|
||||||
|
}
|
||||||
3
src/icons/arrow-left-circle.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m11.25 9-3 3m0 0 3 3m-3-3h7.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 265 B |
3
src/icons/arrow-top-right-on-square.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 6H5.25A2.25 2.25 0 0 0 3 8.25v10.5A2.25 2.25 0 0 0 5.25 21h10.5A2.25 2.25 0 0 0 18 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 316 B |
1
src/images/GitHub.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
|
||||||
|
After Width: | Height: | Size: 822 B |
1
src/images/GitLab.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitLab</title><path d="m23.6004 9.5927-.0337-.0862L20.3.9814a.851.851 0 0 0-.3362-.405.8748.8748 0 0 0-.9997.0539.8748.8748 0 0 0-.29.4399l-2.2055 6.748H7.5375l-2.2057-6.748a.8573.8573 0 0 0-.29-.4412.8748.8748 0 0 0-.9997-.0537.8585.8585 0 0 0-.3362.4049L.4332 9.5015l-.0325.0862a6.0657 6.0657 0 0 0 2.0119 7.0105l.0113.0087.03.0213 4.976 3.7264 2.462 1.8633 1.4995 1.1321a1.0085 1.0085 0 0 0 1.2197 0l1.4995-1.1321 2.4619-1.8633 5.006-3.7489.0125-.01a6.0682 6.0682 0 0 0 2.0094-7.003z"/></svg>
|
||||||
|
After Width: | Height: | Size: 573 B |
7
src/images/Keyoxide.svg
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<svg version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m14.662 2.7734c-0.86914 8.5e-6 -1.5742 0.70509-1.5742 1.5742 0 0.52528 0.26095 1.006 0.67773 1.2949 0.12007 0.083138 0.18912 0.092562 0.20508 0.22266 0.01604 0.13001-0.16211 0.25-0.16211 0.25l-3.3242 2.5859v-0.5293c0.14724-1.4561-0.83223-2.9405-2.2754-3.2793-1.719-0.502-3.7931 1.0298-3.7931 2.6452 0 1.9182 0.00778 8.9247 0.00211 13.429-0.00211 1.6772 1.3577 3.0332 3.0332 3.0332s3.0352-1.3576 3.0352-3.0332v-0.39648c1.365 0.90898 2.7303 1.8174 4.0938 2.7285 1.1299 0.93021 2.9078 0.93859 3.9902-0.07422 1.3712-1.1518 1.323-3.4999-0.0918-4.5957-1.935-1.3219-3.8897-2.6181-5.8418-3.916l5.7734-4.4883c1.1632-0.90466 1.4954-2.5005 0.83398-3.7832-0.04938-0.095755-0.06511-0.12998-0.16797-0.16992-0.10277-0.039938-0.18425 0.00439-0.28711 0.042969-0.14138 0.053062-0.29257 0.080078-0.44531 0.080078-0.69894 0-1.2656-0.56662-1.2656-1.2656 9.4e-5 -0.094853 0.01636-0.14996-0.01172-0.20898-0.02807-0.059023-0.10233-0.097092-0.17578-0.10547-0.12191-0.013926-0.24437-0.020476-0.36719-0.019531-0.12049 8.587e-4 -0.21169-0.00952-0.26367-0.097656-0.05189-0.088142-0.02344-0.18975-0.02344-0.34961 0-0.86915-0.70504-1.5742-1.5742-1.5742z"/>
|
||||||
|
<path d="m12.806 3.085a1.0735 1.0735 0 0 1-1.0735 1.0735 1.0735 1.0735 0 0 1-1.0735-1.0735 1.0735 1.0735 0 0 1 1.0735-1.0735 1.0735 1.0735 0 0 1 1.0735 1.0735z"/>
|
||||||
|
<path d="m13.458 1.0033a0.70038 0.70038 0 0 1-0.70038 0.70038 0.70038 0.70038 0 0 1-0.70038-0.70038 0.70038 0.70038 0 0 1 0.70038-0.70038 0.70038 0.70038 0 0 1 0.70038 0.70038z"/>
|
||||||
|
<path d="m11.339 0.48902a0.48902 0.48902 0 0 1-0.48902 0.48902 0.48902 0.48902 0 0 1-0.48902-0.48902 0.48902 0.48902 0 0 1 0.48902-0.48902 0.48902 0.48902 0 0 1 0.48902 0.48902z"/>
|
||||||
|
<path d="m19.203 5.1296a0.85797 0.85797 0 0 1-0.85797 0.85797 0.85797 0.85797 0 0 1-0.85797-0.85797 0.85797 0.85797 0 0 1 0.85797-0.85797 0.85797 0.85797 0 0 1 0.85797 0.85797z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
5
src/images/LinkedIn.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="1em"
|
||||||
|
viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
||||||
|
<path
|
||||||
|
d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 698 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
21
src/layouts/BaseLayout.astro
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
import "../styles/global.css";
|
||||||
|
const { title } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="color-scheme" content="light dark" />
|
||||||
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
<title>{title}</title>
|
||||||
|
</head>
|
||||||
|
<body
|
||||||
|
class="flex min-h-screen flex-col justify-center p-6 sm:px-14 md:px-24 lg:px-32"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
7
src/link-utils.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export function getRel(
|
||||||
|
external: boolean | "me" | null | undefined,
|
||||||
|
): string | undefined {
|
||||||
|
return external
|
||||||
|
? "external nofollow noreferrer".concat(external === "me" ? " me" : "")
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
@@ -1,49 +1,134 @@
|
|||||||
---
|
---
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import ExternalLink from "../components/external-link.astro";
|
import ButtonLink from "../components/button-link.astro";
|
||||||
import InlineSvg from "../components/inline-svg.astro";
|
import InlineLink from "../components/inline-link.astro";
|
||||||
import MatrixLogo from "../images/matrix-logo.svg";
|
import GitHubLogo from "../images/GitHub.svg";
|
||||||
|
import GitLabLogo from "../images/GitLab.svg";
|
||||||
|
import KeyoxideLogo from "../images/Keyoxide.svg";
|
||||||
|
import LinkedInLogo from "../images/LinkedIn.svg";
|
||||||
|
import MatrixLogo from "../images/Matrix-logo.svg";
|
||||||
import portrait from "../images/portrait.jpg";
|
import portrait from "../images/portrait.jpg";
|
||||||
import "../styles/global.css";
|
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<!doctype html>
|
<BaseLayout title="kmoschcau.de">
|
||||||
<html lang="de">
|
<main>
|
||||||
<head>
|
<article class="flex flex-col items-center gap-10">
|
||||||
<meta charset="utf-8" />
|
<Image
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
alt="Portrait von Kai Moschcau"
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
class="rounded-full"
|
||||||
<meta name="color-scheme" content="light dark" />
|
priority
|
||||||
<meta name="generator" content={Astro.generator} />
|
src={portrait}
|
||||||
<title>kmoschcau.de</title>
|
width={200}
|
||||||
</head>
|
height={200}
|
||||||
<body
|
/>
|
||||||
class="flex min-h-screen flex-col justify-center p-6 sm:px-14 md:px-24 lg:px-32"
|
<h1>Kai Moschcau</h1>
|
||||||
>
|
<p class="text-soft">
|
||||||
<main>
|
<strong>PGP fingerprint:</strong>
|
||||||
<article class="flex flex-col items-center gap-10">
|
<code>0x DF16 F424 1770 90BB</code>
|
||||||
<Image
|
</p>
|
||||||
alt="Portrait von Kai Moschcau"
|
<section class="text-soft">
|
||||||
class="rounded-full"
|
<p><strong>Fachinformatiker</strong> für Anwendungsentwicklung</p>
|
||||||
priority
|
<p><strong>Software Developer & Consultant</strong> @ blecon</p>
|
||||||
src={portrait}
|
</section>
|
||||||
width={200}
|
<nav aria-label="Seitennavigation" class="page-nav">
|
||||||
height={200}
|
<ul class="flex">
|
||||||
/>
|
|
||||||
<h1>Kai Moschcau</h1>
|
|
||||||
<ul class="flex flex-col gap-2">
|
|
||||||
<li>
|
<li>
|
||||||
<ExternalLink
|
<a href="/skills" class="font-medium underline">Skills</a>
|
||||||
cssClass="link-matrix"
|
</li>
|
||||||
href="https://matrix.to/#/@kmoschcau:matrix.org"
|
<li>
|
||||||
title="Mein Matrix Konto"
|
<InlineLink
|
||||||
|
href="https://blecon.de"
|
||||||
|
external
|
||||||
|
class="font-medium underline">blecon.de</InlineLink
|
||||||
>
|
>
|
||||||
<InlineSvg SvgComponent={MatrixLogo} slot="logo" />
|
|
||||||
<span>@kmoschcau:matrix.org</span>
|
|
||||||
</ExternalLink>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</article>
|
</nav>
|
||||||
</main>
|
<nav aria-label="Externe Links">
|
||||||
</body>
|
<ul class="flex flex-col gap-2">
|
||||||
</html>
|
<li>
|
||||||
|
<ButtonLink
|
||||||
|
class="link-matrix"
|
||||||
|
href="https://matrix.to/#/@kmoschcau:matrix.org"
|
||||||
|
title="Mein Matrix-Konto"
|
||||||
|
external="me"
|
||||||
|
>
|
||||||
|
<MatrixLogo
|
||||||
|
class="size-6"
|
||||||
|
fill="currentColor"
|
||||||
|
role="presentation"
|
||||||
|
slot="logo"
|
||||||
|
/>
|
||||||
|
<span>@kmoschcau:matrix.org</span>
|
||||||
|
</ButtonLink>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<ButtonLink
|
||||||
|
class="link-github"
|
||||||
|
href="https://github.com/kmoschcau/"
|
||||||
|
title="Mein GitHub-Konto"
|
||||||
|
external="me"
|
||||||
|
>
|
||||||
|
<GitHubLogo
|
||||||
|
class="size-6"
|
||||||
|
fill="currentColor"
|
||||||
|
role="presentation"
|
||||||
|
slot="logo"
|
||||||
|
/>
|
||||||
|
<span>kmoschcau</span>
|
||||||
|
</ButtonLink>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<ButtonLink
|
||||||
|
class="link-gitlab"
|
||||||
|
href="https://gitlab.com/kmoschcau"
|
||||||
|
title="Mein GitLab-Konto"
|
||||||
|
external="me"
|
||||||
|
>
|
||||||
|
<GitLabLogo
|
||||||
|
class="size-6"
|
||||||
|
fill="currentColor"
|
||||||
|
role="presentation"
|
||||||
|
slot="logo"
|
||||||
|
/>
|
||||||
|
<span>kmoschcau</span>
|
||||||
|
</ButtonLink>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<ButtonLink
|
||||||
|
class="link-linked-in"
|
||||||
|
href="https://www.linkedin.com/in/kmoschcau/"
|
||||||
|
title="Mein LinkedIn-Konto"
|
||||||
|
external="me"
|
||||||
|
>
|
||||||
|
<LinkedInLogo
|
||||||
|
class="size-6"
|
||||||
|
fill="currentColor"
|
||||||
|
role="presentation"
|
||||||
|
slot="logo"
|
||||||
|
/>
|
||||||
|
<span>kmoschcau</span>
|
||||||
|
</ButtonLink>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<ButtonLink
|
||||||
|
class="link-keyoxide"
|
||||||
|
href="https://keyoxide.org/8CE00E9495B5030DA9217208DF16F424177090BB"
|
||||||
|
title="Mein Keyoxide-Eintrag"
|
||||||
|
external="me"
|
||||||
|
>
|
||||||
|
<KeyoxideLogo
|
||||||
|
class="size-6"
|
||||||
|
fill="currentColor"
|
||||||
|
role="presentation"
|
||||||
|
slot="logo"
|
||||||
|
/>
|
||||||
|
<span>Keyoxide</span>
|
||||||
|
</ButtonLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
</BaseLayout>
|
||||||
|
|||||||
223
src/pages/skills.astro
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
---
|
||||||
|
import ArrowLeftCircle from "../icons/arrow-left-circle.svg";
|
||||||
|
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||||
|
import {
|
||||||
|
getDurationInYearsBetween as between,
|
||||||
|
getDurationInYearsFrom as from,
|
||||||
|
} from "../duration-utils";
|
||||||
|
import InlineLink from "../components/inline-link.astro";
|
||||||
|
|
||||||
|
const trStart = new Date(2011, 7, 1);
|
||||||
|
|
||||||
|
const trustStart = new Date(2014, 6, 1);
|
||||||
|
const migrEnd = new Date(2017, 0, 0);
|
||||||
|
|
||||||
|
const cbtStart = new Date(2018, 0, 1);
|
||||||
|
|
||||||
|
const pfmStart = new Date(2020, 0, 1);
|
||||||
|
|
||||||
|
const cbtEnd = new Date(2023, 7, 0);
|
||||||
|
const cbt = [cbtStart, cbtEnd] as const;
|
||||||
|
|
||||||
|
const mcB2cStart = new Date(2023, 10, 1);
|
||||||
|
const mcB2cEnd = new Date(2024, 5, 0);
|
||||||
|
|
||||||
|
const bpStart = new Date(2024, 5, 1);
|
||||||
|
const bpEnd = new Date(2025, 1, 0);
|
||||||
|
const bp = [bpStart, bpEnd] as const;
|
||||||
|
|
||||||
|
const kcStart = new Date(2026, 0, 1);
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout title="kmoschcau.de | Skills">
|
||||||
|
<main class="flex items-center justify-center">
|
||||||
|
<article>
|
||||||
|
<div class="mb-8 flex items-baseline gap-6">
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
aria-label="Zurück"
|
||||||
|
title="Zurück"
|
||||||
|
class="text-soft rounded-full"
|
||||||
|
><ArrowLeftCircle role="presentation" class="size-9" /></a
|
||||||
|
>
|
||||||
|
<h1>Skills</h1>
|
||||||
|
</div>
|
||||||
|
<div class="prose prose-zinc dark:prose-invert">
|
||||||
|
<section>
|
||||||
|
<h2>💻 Softwareentwicklung & Technologien</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Webentwicklung – {from(cbtStart)}+ Jahre<br />
|
||||||
|
(moderne Web-UIs, Responsive Design, komplexe Komponenten, Frontend-Integration,
|
||||||
|
Web Accessibility, Web App Security)<br />
|
||||||
|
(HTML, CSS, JavaScript, Typescript, TailwindCSS, daisyUI, SASS, vite,
|
||||||
|
WebSocket, jQuery, drizzle ORM, Mocha, Chai, Jest)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Frontend-Frameworks – {from(cbtStart)}+ Jahre<br />
|
||||||
|
(Erweitern und Umbauen von statischen Web-App Frontends in reactive
|
||||||
|
Frontends, Neubau von reaktiven Frontends)<br />
|
||||||
|
(Vue 2, Vue 3, Astro, Svelte, SvelteKit, React)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Java – {between(...cbt) + from(kcStart)}+ Jahre<br />
|
||||||
|
(Enterprise B2B und B2C Web-Anwendungen, Web-APIs, Keycloak-Plugins,
|
||||||
|
saubere Architekturen, Web App Security)<br />
|
||||||
|
(Spring Boot, Spring MVC, Spring Security, Hibernate, JPA, Freemarker,
|
||||||
|
Thymeleaf, JSP, REST, JUnit, Mockito, Gradle, Maven)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
C# - {from(pfmStart)}+ Jahre<br />
|
||||||
|
(REST- und SOAP-APIs mit hohem Durchsatz, Enterprise-Anwendungen, Web-APIs,
|
||||||
|
Backend-Systeme, saubere Architekturen, Web App Security)<br />
|
||||||
|
(.NET 8, .NET Framework 4.8, Entity Framework Core, NHibernate, ASP.NET
|
||||||
|
Core, Blazor, Razor, REST, SOAP, NUnit, Moq)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
REST-APIs & Backend-Services - {from(cbtStart)}+ Jahre<br />
|
||||||
|
(Schnittstellenkonzeption, REST, SignalR, WebSockets)
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>🛡️ IT-Sicherheit</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Sichere Anwendungsentwicklung & Design – {from(cbtStart)}+
|
||||||
|
Jahre<br />
|
||||||
|
(OWASP, SSDLC, Threat Modeling, Web App Security)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Authentication & Authorization – {from(cbtStart)}+ Jahre<br />
|
||||||
|
(in-App & extern)<br />
|
||||||
|
(OAuth2, OIDC, Keycloak)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Observability im Betrieb – {from(cbtStart)}+ Jahre<br />
|
||||||
|
(Log-Analyse und statistische Auswertung, Telemetrie und Alarme)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Sicherheits-Analyse und Tests – {between(...cbt)}+ Jahre<br />
|
||||||
|
(statische und Dynamische Code Analyse, manuelles Penetration Testing)<br
|
||||||
|
/>
|
||||||
|
(SonarQube, Veracode, Qualys, Zed Attack Proxy)
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>☁️ Cloud, DevOps & Betrieb</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Public, Private & Clouds – {between(cbtStart, mcB2cEnd)}+
|
||||||
|
Jahre<br />
|
||||||
|
(<InlineLink
|
||||||
|
href="https://www.credly.com/badges/e06dda2d-a444-448d-809a-31565c3b8c8d/public_url"
|
||||||
|
external="me"
|
||||||
|
>AWS Certified Solutions Architect – Associate</InlineLink
|
||||||
|
>, AWS, GCP, Azure, CloudFormation, HashiCorp Terraform)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
CI/CD & DevOps – {from(cbtStart)}+ Jahre<br />
|
||||||
|
(Git, GitHub Actions, GitLab, Gitrunner, Azure DevOps, Jenkins)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Containerisierung & Images – {from(cbtStart)}+ Jahre<br />
|
||||||
|
(Docker, Docker Compose, Kubernetes, Helm, HashiCorp Packer)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Deployment- & Release-Management – {from(cbtStart)}+ Jahre
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>🗄️ Datenbanken & Persistence</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Relationale Datenbanken – {from(trustStart)}+ Jahre<br />
|
||||||
|
(MySQL, Oracle DB, Microsoft SQL Server, SQLite, PostgreSQL)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Datenmodellierung & Performance-Optimierung – {
|
||||||
|
between(...cbt) + between(...bp)
|
||||||
|
}+ Jahre
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Data Warehousing – {between(trustStart, migrEnd)}+ Jahre
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>🧱 Architektur & Software Design</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Software-Architektur & Systemdesign – {from(cbtStart)}+ Jahre
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Modulare Systeme & Multitenancy-Architekturen – {
|
||||||
|
from(cbtStart)
|
||||||
|
}+ Jahre
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Clean Code, Wartbarkeit & Skalierbarkeit – {from(cbtStart)}+
|
||||||
|
Jahre
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>🔁 Methoden & Projektarbeit</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Agile Entwicklung (Scrum) – {from(trustStart)}+ Jahre
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Technische Projektverantwortung – {
|
||||||
|
between(...cbt) + between(...bp) + from(kcStart)
|
||||||
|
}+ Jahre
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Kundenberatung & technische Abstimmung – {from(mcB2cStart)}+
|
||||||
|
Jahre
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Code Reviews & technische Qualitätssicherung – {
|
||||||
|
from(cbtStart)
|
||||||
|
}+ Jahre
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>🧪 Weitere Technologien & Interessen</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Mentoring & Wissensvermittlung im Team – {from(mcB2cStart)}+
|
||||||
|
Jahre
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Git & GitHub (Open Source, Versionskontrolle) – {
|
||||||
|
from(trStart)
|
||||||
|
}+ Jahre
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Betriebssysteme: Linux (Daily Driver privat), Windows (Daily
|
||||||
|
Driver Arbeit)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Weitere Sprachen, Frameworks und Tools: Ruby, Rust, LaTeX, Lua,
|
||||||
|
treesitter, Shell, Python, C/C++, SSH, systemd, cron, Vim, Neovim
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Interesse an 3D-Grafik: 3D Modellierung, Blender, Grundkonzepte
|
||||||
|
3D-Renderer
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
</BaseLayout>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
@plugin "@tailwindcss/typography";
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--color-background-dark: oklch(from var(--color-violet-950) 24% 0.08 h);
|
--color-background-dark: oklch(from var(--color-violet-950) 24% 0.08 h);
|
||||||
@@ -6,14 +7,24 @@
|
|||||||
--link-bg-l: 53.5%;
|
--link-bg-l: 53.5%;
|
||||||
--hover-darken: 0.05;
|
--hover-darken: 0.05;
|
||||||
|
|
||||||
--color-fur-affinity: oklch(from #353b45 var(--link-bg-l) c h);
|
--color-github: #1f2328;
|
||||||
--color-fur-affinity-hover: oklch(
|
--color-github-hover: oklch(
|
||||||
from var(--color-fur-affinity) calc(l - var(--hover-darken)) c h
|
from var(--color-github) calc(l - var(--hover-darken)) c h
|
||||||
);
|
);
|
||||||
|
|
||||||
--color-mastodon: oklch(from #6364ff var(--link-bg-l) c h);
|
--color-gitlab: #e24329;
|
||||||
--color-mastodon-hover: oklch(
|
--color-gitlab-hover: oklch(
|
||||||
from var(--color-mastodon) calc(l - var(--hover-darken)) c h
|
from var(--color-gitlab) calc(l - var(--hover-darken)) c h
|
||||||
|
);
|
||||||
|
|
||||||
|
--color-keyoxide: #6855c3;
|
||||||
|
--color-keyoxide-hover: oklch(
|
||||||
|
from var(--color-keyoxide) calc(l - var(--hover-darken)) c h
|
||||||
|
);
|
||||||
|
|
||||||
|
--color-linked-in: #0b66c3;
|
||||||
|
--color-linked-in-hover: oklch(
|
||||||
|
from var(--color-linked-in) calc(l - var(--hover-darken)) c h
|
||||||
);
|
);
|
||||||
|
|
||||||
--color-matrix: oklch(from #0dbd8b var(--link-bg-l) c h);
|
--color-matrix: oklch(from #0dbd8b var(--link-bg-l) c h);
|
||||||
@@ -24,7 +35,7 @@
|
|||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
body {
|
body {
|
||||||
@apply dark:bg-background-dark bg-neutral-50 text-black dark:text-white;
|
@apply dark:bg-background-dark bg-neutral-50 text-zinc-900 dark:text-zinc-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@@ -33,12 +44,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
.link-fur-affinity {
|
.page-nav li:not(:first-child) {
|
||||||
@apply bg-fur-affinity hover:bg-fur-affinity-hover text-white;
|
@apply ms-2 border-s border-zinc-600 ps-2 dark:border-zinc-400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-mastodon {
|
.link-github {
|
||||||
@apply bg-mastodon hover:bg-mastodon-hover text-white;
|
@apply bg-github hover:bg-github-hover text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-gitlab {
|
||||||
|
@apply bg-gitlab hover:bg-gitlab-hover text-black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-keyoxide {
|
||||||
|
@apply bg-keyoxide hover:bg-keyoxide-hover text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-linked-in {
|
||||||
|
@apply bg-linked-in hover:bg-linked-in-hover text-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-matrix {
|
.link-matrix {
|
||||||
|
|||||||