+ Ship Repair Queue +
+ +
+ in progress
++ USS LeafyCruiser +
+Captain
+Jean-Luc Pickles
+Class
+Garden
++ Looking for your next galactic ride? + Browse the {{ ships|length * 10 }} starships for sale! +
+diff --git a/.gitignore b/.gitignore index 85f4726..5c8e16e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,8 @@ /.php-cs-fixer.php /.php-cs-fixer.cache ###< php-cs-fixer/shim ### + +###> symfony/asset-mapper ### +/public/assets/ +/assets/vendor/ +###< symfony/asset-mapper ### 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/app.js b/assets/app.js new file mode 100644 index 0000000..6174cc6 --- /dev/null +++ b/assets/app.js @@ -0,0 +1,9 @@ +/* + * Welcome to your app's main JavaScript file! + * + * This file will be included onto the page via the importmap() Twig function, + * which should already be in your base.html.twig. + */ +import './styles/app.css'; + +console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉'); diff --git a/assets/images/purple-rocket.png b/assets/images/purple-rocket.png new file mode 100644 index 0000000..865da4b Binary files /dev/null and b/assets/images/purple-rocket.png differ diff --git a/assets/images/starshop-logo.png b/assets/images/starshop-logo.png new file mode 100644 index 0000000..6a856ee Binary files /dev/null and b/assets/images/starshop-logo.png differ diff --git a/assets/images/statis-complete.png b/assets/images/statis-complete.png new file mode 100755 index 0000000..d53997d Binary files /dev/null and b/assets/images/statis-complete.png differ diff --git a/assets/images/status-complete.png b/assets/images/status-complete.png new file mode 100755 index 0000000..d53997d Binary files /dev/null and b/assets/images/status-complete.png differ diff --git a/assets/images/status-in-progress.png b/assets/images/status-in-progress.png new file mode 100644 index 0000000..553dc3b Binary files /dev/null and b/assets/images/status-in-progress.png differ diff --git a/assets/images/status-waiting.png b/assets/images/status-waiting.png new file mode 100755 index 0000000..646a0f2 Binary files /dev/null and b/assets/images/status-waiting.png differ diff --git a/assets/styles/app.css b/assets/styles/app.css new file mode 100644 index 0000000..a90f074 --- /dev/null +++ b/assets/styles/app.css @@ -0,0 +1,4 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + diff --git a/composer.json b/composer.json index 3cdbbc0..c1da7cc 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,8 @@ "php-cs-fixer/shim": "^3.64", "phpdocumentor/reflection-docblock": "^5.4", "phpstan/phpdoc-parser": "^1.33", + "symfony/asset": "7.1.*", + "symfony/asset-mapper": "7.1.*", "symfony/console": "7.1.*", "symfony/dotenv": "7.1.*", "symfony/flex": "^2", @@ -21,6 +23,7 @@ "symfony/serializer": "7.1.*", "symfony/twig-bundle": "7.1.*", "symfony/yaml": "7.1.*", + "symfonycasts/tailwind-bundle": "^0.6.0", "twig/extra-bundle": "^2.12|^3.0", "twig/twig": "^2.12|^3.0" }, @@ -55,7 +58,8 @@ "scripts": { "auto-scripts": { "cache:clear": "symfony-cmd", - "assets:install %PUBLIC_DIR%": "symfony-cmd" + "assets:install %PUBLIC_DIR%": "symfony-cmd", + "importmap:install": "symfony-cmd" }, "post-install-cmd": [ "@auto-scripts" diff --git a/composer.lock b/composer.lock index 980cf50..4242a05 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,89 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "52bfebc375d20e1c88d02e27bac1434b", + "content-hash": "231f06ecf107b9b13d6a816a7d050d04", "packages": [ + { + "name": "composer/semver", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-09-19T14:15:21+00:00" + }, { "name": "doctrine/deprecations", "version": "1.1.3", @@ -630,6 +711,154 @@ }, "time": "2024-09-11T13:17:53+00:00" }, + { + "name": "symfony/asset", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/asset.git", + "reference": "8970de4a0cedd34e097c0f5c502a614780b9ca43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/asset/zipball/8970de4a0cedd34e097c0f5c502a614780b9ca43", + "reference": "8970de4a0cedd34e097c0f5c502a614780b9ca43", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "conflict": { + "symfony/http-foundation": "<6.4" + }, + "require-dev": { + "symfony/http-client": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Asset\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/asset/tree/v7.1.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-05-31T14:57:53+00:00" + }, + { + "name": "symfony/asset-mapper", + "version": "v7.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/asset-mapper.git", + "reference": "e3ae56f965f1fe503db1f604756a44d40e6dea16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/asset-mapper/zipball/e3ae56f965f1fe503db1f604756a44d40e6dea16", + "reference": "e3ae56f965f1fe503db1f604756a44d40e6dea16", + "shasum": "" + }, + "require": { + "composer/semver": "^3.0", + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/filesystem": "^7.1", + "symfony/http-client": "^6.4|^7.0" + }, + "conflict": { + "symfony/framework-bundle": "<6.4" + }, + "require-dev": { + "symfony/asset": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/event-dispatcher-contracts": "^3.0", + "symfony/finder": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\AssetMapper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps directories of assets & makes them available in a public directory with versioned filenames.", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/asset-mapper/tree/v7.1.5" + }, + "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-09-19T08:57:32+00:00" + }, { "name": "symfony/cache", "version": "v7.1.5", @@ -1768,6 +1997,178 @@ ], "time": "2024-09-20T13:35:23+00:00" }, + { + "name": "symfony/http-client", + "version": "v7.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "abca35865118edf35a23f2f24978a1784c831cb4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/abca35865118edf35a23f2f24978a1784c831cb4", + "reference": "abca35865118edf35a23f2f24978a1784c831cb4", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "^3.4.1", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "keywords": [ + "http" + ], + "support": { + "source": "https://github.com/symfony/http-client/tree/v7.1.5" + }, + "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-09-20T13:35:23+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "20414d96f391677bf80078aa55baece78b82647d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", + "reference": "20414d96f391677bf80078aa55baece78b82647d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" + }, + "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-04-18T09:32:20+00:00" + }, { "name": "symfony/http-foundation", "version": "v7.1.5", @@ -2433,6 +2834,67 @@ ], "time": "2024-09-09T11:45:10+00:00" }, + { + "name": "symfony/process", + "version": "v7.1.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "5c03ee6369281177f07f7c68252a280beccba847" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/5c03ee6369281177f07f7c68252a280beccba847", + "reference": "5c03ee6369281177f07f7c68252a280beccba847", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.1.5" + }, + "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-09-19T21:48:23+00:00" + }, { "name": "symfony/property-access", "version": "v7.1.4", @@ -3605,6 +4067,60 @@ ], "time": "2024-09-17T12:49:58+00:00" }, + { + "name": "symfonycasts/tailwind-bundle", + "version": "v0.6.0", + "source": { + "type": "git", + "url": "https://github.com/SymfonyCasts/tailwind-bundle.git", + "reference": "4cde58e23605e136d5c40a9c945c673b488d4fd6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SymfonyCasts/tailwind-bundle/zipball/4cde58e23605e136d5c40a9c945c673b488d4fd6", + "reference": "4cde58e23605e136d5c40a9c945c673b488d4fd6", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/asset-mapper": "^6.3|^7.0", + "symfony/cache": "^6.3|^7.0", + "symfony/console": "^5.4|^6.3|^7.0", + "symfony/http-client": "^5.4|^6.3|^7.0", + "symfony/process": "^5.4|^6.3|^7.0" + }, + "require-dev": { + "symfony/filesystem": "^6.3|^7.0", + "symfony/framework-bundle": "^6.3|^7.0", + "symfony/phpunit-bridge": "^6.3|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfonycasts\\TailwindBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ryan Weaver", + "homepage": "https://symfonycasts.com" + } + ], + "description": "Delightful Tailwind Support for Symfony + AssetMapper", + "keywords": [ + "asset-mapper", + "tailwind" + ], + "support": { + "issues": "https://github.com/SymfonyCasts/tailwind-bundle/issues", + "source": "https://github.com/SymfonyCasts/tailwind-bundle/tree/v0.6.0" + }, + "time": "2024-07-05T21:02:14+00:00" + }, { "name": "twig/extra-bundle", "version": "v3.13.0", diff --git a/config/bundles.php b/config/bundles.php index 8be0b00..f6b8cf2 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -7,4 +7,5 @@ return [ Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true], + Symfonycasts\TailwindBundle\SymfonycastsTailwindBundle::class => ['all' => true], ]; diff --git a/config/packages/asset_mapper.yaml b/config/packages/asset_mapper.yaml new file mode 100644 index 0000000..d1ac653 --- /dev/null +++ b/config/packages/asset_mapper.yaml @@ -0,0 +1,5 @@ +framework: + asset_mapper: + # The paths to make available to the asset mapper. + paths: + - assets/ diff --git a/importmap.php b/importmap.php new file mode 100644 index 0000000..70ebf14 --- /dev/null +++ b/importmap.php @@ -0,0 +1,19 @@ + [ + 'path' => './assets/app.js', + 'entrypoint' => true, + ], +]; diff --git a/src/Controller/MainController.php b/src/Controller/MainController.php index b66f4de..91ebd7b 100644 --- a/src/Controller/MainController.php +++ b/src/Controller/MainController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use App\Repository\StarshipRepository; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -9,8 +10,11 @@ use Symfony\Component\Routing\Attribute\Route; class MainController extends AbstractController { #[Route('/', name: 'main')] - public function homepage(): Response + public function homepage(StarshipRepository $repository): Response { - return $this->render('main/homepage.html.twig', ['variable' => random_int(0, 1e10)]); + $starships = $repository->findAll(); + $starship = $starships[array_rand($starships)]; + + return $this->render('main/homepage.html.twig', ['ships' => $starships, 'myShip' => $starship]); } } diff --git a/src/Repository/StarshipRepository.php b/src/Repository/StarshipRepository.php index 50381ac..a049657 100644 --- a/src/Repository/StarshipRepository.php +++ b/src/Repository/StarshipRepository.php @@ -16,12 +16,18 @@ class StarshipRepository $this->logger->info('Starship Repository: Finding Starships'); return [ - new Starship( - 1, 'Starship 01', 'Heavy Starship', 'Human Captain', 'damaged', - ), - new Starship( - 2, 'Starship 02', 'Light Starship', 'Robot Captain', 'new', - ), + new Starship(1, 'Starship 01', 'Heavy Starship', 'Human Captain', 'damaged'), + new Starship(2, 'Starship 02', 'Light Starship', 'Robot Captain', 'new'), + new Starship(3, 'USS Voyager', 'Intrepid-class', 'Kathryn Janeway', 'Active'), + new Starship(4, 'Starblade', 'Interceptor-class', 'Lance Stellar', 'In repair'), + new Starship(5, 'Black Star', 'Battlecruiser-class', 'Zara Nox', 'Active'), + new Starship(6, 'SS Horizon', 'Explorer-class', 'James Marshall', 'Decommissioned'), + new Starship(7, 'Nebula Queen', 'Transport-class', 'Elara Trent', 'Under inspection'), + new Starship(8, 'Celestial Wave', 'Frigate-class', 'Talon Skye', 'On mission'), + new Starship(9, 'Galactic Serpent', 'Destroyer-class', 'Viktor Helios', 'Active'), + new Starship(10, 'Phoenix Wing', 'Carrier-class', 'Aurora Drake', 'Awaiting orders'), + new Starship(11, 'Silver Comet', 'Scout-class', 'Finn O\'Neil', 'In dock'), + new Starship(12, 'Crimson Spear', 'Corvette-class', 'Raven Callen', 'Destroyed'), ]; } @@ -32,6 +38,7 @@ class StarshipRepository return $starship; } } + return null; } } diff --git a/symfony.lock b/symfony.lock index 1148a0b..2bb4c46 100644 --- a/symfony.lock +++ b/symfony.lock @@ -11,6 +11,21 @@ ".php-cs-fixer.dist.php" ] }, + "symfony/asset-mapper": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "6c28c471640cc2c6e60812ebcb961c526ef8997f" + }, + "files": [ + "assets/app.js", + "assets/styles/app.css", + "config/packages/asset_mapper.yaml", + "importmap.php" + ] + }, "symfony/console": { "version": "7.1", "recipe": { @@ -117,6 +132,9 @@ "config/routes/web_profiler.yaml" ] }, + "symfonycasts/tailwind-bundle": { + "version": "v0.6.0" + }, "twig/extra-bundle": { "version": "v3.13.0" } diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..bb226fb --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./assets/**/*.js", + "./templates/**/*.html.twig", + ], + theme: { + extend: {}, + }, + plugins: [], +} diff --git a/templates/base.html.twig b/templates/base.html.twig index b199509..789700a 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -3,14 +3,41 @@
+
+
+
+ in progress
+Captain
+Jean-Luc Pickles
+Class
+Garden
++ Looking for your next galactic ride? + Browse the {{ ships|length * 10 }} starships for sale! +
+
+ {{ ship.status }}
+| Class | -{{ ship.class }} | -
|---|---|
| Captain | -{{ ship.captain }} | -
{{ ship.captain }}
+ +{{ ship.class }}
+ +30,000 lys to next service
+