mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 10:04:18 +00:00
A wiki is where somebody already inside GitHub looks. It has no way to be the thing a link to plMail shows a person who has never seen it, so there is now a site as well: a landing page and the whole handbook, at karatektus.github.io/pl_mail, deployed by .github/workflows/pages.yml on every push to main. It holds no content. The landing page IS README.md and the handbook IS docs/, rendered into a shell by bin/build-site.php — nothing on the site can say something the repository does not, because there is nowhere for it to be written down. Even the hero is lifted rather than written: its lead is README's own opening paragraph, because a hero composed here would be the one piece of prose no file backs and the first thing to go stale. The wiki mirror stays; two outputs of one source cannot disagree with each other. The tree is preserved rather than flattened, unlike the wiki mirror, which had to flatten because a wiki has one namespace. So a cross-link between two pages needs only its extension changed and an image reference needs nothing, and the rewriting that remains is the small honest kind: a path that escapes docs/ becomes a link into GitHub, because the site carries the handbook and not the source. **The theme picker is generated from the app's own enum.** Theme::swatch() already carries surface, ink and accent per theme for the appearance picker, and the rest of a palette is derived from those at build time — so the site offers exactly the seven plMail offers, and adding an eighth to the app adds it here. Transcribing them would have agreed until somebody added one, and then the site would quietly offer six of seven. The language picker lists a locale as available when docs/<locale>/ exists and as "not translated yet" when it does not, which makes translating the handbook the act of creating that directory and nothing else. Today that means English, with German and Pirate shown and disabled — a switcher that silently omitted them would say the site has no opinion about German, where this says where the gap is. Search is the whole handbook as 140KB of JSON, fetched on first focus and matched in the browser. A hosted index would be faster to write and would stop the site being a directory of files that works from a checkout, from a fork's Pages, and behind whatever proxy somebody puts it behind. league/commonmark is a require-dev dependency: the site is built in CI and never by the application, so a Markdown parser in the runtime image would be a package nothing runs. Bumped guzzlehttp/guzzle to 7.15.2 while composer was open — 7.15.1 carries two advisories, one of which is a noncanonical host bypassing host-based checks, which is the shape of the SSRF guard. Also corrects this file's claim that the non-Docker Playwright variants start `symfony serve`. They have not since that server was replaced. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
152 lines
5.1 KiB
JSON
152 lines
5.1 KiB
JSON
{
|
|
"type": "project",
|
|
"license": "AGPL-3.0-or-later",
|
|
"minimum-stability": "stable",
|
|
"prefer-stable": true,
|
|
"require": {
|
|
"php": ">=8.4",
|
|
"ext-ctype": "*",
|
|
"ext-iconv": "*",
|
|
"ext-pcntl": "*",
|
|
"doctrine/doctrine-bundle": "^3.3.1",
|
|
"doctrine/doctrine-migrations-bundle": "^4.0",
|
|
"doctrine/orm": "^3.6",
|
|
"dragonmantank/cron-expression": "^3.6",
|
|
"endroid/qr-code": "^6.1",
|
|
"knplabs/knp-paginator-bundle": "*",
|
|
"league/oauth2-client": "^2.9",
|
|
"league/oauth2-google": "^5.0",
|
|
"lexik/jwt-authentication-bundle": "^3.2",
|
|
"minishlink/web-push": "^11.0",
|
|
"phpdocumentor/reflection-docblock": "^6.0",
|
|
"phpstan/phpdoc-parser": "^2.3.3",
|
|
"sabre/vobject": "^4.6",
|
|
"scheb/2fa-backup-code": "^8.6",
|
|
"scheb/2fa-bundle": "^8.6",
|
|
"scheb/2fa-totp": "^8.6",
|
|
"scheb/2fa-trusted-device": "^8.6",
|
|
"symfony/asset": "8.1.*",
|
|
"symfony/asset-mapper": "8.1.*",
|
|
"symfony/console": "8.1.*",
|
|
"symfony/doctrine-messenger": "8.1.*",
|
|
"symfony/dotenv": "8.1.*",
|
|
"symfony/expression-language": "8.1.*",
|
|
"symfony/flex": "^2",
|
|
"symfony/form": "8.1.*",
|
|
"symfony/framework-bundle": "8.1.*",
|
|
"symfony/html-sanitizer": "8.1.*",
|
|
"symfony/http-client": "8.1.*",
|
|
"symfony/intl": "8.1.*",
|
|
"symfony/mailer": "8.1.*",
|
|
"symfony/mercure-bundle": "^0.4.2",
|
|
"symfony/mime": "8.1.*",
|
|
"symfony/monolog-bundle": "^3.0|^4.0",
|
|
"symfony/notifier": "8.1.*",
|
|
"symfony/process": "8.1.*",
|
|
"symfony/property-access": "8.1.*",
|
|
"symfony/property-info": "8.1.*",
|
|
"symfony/rate-limiter": "8.1.*",
|
|
"symfony/runtime": "8.1.*",
|
|
"symfony/scheduler": "8.1.*",
|
|
"symfony/security-bundle": "8.1.*",
|
|
"symfony/serializer": "8.1.*",
|
|
"symfony/stimulus-bundle": "^3.3",
|
|
"symfony/string": "8.1.*",
|
|
"symfony/translation": "8.1.*",
|
|
"symfony/twig-bundle": "8.1.*",
|
|
"symfony/uid": "8.1.*",
|
|
"symfony/ux-autocomplete": "^3.3",
|
|
"symfony/ux-turbo": "^3.3",
|
|
"symfony/validator": "8.1.*",
|
|
"symfony/web-link": "8.1.*",
|
|
"symfony/yaml": "8.1.*",
|
|
"symfonycasts/tailwind-bundle": "^0.14.0",
|
|
"thenetworg/oauth2-azure": "*",
|
|
"tijsverkoyen/css-to-inline-styles": "^2.4",
|
|
"twig/extra-bundle": "^2.12|^3.0",
|
|
"twig/twig": "^2.12|^3.28",
|
|
"webklex/php-imap": "^6.2"
|
|
},
|
|
"config": {
|
|
"allow-plugins": {
|
|
"php-http/discovery": true,
|
|
"symfony/flex": true,
|
|
"symfony/runtime": true
|
|
},
|
|
"bump-after-update": true,
|
|
"sort-packages": true
|
|
},
|
|
"autoload": {
|
|
"psr-4": {
|
|
"App\\": "src/"
|
|
},
|
|
"files": [
|
|
"config/bootstrap_generated_secrets.php"
|
|
]
|
|
},
|
|
"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": "*",
|
|
"symfony/polyfill-php82": "*",
|
|
"symfony/polyfill-php83": "*",
|
|
"symfony/polyfill-php84": "*"
|
|
},
|
|
"scripts": {
|
|
"site": "php bin/build-site.php",
|
|
"auto-scripts": {
|
|
"cache:clear": "symfony-cmd",
|
|
"assets:install %PUBLIC_DIR%": "symfony-cmd",
|
|
"importmap:install": "symfony-cmd"
|
|
},
|
|
"post-install-cmd": [
|
|
"@auto-scripts"
|
|
],
|
|
"post-update-cmd": [
|
|
"@auto-scripts"
|
|
],
|
|
"test": [
|
|
"vendor/bin/phpunit"
|
|
],
|
|
"stan": [
|
|
"vendor/bin/phpstan analyse --configuration=phpstan.dist.neon"
|
|
]
|
|
},
|
|
"scripts-descriptions": {
|
|
"test": "Run the PHPUnit suite (unit tests). Browser end-to-end tests live in tests/e2e and run via `npm run test:e2e`.",
|
|
"site": "Build the landing page and handbook into build/site — the same command GitHub Pages runs. Open build/site/index.html or serve it with `php -S 127.0.0.1:8080 -t build/site`.",
|
|
"stan": "Run PHPStan at level 5 against src/ and tests/, ignoring what phpstan-baseline.neon already records."
|
|
},
|
|
"conflict": {
|
|
"symfony/symfony": "*"
|
|
},
|
|
"extra": {
|
|
"symfony": {
|
|
"allow-contrib": false,
|
|
"require": "8.1.*"
|
|
}
|
|
},
|
|
"require-dev": {
|
|
"league/commonmark": "^2.9",
|
|
"phpstan/phpstan": "^2.2",
|
|
"phpstan/phpstan-doctrine": "^2.0",
|
|
"phpstan/phpstan-symfony": "^2.0",
|
|
"phpunit/phpunit": "^13.2.5",
|
|
"symfony/browser-kit": "8.1.*",
|
|
"symfony/css-selector": "8.1.*",
|
|
"symfony/debug-bundle": "8.1.*",
|
|
"symfony/maker-bundle": "^1.0",
|
|
"symfony/stopwatch": "8.1.*",
|
|
"symfony/web-profiler-bundle": "8.1.*"
|
|
}
|
|
}
|