Compare commits

..
10 Commits
36 changed files with 1599 additions and 397 deletions
+5
View File
@@ -40,3 +40,8 @@ desktop.ini
npm-debug.log
yarn-error.log
###< symfony/webpack-encore-bundle ###
###> symfony/asset-mapper ###
/public/assets/
/assets/vendor/
###< symfony/asset-mapper ###
+1
View File
@@ -6,6 +6,7 @@
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="App\Tests\" />
<excludeFolder url="file://$MODULE_DIR$/var" />
<excludeFolder url="file://$MODULE_DIR$/vendor" />
<excludeFolder url="file://$MODULE_DIR$/public/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
+24
View File
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PhpDockerContainerSettings">
<list>
<map>
<entry key="0bef9119-879f-4b48-9f5f-1234513849a3">
<value>
<DockerContainerSettings>
<option name="version" value="1" />
<option name="volumeBindings">
<list>
<DockerVolumeBindingImpl>
<option name="containerPath" value="/opt/project" />
<option name="hostPath" value="$PROJECT_DIR$" />
</DockerVolumeBindingImpl>
</list>
</option>
</DockerContainerSettings>
</value>
</entry>
</map>
</list>
</component>
</project>
Generated
+6
View File
@@ -59,6 +59,12 @@
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/webpack-encore-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/asset" />
<path value="$PROJECT_DIR$/vendor/twig/extra-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/asset-mapper" />
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
<path value="$PROJECT_DIR$/vendor/psr/link" />
<path value="$PROJECT_DIR$/vendor/symfony/web-link" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Symfony2PluginSettings">
<option name="pluginEnabled" value="true" />
<option name="profilerCsvPath" value="" />
</component>
</project>
+1 -1
View File
@@ -5,7 +5,7 @@
* (and its CSS file) in your base layout (base.html.twig).
*/
// require('bootstrap');
require('bootstrap');
// any CSS you import will output into a single css file (app.scss in this case)
import './styles/app.scss';
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

+74 -17
View File
@@ -1,3 +1,37 @@
@use 'app/nav';
@use 'app/footer';
// =============================================================================
// Fonts
// =============================================================================
@font-face {
font-family: 'Agave';
src: url('../fonts/agave-regular.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Fantasque Sans Mono';
src: url('../fonts/fantasque-sans-mono-regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('../fonts/jetbrains-mono-regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Material Symbols Outlined';
font-style: normal;
src: url('../fonts/material-symbols-outlined.woff2') format('woff');
}
// =============================================================================
// Design Tokens — Light Palette
// =============================================================================
@@ -90,8 +124,8 @@ $dk-on-background: #dae2fd;
// Shared Tokens — Typography & Radius
// =============================================================================
$font-display: 'Space Grotesk', system-ui, sans-serif;
$font-body: 'Geist', system-ui, -apple-system, sans-serif;
$font-display: 'Agave', system-ui, sans-serif;
$font-body: 'Fantasque Sans Mono', system-ui, -apple-system, sans-serif;
$font-mono: 'JetBrains Mono', 'Courier New', monospace;
$radius-sm: 0.25rem;
@@ -325,15 +359,15 @@ $code-color-dark: $dk-tertiary; // #c0c1ff
body {
background-color: var(--color-background);
color: var(--color-on-surface);
font-family: var(--font-body);
font-family: var(--font-body), sans-serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-display);
font-family: var(--font-display), serif;
}
code, kbd, pre, samp {
font-family: var(--font-mono);
font-family: var(--font-mono), monospace;
}
// =============================================================================
@@ -341,7 +375,7 @@ code, kbd, pre, samp {
// =============================================================================
.text-display-lg {
font-family: var(--font-display);
font-family: var(--font-display), serif;
font-size: 64px;
font-weight: 700;
line-height: 1.1;
@@ -354,27 +388,27 @@ code, kbd, pre, samp {
}
.text-headline-md {
font-family: var(--font-display);
font-family: var(--font-display), serif;
font-size: 32px;
font-weight: 600;
line-height: 1.3;
}
.text-body-lg {
font-family: var(--font-body);
font-family: var(--font-body), sans-serif;
font-size: 18px;
line-height: 1.6;
}
.text-body-md {
font-family: var(--font-body);
font-family: var(--font-body), sans-serif;
font-size: 16px;
line-height: 1.5;
}
// Primary label style (light design doc)
.text-label-sm {
font-family: var(--font-mono);
font-family: var(--font-mono), monospace;
font-size: 13px;
font-weight: 500;
line-height: 1;
@@ -383,7 +417,7 @@ code, kbd, pre, samp {
// Variant with uppercase transform (dark design doc)
.text-label-caps {
font-family: var(--font-mono);
font-family: var(--font-mono), monospace;
font-size: 12px;
font-weight: 600;
line-height: 1;
@@ -432,7 +466,7 @@ code, kbd, pre, samp {
}
.card-title {
font-family: var(--font-display);
font-family: var(--font-display), serif;
color: var(--color-on-surface);
}
}
@@ -461,7 +495,7 @@ code, kbd, pre, samp {
// JetBrains Mono for all form labels
label,
.form-label {
font-family: var(--font-mono);
font-family: var(--font-mono), monospace;
font-size: 13px;
font-weight: 500;
letter-spacing: 0.05em;
@@ -479,7 +513,7 @@ label,
border-bottom: 1px solid var(--color-outline-variant);
.nav-link {
font-family: var(--font-mono);
font-family: var(--font-mono), monospace;
font-size: 13px;
font-weight: 500;
letter-spacing: 0.05em;
@@ -496,7 +530,7 @@ label,
// --- Tech Chips / Badges ---
.badge-tech {
font-family: var(--font-mono);
font-family: var(--font-mono), monospace;
font-size: 12px;
font-weight: 500;
letter-spacing: 0.05em;
@@ -517,7 +551,7 @@ pre {
border-radius: var(--radius);
code {
font-family: var(--font-mono);
font-family: var(--font-mono), monospace;
font-size: 14px;
color: var(--color-on-surface);
}
@@ -526,7 +560,7 @@ pre {
position: absolute;
top: var(--spacing-sm);
right: var(--spacing-md);
font-family: var(--font-mono);
font-family: var(--font-mono), monospace;
font-size: 12px;
font-weight: 500;
letter-spacing: 0.05em;
@@ -545,3 +579,26 @@ pre {
box-shadow: var(--glow-primary);
}
}
.material-symbols-outlined {
font-family: 'Material Symbols Outlined', serif;
font-weight: normal;
font-style: normal;
font-size: 20px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
}
// =============================================================================
// CSS Settings
// =============================================================================
main {
margin-top: 64px;
margin-bottom: 45px;
}
+20
View File
@@ -0,0 +1,20 @@
.footer-link {
color: rgba(255, 255, 255, .6);
transition: color .15s ease;
}
.footer-link:hover {
color: var(--color-primary-container);
}
#footer {
z-index: 50;
background: rgba(0,0,0,.3);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
border-color: rgba(192, 199, 211, .1) !important;
}
#footer-copyright {
color: rgba(255,255,255,.4);
}
+37
View File
@@ -0,0 +1,37 @@
nav div {
min-height: 64px;
}
/* Glassmorphism nav — uses RGB channel var for rgba() composition */
.nav-glass {
background-color: rgba(var(--color-surface-container-lowest-rgb), .85);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
/* Nav link colours — needs :hover, can't do inline */
.nav-link-ds {
color: var(--color-on-surface-variant);
transition: color .15s ease;
}
.nav-link-ds:hover {
color: #50a7fa;
}
#top-nav {
z-index: 50;
border-color: rgba(192, 199, 211, .3) !important;
}
#nav-site-name {
font-family: var(--font-display), serif;
letter-spacing: -.02em;
font-size: 1rem;
text-decoration: none;
}
#nav-brand-logo {
height: 30px;
width: auto;
}
+159
View File
@@ -0,0 +1,159 @@
body {
height: 100vh;
}
main {
margin-top: 0 !important;
margin-bottom: 0 !important;
}
/* Scanline sweep */
.scanline {
position: absolute;
bottom: 100%;
width: 100%;
height: 100px;
pointer-events: none;
background: linear-gradient(0deg, transparent 0%, rgba(80, 167, 250, .05) 50%, transparent 100%);
opacity: .1;
animation: scanline 8s linear infinite;
}
@keyframes scanline {
0% {
bottom: 100%;
}
100% {
bottom: -100px;
}
}
/* Primary hero button shimmer */
.hero-btn-primary {
position: relative;
overflow: hidden;
}
.hero-btn-primary::before {
content: '';
position: absolute;
inset: 0;
background: rgba(255, 255, 255, .2);
transform: translateY(100%);
transition: transform .3s ease;
}
.hero-btn-primary:hover::before {
transform: translateY(0);
}
/* Azure glow on hover */
.glow-hover:hover {
box-shadow: 0 0 25px rgba(80, 167, 250, .4);
}
.badge {
background: rgba(80, 167, 250, .1);
border: 1px solid rgba(80, 167, 250, .3);
}
.badge .text-label-sm {
color: var(--color-primary-container);
letter-spacing: .15em;
}
/* Pulsing availability dot */
.dot-pulse {
animation: dot-pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;
display: inline-block;
width: 8px;
height: 8px;
background: #50a7fa;
}
@keyframes dot-pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: .35;
}
}
.headline {
text-shadow: 0 2px 4px rgba(0, 0, 0, .8);
}
.headline span {
color: var(--color-primary-container);
}
.subheadline {
max-width: 640px;
color: rgba(255, 255, 255, .85);
text-shadow: 0 1px 2px rgba(0, 0, 0, .9);
}
/* Scroll indicator line */
.scroll-line {
width: 1px;
height: 48px;
background: linear-gradient(to bottom, #50a7fa, transparent);
}
.hud-decorator-line {
width: 128px;
height: 1px;
background-color: var(--color-primary-container);
}
.hud-decorator {
opacity: .4;
}
.hud-decorator p {
color: var(--color-primary-container);
letter-spacing: .3em;
}
#bg {
z-index: 0;
}
#bg-img {
filter: grayscale(.2) brightness(.75);
transform: scale(1.05);
}
#bg-overlay {
background: linear-gradient(to bottom, rgba(0, 0, 0, .6) 0%, transparent 50%, rgba(0, 0, 0, .8) 100%);
}
#content-div {
z-index: 10;
min-height: 100vh;
}
#hud-decorator-top-left {
margin-top: 96px;
}
#hud-decorator-bottom-right {
margin-bottom: 96px;
}
#hud-decorator-bottom span {
letter-spacing: .2em;
}
#hero-content {
max-width: 896px;
}
#button-about-me {
background: rgba(255, 255, 255, .05);
border: 1px solid rgba(255, 255, 255, .2);
backdrop-filter: blur(4px);
}
+11
View File
@@ -0,0 +1,11 @@
import "../../styles/root/root.css";
document.addEventListener('mousemove', (e) => {
const bg = document.getElementById('bg-img');
const x = (e.clientX - window.innerWidth / 2) * 0.005;
const y = (e.clientY - window.innerHeight / 2) * 0.005;
if (bg) {
bg.style.transform = `scale(1.05) translate(${x}px, ${y}px)`;
}
});
+1 -1
View File
@@ -14,7 +14,7 @@ if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
return static function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
return new Application($kernel);
+10 -2
View File
@@ -10,14 +10,21 @@
"ext-ctype": "*",
"ext-iconv": "*",
"ext-redis": "*",
"ext-zend-opcache": "*",
"symfony/asset": "8.1.*",
"symfony/asset-mapper": "8.1.*",
"symfony/cache": "8.1.*",
"symfony/console": "8.1.*",
"symfony/dotenv": "8.1.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "8.1.*",
"symfony/runtime": "8.1.*",
"symfony/twig-bundle": "8.1.*",
"symfony/web-link": "8.1.*",
"symfony/webpack-encore-bundle": "^2.4",
"symfony/yaml": "8.1.*"
"symfony/yaml": "8.1.*",
"twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0"
},
"require-dev": {
"symfony/debug-bundle": "8.1.*",
@@ -47,7 +54,8 @@
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
"assets:install %PUBLIC_DIR%": "symfony-cmd",
"importmap:install": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
Generated
+908 -356
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -7,4 +7,5 @@ return [
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
];
+11
View File
@@ -0,0 +1,11 @@
framework:
asset_mapper:
# The paths to make available to the asset mapper.
paths:
- assets/
missing_import_mode: strict
when@prod:
framework:
asset_mapper:
missing_import_mode: warn
+4
View File
@@ -17,3 +17,7 @@ when@test:
test: true
session:
storage_factory_id: session.storage.factory.mock_file
when@prod:
framework:
http_cache: true
+1 -1
View File
@@ -1,5 +1,5 @@
<?php
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
opcache_compile_file(dirname(__DIR__) . '/var/cache/prod/App_KernelProdContainer.preload.php');
}
+54 -3
View File
@@ -286,7 +286,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* }>,
* },
* asset_mapper?: bool|array{ // Asset Mapper configuration
* enabled?: bool|Param, // Default: false
* enabled?: bool|Param, // Default: true
* paths?: string|array<string, scalar|Param|null>,
* excluded_patterns?: list<scalar|Param|null>,
* exclude_dotfiles?: bool|Param, // If true, any files starting with "." will be excluded from the asset mapper. // Default: true
@@ -416,7 +416,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* log_channel?: scalar|Param|null, // The channel of log message. Null to let Symfony decide. // Default: null
* }>,
* web_link?: bool|array{ // Web links configuration
* enabled?: bool|Param, // Default: false
* enabled?: bool|Param, // Default: true
* },
* lock?: bool|string|array{ // Lock configuration
* enabled?: bool|Param, // Default: false
@@ -471,7 +471,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* },
* disallow_search_engine_index?: bool|Param, // Enabled by default when debug is enabled. // Default: true
* http_client?: bool|array{ // HTTP Client configuration
* enabled?: bool|Param, // Default: false
* enabled?: bool|Param, // Default: true
* max_host_connections?: int|Param, // The maximum number of connections to a single host.
* default_options?: array{
* headers?: array<string, mixed>,
@@ -763,6 +763,53 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* script_attributes?: array<string, scalar|Param|null>,
* link_attributes?: array<string, scalar|Param|null>,
* }
* @psalm-type TwigExtraConfig = array{
* cache?: bool|array{
* enabled?: bool|Param, // Default: false
* },
* html?: bool|array{
* enabled?: bool|Param, // Default: false
* },
* markdown?: bool|array{
* enabled?: bool|Param, // Default: false
* },
* intl?: bool|array{
* enabled?: bool|Param, // Default: false
* },
* cssinliner?: bool|array{
* enabled?: bool|Param, // Default: false
* },
* inky?: bool|array{
* enabled?: bool|Param, // Default: false
* },
* string?: bool|array{
* enabled?: bool|Param, // Default: false
* },
* commonmark?: array{
* renderer?: array{ // Array of options for rendering HTML.
* block_separator?: scalar|Param|null,
* inner_separator?: scalar|Param|null,
* soft_break?: scalar|Param|null,
* },
* html_input?: "strip"|"allow"|"escape"|Param, // How to handle HTML input.
* allow_unsafe_links?: bool|Param, // Remove risky link and image URLs by setting this to false. // Default: true
* max_nesting_level?: int|Param, // The maximum nesting level for blocks. // Default: 9223372036854775807
* max_delimiters_per_line?: int|Param, // The maximum number of strong/emphasis delimiters per line. // Default: 9223372036854775807
* slug_normalizer?: array{ // Array of options for configuring how URL-safe slugs are created.
* instance?: mixed,
* max_length?: int|Param, // Default: 255
* unique?: mixed,
* },
* commonmark?: array{ // Array of options for configuring the CommonMark core extension.
* enable_em?: bool|Param, // Default: true
* enable_strong?: bool|Param, // Default: true
* use_asterisk?: bool|Param, // Default: true
* use_underscore?: bool|Param, // Default: true
* unordered_list_markers?: list<scalar|Param|null>,
* },
* ...<string, mixed>
* },
* }
* @psalm-type ConfigType = array{
* imports?: ImportsConfig,
* parameters?: ParametersConfig,
@@ -770,6 +817,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* framework?: FrameworkConfig,
* twig?: TwigConfig,
* webpack_encore?: WebpackEncoreConfig,
* twig_extra?: TwigExtraConfig,
* "when@dev"?: array{
* imports?: ImportsConfig,
* parameters?: ParametersConfig,
@@ -780,6 +828,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* twig?: TwigConfig,
* maker?: MakerConfig,
* webpack_encore?: WebpackEncoreConfig,
* twig_extra?: TwigExtraConfig,
* },
* "when@prod"?: array{
* imports?: ImportsConfig,
@@ -788,6 +837,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* framework?: FrameworkConfig,
* twig?: TwigConfig,
* webpack_encore?: WebpackEncoreConfig,
* twig_extra?: TwigExtraConfig,
* },
* "when@test"?: array{
* imports?: ImportsConfig,
@@ -798,6 +848,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* debug?: DebugConfig,
* twig?: TwigConfig,
* webpack_encore?: WebpackEncoreConfig,
* twig_extra?: TwigExtraConfig,
* },
* ...<string, ExtensionType|array{ // extra keys must follow the when@%env% pattern or match an extension alias
* imports?: ImportsConfig,
+31
View File
@@ -0,0 +1,31 @@
<?php
/**
* Returns the importmap for this application.
*
* - "path" is a path inside the asset mapper system. Use the
* "debug:asset-map" command to see the full list of paths.
*
* - "entrypoint" (JavaScript only) set to true for any module that will
* be used as an "entrypoint" (and passed to the importmap() Twig function).
*
* The "importmap:require" command can be used to add new entries to this file.
*
* @return array<string, array{ // Import name as key, description of the imported file as value
* path: string, // Logical, relative or absolute path to the file
* type?: 'js'|'css'|'json', // Type of the file, defaults to 'js'
* entrypoint?: bool, // Whether the file is an entrypoint, for 'js' only
* }|array{
* version: string, // Version of the remote package
* package_specifier?: string, // Remote "package-name/path" specifier, defaults to the import name
* type?: 'js'|'css'|'json',
* entrypoint?: bool,
* }>
*/
return [
'app' => ['path' => './assets/app.js', 'entrypoint' => true],
'@symfony/webpack-encore' => ['version' => '6.0.0'],
'bootstrap' => ['version' => '5.3.8'],
'@popperjs/core' => ['version' => '2.11.8'],
'bootstrap/dist/css/bootstrap.min.css' => ['version' => '5.3.8', 'type' => 'css'],
];
+1
View File
@@ -24,6 +24,7 @@ server {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param PHP_IDE_CONFIG "serverName=localhost";
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
+1 -1
View File
@@ -4,6 +4,6 @@ use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
return static function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};
+18
View File
@@ -0,0 +1,18 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
final class RootController extends AbstractController
{
#[Route('/', name: 'app_root')]
public function index(): Response
{
return $this->render('root/root.html.twig', [
'controller_name' => 'RootController',
]);
}
}
+19 -1
View File
@@ -1,4 +1,19 @@
{
"symfony/asset-mapper": {
"version": "8.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.4",
"ref": "c01c47af2ec66a74ec046eccb919cfe27d3464ec"
},
"files": [
"assets/app.js",
"assets/styles/app.css",
"config/packages/asset_mapper.yaml",
"importmap.php"
]
},
"symfony/console": {
"version": "8.1",
"recipe": {
@@ -113,11 +128,14 @@
"ref": "b346dae458e64a1921ded2125993d94bd719a8dd"
},
"files": [
"assets/app.ts",
"assets/app.js",
"assets/styles/app.css",
"config/packages/webpack_encore.yaml",
"package.json",
"webpack.config.js"
]
},
"twig/extra-bundle": {
"version": "v3.24.0"
}
}
+13 -5
View File
@@ -1,13 +1,18 @@
<!DOCTYPE html>
<html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}creative-dragonslayer.de{% endblock %}</title>
<link rel="icon" href="{{ asset('images/logo.png') }}">
{% block stylesheets %}
{{ encore_entry_link_tags('app') }}
{% endblock %}
{% block head %}{% endblock %}
{% set frankenphpHotReload = app.request.server.get('FRANKENPHP_HOT_RELOAD') %}
{% if frankenphpHotReload %}
<meta name="frankenphp-hot-reload:url" content="{{ frankenphpHotReload }}">
@@ -16,14 +21,17 @@
{% endif %}
</head>
<body>
{% include 'widgets/nav_bar.html.twig' %}
<main>
{% block body %}{% endblock %}
</main>
<footer>
{% include 'widgets/footer.html.twig' %}
{% block javascripts %}
{% block importmap %}{{ importmap('app') }}{% endblock %}
{{ encore_entry_script_tags('app') }}
{% endblock %}
</footer>
</body>
</html>
+97
View File
@@ -0,0 +1,97 @@
{% extends 'base.html.twig' %}
{% block title %}creative-dragonslayer.de | Deep Space Engineering{% endblock %}
{% block stylesheets %}
{{ parent() }}
{{ encore_entry_link_tags('root') }}
<link rel="preload" href="{{ preload(asset('images/root/background.jpg'), { as: 'image' }) }}">
{% endblock %}
{% block javascripts %}
{{ parent() }}
{{ encore_entry_script_tags('root') }}
{% endblock %}
{% block body %}
{# ── Fixed Background ────────────────────────────────────────────────────── #}
<div id="bg" class="position-fixed top-0 start-0 w-100 h-100">
<img
id="bg-img"
src="{{ asset('images/root/background.jpg') }}"
alt="Hintergrundbild"
class="w-100 h-100 object-fit-cover"
>
<div id="bg-overlay" class="position-absolute top-0 start-0 w-100 h-100"></div>
<div class="scanline"></div>
</div>
<div id="content-div" class="position-relative d-flex flex-column align-items-center justify-content-center
w-100 text-center px-4">
{# HUD Decorator — Top Left #}
<div id="hud-decorator-top-left"
class="hud-decorator position-absolute top-0 start-0 d-none d-xl-flex flex-column gap-3 ps-4">
<div class="hud-decorator-line"></div>
<p class="text-label-sm mb-0 text-uppercase">System.Status: Stable</p>
<p class="text-label-sm mb-0 text-uppercase">Lat: 52.5200° N</p>
</div>
{# HUD Decorator — Bottom Right #}
<div id="hud-decorator-bottom-right"
class="hud-decorator position-absolute bottom-0 end-0 d-none d-xl-flex flex-column align-items-end gap-3 pe-4">
<p class="text-label-sm mb-0 text-end text-uppercase">V.0.9.0 // CORE</p>
<p class="text-label-sm mb-0 text-end text-uppercase">Syncing Precision...</p>
<div class="hud-decorator-line"></div>
</div>
{# Hero Content #}
<div id="hero-content" class="d-flex flex-column align-items-center gap-4">
{# Badge #}
<div class="badge d-inline-flex align-items-center gap-2 px-3 py-1 rounded-pill">
<span class="rounded-circle dot-pulse"></span>
<span class="text-label-sm text-uppercase">
Debugging Life Since 2018
</span>
</div>
{# Headline #}
<h1 class="text-display-lg mb-0 text-white lh-1 headline">
CREATIVE
<span class="fst-italic fw-light">
DRAGONSLAYER
</span>
</h1>
{# Subheadline #}
<p class="text-body-lg mb-0 mx-auto subheadline">
Code, Kommandozeile und Kaffee. Dies ist eine Sammlung meiner Hobbyprojekte, entwickelt mit
Leidenschaft. Hier geht es nicht um Skalierung oder Marktanteile, sondern darum, Probleme zu lösen,
die mich beschäftigen, und Techniken auszuprobieren, die mich neugierig machen.
</p>
{# CTAs #}
<div class="d-flex flex-column flex-sm-row gap-3 justify-content-center align-items-center mt-2">
<a href="#projects"
class="hero-btn-primary btn btn-primary text-white fw-bold px-5 py-3 rounded-3
glow-hover d-inline-flex align-items-center gap-2">
Zu den Projekten
<span class="material-symbols-outlined">arrow_forward</span>
</a>
<a href="#about" id="button-about-me" class="btn fw-bold px-5 py-3 rounded-3 text-white">
Werdegang
</a>
</div>
</div>
{# Scroll Indicator #}
<div id="hud-decorator-bottom" class="position-absolute bottom-0 start-50 translate-middle-x
d-flex flex-column align-items-center gap-2 pb-4 hud-decorator">
<span class="text-label-sm text-white text-uppercase">Deploying Scroll</span>
<div class="scroll-line"></div>
</div>
</div>
{% endblock %}
+14
View File
@@ -0,0 +1,14 @@
<footer class="position-fixed bottom-0 start-0 end-0 border-top"
id="footer">
<div class="container d-flex flex-column flex-md-row justify-content-between align-items-center py-3">
<div id="footer-copyright" class="text-label-sm fw-bold">
© 2026 creative-dragonslayer.de
</div>
<div class="d-flex gap-4 mt-2 mt-md-0">
{# <a href="#" class="text-label-sm text-decoration-none footer-link">Impressum</a>#}
{# <a href="#" class="text-label-sm text-decoration-none footer-link">Datenschutz</a>#}
{# <a href="#" class="text-label-sm text-decoration-none footer-link">Nutzungsbedingungen</a>#}
<a href="#" class="text-label-sm text-decoration-none footer-link">Credits</a>
</div>
</div>
</footer>
+51
View File
@@ -0,0 +1,51 @@
<nav class="position-fixed top-0 start-0 end-0 nav-glass border-bottom"
id="top-nav"
aria-label="Hauptnavigation">
<div class="container d-flex justify-content-between align-items-center">
{# Links: Logo + CTDRA #}
<a href="/" id="nav-site-name" class="d-flex align-items-center gap-2 text-decoration-none">
<img src="{{ asset('images/logo.png') }}"
alt="CTDRA Logo"
id="nav-brand-logo"
style="height: 40px; width: auto;">
<span class="fw-bold text-white">CTDRA</span>
</a>
{# Mitte: Desktop-Links zentriert #}
<div class="d-none d-md-flex align-items-center gap-4 mx-auto">
<a href="#" class="text-label-sm text-decoration-none nav-link-ds">News</a>
<a href="#" class="text-label-sm text-decoration-none nav-link-ds">Projects</a>
<a href="#" class="text-label-sm text-decoration-none nav-link-ds">About Me</a>
</div>
{# Rechts: Hamburger-Button (nur Mobile) + Platzhalter für Desktop #}
<div class="d-flex align-items-center">
{# Hamburger Button für Mobile mit Material Icon #}
<button class="navbar-toggler d-md-none border-0 text-white p-0"
type="button"
data-bs-toggle="collapse"
data-bs-target="#mobile-menu"
aria-controls="mobile-menu"
aria-expanded="false"
aria-label="Navigation umschalten">
<span class="material-symbols-outlined">menu</span>
</button>
{# Platzhalter für Desktop (hält Balance) #}
<div class="d-none d-md-block">&nbsp;</div>
</div>
</div>
{# Mobile Menu Container (Collapsible) #}
<div class="collapse d-md-none" id="mobile-menu">
<div class="container py-3">
<div class="d-flex flex-column gap-3">
<a href="#" class="text-label-sm text-decoration-none text-white fs-6">News</a>
<a href="#" class="text-label-sm text-decoration-none text-white fs-6">Projects</a>
<a href="#" class="text-label-sm text-decoration-none text-white fs-6">About Me</a>
</div>
</div>
</div>
</nav>
+6 -1
View File
@@ -8,7 +8,12 @@
"isolatedModules": true,
"esModuleInterop": true,
"skipLibCheck": true,
"noEmit": true
"noEmit": true,
"plugins":[
{
"name": "typescript-plugin-css"
}
]
},
"include": ["assets/**/*"]
}
+6 -1
View File
@@ -20,7 +20,9 @@ Encore
* Each entry will result in one JavaScript file (e.g. app.js)
* and one CSS file (e.g. app.css) if your JavaScript imports CSS.
*/
.addEntry('app', './assets/app.ts')
.addEntry('app', './assets/app.js')
.addEntry('root', './assets/ts/root/root.ts')
// When enabled, Webpack "splits" your files into smaller pieces for greater optimization.
.splitEntryChunks()
@@ -61,6 +63,9 @@ Encore
// uncomment if you use TypeScript
.enableTypeScriptLoader()
// optionally enable forked type script for faster builds
// https://www.npmjs.com/package/fork-ts-checker-webpack-plugin
// requires that you have a tsconfig.json file that is setup correctly.
.enableForkedTypeScriptTypesChecking()
// uncomment if you use React