first commit

This commit is contained in:
2022-11-20 21:46:36 +00:00
commit e3f445cd0d
54 changed files with 10801 additions and 0 deletions

24
.env Normal file
View File

@@ -0,0 +1,24 @@
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=b0d53a61c5f01a98f6a4cabc3398e307
###< symfony/framework-bundle ###
###> symfony/mailer ###
# MAILER_DSN=null://null
###< symfony/mailer ###

15
.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###
###> pentatrion/vite-bundle ###
/node_modules/
/public/build/
###< pentatrion/vite-bundle ###

1
README.md Normal file
View File

@@ -0,0 +1 @@
# portfolio

3
assets/app.css Normal file
View File

@@ -0,0 +1,3 @@
body {
background-color: #eeeeee;
}

3
assets/app.js Normal file
View File

@@ -0,0 +1,3 @@
import "./app.css";
console.log("Happy coding !!");

9
assets/js/main.js Executable file
View File

@@ -0,0 +1,9 @@
import "../scss/style.scss";
import "./simple-lightbox.js";
(function () {
var $gallery = new SimpleLightbox(".gallery a", {});
})();
// import "./pagination.js"

3093
assets/js/simple-lightbox.js Normal file

File diff suppressed because it is too large Load Diff

8
assets/scss/album/basic.scss Executable file
View File

@@ -0,0 +1,8 @@
@import "./details.scss";
@import "./child.scss";
.my_album {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-gap: 50px;
}

View File

@@ -0,0 +1,20 @@
$ImageWidth: 260px;
$ImageHeight: 180px;
$BDRadius: 15px;
.my_album_child {
img {
display: block;
border-radius: $BDRadius;
width: $ImageWidth;
height: $ImageHeight;
object-fit: cover;
box-shadow: $BorderShadow;
}
}

View File

12
assets/scss/breadcrumbs.scss Executable file
View File

@@ -0,0 +1,12 @@
.my_breadcrumbs {
padding-top: 3rem;
padding-bottom: 1rem;
margin: 0 auto;
max-width: 1200px;
.my_border {
box-shadow: $BorderShadow;
border-radius: $BDRadius;
}
}

10
assets/scss/container.scss Executable file
View File

@@ -0,0 +1,10 @@
@import "./gallery/basic.scss";
@import "./album/basic.scss";
.my_container {
padding-top: 2rem;
padding-bottom: 3rem;
margin: 0 auto;
max-width: 1200px;
}

7
assets/scss/gallery/basic.scss Executable file
View File

@@ -0,0 +1,7 @@
@import "./card.scss";
.my_gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-gap: 50px;
}

21
assets/scss/gallery/card.scss Executable file
View File

@@ -0,0 +1,21 @@
@import "./child.scss";
@import "./simple-lightbox.scss";
.my_card {
cursor: pointer;
position: relative;
height: 0;
padding-bottom: 200px;
--offset-multiplier: 4px;
transition: transform 0.6s ease;
--translate: 0;
transform: translate(var(--translate), var(--translate));
filter: brightness(70%);
}
.my_card:hover {
--offset-multiplier: 6px;
--translate: calc(-1px * (var(--cards) - 1));
transition: transform 0.3s ease;
filter: none;
}

71
assets/scss/gallery/child.scss Executable file
View File

@@ -0,0 +1,71 @@
$ImageWidth: 260px;
$ImageHeight: 180px;
$BDRadius: 15px;
$BorderShadow: 0px 4px 8px rgba(0, 0, 0, 0.1),
0px -4px 8px rgba(255, 255, 255, 0.8);
.my_gallery_child {
position: absolute;
width: $ImageWidth;
height: $ImageHeight;
color: white;
box-sizing: border-box;
background-size: cover;
border-radius: $BDRadius;
transition: inherit;
--translate: calc(var(--offset) * var(--offset-multiplier));
transform: translate(var(--translate), var(--translate));
.child-title {
text-decoration: none;
filter: none;
}
img {
display: block;
border-radius: $BDRadius;
width: $ImageWidth;
height: $ImageHeight;
object-fit: cover;
box-shadow: $BorderShadow;
}
}
.my_gallery_child:nth-child(1) {
display: flex;
padding-top: 0.5rem;
justify-items: left;
font-size: 30px;
div:hover {
filter: none;
}
--offset: 0;
z-index: 4;
}
.my_gallery_child:nth-child(2) {
box-shadow: $BorderShadow;
--offset: 1;
z-index: 3;
}
.my_gallery_child:nth-child(3) {
box-shadow: $BorderShadow;
--offset: 2;
z-index: 2;
}
.my_gallery_child:nth-child(4) {
box-shadow: $BorderShadow;
--offset: 3;
z-index: 1;
}
.my_gallery_child:nth-child(5) {
box-shadow: $BorderShadow;
--offset: 4;
z-index: 0;
}

View File

@@ -0,0 +1,326 @@
// You can customize Simplelightbox with the following variables:
$sl-font-family: Arial, Baskerville, monospace !default;
$sl-overlay-background: #fff !default;
$sl-navigation-color: #000 !default;
$sl-caption-color: #fff !default;
$sl-caption-background: rgba(0, 0, 0, 0.8) !default;
$sl-counter-fontsize: 1rem !default;
$sl-caption-fontsize: 1rem !default;
$sl-close-fontsize: 3rem !default;
$sl-breakpoint-medium: 35.5em !default; // 568px, when 1em == 16px
$sl-breakpoint-large: 50em !default; // 800px, when 1em == 16px
$sl-arrow-fontsize-small: 2rem !default;
$sl-arrow-fontsize-medium: 3rem !default;
$sl-arrow-fontsize-large: 3rem !default;
$sl-img-border-small: 0 none !default;
$sl-img-border-medium: 0 none !default;
$sl-img-border-large: 0 none !default;
$sl-iframe-border-small: 0 none !default;
$sl-iframe-border-medium: 0 none !default;
$sl-iframe-border-large: 0 none !default;
$add-vendor-prefixes: true !default;
body.hidden-scroll {
overflow: hidden;
}
.sl-overlay {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: $sl-overlay-background;
display: none;
z-index: 1035;
}
.sl-wrapper {
z-index: 1040;
width: 100%;
height: 100%;
left: 0;
top: 0;
position: fixed;
* {
box-sizing: border-box;
}
button {
border: 0 none;
background: transparent;
font-size: 28px;
padding: 0;
cursor: pointer;
&:hover {
opacity: 0.7;
}
}
.sl-close {
display: none;
position: fixed;
right: 30px;
top: 30px;
z-index: 10060;
margin-top: -14px;
margin-right: -14px;
height: 44px;
width: 44px;
line-height: 44px;
font-family: $sl-font-family;
color: $sl-navigation-color;
font-size: $sl-close-fontsize;
}
.sl-counter {
display: none;
position: fixed;
top: 30px;
left: 30px;
z-index: 1060;
color: $sl-navigation-color;
font-size: $sl-counter-fontsize;
}
.sl-navigation {
width: 100%;
display: none;
button {
position: fixed;
top: 50%;
margin-top: -22px;
height: 44px;
width: 22px;
line-height: 44px;
text-align: center;
display: block;
z-index: 10060;
font-family: $sl-font-family;
color: $sl-navigation-color;
&.sl-next {
right: 5px;
font-size: $sl-arrow-fontsize-small;
}
&.sl-prev {
left: 5px;
font-size: $sl-arrow-fontsize-small;
}
@media (min-width: $sl-breakpoint-medium) {
width: 44px;
&.sl-next {
right: 10px;
font-size: $sl-arrow-fontsize-medium;
}
&.sl-prev {
left: 10px;
font-size: $sl-arrow-fontsize-medium;
}
}
@media (min-width: $sl-breakpoint-large) {
width: 44px;
&.sl-next {
right: 20px;
font-size: $sl-arrow-fontsize-large;
}
&.sl-prev {
left: 20px;
font-size: $sl-arrow-fontsize-large;
}
}
}
}
&.sl-dir-rtl {
.sl-navigation {
direction: ltr;
}
}
.sl-image {
position: fixed;
@if $add-vendor-prefixes {
-ms-touch-action: none;
}
touch-action: none;
z-index: 10000;
img {
margin: 0;
padding: 0;
display: block;
border: $sl-img-border-small;
width: 100%;
height: auto;
border-radius: 15px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1),
0px -4px 8px rgba(255, 255, 255, 0.8);
@media (min-width: $sl-breakpoint-medium) {
border: $sl-img-border-medium;
}
@media (min-width: $sl-breakpoint-large) {
border: $sl-img-border-large;
}
}
iframe {
background: #000;
border: $sl-iframe-border-small;
@media (min-width: $sl-breakpoint-medium) {
border: $sl-iframe-border-medium;
}
@media (min-width: $sl-breakpoint-large) {
border: $sl-iframe-border-large;
}
}
.sl-caption {
display: none;
padding: 10px;
color: $sl-caption-color;
background: $sl-caption-background;
font-size: $sl-caption-fontsize;
position: absolute;
bottom: 0;
left: 0;
right: 0;
&.pos-top {
bottom: auto;
top: 0;
}
&.pos-outside {
bottom: auto;
}
}
.sl-download {
display: none;
position: absolute;
bottom: 5px;
right: 5px;
color: $sl-navigation-color;
z-index: 1060;
}
}
}
.sl-spinner {
display: none;
border: 5px solid #333;
border-radius: 40px;
height: 40px;
left: 50%;
margin: -20px 0 0 -20px;
opacity: 0;
position: fixed;
top: 50%;
width: 40px;
z-index: 1007;
@if $add-vendor-prefixes {
-webkit-animation: pulsate 1s ease-out infinite;
-moz-animation: pulsate 1s ease-out infinite;
-ms-animation: pulsate 1s ease-out infinite;
-o-animation: pulsate 1s ease-out infinite;
}
animation: pulsate 1s ease-out infinite;
}
.sl-scrollbar-measure {
position: absolute;
top: -9999px;
width: 50px;
height: 50px;
overflow: scroll;
}
.sl-transition {
@if $add-vendor-prefixes {
transition: -moz-transform ease 200ms;
transition: -ms-transform ease 200ms;
transition: -o-transform ease 200ms;
transition: -webkit-transform ease 200ms;
}
transition: transform ease 200ms;
}
@-webkit-keyframes pulsate {
0% {
transform: scale(0.1);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: scale(1.2);
opacity: 0;
}
}
@keyframes pulsate {
0% {
transform: scale(0.1);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: scale(1.2);
opacity: 0;
}
}
@if $add-vendor-prefixes {
@-moz-keyframes pulsate {
0% {
transform: scale(0.1);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: scale(1.2);
opacity: 0;
}
}
@-o-keyframes pulsate {
0% {
transform: scale(0.1);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: scale(1.2);
opacity: 0;
}
}
@-ms-keyframes pulsate {
0% {
transform: scale(0.1);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: scale(1.2);
opacity: 0;
}
}
}

12
assets/scss/navigation.scss Executable file
View File

@@ -0,0 +1,12 @@
.my_navigation {
padding-top: 3rem;
padding-bottom: 1rem;
margin: 0 auto;
max-width: 1200px;
.my_border {
box-shadow: $BorderShadow;
border-radius: $BDRadius;
}
}

View File

@@ -0,0 +1,96 @@
@media (min-width: 580px) {
.images {
grid-template-columns: 25% 25% 25% 25%;
}
}
img {
height: auto;
width: 100%;
max-width: 100%;
vertical-align: middle;
}
.template {
transition: all 0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955);
opacity: 0;
position: relative;
background: #707070;
}
.template p {
position: absolute;
left: 0;
bottom: 0;
color: #fff;
text-transform: uppercase;
font-size: 13px;
letter-spacing: 1px;
margin: 0;
width: 100%;
background: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.5));
padding: 25px 10px 10px 10px;
}
.template.animate {
transform: scale(1);
opacity: 1;
}
#gallery-pagination {
margin: 30px 0;
}
#btnNext,
#btnPrevious {
background: transparent;
color: #609ea5;
padding: 8px 28px;
border: 0;
font-size: 18px;
cursor: pointer;
outline: none;
}
#gallery-pagination #page {
margin-left: 15px;
margin-right: 15px;
color: #707070;
font-style: italic;
font-size: 13px;
}
.sr-only {
position: absolute !important;
overflow: hidden;
clip: rect(0 0 0 0);
height: 1px;
width: 1px;
margin: -1px;
padding: 0;
border: 0;
}
#gallery-dots {
margin-bottom: 15px;
}
.gallery-dot {
background: #609ea5;
border: 0;
padding: 0;
width: 50px;
height: 8px;
margin: 5px;
opacity: 0.4;
outline: none;
cursor: pointer;
}
.gallery-dot.active {
opacity: 1;
}
#gallery-pagination {
display: grid;
grid-template-columns: 1fr 3fr 1fr;
align-items: start;
}

20
assets/scss/style.scss Executable file
View File

@@ -0,0 +1,20 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
$BDRadius: 15px;
$BorderShadow: 0px 4px 8px rgba(0, 0, 0, 0.1),
0px -4px 8px rgba(255, 255, 255, 0.8);
@import "./navigation.scss";
@import "./breadcrumbs.scss";
@import "./container.scss";
@import "gallery/basic.scss";
@import "album/basic.scss";
@import "./pagination.scss";
body {
margin-right: 40px;
margin-left: 40px;
align-items: center;
}

17
bin/console Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
return new Application($kernel);
};

75
composer.json Normal file
View File

@@ -0,0 +1,75 @@
{
"type": "project",
"license": "proprietary",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"pentatrion/vite-bundle": "^2.3",
"symfony/asset": "6.1.*",
"symfony/console": "6.1.*",
"symfony/dependency-injection": "6.1.*",
"symfony/dotenv": "6.1.*",
"symfony/finder": "6.1.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "6.1.*",
"symfony/mailer": "6.1.*",
"symfony/maker-bundle": "^1.47",
"symfony/runtime": "6.1.*",
"symfony/twig-bundle": "6.1.*",
"symfony/yaml": "6.1.*",
"twig/extra-bundle": "^3.4",
"twig/twig": "^2.12|^3.0"
},
"config": {
"allow-plugins": {
"composer/package-versions-deprecated": true,
"symfony/flex": true,
"symfony/runtime": true
},
"optimize-autoloader": true,
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "6.1.*"
}
}
}

3741
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

9
config/bundles.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
Pentatrion\ViteBundle\PentatrionViteBundle::class => ['all' => true],
];

View File

@@ -0,0 +1,19 @@
framework:
cache:
# Unique name of your app: used to compute stable namespaces for cache keys.
#prefix_seed: your_vendor_name/app_name
# The "app" cache stores to the filesystem by default.
# The data in this cache should persist between deploys.
# Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
# Namespaced pools use the above "app" backend by default
#pools:
#my.dedicated.cache: null

View File

@@ -0,0 +1,24 @@
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
secret: '%env(APP_SECRET)%'
#csrf_protection: true
http_method_override: false
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
handler_id: null
cookie_secure: auto
cookie_samesite: lax
storage_factory_id: session.storage.factory.native
#esi: true
#fragments: true
php_errors:
log: true
when@test:
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file

View File

@@ -0,0 +1,3 @@
framework:
mailer:
dsn: '%env(MAILER_DSN)%'

View File

@@ -0,0 +1,14 @@
# config/packages/pentatrion_vite.yaml
pentatrion_vite:
# Base public path when served in development or production
base: /build/
# path to the web root relative to the Symfony project root directory
public_dir: /public
script_attributes:
# you can define your attributes that you want to apply
# for all your script tags
link_attributes:
# you can define your attributes that you want to apply
# for all your link tags

View File

@@ -0,0 +1,12 @@
framework:
router:
utf8: true
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
#default_uri: http://localhost
when@prod:
framework:
router:
strict_requirements: null

5
config/preload.php Normal file
View File

@@ -0,0 +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';
}

3
config/routes.yaml Normal file
View File

@@ -0,0 +1,3 @@
controllers:
resource: ../src/Controller/
type: attribute

View File

@@ -0,0 +1,3 @@
_pentatrion_vite:
prefix: /build
resource: "@PentatrionViteBundle/Resources/config/routing.yaml"

View File

@@ -0,0 +1,4 @@
when@dev:
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /_error

24
config/services.yaml Normal file
View File

@@ -0,0 +1,24 @@
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones

2323
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

17
package.json Normal file
View File

@@ -0,0 +1,17 @@
{
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build"
},
"license": "UNLICENSED",
"devDependencies": {
"vite": "^3.0",
"vite-plugin-symfony": "^0.7.0"
},
"dependencies": {
"autoprefixer": "^10.4.13",
"daisyui": "^2.41.0",
"tailwindcss": "^3.2.4"
}
}

3
postcss.config.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
plugins: [require("tailwindcss"), require("autoprefixer")],
};

9
public/index.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
#[Route('/album', name: 'album.')]
class AlbumController extends AbstractController
{
#[Route('/{album_id}', name: 'index')]
public function album(Request $child)
{
/* $LoggerBuilder = new ContainerBuilder();
$LoggerBuilder->register('logger.service', 'LoggerService');
$LoggerService = $LoggerBuilder->get('logger.service'); */
$album_id = $child->attributes->get('album_id');
$imagepath = $_SERVER['DOCUMENT_ROOT'] . '/images/gallery/';
$JSON = file_get_contents($imagepath . '01_JSON' . '/' . $album_id . '.json');
$items = json_decode($JSON, true);
$img_count = count($items[$album_id]);
$per_page = 10;
$max_pages = ceil($img_count / $per_page);
// $LoggerService->logData($_SERVER["REMOTE_ADDR"] . ' - ' . 'Album ' . $album_id . ' wurde aufgerufen');
return $this->render('album/album.html.twig', [
'album' => $album_id,
'items' => $items,
'img_count' => $img_count,
'per_page' => $per_page,
'max_pages' => $max_pages
]);
}
#[Route('/{album_id}/{image_id}', name: 'details')]
public function details(Request $child)
{
/* $LoggerBuilder = new ContainerBuilder();
$LoggerBuilder->register('logger.service', 'LoggerService');
$LoggerService = $LoggerBuilder->get('logger.service'); */
$album_id = $child->attributes->get('album_id');
$image_id = $child->attributes->get('image_id');
$imagepath = $_SERVER['DOCUMENT_ROOT'] . '/images/gallery/';
$JSON = file_get_contents($imagepath . '01_JSON' . '/' . $album_id . '.json');
$items = json_decode($JSON, true);
$details_items = $items[$album_id][$image_id];
$details_tags = $items[$album_id][$image_id]['Tags'];
// $LoggerService->logData($_SERVER["REMOTE_ADDR"] . ' - ' . 'Bild ' . $image_id . ' aus Album ' . $album_id . ' wurde aufgerufen');
return $this->render('album/details.html.twig', [
'album' => $album_id,
'image' => $image_id,
'items' => $details_items,
'tags' => $details_tags
]);
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
#[Route('/', name: 'gallery.')]
class GalleryController extends AbstractController
{
#[Route('/', name: 'base')]
public function index()
{
// $logger->logData($_SERVER["REMOTE_ADDR"].' - '.$_SERVER["HTTP_USER_AGENT"]);
$imagepath = './images/gallery/';
/* $LoggerBuilder = new ContainerBuilder();
$LoggerBuilder->register('logger.service', 'LoggerService');
$LoggerService = $LoggerBuilder->get('logger.service'); */
$JSONBuilder = new ContainerBuilder();
$JSONBuilder->register('json.service', 'JSONService');
$JSONService = $JSONBuilder->get('json.service');
/* $DBBuilder = new ContainerBuilder();
$DBBuilder->register('db.service', 'DBService');
$DBService = $DBBuilder->get('db.service'); */
/* $MailerBuilder = new ContainerBuilder();
$MailerBuilder->register('mailer.service', 'MailerService');
$MailerService = $MailerBuilder->get('mailer.service'); */
/*
$containerBuilder
->register('newsletter_manager', 'NewsletterManager')
->addMethodCall('setMailer', [new Reference('mailer')]);
$newsletterManager = $containerBuilder->get('newsletter_manager');
$MailerBuilder = new ContainerBuilder();
$MailerBuilder->register('mailer.service', 'MailerService');
$MailerService = $MailerBuilder->get('mailer.service');
*/
// $LoggerService->logData($_SERVER["REMOTE_ADDR"] . ' - ' . $_SERVER["HTTP_USER_AGENT"]);
if (!file_exists($imagepath . '01_JSON/' . '01_All.json')) {
$JSONService->dirToArray($imagepath);
$JSONService->MergeJSON($imagepath);
}
$JSON_File = $imagepath . '01_JSON' . '/' . '01_All' . '.json';
$JSON = file_get_contents($JSON_File);
$items = json_decode($JSON, true);
$img_count = count($items);
$per_page = 10;
$max_pages = ceil($img_count / $per_page);
// $show = array_slice($items, $per_page * intval($_GET['page']) - 1, $per_page);
return $this->render('gallery/gallery.html.twig', [
'items' => $items,
'img_count' => $img_count,
'per_page' => $per_page,
'max_pages' => $max_pages
]);
}
}

11
src/Kernel.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
}

View File

@@ -0,0 +1,88 @@
<?php
use Symfony\Component\Finder\Finder;
class JSONService
{
function dirToArray($dir_albums) {
$result = array();
$cdir = scandir($dir_albums);
$imagepath = $dir_albums;
$filename = $imagepath.'01_JSON'.'/'.'Aarburg'.'.json';
foreach ($cdir as $key => $value) {
if (!in_array($value,array(".","..","01_JSON"))) {
if (is_dir($dir_albums . $value)) {
$filename = $imagepath.'01_JSON'.'/'.$value.'.json';
$result[$value][$value] = $this->dirToArray($dir_albums . $value);
$json_encoded = json_encode($result[$value]);
file_put_contents($filename, $json_encoded);
}
else {
$value_image = $imagepath.'/'.$value;
getimagesize($value_image, $infos);
$exif = exif_read_data($value_image, 0, true);
$tags = iptcparse($infos['APP13']);
if(!isset(($tags['2#025']))) {
$tags['2#025'] = null;
}
$metadata = array(
'ApertureFNumber' => $exif['COMPUTED']['ApertureFNumber'],
'FocalLength' => substr($exif['EXIF']['FocalLength'], 0, -2),
'ExposureTime' => $exif['EXIF']['ExposureTime'],
'ISOSpeedRatings' => $exif['EXIF']['ISOSpeedRatings'],
'DateTimeOriginal' => date('d.m.Y H:i:s', strtotime($exif['EXIF']['DateTimeOriginal'])),
'Lens' => $exif['EXIF']['UndefinedTag:0xA434'],
'Tags' => $tags['2#025']
/* 'Height' => $exif['COMPUTED']['Height'],
'Width' => $exif['COMPUTED']['Width'],
'Model' => $exif['IFD0']['Model'],
'Artist' => $exif['IFD0']['Artist'], */
);
$result[$value] = $metadata;
}
}
}
return $result;
}
function MergeJSON($dir_json) {
$JSONFiles = new Finder();
$JSONFiles
->name('*.json')
->files()->in($dir_json);
foreach ($JSONFiles as $file) {
$file->getContents();
}
$valle = array();
foreach($JSONFiles as $vurl) {
if (file_exists($vurl)) {
$vres = json_decode(file_get_contents($vurl), true);
$valle = array_merge($valle,$vres);
}
}
$savedata2 = json_encode($valle);
$savefile2 = $dir_json.'/01_JSON/'.'01_All.json';
file_put_contents($savefile2, $savedata2, LOCK_EX);
}
}

View File

View File

@@ -0,0 +1,21 @@
<?php
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
class MailerService
{
public static function sendMail(MailerInterface $mailer)
{
$email = new Email();
$email
->from('michael.schwab@outlook.com')
->to('michael.schwab@gmx.ch')
->subject('Site update just happened!')
->text('Someone just updated the site. We told them:');
$mailer->send($email);
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
class ViteExtension extends AbstractExtension
{
public function getFilters(): array
{
return [
// If your filter generates SAFE HTML, you should add a third
// parameter: ['is_safe' => ['html']]
// Reference: https://twig.symfony.com/doc/2.x/advanced.html#automatic-escaping
new TwigFilter('filter_name', [$this, 'doSomething']),
];
}
public function getFunctions(): array
{
return [
new TwigFunction('vite_entry_script_tags', [$this, 'renderViteScriptTags'], ['is_safe' => ['html']]),
new TwigFunction('vite_entry_link_tags', [$this, 'renderViteLinkTags'], ['is_safe' => ['html']]),
];
}
public function renderViteScriptTags(string $entryName, array $options = []): string
{
return $this->entrypointRenderer->renderScripts($entryName, $options);
}
public function renderViteLinkTags(string $entryName, array $options = []): string
{
return $this->entrypointRenderer->renderLinks($entryName, $options);
}
}

107
symfony.lock Normal file
View File

@@ -0,0 +1,107 @@
{
"pentatrion/vite-bundle": {
"version": "2.3",
"recipe": {
"repo": "github.com/symfony/recipes-contrib",
"branch": "main",
"version": "1.0",
"ref": "33d48a1c831b2d29641175c8320e66a9f1c9911f"
},
"files": [
"config/routes/dev/pentatrion_vite.yaml"
]
},
"symfony/console": {
"version": "6.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "da0c8be8157600ad34f10ff0c9cc91232522e047"
},
"files": [
"bin/console"
]
},
"symfony/flex": {
"version": "2.2",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "146251ae39e06a95be0fe3d13c807bcf3938b172"
},
"files": [
".env"
]
},
"symfony/framework-bundle": {
"version": "6.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.4",
"ref": "3cd216a4d007b78d8554d44a5b1c0a446dab24fb"
},
"files": [
"config/packages/cache.yaml",
"config/packages/framework.yaml",
"config/preload.php",
"config/routes/framework.yaml",
"config/services.yaml",
"public/index.php",
"src/Controller/.gitignore",
"src/Kernel.php"
]
},
"symfony/mailer": {
"version": "6.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "4.3",
"ref": "97a61eabb351d7f6cb7702039bcfe07fe9d7e03c"
},
"files": [
"config/packages/mailer.yaml"
]
},
"symfony/maker-bundle": {
"version": "1.48",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
}
},
"symfony/routing": {
"version": "6.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.1",
"ref": "a44010c0d06989bd4f154aa07d2542d47caf5b83"
},
"files": [
"config/packages/routing.yaml",
"config/routes.yaml"
]
},
"symfony/twig-bundle": {
"version": "6.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.4",
"ref": "bb2178c57eee79e6be0b297aa96fc0c0def81387"
},
"files": [
"config/packages/twig.yaml",
"templates/base.html.twig"
]
},
"twig/extra-bundle": {
"version": "v3.4.0"
}
}

15
tailwind.config.js Normal file
View File

@@ -0,0 +1,15 @@
module.exports = {
content: [
'./templates/**/*.{twig,html,js}',
'./public/**/*.html'
],
future: {
// removeDeprecatedGapUtilities: true,
// purgeLayersByDefault: true,
},
theme: {
extend: {},
},
variants: {},
plugins: [require("daisyui")],
}

View File

@@ -0,0 +1,20 @@
{% extends 'base.html.twig' %}
{% block title %}Hello AboutController!{% endblock %}
{% block body %}
<style>
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>
<div class="example-wrapper">
<h1>Hello {{ controller_name }}! ✅</h1>
This friendly message is coming from:
<ul>
<li>Your controller at <code><a href="{{ 'C:/xampp/htdocs/portfolio/src/Controller/AboutController.php'|file_link(0) }}">src/Controller/AboutController.php</a></code></li>
<li>Your template at <code><a href="{{ 'C:/xampp/htdocs/portfolio/templates/about/index.html.twig'|file_link(0) }}">templates/about/index.html.twig</a></code></li>
</ul>
</div>
{% endblock %}

View File

@@ -0,0 +1,35 @@
{% extends 'base.html.twig' %}
{% block title %}Home -
{{ album }}
{% endblock %}
{% block album %}
<div class="my_album">
{% for album_1, albums_1 in items %}
{% for album_2, albums_2 in albums_1 %}
<div class="my_album_child card bg-base-50 shadow-xl">
<figure class="px-2 pt-2">
<img class="rounded-xl" src="{{ asset('images/gallery') }}/{{ album_1 }}/{{ album_2 }}"/>
</figure>
<div class="p-6">
<div class="flex flex-row">
<div class="basis-1/2 justify-items-start gallery">
<a href="{{ asset('images/gallery') }}/{{ album_1 }}/{{ album_2 }}">
<button type="button" class="inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-blue-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-blue-800 active:shadow-lg transition duration-150 ease-in-out">DiaShow</button>
</a>
</div>
<div class="basis-1/2 justify-items-end">
<a href="{{ path ('album.details',{album_id: album_1, image_id:album_2}) }}">
<button type="button" class="inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-blue-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-blue-800 active:shadow-lg transition duration-150 ease-in-out">Details</button>
</a>
</div>
</div>
</div>
</div>
{% endfor %}
{% endfor %}
</div>
{% endblock %}

View File

@@ -0,0 +1,63 @@
{% extends 'base.html.twig' %}
{% block title %}Home -
{{ album }}
-
{{ image }}
{% endblock %}
{% block details %}
<div class="card bg-base-50 shadow-xl">
<figure class="px-2 pt-2">
<img class="rounded-xl" src="{{ asset('images/gallery') }}/{{ album }}/{{ image }}"/>
</figure>
<div class="card-body items-left text-left">
<p>
<div class="stats shadow">
<div class="stat">
<div class="stat-title">Blende</div>
<div class="stat-value text-lg">{{ items.ApertureFNumber }}</div>
</div>
<div class="stat">
<div class="stat-title">Brennweite</div>
<div class="stat-value text-lg">{{ items.FocalLength }}
mm</div>
</div>
<div class="stat">
<div class="stat-title">Verschlusszeit</div>
<div class="stat-value text-lg">{{ items.ExposureTime }}
sek.</div>
</div>
<div class="stat">
<div class="stat-title">ISO Wert</div>
<div class="stat-value text-lg">{{ items.ISOSpeedRatings }}</div>
</div>
</div>
<div class="stats shadow">
<div class="stat">
<div class="stat-title">Objektiv</div>
<div class="stat-value text-lg">{{ items.Lens }}</div>
</div>
<div class="stat">
<div class="stat-title">Aufnahmedatum</div>
<div class="stat-value text-lg">{{ items.DateTimeOriginal }}</div>
</div>
</div>
<div class="stats shadow">
<div class="stat">
<div class="stat-title">Tags</div>
<div class="stat-value text-lg">
{% if items.Tags is not null %}
{% for tag_1, tags_1 in tags %}
#{{ tags_1 }}
{% endfor %}
{% endif %}
</div>
</div>
</div>
</p>
</div>
</div>
{% endblock %}

46
templates/base.html.twig Normal file
View File

@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"/>
<title>
{% block title %}{% endblock %}
</title>
{{ vite_entry_link_tags('app') }}
</head>
<!-- ANCHOR Body -->
<body>
{% block body %}
{# {% block navigation %}
<div class="my_navigation">{% include 'navigation.html.twig' %}</div>
{% endblock %} #}
{% block breadcrumbs %}
<div class="my_breadcrumbs">{% include 'breadcrumbs.html.twig' %}</div>
{% endblock %}
<div class="my_container">
{% block gallery %}{% endblock %}
{% block album %}{% endblock %}
{% block details %}{% endblock %}
</div>
{% endblock %}
{# {% block pagination %}
<div class="my_pagination">{% include 'pagination.html.twig' %}</div>
{% endblock %} #}
<!-- ANCHOR JS -->
<script src="https://kit.fontawesome.com/ea07098c7f.js" crossorigin="anonymous"></script>
{{ vite_entry_script_tags('app') }}
</body>
</html>

View File

@@ -0,0 +1,24 @@
{% block breadcrumbs %}
<div class="text-xl breadcrumbs">
<ul>
<li>
<a href="{{ path ('gallery.base') }}">Home</a>
</li>
{% if album is defined %}
<li>
<a href="{{ path ('album.index',{album_id: album}) }}">{{ album }}</a>
</li>
{% endif %}
{% if image is defined %}
<li>
{{ image }}
</li>
{% endif %}
</ul>
</div>
{% endblock %}

View File

@@ -0,0 +1,35 @@
{% extends 'base.html.twig' %}
{% block title %}Gallerien
{% endblock %}
{% block gallery %}
<div class="my_gallery">
{% for album_1, albums_1 in items %}
{% for album_2, albums_2 in albums_1 %}
{% if loop.index == 1 %}
<a href="{{ path ('album.index',{album_id: album_1}) }}/?page=1">
<div class="my_card card" style="--cards:5">
<div class="my_gallery_child rounded-xl">
<div class="my_gallery_child-title">
<button class="btn btn-warning">{{ album_1 }}</button>
</div>
</div>
<div class="my_gallery_child rounded-xl">
<img src="{{ asset('images/gallery') }}/{{ album_1 }}/{{ album_2 }}" alt="{{ album_1 }}" class="object-cover">
</div>
<div class="my_gallery_child"></div>
<div class="my_gallery_child"></div>
<div class="my_gallery_child"></div>
<div class="my_gallery_child"></div>
</div>
</a>
{% endif %}
{% endfor %}
{% endfor %}
</div>
{% endblock %}

View File

@@ -0,0 +1,60 @@
<div class="my_border navbar bg-base-100">
<div class="navbar-start">
<div class="dropdown">
<label tabindex="0" class="btn btn-ghost lg:hidden">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewbox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h8m-8 6h16"/></svg>
</label>
<ul tabindex="0" class="menu menu-compact dropdown-content mt-3 p-2 shadow bg-base-100 rounded-box w-52">
<li>
<a>Item 1</a>
</li>
<li tabindex="0">
<a class="justify-between">
Parent
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24"><path d="M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z"/></svg>
</a>
<ul class="p-2 bg-base-100">
<li>
<a>Submenu 1</a>
</li>
<li>
<a>Submenu 2</a>
</li>
</ul>
</li>
<li>
<a>Item 3</a>
</li>
</ul>
</div>
<a href="{{ path ('gallery.base') }}" class="btn btn-ghost normal-case text-xl">mschwab.net</a>
</div>
<div class="navbar-center hidden lg:flex">
<ul class="menu menu-horizontal p-0">
<li>
<a href="{{ path ('gallery.base') }}">Home</a>
</li>
<li tabindex="0">
<a>
Gallery
<svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewbox="0 0 24 24"><path d="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z"/></svg>
</a>
<ul class="p-2">
<li>
<a>Submenu 1</a>
</li>
<li>
<a>Submenu 2</a>
</li>
</ul>
</li>
<li>
<a>About</a>
</li>
</ul>
</div>
</div>

26
vite.config.js Normal file
View File

@@ -0,0 +1,26 @@
import { resolve } from "path";
import { defineConfig } from "vite";
import symfonyPlugin from "vite-plugin-symfony";
/* if you're using React */
// import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
/* react(), // if you're using React */
symfonyPlugin(),
],
build: {
manifest: true,
emptyOutDir: true,
assetsDir: "",
cssCodeSplit: true,
format: "cjs",
outDir: "./public/build/",
rollupOptions: {
input: {
app: "./assets/js/main.js",
},
},
},
});