diff --git a/.symfony.local.yaml b/.symfony.local.yaml new file mode 100644 index 0000000..1198458 --- /dev/null +++ b/.symfony.local.yaml @@ -0,0 +1,3 @@ +workers: + tailwind: + cmd: ['symfony', 'console', 'tailwind:build', '--watch'] \ No newline at end of file diff --git a/assets/icons/symfony.svg b/assets/icons/symfony.svg new file mode 100644 index 0000000..93fb329 --- /dev/null +++ b/assets/icons/symfony.svg @@ -0,0 +1 @@ + diff --git a/assets/images/favicon.ico b/assets/images/favicon.ico new file mode 100644 index 0000000..b33b198 Binary files /dev/null and b/assets/images/favicon.ico differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..d28b069 Binary files /dev/null and b/assets/images/logo.png differ diff --git a/composer.json b/composer.json index 9e581eb..b92ad34 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,9 @@ "symfony/string": "7.2.*", "symfony/translation": "7.2.*", "symfony/twig-bundle": "7.2.*", + "symfony/ux-icons": "^2.22", "symfony/ux-turbo": "^2.22", + "symfony/ux-twig-component": "^2.22", "symfony/validator": "7.2.*", "symfony/web-link": "7.2.*", "symfony/yaml": "7.2.*", diff --git a/composer.lock b/composer.lock index 65d7b97..8cc464b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c8e8b543137984b211315030412feaf7", + "content-hash": "b7708b5019145d17ad3512f8c441f6bc", "packages": [ { "name": "composer/semver", @@ -7123,6 +7123,95 @@ ], "time": "2024-12-11T07:49:41+00:00" }, + { + "name": "symfony/ux-icons", + "version": "v2.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-icons.git", + "reference": "3a6fd4293fc200530b09960c41941a71354bc5fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-icons/zipball/3a6fd4293fc200530b09960c41941a71354bc5fc", + "reference": "3a6fd4293fc200530b09960c41941a71354bc5fc", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/twig-bundle": "^6.4|^7.0" + }, + "conflict": { + "symfony/flex": "<1.13", + "symfony/ux-twig-component": "<2.21" + }, + "require-dev": { + "psr/log": "^2|^3", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/http-client": "6.4|^7.0", + "symfony/phpunit-bridge": "^6.3|^7.0", + "symfony/ux-twig-component": "^2.14", + "zenstruck/console-test": "^1.5" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\Icons\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Bond", + "email": "kevinbond@gmail.com" + }, + { + "name": "Simon André", + "email": "smn.andre@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Renders local and remote SVG icons in your Twig templates.", + "homepage": "https://symfony.com", + "keywords": [ + "icons", + "svg", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-icons/tree/v2.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-04T11:34:13+00:00" + }, { "name": "symfony/ux-turbo", "version": "v2.22.1", @@ -7221,6 +7310,89 @@ ], "time": "2024-12-05T14:25:02+00:00" }, + { + "name": "symfony/ux-twig-component", + "version": "v2.22.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/ux-twig-component.git", + "reference": "9b347f6ca2d9e18cee630787f0a6aa453982bf18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/9b347f6ca2d9e18cee630787f0a6aa453982bf18", + "reference": "9b347f6ca2d9e18cee630787f0a6aa453982bf18", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.2|^3.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "twig/twig": "^3.8" + }, + "conflict": { + "symfony/config": "<5.4.0" + }, + "require-dev": { + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^6.0|^7.0", + "symfony/stimulus-bundle": "^2.9.1", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/webpack-encore-bundle": "^1.15" + }, + "type": "symfony-bundle", + "extra": { + "thanks": { + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" + } + }, + "autoload": { + "psr-4": { + "Symfony\\UX\\TwigComponent\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Twig components for Symfony", + "homepage": "https://symfony.com", + "keywords": [ + "components", + "symfony-ux", + "twig" + ], + "support": { + "source": "https://github.com/symfony/ux-twig-component/tree/v2.22.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-07T18:05:50+00:00" + }, { "name": "symfony/validator", "version": "v7.2.0", diff --git a/config/bundles.php b/config/bundles.php index d9bb288..c5154d6 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -15,4 +15,6 @@ return [ Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Symfonycasts\TailwindBundle\SymfonycastsTailwindBundle::class => ['all' => true], Oneup\FlysystemBundle\OneupFlysystemBundle::class => ['all' => true], + Symfony\UX\Icons\UXIconsBundle::class => ['all' => true], + Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true], ]; diff --git a/config/packages/twig_component.yaml b/config/packages/twig_component.yaml new file mode 100644 index 0000000..fd17ac6 --- /dev/null +++ b/config/packages/twig_component.yaml @@ -0,0 +1,5 @@ +twig_component: + anonymous_template_directory: 'components/' + defaults: + # Namespace & directory for components + App\Twig\Components\: 'components/' diff --git a/src/Controller/DashboardController.php b/src/Controller/DashboardController.php index b52543f..ff6a1ef 100644 --- a/src/Controller/DashboardController.php +++ b/src/Controller/DashboardController.php @@ -3,6 +3,8 @@ namespace App\Controller; use League\Flysystem\Filesystem; +use League\Flysystem\FilesystemException; +use League\Flysystem\FilesystemReader; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -13,25 +15,53 @@ use Symfony\Component\HttpFoundation\HeaderUtils; class DashboardController extends AbstractController { + /** + * @throws FilesystemException + */ #[Route('/', name: 'app_dashboard')] - public function index(Filesystem $defaultAdapter, UrlGeneratorInterface $urlGenerator): Response + public function index(Filesystem $defaultAdapter, UrlGeneratorInterface $urlGenerator, #[MapQueryParameter('path')] string $path = ''): Response { - $files = $defaultAdapter->listContents('/', Filesystem::LIST_DEEP); + // On retire les slashs en début et fin de chaîne + $path = trim($path, '/'); + // On retire les chemins relatifs + $path = str_replace('..', '', $path); + $path = str_replace('//', '/', $path); + + if ($path !== '' && !$defaultAdapter->directoryExists($path)) { + throw $this->createNotFoundException("Ce dossier n'existe pas !"); + } + + + $files = $defaultAdapter->listContents('/' . $path); $realFiles = []; - foreach ($files as $key => $file) { - if ($file['type'] === 'file' && !str_starts_with($file['path'], '.')) { + foreach ($files as $file) { + if (!str_starts_with($file['path'], '.')) { $realFiles[] = [ + 'type' => $file['type'], 'path' => $file['path'], - 'url' => $this->generateUrl('app_file_proxy', ['filename' => $file['path']], UrlGeneratorInterface::ABSOLUTE_URL), + 'last_modified' => $file['lastModified'], + 'size' => $file['fileSize'] ?? null, + 'url' => $file['type'] === 'file' + ? $this->generateUrl('app_file_proxy', ['filename' => $file['path']], UrlGeneratorInterface::ABSOLUTE_URL) + : $this->generateUrl('app_dashboard', ['path' => $path . '/' . $file['path']]), ]; } } + // On trie par type puis par nom + usort($realFiles, static function ($a, $b) { + if ($a['type'] === $b['type']) { + return $a['path'] <=> $b['path']; + } else { + return $a['type'] <=> $b['type']; + } + }); return $this->render('dashboard/index.html.twig', [ 'files' => $realFiles, + 'path' => $path, ]); } diff --git a/src/Twig/Extension/BasenameExtension.php b/src/Twig/Extension/BasenameExtension.php new file mode 100644 index 0000000..b5063c4 --- /dev/null +++ b/src/Twig/Extension/BasenameExtension.php @@ -0,0 +1,18 @@ + ['html']] + // Reference: https://twig.symfony.com/doc/3.x/advanced.html#automatic-escaping + new TwigFilter('time_diff', [TimeExtensionRuntime::class, 'timeDiff']), + ]; + } +} diff --git a/src/Twig/Runtime/BasenameExtensionRuntime.php b/src/Twig/Runtime/BasenameExtensionRuntime.php new file mode 100644 index 0000000..72fbe7c --- /dev/null +++ b/src/Twig/Runtime/BasenameExtensionRuntime.php @@ -0,0 +1,14 @@ + 1 ? 's' : ''); + } + + // Moins d'une heure + if ($diff < 3600) { + $minutes = floor($diff / 60); + return 'Il y a ' . $minutes . ' minute' . ($minutes > 1 ? 's' : ''); + } + + // Moins d'un jour + if ($diff < 86400) { + $hours = floor($diff / 3600); + return 'Il y a ' . $hours . ' heure' . ($hours > 1 ? 's' : ''); + } + + // Plus d'un jour + $days = floor($diff / 86400); + return 'Il y a ' . $days . ' jour' . ($days > 1 ? 's' : ''); + } +} diff --git a/symfony.lock b/symfony.lock index 88c4523..495ad26 100644 --- a/symfony.lock +++ b/symfony.lock @@ -274,6 +274,18 @@ "templates/base.html.twig" ] }, + "symfony/ux-icons": { + "version": "2.22", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.17", + "ref": "803a3bbd5893f9584969ab8670290cdfb6a0a5b5" + }, + "files": [ + "assets/icons/symfony.svg" + ] + }, "symfony/ux-turbo": { "version": "2.22", "recipe": { @@ -283,6 +295,18 @@ "ref": "c85ff94da66841d7ff087c19cbcd97a2df744ef9" } }, + "symfony/ux-twig-component": { + "version": "2.22", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.13", + "ref": "67814b5f9794798b885cec9d3f48631424449a01" + }, + "files": [ + "config/packages/twig_component.yaml" + ] + }, "symfony/validator": { "version": "7.2", "recipe": { diff --git a/templates/base.html.twig b/templates/base.html.twig index 0523980..063c794 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -1,9 +1,9 @@ - + Kumora - {% block title %}Accueil{% endblock %} - + {% block stylesheets %} {% endblock %} diff --git a/templates/dashboard/index.html.twig b/templates/dashboard/index.html.twig index 8da9453..3b3cf97 100644 --- a/templates/dashboard/index.html.twig +++ b/templates/dashboard/index.html.twig @@ -4,11 +4,66 @@ {% block body %}
-

Bienvenue sur le dashboard

- +

Liste des fichiers

+
+ {% include 'partials/breadbrumb.html.twig' %} +
+ + +
+ + + + + + + + + + + {% for file in files %} + + + + + + + {% endfor %} + +
+ Nom + + Taille + + Modifié le + + Action +
+ {% if file.type == 'file' %} + + {% else %} + + {% endif %} + {{ file.path|basename }} + + {% if file.type == 'file' %} + {{ file.size|show_size }} + {% endif %} + + {{ file.last_modified|time_diff }} + + {% if file.type == 'file' %} + + + + + + {% else %} + + + + {% endif %} +
+
{% endblock %} diff --git a/templates/partials/breadbrumb.html.twig b/templates/partials/breadbrumb.html.twig new file mode 100644 index 0000000..ea7bb0a --- /dev/null +++ b/templates/partials/breadbrumb.html.twig @@ -0,0 +1,33 @@ + diff --git a/templates/partials/navbar.html.twig b/templates/partials/navbar.html.twig index 4dbe27d..7651992 100644 --- a/templates/partials/navbar.html.twig +++ b/templates/partials/navbar.html.twig @@ -1,6 +1,34 @@ - \ No newline at end of file + +