diff --git a/.php-cs-fixer.cache b/.php-cs-fixer.cache index 3aebe69..d8a3406 100644 --- a/.php-cs-fixer.cache +++ b/.php-cs-fixer.cache @@ -1 +1 @@ -{"php":"8.3.6","version":"3.89.1:v3.89.1#f34967da2866ace090a2b447de1f357356474573","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"modifier_keywords":true,"new_with_parentheses":{"anonymous_class":true},"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":{"closure_fn_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"after_heredoc":false,"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true,"strict_param":true,"declare_strict_types":true,"no_unused_imports":true,"single_quote":true},"hashes":{"templates\/post_view.php":"3c83bdaa22dc0c01bb0b043e0c07784d","templates\/header.php":"f4b64c4ecb4dadec166cb7935309096a","templates\/post_list.php":"191d1349cc7b0972a0ebbb99149590d3","templates\/layout.php":"7fbb10d6a3693b543efb83eee52b049c","templates\/footer.php":"3111b4701ea698ba11c3423260657e28","public\/login\/oidc.php":"8ec86d6f3af33f64d586109ec17f817d","public\/login\/config.php":"5b7b3e2937b349c76a2fd239c3ae06f8","public\/login\/magic.php":"54ef6b7ef80e608905e64e4fa8539846","public\/login\/index.php":"063d7b997bf8292d2b3f8c34dae3252f","public\/route.php":"f35dadd27dbdea162b67c42002519be9","public\/oidc\/callback.php":"793ff84451299c9984ac4742f02ca842","public\/oidc\/start.php":"87ddb61a0ef796d7303709ffa741c9c7","public\/oidc\/me.php":"d0439342011bb0e58ef8738b3b81cc2f","public\/index.php":"73a917520ea547ae8a122bd90098bf46","src\/Infrastructure\/DbAdapter.php":"3899a835130c146e2d30dbcca88d8f33","src\/Infrastructure\/Database.php":"6f2848ed70b29d9c2e2d259be611b9b0","src\/Infrastructure\/Session.php":"3538a1147cc81678c470d45ea8574a95","src\/Domain\/User.php":"02213454f7edf43f4afae3f2f81aaf01","src\/Http\/Csrf.php":"55631812cab4b1192f8e30c5d35fd5eb","src\/FileManager.php":"a51dda44f293f238aea295fd56b2fa99","src\/PostManager.php":"25f0179c4d96e9aa04218d54bf45a029","src\/helpers.php":"3a83a4872b1e3e3c58898b54f51e72b4","src\/db.php":"8888b7fbc9740eb3c60dd2374d0cb5d6","src\/auth.php":"d237017d90091f5fb75a133d08d5e544","src\/ConfigRepo.php":"c2dcee160a272d27725d480a90e76dcf","src\/Parsedown.php":"85da2b47eca1a703fdfe44753bf912df","src\/Service\/MailQueue.php":"7e040056aec64cfd780e3c9e7d04748a","src\/Service\/Validator.php":"7c267b8b9f3f1bac0f2520dd10364831","src\/Service\/UiFormRenderer.php":"065617191c6d680ce97588f4fa159688","src\/Service\/AuthService.php":"51c714164c6bd453154c024d9aa814e9","src\/Service\/MailService.php":"e1ef847a70551ae8887b86b3fb4167d0","src\/mailer.php":"17e6b19103c880cc9a6c6634486506c2","src\/Repository\/DictionnaryRepository.php":"f937e98cf0f27b59ae00e430b52a586d","src\/Repository\/ProfileRepository.php":"b1cd483652500ee4e2aaaa9e0330ff1d","src\/Repository\/UserRepository.php":"d75fed70910d0e6450a5b6c8ce9608c2","versions.php":"51a72261e1a507d3435b4a24e5f5fc09","config\/config.php":"a8b7698b01ab9b40eea655e8fcc194fc"}} \ No newline at end of file +{"php":"8.3.6","version":"3.89.1:v3.89.1#f34967da2866ace090a2b447de1f357356474573","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"modifier_keywords":true,"new_with_parentheses":{"anonymous_class":true},"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":{"closure_fn_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"after_heredoc":false,"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true,"strict_param":true,"declare_strict_types":true,"no_unused_imports":true,"single_quote":true},"hashes":{"templates\/header.php":"f4b64c4ecb4dadec166cb7935309096a","templates\/post_list.php":"191d1349cc7b0972a0ebbb99149590d3","templates\/footer.php":"3111b4701ea698ba11c3423260657e28","public\/login\/oidc.php":"8ec86d6f3af33f64d586109ec17f817d","public\/login\/config.php":"5b7b3e2937b349c76a2fd239c3ae06f8","public\/login\/magic.php":"54ef6b7ef80e608905e64e4fa8539846","public\/login\/index.php":"063d7b997bf8292d2b3f8c34dae3252f","public\/route.php":"f35dadd27dbdea162b67c42002519be9","public\/oidc\/callback.php":"793ff84451299c9984ac4742f02ca842","public\/oidc\/start.php":"87ddb61a0ef796d7303709ffa741c9c7","public\/oidc\/me.php":"d0439342011bb0e58ef8738b3b81cc2f","public\/index.php":"73a917520ea547ae8a122bd90098bf46","src\/Infrastructure\/DbAdapter.php":"3899a835130c146e2d30dbcca88d8f33","src\/Infrastructure\/Database.php":"6f2848ed70b29d9c2e2d259be611b9b0","src\/Infrastructure\/Session.php":"3538a1147cc81678c470d45ea8574a95","src\/Domain\/User.php":"02213454f7edf43f4afae3f2f81aaf01","src\/Http\/Csrf.php":"55631812cab4b1192f8e30c5d35fd5eb","src\/FileManager.php":"a51dda44f293f238aea295fd56b2fa99","src\/PostManager.php":"25f0179c4d96e9aa04218d54bf45a029","src\/helpers.php":"3a83a4872b1e3e3c58898b54f51e72b4","src\/db.php":"8888b7fbc9740eb3c60dd2374d0cb5d6","src\/auth.php":"d237017d90091f5fb75a133d08d5e544","src\/ConfigRepo.php":"c2dcee160a272d27725d480a90e76dcf","src\/Parsedown.php":"85da2b47eca1a703fdfe44753bf912df","src\/Service\/MailQueue.php":"7e040056aec64cfd780e3c9e7d04748a","src\/Service\/Validator.php":"7c267b8b9f3f1bac0f2520dd10364831","src\/Service\/UiFormRenderer.php":"065617191c6d680ce97588f4fa159688","src\/Service\/AuthService.php":"51c714164c6bd453154c024d9aa814e9","src\/Service\/MailService.php":"e1ef847a70551ae8887b86b3fb4167d0","src\/mailer.php":"17e6b19103c880cc9a6c6634486506c2","src\/Repository\/DictionnaryRepository.php":"f937e98cf0f27b59ae00e430b52a586d","src\/Repository\/ProfileRepository.php":"b1cd483652500ee4e2aaaa9e0330ff1d","src\/Repository\/UserRepository.php":"d75fed70910d0e6450a5b6c8ce9608c2","versions.php":"51a72261e1a507d3435b4a24e5f5fc09","config\/config.php":"a8b7698b01ab9b40eea655e8fcc194fc","templates\/post_form.php":"32765f286dc2fc2f9d9790fa3a94bef5"}} \ No newline at end of file diff --git a/docs/notes-dev.md b/docs/notes-dev.md index 4ee2626..89f5d7d 100644 --- a/docs/notes-dev.md +++ b/docs/notes-dev.md @@ -1,32 +1,39 @@ -/journal/ -│ -├── public/ # Fichiers accessibles publiquement -│ ├── index.php -│ ├── assets/ # CSS, JS, fichiers uploadés -│ │ ├── uploads/ -│ │ ├── css/ -│ │ └── js/ -│ -├── templates/ # Templates HTML Bootstrap +# Notes de développement + +## Structure du projet (serveur) + +``` +/var/www/lan.acegrp.varlog/ +├── public/ +│ ├── index.php # Point d'entrée +│ ├── route.php # Routeur (actions GET/POST) +│ └── assets/ # CSS, JS, uploads +├── templates/ # Vues PHP (incluses via extract() + include) │ ├── layout.php │ ├── post_form.php │ └── post_view.php -│ -├── src/ # Classes et fonctions PHP -│ ├── db.php # Connexion PDO à PostgreSQL -│ ├── PostManager.php # Gestion des posts -│ └── FileManager.php # Gestion des fichiers -│ -├── config/ -│ └── config.php # Données de connexion PostgreSQL -│ -└── route.php # Routage de base +├── src/ +│ ├── db.php # Connexion PDO PostgreSQL +│ ├── PostManager.php +│ └── FileManager.php +├── config/ +│ └── config.php # Charge .env, définit les constantes DB +└── docs/ +``` +## Conventions templates +Les templates reçoivent leurs variables via `extract()` depuis `route.php`. Toute variable optionnelle (non transmise dans tous les contextes) doit utiliser `??` pour éviter un `Undefined variable` warning : +```php +// Bon +$dateValue = $published_at ?? date('Y-m-d\TH:i'); += ($published ?? false) ? 'checked' : '' ?> -Un exemple complet de formulaire d’ajout de post avec upload de fichiers ? +// À éviter += $published ? 'checked' : '' ?> // Warning si create (pas d'édition) +``` -Le code PHP pour la gestion des posts et des fichiers ? +## Permissions serveur -Ou encore une page HTML d’affichage d’un post avec tous les médias intégrés ? +PHP-FPM tourne en `www-data`. Les fichiers sensibles (`.env`) appartiennent à `cedrix:www-data 640`. Voir `PROJET.md` § Permissions serveur. diff --git a/public/assets/css/style.css b/public/assets/css/style.css new file mode 100644 index 0000000..a0a3a32 --- /dev/null +++ b/public/assets/css/style.css @@ -0,0 +1,380 @@ +/* varlog — style.css */ + +@import url('https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap'); + +/* ─── Variables ─────────────────────────── */ +:root { + --vl-accent: #4f46e5; + --vl-accent-dark: #4338ca; + --vl-accent-soft: #e0e7ff; + --vl-bg: #f8fafc; + --vl-surface: #ffffff; + --vl-border: #e2e8f0; + --vl-text: #1e293b; + --vl-muted: #64748b; + --vl-radius: 0.75rem; + --vl-shadow-sm: 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04); + --vl-shadow-md: 0 4px 16px rgba(0,0,0,.08), 0 2px 4px rgba(0,0,0,.04); +} + +/* ─── Base ──────────────────────────────── */ +body { + background-color: var(--vl-bg) !important; + color: var(--vl-text); + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + font-size: 1rem; + line-height: 1.7; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* ─── Navbar ────────────────────────────── */ +.navbar { + background-color: var(--vl-surface) !important; + border-bottom: 1px solid var(--vl-border); + box-shadow: var(--vl-shadow-sm); + padding: 0.75rem 1rem; +} + +.navbar-brand { + font-weight: 700; + font-size: 1.15rem; + color: var(--vl-text) !important; + letter-spacing: -0.3px; + transition: color 0.15s; +} + +.navbar-brand:hover { + color: var(--vl-accent) !important; +} + +.nav-link { + color: var(--vl-muted) !important; + font-weight: 500; + font-size: 0.9rem; + padding: 0.4rem 0.75rem !important; + border-radius: 0.5rem; + transition: color 0.15s, background 0.15s; +} + +.nav-link:hover { + color: var(--vl-accent) !important; + background-color: var(--vl-accent-soft); +} + +.navbar-toggler { + border-color: var(--vl-border); +} + +.navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2830%2C41%2C59%2C0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +/* ─── Main ───────────────────────────────── */ +main.container { + max-width: 980px; + padding-top: 2rem; + padding-bottom: 3rem; +} + +/* ─── Headings ───────────────────────────── */ +h1 { + font-weight: 700; + font-size: 1.75rem; + letter-spacing: -0.5px; + color: var(--vl-text); +} + +h2 { + font-weight: 600; + letter-spacing: -0.3px; +} + +/* ─── Cards ─────────────────────────────── */ +.card { + border: 1px solid var(--vl-border) !important; + border-radius: var(--vl-radius) !important; + box-shadow: var(--vl-shadow-sm); + background-color: var(--vl-surface); + transition: box-shadow 0.2s ease, transform 0.2s ease; +} + +.card:hover { + box-shadow: var(--vl-shadow-md); + transform: translateY(-2px); +} + +.card-body { + padding: 1.35rem 1.5rem; +} + +.card-title { + font-weight: 600; + font-size: 1rem; + margin-bottom: 0.5rem; + color: var(--vl-text); +} + +/* Override la couleur text-primary Bootstrap sur les card-title */ +.card-title.text-primary { + color: var(--vl-text) !important; +} + +.card-text { + color: var(--vl-muted); + font-size: 0.9rem; + line-height: 1.65; +} + +/* Neutralise les borders colorées Bootstrap */ +.card[class*="border-primary"], +.card[class*="border-warning"], +.card[class*="border-success"], +.card[class*="border-danger"] { + border-color: var(--vl-border) !important; +} + +/* Indicateur brouillon discret */ +.badge.bg-warning { + background-color: #fef3c7 !important; + color: #92400e !important; + font-weight: 500; + font-size: 0.7rem; + border-radius: 0.375rem; +} + +/* ─── Buttons ─────────────────────────────── */ +.btn { + font-weight: 500; + font-size: 0.875rem; + border-radius: 0.5rem; + transition: all 0.15s ease; +} + +.btn-outline-primary { + --bs-btn-color: var(--vl-accent); + --bs-btn-border-color: var(--vl-accent); + --bs-btn-hover-bg: var(--vl-accent); + --bs-btn-hover-border-color: var(--vl-accent); + --bs-btn-active-bg: var(--vl-accent-dark); +} + +.btn-outline-secondary { + --bs-btn-color: var(--vl-muted); + --bs-btn-border-color: var(--vl-border); + --bs-btn-hover-bg: var(--vl-bg); + --bs-btn-hover-border-color: var(--vl-border); + --bs-btn-hover-color: var(--vl-text); +} + +.btn-success { + background-color: var(--vl-accent) !important; + border-color: var(--vl-accent) !important; +} + +.btn-success:hover, +.btn-success:focus { + background-color: var(--vl-accent-dark) !important; + border-color: var(--vl-accent-dark) !important; +} + +.btn-secondary { + background-color: #f1f5f9 !important; + border-color: var(--vl-border) !important; + color: var(--vl-text) !important; +} + +.btn-secondary:hover { + background-color: #e2e8f0 !important; + border-color: var(--vl-border) !important; +} + +.btn-danger { + --bs-btn-bg: #ef4444; + --bs-btn-border-color: #ef4444; + --bs-btn-hover-bg: #dc2626; + --bs-btn-hover-border-color: #dc2626; +} + +/* ─── Forms ──────────────────────────────── */ +.form-control, +.form-select { + border-color: var(--vl-border); + border-radius: 0.5rem; + font-size: 0.9375rem; + padding: 0.5rem 0.75rem; + transition: border-color 0.15s, box-shadow 0.15s; + background-color: var(--vl-surface); +} + +.form-control:focus, +.form-select:focus { + border-color: var(--vl-accent); + box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.12); +} + +.form-label { + font-weight: 500; + font-size: 0.875rem; + color: var(--vl-text); + margin-bottom: 0.375rem; +} + +.form-check-input:checked { + background-color: var(--vl-accent); + border-color: var(--vl-accent); +} + +textarea.form-control { + font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace; + font-size: 0.875rem; + line-height: 1.6; + min-height: 320px; + resize: vertical; +} + +/* ─── Alerts ─────────────────────────────── */ +.alert { + border-radius: var(--vl-radius); + border: none; + font-size: 0.9rem; +} + +.alert-danger { + background-color: #fef2f2; + color: #991b1b; +} + +/* ─── Post content (Markdown rendu) ──────── */ +.post-content { + font-size: 1rem; + line-height: 1.8; + color: var(--vl-text); +} + +.post-content h1, +.post-content h2, +.post-content h3, +.post-content h4, +.post-content h5, +.post-content h6 { + font-weight: 600; + margin-top: 2rem; + margin-bottom: 0.75rem; + letter-spacing: -0.3px; + line-height: 1.3; +} + +.post-content p { + margin-bottom: 1.25rem; +} + +.post-content a { + color: var(--vl-accent); + text-decoration: underline; + text-decoration-color: var(--vl-accent-soft); + text-underline-offset: 3px; + transition: text-decoration-color 0.15s; +} + +.post-content a:hover { + text-decoration-color: var(--vl-accent); +} + +.post-content code { + background: #f1f5f9; + padding: 0.2em 0.45em; + border-radius: 4px; + font-size: 0.85em; + color: #be185d; + font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace; +} + +.post-content pre { + background: #1e293b; + color: #e2e8f0; + padding: 1.25rem 1.5rem; + border-radius: var(--vl-radius); + overflow-x: auto; + font-size: 0.875rem; + line-height: 1.6; + margin: 1.5rem 0; +} + +.post-content pre code { + background: none; + color: inherit; + padding: 0; + font-size: inherit; +} + +.post-content blockquote { + border-left: 3px solid var(--vl-accent); + padding: 0.5rem 0 0.5rem 1.25rem; + margin: 1.5rem 0; + color: var(--vl-muted); + font-style: italic; +} + +.post-content ul, +.post-content ol { + padding-left: 1.5rem; + margin-bottom: 1.25rem; +} + +.post-content li { + margin-bottom: 0.375rem; +} + +.post-content img { + max-width: 100%; + border-radius: var(--vl-radius); + margin: 1rem 0; +} + +.post-content table { + width: 100%; + border-collapse: collapse; + margin: 1.5rem 0; + font-size: 0.9rem; +} + +.post-content th, +.post-content td { + padding: 0.625rem 1rem; + border: 1px solid var(--vl-border); + text-align: left; +} + +.post-content th { + background: var(--vl-bg); + font-weight: 600; +} + +.post-content hr { + border: none; + border-top: 1px solid var(--vl-border); + margin: 2rem 0; +} + +/* ─── Post list — date / meta ─────────────── */ +.post-meta { + font-size: 0.8rem; + color: var(--vl-muted); +} + +/* ─── Footer ─────────────────────────────── */ +footer { + border-top: 1px solid var(--vl-border); + color: var(--vl-muted) !important; + font-size: 0.85rem; +} + +/* ─── Utilitaires ─────────────────────────── */ +.text-muted { + color: var(--vl-muted) !important; +} + +.text-primary { + color: var(--vl-accent) !important; +} diff --git a/public/assets/js/app.js b/public/assets/js/app.js new file mode 100644 index 0000000..603734e --- /dev/null +++ b/public/assets/js/app.js @@ -0,0 +1,25 @@ +// varlog — app.js + +document.addEventListener('DOMContentLoaded', function () { + + // Auto-resize textarea au chargement et à la saisie + document.querySelectorAll('textarea.form-control').forEach(function (ta) { + function resize() { + ta.style.height = 'auto'; + ta.style.height = ta.scrollHeight + 'px'; + } + ta.addEventListener('input', resize); + resize(); + }); + + // Ctrl+Enter (ou Cmd+Enter) pour soumettre le formulaire de post + var form = document.querySelector('form[method="POST"]'); + if (form) { + form.addEventListener('keydown', function (e) { + if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { + form.submit(); + } + }); + } + +}); diff --git a/templates/layout.php b/templates/layout.php index a016202..07e059a 100644 --- a/templates/layout.php +++ b/templates/layout.php @@ -20,15 +20,19 @@ + + + + -
+