diff --git a/assets/controllers/crop_avatar_controller.js b/assets/controllers/crop_avatar_controller.js new file mode 100644 index 0000000..2393657 --- /dev/null +++ b/assets/controllers/crop_avatar_controller.js @@ -0,0 +1,34 @@ +import { Controller } from '@hotwired/stimulus' +import Swal from 'sweetalert2' + +export default class extends Controller { + static values = { + cropImage: String + } + + connect() { + console.log('crop', this.cropImageValue) + window.CropAvatar = this + } + + open() { + console.log('open crop') + Swal.fire({ + title: 'Are you sure?', + text: "You won't be able to revert this!", + icon: 'warning', + showCancelButton: true, + confirmButtonColor: '#3085d6', + cancelButtonColor: '#d33', + confirmButtonText: 'Yes, delete it!', + }).then((result) => { + if (result.isConfirmed) { + Swal.fire( + 'Deleted!', + 'Your file has been deleted.', + 'success', + ) + } + }) + } +} diff --git a/assets/controllers/hello_controller.js b/assets/controllers/hello_controller.js deleted file mode 100644 index e847027..0000000 --- a/assets/controllers/hello_controller.js +++ /dev/null @@ -1,16 +0,0 @@ -import { Controller } from '@hotwired/stimulus'; - -/* - * This is an example Stimulus controller! - * - * Any element with a data-controller="hello" attribute will cause - * this controller to be executed. The name "hello" comes from the filename: - * hello_controller.js -> "hello" - * - * Delete this file or adapt it for your use! - */ -export default class extends Controller { - connect() { - this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js'; - } -} diff --git a/assets/controllers/upload-avatar_controller.js b/assets/controllers/upload-avatar_controller.js new file mode 100644 index 0000000..96d9dd3 --- /dev/null +++ b/assets/controllers/upload-avatar_controller.js @@ -0,0 +1,158 @@ +import { Controller } from '@hotwired/stimulus' +import { Dropzone } from 'dropzone' +import Cropper from 'cropperjs' + +export default class extends Controller { + static values = { + avatarImage: String, + userId: Number + } + + connect() { + console.log('image', this.avatarImageValue) + console.log('id', this.userIdValue) + + /* + const formElement = document.getElementById('avatarDropzone') + const dzMessage = document.getElementsByClassName('dz-message') + formElement.style.backgroundImage = `url('${this.avatarImageValue}')` + formElement.style.backgroundRepeat = 'no-repeat' + formElement.style.backgroundPosition = 'center center' + formElement.style.backgroundSize = 'auto' + formElement.style.borderRadius = '25px' + console.log('formelement', formElement) +*/ + + console.log('init Dropzone') + let avatarDropzone = new Dropzone('#avatarDropzone', { + url: `/user/upload/avatar/${this.userIdValue}`, + avatarUrl: this.avatarImageValue, + acceptedFiles: '.jpg, .jpeg, .png, gif', + maxFiles: 1, + dictDefaultMessage: '', + init() { + avatarDropzone = this + // If the thumbnail is already in the right size on your server: + const mockFile = { name: 'Filename', size: 12345 } + const callback = null // Optional callback when it's done + const crossOrigin = null // Added to the `img` tag for crossOrigin handling + const resizeThumbnail = false // Tells Dropzone whether it should resize the image first + avatarDropzone.displayExistingFile(mockFile, avatarDropzone.options.avatarUrl, callback, crossOrigin, resizeThumbnail); + avatarDropzone.files.push(mockFile); // line missing in official docs + + /* + console.log('url', avatarDropzone.options.foo) + this.hiddenFileInput.removeAttribute('multiple') + this.on('maxfilesexceeded', (file) => { + this.removeAllFiles() + this.addFile(file) + }) + this.on('error', (file, data) => { + console.log('error') + if (data.detail) { + this.emit('error', file, data.detail) + } + }) + console.log('beforemock') + const mockFile = { name: 'Name Image', size: 12345, type: 'image/jpeg' } + this.emit('addedfile', mockFile) + this.emit('success', mockFile) + console.log('avi', this.avatarImageValue) + this.emit('thumbnail', mockFile, avatarDropzone.options.avatarUrl) + console.log('aftermock') + this.emit('complete', mockFile); + this.files.push(mockFile); + */ + }, + transformFile(file, done) { + // Create the image editor overlay + const editor = document.createElement('div') + editor.style.position = 'fixed' + editor.style.left = '25px' + editor.style.right = '25px' + editor.style.top = '25px' + editor.style.bottom = '25px' + editor.style.zIndex = '9999' + editor.style.borderRadius = '15px;' + editor.style.borderColor = '#FF8844' + editor.style.backgroundColor = '#000' + document.body.appendChild(editor) + + // Create an image node for Cropper.js + const image = new Image() + image.src = URL.createObjectURL(file) + editor.appendChild(image) + + // Create Cropper.js + const cropper = new Cropper(image, {aspectRatio: 1}) + + // Create confirm button at the top left of the viewport + const buttonCrop = document.createElement('button') + buttonCrop.style.position = 'absolute' + buttonCrop.style.right = '10px' + buttonCrop.style.bottom = '50px' + buttonCrop.style.zIndex = '9999' + buttonCrop.textContent = 'Crop' + buttonCrop.className = 'btn btn-secondary' + editor.appendChild(buttonCrop) + buttonCrop.addEventListener('click', () => { + // clear preview + //formElement.style.backgroundImage = '' + + const canvas = cropper.getCroppedCanvas({ + width: 256, + height: 256 + }) + canvas.toBlob((blob) => { + avatarDropzone.createThumbnail( + blob, + avatarDropzone.options.thumbnailWidth, + avatarDropzone.options.thumbnailHeight, + avatarDropzone.options.thumbnailMethod, + false, + (dataURL) => { + avatarDropzone.emit('thumbnail', file, dataURL) + done(blob) + } + ) + }) + + // Remove the editor from the view + document.body.removeChild(editor) + }) + + // Create keep original button + const buttonKeep = document.createElement('button') + buttonKeep.style.position = 'absolute' + buttonKeep.style.right = '100px' + buttonKeep.style.bottom = '50px' + buttonKeep.style.zIndex = '9999' + buttonKeep.textContent = 'Keep Original' + buttonKeep.className = 'btn btn-primary' + buttonKeep.focus() + editor.appendChild(buttonKeep) + buttonKeep.addEventListener('click', () => { + //formElement.style.backgroundImage = '' + + // Remove the editor from the view + this.removeAllFiles() + + done(file) + document.body.removeChild(editor) + }) + + // info text + const infoText = document.createElement('span') + infoText.style.position = 'absolute' + infoText.style.opacity = '0.5' + infoText.style.left = '100px' + infoText.style.bottom = '50px' + infoText.style.display = 'inline:block' + infoText.style.zIndex = '9999' + infoText.textContent = 'Use mouse wheel/touchpad to adapt size' + infoText.className = 'btn btn-secondary' + editor.appendChild(infoText) + } + }) + } +} diff --git a/templates/themes/24unix.net/_footer.html.twig b/templates/themes/24unix.net/_footer.html.twig new file mode 100644 index 0000000..a7208df --- /dev/null +++ b/templates/themes/24unix.net/_footer.html.twig @@ -0,0 +1,15 @@ +<footer class="footer"> + <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-bottom navbar-bottom"> + <div class="d-flex justify-content-xl-around"> + <div class="ms-5">powered by + <a href="#"> + <img class="mx-1" src="{{ asset('build/images/Spookie/spookie_64x64.png') }}" alt="Spookie"> + </a> + </div> + <div id="legal"> + <a href="{{ path('pages_display', { 'slug': 'imprint' }) }}">Imprint</a> + <a href="{{ path('pages_display', { 'slug': 'privacy' }) }}">Privacy Policy</a> + </div> + </div> + </nav> +</footer> \ No newline at end of file diff --git a/templates/themes/24unix.net/_header.html.twig b/templates/themes/24unix.net/_header.html.twig new file mode 100644 index 0000000..b99ea83 --- /dev/null +++ b/templates/themes/24unix.net/_header.html.twig @@ -0,0 +1,79 @@ +<nav + class="navbar navbar-expand-md navbar-dark sticky-top px-sm-5 border-0 {{ is_granted('ROLE_PREVIOUS_ADMIN') ? 'bg-light' : 'bg-dark' }}" +> + + <a class="navbar-brand border-0" href="{{ path('app_main') }}"> + <img src="{{ asset('build/images/24unix/24_logo_bg_64x64.png') }}" alt="24unix.net" id="site-logo"> + </a> + + <button class="navbar-toggler border-0" type="button" data-toggle="collapse" data-target="#CollapsingNavbar"> + ☰ + </button> + + <div class="collapse navbar-collapse" id="CollapsingNavbar"> + <ul class="navbar-nav ms-auto"> + <!-- + <li> + <form class="d-flex"> + <input class="form-control me-2 my-2" type="search" placeholder="Search" aria-label="Search"> + <button class="btn" type="submit">Search</button> + </form> + </li> + --> + {% if is_granted('ROLE_USER') %} + <li class="nav-item dropdown me-auto"> + <button type="button" id="navbar-dropdown" data-bs-target="#dropdown-menu" data-bs-toggle="dropdown" + class="btn btn-outline-dark dropdown-toggle button-login"> + {% if app.user.avatar %} + <img class="rounded-circle border border-primary" + width="50px" + src="{{ avatar_asset(app.user.avatar)|imagine_filter('squared_thumbnail_small') }}" + alt="profile image"/> + {% else %} + {{ app.user.username }} + {% endif %} + </button> + + <div class="dropdown-menu dropdown-menu-dark dropdown-menu-end" id="dropdown-menu" + aria-labelledby="navbar-dropdown"> + <a class="dropdown-item" href="{{ path('app_profile_edit', { 'username': app.user.username }) }}"> + <span class="fa fa-lg fa-fw fa-user" aria-hidden="true"></span> + Profile</a> + <a class="dropdown-item" href="#"> + <span class="fa fa-lg fa-fw fa-wrench" aria-hidden="true"></span> + Settings</a> + <div class="dropdown-divider"></div> + {% if is_granted('ROLE_ADMIN') %} + <a class="dropdown-item" href="{{ path('admin') }}"> + <span class="fa fa-lg fa-fw fa-cog" aria-hidden="true"></span> + Administration + </a> + <div class="dropdown-divider"></div> + {% endif %} + + {% if is_granted('ROLE_PREVIOUS_ADMIN') %} + <a class="dropdown-item" href="{{ path('app_main', { + '_switch_user': '_exit' + }) }}"> + <span class="fa fa-lg fa-fw fa-backward" aria-hidden="true"></span> + Back to Admin</a> + <div class="dropdown-divider"></div> + {% endif %} + + <a class="dropdown-item" href="{{ path('security_logout') }}"> + <span class="fa fa-lg fa-fw fa-sign-out" aria-hidden="true"></span> + Logout + </a> + </div> + </li> + {% else %} + <li class="nav-item"> + <a class="btn btn-primary button-login" href="{{ path('security_login') }}" role="button" + id="buttonLogin"> + <span class="fa fa-sign-in fa-lg fa-fw" aria-hidden="true"></span>Log In + </a> + </li> + {% endif %} + </ul> + </div> +</nav> diff --git a/templates/themes/24unix.net/base.html.twig b/templates/themes/24unix.net/base.html.twig new file mode 100644 index 0000000..9110af2 --- /dev/null +++ b/templates/themes/24unix.net/base.html.twig @@ -0,0 +1,117 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>{% block title %}Spookie{% 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></svg>"> + + {% block stylesheets %} + {{ encore_entry_link_tags('app') }} + {% endblock %} + + {% block javascripts %} + {{ encore_entry_script_tags('app') }} + + <!-- Matomo --> + <script> + let _paq = window._paq = window._paq || [] + /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ + _paq.push(["trackPageView"]) + _paq.push(["enableLinkTracking"]); + (function () { + const u = "https://analytics.24unix.net/" + _paq.push(["setTrackerUrl", u + "matomo.php"]) + _paq.push(["setSiteId", "1"]) + const d = document, g = d.createElement("script"), s = d.getElementsByTagName("script")[0] + g.async = true + g.src = u + "matomo.js" + s.parentNode.insertBefore(g, s) + })() + </script> + <!-- End Matomo Code --> + {% endblock %} + +</head> +<body data-turbo="false"> + +{% include '@default/_header.html.twig' %} + +<!-- sidebar --> +<nav id="sidebar" class="m-3"> + <ul class="list-group ml1" id="main-menu"> + <li class="list-group-item list-group-item-action"> + <a href="{{ path('app_projects') }}" class="text-decoration-none"> + <span class="fa fa-lg fa-fw fa-file-code-o" aria-hidden="true" title="Projects"></span> + <span class="menuText"> Projects</span> + </a> + </li> + <li class="list-group-item list-group-item-action"> + <a href="//git.24unix.net" class="text-decoration-none" target="_blank"> + <span class="fa fa-lg fa-fw fa-gitea" aria-hidden="true" title="Gitea"></span> + <span class="menuText"> Gitea</span> + </a> + <span class="menuText"><span class="fa fa-external-link" aria-hidden="true"></span></span> + </li> + <li class="list-group-item list-group-item-action"> + <a href="//cloud.24unix.net" class="text-decoration-none" target="_blank"> + <span class="fa fa-lg fa-fw fa-nextcloud" aria-hidden="true" title="NextCloud"></span> + <span class="menuText"> NextCloud</span> + </a> + <span class="menuText"><span class="fa fa-external-link" aria-hidden="true"></span></span> + </li> + <li class="list-group-item list-group-item-action"> + <a href="#" id="toggleSidebar"> + <span id="toggleIcon" class="fa fa-lg fa-caret-square-o-left"></span> + </a> + </li> + <!-- <a href="//pastebin.24unix.net">pastebin.24unix.net</a>--> + </ul> +</nav> + +<div class="container-fluid" id="content"> + + + <div class="col m-3" id="main_content"> + + {# + <div data-turbo="false"> + {% for message in app.flashes('success') %} + <div id="react"></div> + <div + {{ stimulus_controller('toastify', { + flash: message + }) }} + > + </div> + dump(app) + {% endfor %} + </div> + #} + + {% for message in app.flashes('error') %} + <div class="alert alert-danger"> + {{ message }} + </div> + {% endfor %} + + {% block body %} + <div class="m-5"> + <h1 class="title-show">Quote of the Moment</h1> + <div class="quote-box p-3"> + <span class="fa fa-quote-left"></span><br> + {{ quote | raw | nl2br }} + </div> + </div> + {% endblock %} + </div> + +</div> + +{% include '@default/_footer.html.twig' %} + + + +</body> +</html> \ No newline at end of file diff --git a/templates/themes/24unix.net/pages/index.html.twig b/templates/themes/24unix.net/pages/index.html.twig new file mode 100644 index 0000000..7eb1db0 --- /dev/null +++ b/templates/themes/24unix.net/pages/index.html.twig @@ -0,0 +1,13 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}page_name{% endblock %} + +{% block body %} + {{ page.content | raw }} + <br> + Page created by: <a href="{{ path('app_profile', { 'username': page.owner.username }) }}">{{ page.owner.username }}</a> + {{ page.createdAt | ago }} + {% if page.modifiedAt %} + (last update: {{ page.modifiedAt | ago }}) + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/templates/themes/24unix.net/projects/index.html.twig b/templates/themes/24unix.net/projects/index.html.twig new file mode 100644 index 0000000..003002d --- /dev/null +++ b/templates/themes/24unix.net/projects/index.html.twig @@ -0,0 +1,74 @@ +{# templates/projects/index.html.twig #} +{% extends '@default/base.html.twig' %} + +{% block title %} Projects {% endblock %} + +{% block body %} + <div class="container-fluid box"> + <div class="row"> + <h2>This is an overview of my current public (and open source) projects.</h2> + + <!-- projects List --> + <div class="col-sm-12"> + {% for project in projects %} + <div class="project-container bg-dark my-4"> + <div class="row"> + <div class="col-sm-3"> + <a href="{{ path('app_projects', { name: project.name }) }}"> + {% if project.teaserImage %} + <img + class="project-image" + src="/uploads/projects/{{ project.teaserImage }}" + alt="Teaser"> + {% else %} + <img + class="project-image" + src="{{ asset('build/images/24unix/24_logo_bg_96x96.png') }}" + alt="Teaser"> + {% endif %} + </a> + <br> + <div> + {% for developer in project.developer %} + <a class="align-left blog-details" + href="{{ path('app_profile', { 'username':developer.username }) }}"> + {% if developer.avatar is not null %} + <img class="rounded-circle mt-5 mb-4 ms-5" + src="{{ avatar_asset(developer.avatar)|imagine_filter('squared_thumbnail_small') }}" alt="profile image"/> + <br> + {% endif %} + <div class="ms-5 mb-4"> + <a href="{{ path('app_profile', { 'username':developer.username }) }}">{{ developer.username }}</a> + </div> + {% endfor %} + </div> + + </div> + <div class="col-sm-8 mt-2"> + <a href="{{ path('app_projects', { name: project.name }) }}"> + <div class="article-title d-inline-block pl-3 align-middle"> + <h2>{{ project.name }}</h2> + </div> + </a> + <br> + <div class="blog-teaser mb-2 pb-2 text-xl-start"> + {{ project.description }} + <br> + <br> + started: {{ project.createdAt | ago }} + </div> + </div> + </div> + + </div> + {% endfor %} + </div> + + {% if is_granted('ROLE_ADMIN') %} + <div class="text-xl-start"> + <a href="{{ path('app_main') }}"><span class="fa fa-plus-circle"></span></a> + </div> + {% endif %} + </div> + </div> +{% endblock %} \ No newline at end of file diff --git a/templates/themes/24unix.net/projects/show.html.twig b/templates/themes/24unix.net/projects/show.html.twig new file mode 100644 index 0000000..4c586f1 --- /dev/null +++ b/templates/themes/24unix.net/projects/show.html.twig @@ -0,0 +1,35 @@ +{# templates/blog/blog_show.html.twig #} +{% extends '@default/base.html.twig' %} + +{% block title %}Projects{% endblock %} + +{% block body %} + + <div class="row"> + <div class="col-sm-12"> + {% if is_granted('ROLE_ADMIN') %} + <div class="d-flex justify-content-end"> + <a href="{{ path('app_main', { id : project.id }) }}"><span class="fa fa-3x fa-fw fa-edit"></span></a> + <a href="{{ path('app_main', { id : project.id }) }}"><span class="fa fa-3x fa-fw fa-trash"></span></a> + </div> + {% endif %} + + <div class="show-article-container p-3 mt-4"> + <div class="show-article-title-container d-inline-block pl-3 align-middle"> + <h2>{{ project.name }}</h2> + </div> + <div> + Source: <a href="{{ project.url }}" target="_blank">{{ project.url }}</a> + <span class="fa fa-external-link" aria-hidden="true"></span> + </div> + <div class="row"> + <div class="col-sm-12"> + <div class="article-text"> + {{ readme | markdown_to_html }} + </div> + </div> + </div> + </div> + </div> + </div> +{% endblock %} \ No newline at end of file diff --git a/templates/themes/24unix.net/security/forgot_password.html.twig b/templates/themes/24unix.net/security/forgot_password.html.twig new file mode 100644 index 0000000..c397c08 --- /dev/null +++ b/templates/themes/24unix.net/security/forgot_password.html.twig @@ -0,0 +1,22 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Reset your password{% endblock %} + +{% block body %} + {% for flash_error in app.flashes('reset_password_error') %} + <div class="alert alert-danger" role="alert">{{ flash_error }}</div> + {% endfor %} + <h1>Reset your password</h1> + + {{ form_start(requestForm) }} + {{ form_row(requestForm.account) }} + <div> + <small> + Enter your email address or your username and we will send you a + link to reset your password. + </small> + </div> + + <button class="btn btn-primary float-end">Send password reset email</button> + {{ form_end(requestForm) }} +{% endblock %} diff --git a/templates/themes/24unix.net/security/login.html.twig b/templates/themes/24unix.net/security/login.html.twig new file mode 100644 index 0000000..5522024 --- /dev/null +++ b/templates/themes/24unix.net/security/login.html.twig @@ -0,0 +1,60 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Log In!{% endblock %} + +{% block body %} + <div class="container rounded"> + <div class="row"> + <div class="login-form bg-dark mt-4 p-4"> + <form method="post" class="row g-3"> + <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1> + + {% if error %} + <div class="alert-dark alert-danger"> + {{ error.messageKey|trans(error.messageData, 'security') }} + </div> + {% endif %} + + + <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"> + + <div class="col-12"> + <label for="inputUsername">Username or eMail</label> + <input type="text" + name="username" + autocomplete="nickname" + id="inputUsername" + class="form-control" + value="{{ last_username }}" + required + autofocus + > + </div> + <div class="col-12"> + <label for="inputPassword">Password</label> + <input + type="password" + name="password" + autocomplete="current-password" + id="inputPassword" + class="form-control" + required + > + </div> + <div class="form-check mx-3"> + <label> + <input type="checkbox" name="_remember_me" class="form-check-input">Remember me + </label> + </div> + <div> + <a href="{{ path('security_forgot_password') }}">Forgot password?</a> + <button class="btn btn-primary float-end" type="submit"> + Sign in + </button> + </div> + <a href="{{ path('security_register') }}">Need an account? Register now.</a> + </form> + </div> + </div> + </div> +{% endblock %} diff --git a/templates/themes/24unix.net/security/mail/recovery.html.twig b/templates/themes/24unix.net/security/mail/recovery.html.twig new file mode 100644 index 0000000..a651258 --- /dev/null +++ b/templates/themes/24unix.net/security/mail/recovery.html.twig @@ -0,0 +1,9 @@ +<h1>Hi!</h1> + +<p>To reset your password, please visit the following link</p> + +<a href="{{ url('security_recovery_reset', {token: resetToken.token}) }}">Reset password</a> + +<p>This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.</p> + +<p>Cheers!</p> diff --git a/templates/themes/24unix.net/security/mail/registration.html.twig b/templates/themes/24unix.net/security/mail/registration.html.twig new file mode 100644 index 0000000..665506f --- /dev/null +++ b/templates/themes/24unix.net/security/mail/registration.html.twig @@ -0,0 +1,39 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html lang="en" style="margin:0;padding:0;"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <meta name="viewport" content="width=device-width, initial-scale=1"/> + <meta http-equiv="X-UA-Compatible" content="IE=edge"/> + <meta name="format-detection" content="telephone=no"/> + <title></title> + <style type="text/css"> + @media screen and (max-width: 599px) { + div { + max-width: 100% !important; + } + } + body { + background-color: #1e1f1e; + margin:25px; + padding:0; + } + </style> +</head> +<body> +<div style="border-collapse:collapse;border-spacing:0;"> + <h1>Hi {{ username }}, please confirm your email!</h1> + + <p> + Please confirm your email address by clicking the following link: <br><br> + <a href="{{ signedUrl|raw }}">Confirm my Email</a>. + <br> + This link will expire in {{ expiresAtMessageKey|trans(expiresAtMessageData, 'VerifyEmailBundle') }}. + </p> + + <p> + Kind regards, + 24unix.net + </p> +</div> +</body> +</html> diff --git a/templates/themes/24unix.net/security/recovery_mail_sent.html.twig b/templates/themes/24unix.net/security/recovery_mail_sent.html.twig new file mode 100644 index 0000000..8786623 --- /dev/null +++ b/templates/themes/24unix.net/security/recovery_mail_sent.html.twig @@ -0,0 +1,11 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Password Reset Email Sent{% endblock %} + +{% block body %} + <p> + If an account matching your email exists, then an email was just sent that contains a link that you can use to reset your password. + This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}. + </p> + <p>If you don't receive an email please check your spam folder or <a href="{{ path('security_forgot_password') }}">try again</a>.</p> +{% endblock %} diff --git a/templates/themes/24unix.net/security/register.html.twig b/templates/themes/24unix.net/security/register.html.twig new file mode 100644 index 0000000..6b3a3bc --- /dev/null +++ b/templates/themes/24unix.net/security/register.html.twig @@ -0,0 +1,60 @@ +{% extends '@default/base.html.twig' %} +{% form_theme registrationForm _self %} + +{% block title %}Register{% endblock %} + + +{% block form_row %} + {%- set widget_attr = {} -%} + {%- if help is not empty -%} + {%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%} + {%- endif -%} + + {{- form_label(form, null, { + label_attr: { class: 'sr-only' } + }) -}} + {{- form_errors(form) -}} + {{- form_widget(form, widget_attr) -}} + {{- form_help(form) -}} +{% endblock %} + + +{% block body %} + {% for flash_error in app.flashes('verify_email_error') %} + <div class="alert alert-danger" role="alert">{{ flash_error }}</div> + {% endfor %} + + <div class="container rounded"> + <div class="row"> + <div class="login-form bg-dark mt-4 p-4"> + <h1 class="h3 mb-3 font-weight-normal">Register</h1> + + {{ form_start(registrationForm, { + attr: { class: 'form-signin' } + }) }} + <input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"> + {{ form_row(registrationForm.username, { + attr: { placeholder: 'User name' } + }) }} + {{ form_row(registrationForm.email, { + attr: { placeholder: 'eMail' } + }) }} + {{ form_row(registrationForm.password.first, { + attr: { placeholder: 'Password'} + }) }} + {{ form_row(registrationForm.password.second, { + attr: { placeholder: 'Confirm password'} + }) }} + + {{ form_row(registrationForm.agreeTerms) }} + + <button type="submit" class="btn btn-primary float-end">Register</button> + {{ form_end(registrationForm) }} + + </div> + </div> + </div> + +{% endblock %} + + diff --git a/templates/themes/24unix.net/security/registration_finished.html.twig b/templates/themes/24unix.net/security/registration_finished.html.twig new file mode 100644 index 0000000..5f12a74 --- /dev/null +++ b/templates/themes/24unix.net/security/registration_finished.html.twig @@ -0,0 +1,19 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Registration finished{% endblock %} + +{% block body %} + + <div class="container rounded"> + <div class="row"> + <div class="login-form bg-dark mt-4 p-4"> + <h1 class="h3 mb-3 font-weight-normal">Registration finished</h1> + <p>You'll receive an email soon to confirm your identity.</p> + + </div> + </div> + </div> + +{% endblock %} + + diff --git a/templates/themes/24unix.net/security/resend_activation.html.twig b/templates/themes/24unix.net/security/resend_activation.html.twig new file mode 100644 index 0000000..c0e89c2 --- /dev/null +++ b/templates/themes/24unix.net/security/resend_activation.html.twig @@ -0,0 +1,20 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Verify eMail{% endblock %} + +{% block body %} + <div class="container"> + <div class="row"> + <div class="login-form bg-dark mt-4 p-4"> + <h1 class="h3 mb-3 font-weight-normal">Verify your Email</h1> + <p> + A verification email was sent - please check it to enable your + account before logging in. + </p> + <form method="POST"> + <button type="submit" class="btn btn-primary">Re-send Email</button> + </form> + </div> + </div> + </div> +{% endblock %} diff --git a/templates/themes/24unix.net/security/reset_password.html.twig b/templates/themes/24unix.net/security/reset_password.html.twig new file mode 100644 index 0000000..ed95f9b --- /dev/null +++ b/templates/themes/24unix.net/security/reset_password.html.twig @@ -0,0 +1,12 @@ +{% extends '@default/base.html.twig' %} + +{% block title %}Reset your password{% endblock %} + +{% block body %} + <h1>Reset your password</h1> + + {{ form_start(resetForm) }} + {{ form_row(resetForm.plainPassword) }} + <button class="btn btn-primary">Update password</button> + {{ form_end(resetForm) }} +{% endblock %} diff --git a/templates/themes/24unix.net/user/edit_profile.html.twig b/templates/themes/24unix.net/user/edit_profile.html.twig new file mode 100644 index 0000000..84d5f97 --- /dev/null +++ b/templates/themes/24unix.net/user/edit_profile.html.twig @@ -0,0 +1,62 @@ +{% extends '@default/base.html.twig' %} + +{% block title %} + Profile of {{ user.username }} +{% endblock %} + +{% block body %} + + <div class="container box rounded bg-dark mt-5 mb-5"> + {{ form_start(userForm) }} + <div class="row"> + + <div class="col-md-3 border-right"> + <div class="d-flex flex-column align-items-center text-center p-3 py-5"> + {# + {% if user.avatar is not null %} + <img class="rounded-circle mt-5 mb-4" + src="{{ avatar_asset(user.avatar)|imagine_filter('squared_thumbnail_small') }}" + alt="profile image"/> + {% endif %} + #} + + <div + class="dropzone" + id="avatarDropzone" + style="width:172px;" + {{ stimulus_controller('upload_avatar', { + avatarImage: avatar_asset(user.avatar)|imagine_filter('squared_thumbnail_small') , + userId: user.id + }) }} + > + </div> + <span class="font-weight-bold">{{ user.username }}</span> + <span class="text-white-50"><span class="fa fa-lg fa-envelope me-1"></span><a href="mailto:{{ user.email }}">{{ user.email }}</a></span> + </div> + </div> + <div class="col-md-8 border-right"> + <div class="p-3 py-5"> + <div class="d-flex justify-content-between align-items-center mb-3"> + <h4 class="text-right">User Profile</h4> + </div> + <div class="row mt-2"> + {{ form_row(userForm.username) }} + {{ form_row(userForm.firstName) }} + {{ form_row(userForm.lastName) }} + {{ form_row(userForm.email) }} + {{ form_row(userForm.newPassword.first) }} + {{ form_row(userForm.newPassword.second) }} + {{ form_rest(userForm) }} + </div> + <div class="mb-5 text-center float-end"> + <button class="btn btn-primary profile-button" type="submit">Save Profile</button> + </div> + </div> + </div> + </div> + {{ form_end(userForm) }} + + + </div> + +{% endblock %} diff --git a/templates/themes/24unix.net/user/list_users.html.twig b/templates/themes/24unix.net/user/list_users.html.twig new file mode 100644 index 0000000..7893a17 --- /dev/null +++ b/templates/themes/24unix.net/user/list_users.html.twig @@ -0,0 +1,49 @@ +{% extends '@default/base.html.twig' %} + +{% block title %} + Userlist +{% endblock %} + +{% block body %} + + + <div class="container box rounded bg-dark mt-5 mb-5"> + <div class="row"> + <table class="table table-striped"> + <thead> + <tr> + <th scope="col">Username</th> + <th scope="col">First</th> + <th scope="col">Last</th> + <th scope="col">eMail</th> + <th scope="col">Registered</th> + <th scope="col">Manage</th> + </tr> + </thead> + {% for user in users %} + <tr> + <td> + <a href="{{ path('app_main', { '_switch_user': user.username }) }}">{{ user.username }}</a> + </td> + <td> + {{ user.firstName }} + </td> + <td> + {{ user.lastName }} + </td> + <td> + {{ user.email }} + </td> + <td> + {{ user.createdAt|ago }} + </td> + <td> + <button type="button" class="btn btn-outline-primary btn-lg btn-circle ml-2"><i class="fa fa-edit"></i> </button> + </td> + + </tr> + {% endfor %} + </table> + </div> + </div> +{% endblock %} diff --git a/templates/themes/24unix.net/user/show_profile.html.twig b/templates/themes/24unix.net/user/show_profile.html.twig new file mode 100644 index 0000000..55b038c --- /dev/null +++ b/templates/themes/24unix.net/user/show_profile.html.twig @@ -0,0 +1,46 @@ +{% extends '@default/base.html.twig' %} + +{% block title %} + Profile of {{ user.username }} +{% endblock %} + +{% block body %} + + <div class="container box rounded bg-dark mt-5 mb-5"> + <div class="row"> + <div class="col-md-3 border-right"> + <div class="d-flex flex-column align-items-center text-center p-3 py-5"> + {% if user.avatar is not null %} + <img class="rounded-circle mt-5 mb-4" + src="{{ avatar_asset(user.avatar)|imagine_filter('squared_thumbnail_small') }}" + alt="profile image"/> + {% endif %} + <span class="font-weight-bold">{{ user.username }}</span> + {% if is_granted('ROLE_ADMIN') %} + <span class="font-weight-bold"> + <a href="{{ path('app_main', { '_switch_user': user.username }) }}">switch user</a> + </span> + {% endif %} + + <span class="text-white-50"><i class="fa fa-lg fa-envelope me-1"></i><a href="mailto:{{ user.email }}">{{ user.email }}</a></span> + </div> + </div> + <div class="col-md-5 border-right"> + <div class="p-3 py-5"> + <div class="d-flex justify-content-between align-items-center mb-3"> + <h4 class="text-right">User Profile</h4> + </div> + <div class="row mt-2"> + <label class="labels" for="first-name">First Name</label> + <input type="text" disabled id="first-name" class="form-control" value="{{ user.firstName }}"> + + <label class="labels" for="last-name">Last Name</label> + <input type="text" disabled id="last-name" class="form-control" value="{{ user.lastName }}"> + </div> + </div> + </div> + </div> + </div> + + +{% endblock %}