From c8cbfa8ce1e117f8d277421415cc6a5127997a76 Mon Sep 17 00:00:00 2001 From: Luis Pabon Date: Wed, 11 Mar 2026 22:16:21 +0000 Subject: [PATCH 1/4] =?UTF-8?q?Replace=20Bootstrap=203=20with=20Tailwind?= =?UTF-8?q?=20CSS=20=E2=80=94=20dark-mode=20redesign?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Tailwind CSS v3 build pipeline (postcss, autoprefixer, assets/css/app.css) - Dark-mode-only "Deep Code" aesthetic: deep-space navy, sky-blue/indigo accents - Remove Bootstrap CSS and old base.css/dark.css/media-queries.css - Remove bootstrap-toggle entirely; replace with pure CSS toggle (appearance:none) - Keep bootstrap-multiselect with full dark theme overrides - Rewrite layout.html.twig header/footer with Tailwind utility classes - Switch form theme to tailwind_2_layout.html.twig; preserve .form-group and .checkbox wrappers required by main-form.js JS selectors - Replace Bootstrap grid in generator.html.twig with Tailwind grid/flex panels - Disabled database panels show greyed-out contents instead of collapsing - Integrate CSS build into Makefile (build-css target) and Dockerfile frontend stage Co-Authored-By: Claude Sonnet 4.6 --- Dockerfile | 8 +- Makefile | 11 +- assets/css/app.css | 264 +++++++++ package.json | 13 +- postcss.config.js | 1 + public/css/app.css | 935 ++++++++++++++++++++++++++++++++ public/css/base.css | 207 ------- public/css/dark.css | 121 ----- public/css/media-queries.css | 66 --- public/js/main-form.js | 4 - tailwind.config.js | 23 + templates/form_layout.html.twig | 90 ++- templates/generator.html.twig | 142 +++-- templates/layout.html.twig | 59 +- yarn.lock | 738 ++++++++++++++++++++++++- 15 files changed, 2097 insertions(+), 585 deletions(-) create mode 100644 assets/css/app.css create mode 100644 postcss.config.js create mode 100644 public/css/app.css delete mode 100644 public/css/base.css delete mode 100644 public/css/dark.css delete mode 100644 public/css/media-queries.css create mode 100644 tailwind.config.js diff --git a/Dockerfile b/Dockerfile index 6a4159de..a68b98ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -71,6 +71,12 @@ COPY yarn.lock . RUN yarn install --immutable +COPY tailwind.config.js postcss.config.js ./ +COPY assets/ ./assets/ +COPY templates/ ./templates/ + +RUN yarn build:css + ## Actual deployable frontend image FROM nginx:alpine AS frontend-deployment @@ -84,6 +90,6 @@ RUN sed -i "s/# %DEPLOYMENT //g" /etc/nginx/conf.d/default.conf \ && sed -i "s/ssl_/#ssl_/g" /etc/nginx/conf.d/default.conf COPY --from=frontend-installer node_modules/@bower_components public/vendor +COPY --from=frontend-installer /public/css public/css -COPY public/css public/css COPY public/js public/js diff --git a/Makefile b/Makefile index e4c3b1a1..7d62c8b1 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,16 @@ yarn-install: node:alpine \ sh -c "yarn install --immutable" -install-dependencies: composer-install yarn-install +build-css: + docker run \ + --rm \ + -t \ + -v "`pwd`:/workdir" \ + -w /workdir \ + node:alpine \ + sh -c "yarn install && yarn build:css" + +install-dependencies: composer-install yarn-install build-css composer-update: $(PHP_RUN) composer update --no-scripts diff --git a/assets/css/app.css b/assets/css/app.css new file mode 100644 index 00000000..6aeda90b --- /dev/null +++ b/assets/css/app.css @@ -0,0 +1,264 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@import url('https://fonts.googleapis.com/css2?family=Syne:wght@700;800&family=DM+Sans:wght@400;500&family=JetBrains+Mono:wght@400;500&display=swap'); + +@layer base { + html { + background-color: #080d19; + color: #e2e8f0; + font-family: 'DM Sans', sans-serif; + } + + body { + min-height: 100vh; + background-color: #080d19; + background-image: radial-gradient(circle, rgba(56, 189, 248, 0.06) 1px, transparent 1px); + background-size: 28px 28px; + } + + h1, h2, h3, h4, h5 { + font-family: 'Syne', sans-serif; + font-weight: 700; + } + + a { + color: #38bdf8; + font-weight: 600; + } + + * { + scrollbar-color: #1c3050 #0d1628; + scrollbar-width: thin; + } +} + +@layer components { + /* form-panel: glass-like dark card */ + .form-panel { + background: #0d1628; + border: 1px solid #1c3050; + border-radius: .5rem; + box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.08), 0 4px 24px rgba(8, 13, 25, .6); + overflow: hidden; + margin-bottom: 1rem; + } + + /* panel-header: dark bar + left 3px sky accent stripe */ + .panel-header { + background: #0a1220; + border-bottom: 1px solid #1c3050; + border-left: 3px solid #38bdf8; + padding: .625rem 1rem; + display: flex; + align-items: center; + gap: .5rem; + font-family: 'Syne', sans-serif; + font-weight: 700; + font-size: 1rem; + color: #e2e8f0; + margin: 0; + } + + .panel-body { + padding: 1.25rem; + } + + .panel-body.disabled { + opacity: 0.35; + pointer-events: none; + } + + /* form inputs / selects */ + .form-input, + .form-select { + background: #080d19; + border: 1px solid #1c3050; + border-radius: .375rem; + color: #e2e8f0; + padding: .5rem .75rem; + width: 100%; + font-family: 'JetBrains Mono', monospace; + font-size: .875rem; + transition: border-color .15s, box-shadow .15s; + } + + .form-input:focus, + .form-select:focus { + outline: none; + border-color: #38bdf8; + box-shadow: 0 0 0 3px rgba(56, 189, 248, .2); + } + + .form-label { + display: block; + color: #94a3b8; + font-size: .8125rem; + font-weight: 500; + margin-bottom: .25rem; + } + + .form-note { + font-style: italic; + font-size: .75rem; + color: #94a3b8; + } + + .form-error { + color: #f87171; + font-size: .75rem; + margin-top: .25rem; + } + + /* submit button */ + .btn-generate { + background: linear-gradient(135deg, #0ea5e9, #6366f1); + color: #fff; + font-family: 'Syne', sans-serif; + font-weight: 700; + font-size: 1rem; + padding: .875rem 2.5rem; + border-radius: .5rem; + border: none; + cursor: pointer; + box-shadow: 0 0 20px rgba(56, 189, 248, .25); + transition: opacity .2s, box-shadow .2s; + letter-spacing: .025em; + } + + .btn-generate:hover { + opacity: .9; + box-shadow: 0 0 30px rgba(56, 189, 248, .4); + } +} + +/* bootstrap-multiselect overrides */ +button.multiselect.dropdown-toggle { + display: block; + width: 100%; + background: #080d19; + border: 1px solid #1c3050; + border-radius: .375rem; + color: #e2e8f0; + padding: .5rem .75rem; + font-family: 'JetBrains Mono', monospace; + font-size: .875rem; + text-align: left; + cursor: pointer; + transition: border-color .15s, box-shadow .15s; +} + +button.multiselect.dropdown-toggle:hover, +button.multiselect.dropdown-toggle:focus { + border-color: #38bdf8; + box-shadow: 0 0 0 3px rgba(56, 189, 248, .2); + outline: none; +} + +.multiselect-container.dropdown-menu { + display: block; + position: relative; + z-index: 10; + width: 100%; + background: #080d19; + border: 1px solid #1c3050; + border-radius: .375rem; + margin-top: 2px; + padding: 4px 0; + list-style: none; + max-height: 200px; + overflow-y: auto; +} + +.multiselect-container > li > a { + display: block; + padding: 0; + color: #e2e8f0; + text-decoration: none; +} + +.multiselect-container > li > a > label { + display: block; + padding: 5px 12px 5px 36px; + cursor: pointer; + color: #e2e8f0; + font-size: .875rem; + font-family: 'DM Sans', sans-serif; + margin: 0; +} + +.multiselect-container > li > a > label:hover { + background: #1c3050; + color: #38bdf8; +} + +.multiselect-container > li > a > label > input[type=checkbox] { + margin-right: 8px; + accent-color: #34d399; +} + +.input-group-addon { + background: #0d1628; + border: 1px solid #1c3050; + color: #94a3b8; + padding: .375rem .5rem; + font-size: .875rem; +} + +.multiselect-container .input-group input.form-control { + background: #080d19; + border: 1px solid #1c3050; + border-left: 0; + color: #e2e8f0; + padding: .375rem .5rem; + font-size: .875rem; +} + +button.btn.btn-default.multiselect-clear-filter { + background: #0d1628; + border: 1px solid #1c3050; + color: #94a3b8; + padding: .25rem .5rem; + border-radius: .25rem; + cursor: pointer; +} + +/* Pure CSS toggles — replaces bootstrap-toggle entirely */ +#generator input[type=checkbox] { + appearance: none; + -webkit-appearance: none; + position: relative; + display: inline-block; + width: 44px; + min-width: 44px; + height: 24px; + background: #1c3050; + border: 1px solid #2d4a6e; + border-radius: 9999px; + cursor: pointer; + vertical-align: middle; + transition: background .2s, border-color .2s; +} + +#generator input[type=checkbox]::after { + content: ''; + position: absolute; + width: 18px; + height: 18px; + background: #94a3b8; + border-radius: 9999px; + top: 2px; + left: 2px; + transition: left .2s, background .2s; +} + +#generator input[type=checkbox]:checked { + background: #34d399; + border-color: #34d399; +} + +#generator input[type=checkbox]:checked::after { + left: 22px; + background: #fff; +} diff --git a/package.json b/package.json index 2a36fd3a..a1197b9d 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,19 @@ { "dependencies": { - "@bower_components/bootstrap": "twbs/bootstrap#^3.3.6", "@bower_components/bootstrap-multiselect": "davidstutz/bootstrap-multiselect#0.9.13", - "@bower_components/bootstrap-toggle": "minhur/bootstrap-toggle#^2.2.2", - "@bower_components/font-awesome": "FortAwesome/Font-Awesome#^4.5.0", +"@bower_components/font-awesome": "FortAwesome/Font-Awesome#^4.5.0", "@bower_components/jquery": "jquery/jquery-dist#^2.2.2", "@bower_components/jquery-ui": "components/jqueryui#^1.11.4" }, + "devDependencies": { + "tailwindcss": "^3.4", + "postcss": "^8.4", + "postcss-cli": "^11", + "autoprefixer": "^10.4" + }, + "scripts": { + "build:css": "postcss assets/css/app.css -o public/css/app.css" + }, "engines": { "yarn": ">= 1.0.0" } diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..29595670 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1 @@ +module.exports = { plugins: { tailwindcss: {}, autoprefixer: {} } } diff --git a/public/css/app.css b/public/css/app.css new file mode 100644 index 00000000..ce565483 --- /dev/null +++ b/public/css/app.css @@ -0,0 +1,935 @@ +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +}/* +! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com +*//* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; /* 1 */ + border-width: 0; /* 2 */ + border-style: solid; /* 2 */ + border-color: #e5e7eb; /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + -moz-tab-size: 4; /* 3 */ + -o-tab-size: 4; + tab-size: 4; /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ + font-feature-settings: normal; /* 5 */ + font-variation-settings: normal; /* 6 */ + -webkit-tap-highlight-color: transparent; /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; /* 1 */ + line-height: inherit; /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; /* 1 */ + color: inherit; /* 2 */ + border-top-width: 1px; /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: JetBrains Mono, monospace; /* 1 */ + font-feature-settings: normal; /* 2 */ + font-variation-settings: normal; /* 3 */ + font-size: 1em; /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; /* 1 */ + border-color: inherit; /* 2 */ + border-collapse: collapse; /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-feature-settings: inherit; /* 1 */ + font-variation-settings: inherit; /* 1 */ + font-size: 100%; /* 1 */ + font-weight: inherit; /* 1 */ + line-height: inherit; /* 1 */ + letter-spacing: inherit; /* 1 */ + color: inherit; /* 1 */ + margin: 0; /* 2 */ + padding: 0; /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; /* 1 */ + background-color: transparent; /* 2 */ + background-image: none; /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; /* 1 */ + color: #9ca3af; /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; /* 1 */ + color: #9ca3af; /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; /* 1 */ + vertical-align: middle; /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ +[hidden]:where(:not([hidden="until-found"])) { + display: none; +} + html { + background-color: #080d19; + color: #e2e8f0; + font-family: 'DM Sans', sans-serif; + } + + body { + min-height: 100vh; + background-color: #080d19; + background-image: radial-gradient(circle, rgba(56, 189, 248, 0.06) 1px, transparent 1px); + background-size: 28px 28px; + } + + h1, h2, h3, h4, h5 { + font-family: 'Syne', sans-serif; + font-weight: 700; + } + + a { + color: #38bdf8; + font-weight: 600; + } + + * { + scrollbar-color: #1c3050 #0d1628; + scrollbar-width: thin; + } +/* form-panel: glass-like dark card */ +.form-panel { + background: #0d1628; + border: 1px solid #1c3050; + border-radius: .5rem; + box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.08), 0 4px 24px rgba(8, 13, 25, .6); + overflow: hidden; + margin-bottom: 1rem; + } +/* panel-header: dark bar + left 3px sky accent stripe */ +.panel-header { + background: #0a1220; + border-bottom: 1px solid #1c3050; + border-left: 3px solid #38bdf8; + padding: .625rem 1rem; + display: flex; + align-items: center; + gap: .5rem; + font-family: 'Syne', sans-serif; + font-weight: 700; + font-size: 1rem; + color: #e2e8f0; + margin: 0; + } +.panel-body { + padding: 1.25rem; + } +.panel-body.disabled { + opacity: 0.35; + pointer-events: none; + } +/* form inputs / selects */ +.form-input, + .form-select { + background: #080d19; + border: 1px solid #1c3050; + border-radius: .375rem; + color: #e2e8f0; + padding: .5rem .75rem; + width: 100%; + font-family: 'JetBrains Mono', monospace; + font-size: .875rem; + transition: border-color .15s, box-shadow .15s; + } +.form-input:focus, + .form-select:focus { + outline: none; + border-color: #38bdf8; + box-shadow: 0 0 0 3px rgba(56, 189, 248, .2); + } +.form-label { + display: block; + color: #94a3b8; + font-size: .8125rem; + font-weight: 500; + margin-bottom: .25rem; + } +.form-note { + font-style: italic; + font-size: .75rem; + color: #94a3b8; + } +.form-error { + color: #f87171; + font-size: .75rem; + margin-top: .25rem; + } +/* submit button */ +.btn-generate { + background: linear-gradient(135deg, #0ea5e9, #6366f1); + color: #fff; + font-family: 'Syne', sans-serif; + font-weight: 700; + font-size: 1rem; + padding: .875rem 2.5rem; + border-radius: .5rem; + border: none; + cursor: pointer; + box-shadow: 0 0 20px rgba(56, 189, 248, .25); + transition: opacity .2s, box-shadow .2s; + letter-spacing: .025em; + } +.btn-generate:hover { + opacity: .9; + box-shadow: 0 0 30px rgba(56, 189, 248, .4); + } +.relative { + position: relative; +} +.mx-auto { + margin-left: auto; + margin-right: auto; +} +.mb-1 { + margin-bottom: 0.25rem; +} +.mb-3 { + margin-bottom: 0.75rem; +} +.mb-4 { + margin-bottom: 1rem; +} +.mt-0\.5 { + margin-top: 0.125rem; +} +.mt-1 { + margin-top: 0.25rem; +} +.mt-2 { + margin-top: 0.5rem; +} +.mt-8 { + margin-top: 2rem; +} +.block { + display: block; +} +.flex { + display: flex; +} +.grid { + display: grid; +} +.max-w-screen-xl { + max-width: 1280px; +} +.list-inside { + list-style-position: inside; +} +.list-disc { + list-style-type: disc; +} +.list-none { + list-style-type: none; +} +.grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); +} +.flex-col { + flex-direction: column; +} +.items-center { + align-items: center; +} +.justify-center { + justify-content: center; +} +.justify-between { + justify-content: space-between; +} +.gap-2 { + gap: 0.5rem; +} +.gap-3 { + gap: 0.75rem; +} +.gap-4 { + gap: 1rem; +} +.gap-6 { + gap: 1.5rem; +} +.space-y-1 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.25rem * var(--tw-space-y-reverse)); +} +.border-b { + border-bottom-width: 1px; +} +.border-t { + border-top-width: 1px; +} +.border-\[\#1c3050\] { + --tw-border-opacity: 1; + border-color: rgb(28 48 80 / var(--tw-border-opacity, 1)); +} +.bg-\[\#080d19\] { + --tw-bg-opacity: 1; + background-color: rgb(8 13 25 / var(--tw-bg-opacity, 1)); +} +.p-0 { + padding: 0px; +} +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} +.py-4 { + padding-top: 1rem; + padding-bottom: 1rem; +} +.py-6 { + padding-top: 1.5rem; + padding-bottom: 1.5rem; +} +.py-8 { + padding-top: 2rem; + padding-bottom: 2rem; +} +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} +.font-extrabold { + font-weight: 800; +} +.font-normal { + font-weight: 400; +} +.tracking-tight { + letter-spacing: -0.025em; +} +.text-\[\#94a3b8\] { + --tw-text-opacity: 1; + color: rgb(148 163 184 / var(--tw-text-opacity, 1)); +} +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity, 1)); +} +.no-underline { + text-decoration-line: none; +} + +@import url('https://fonts.googleapis.com/css2?family=Syne:wght@700;800&family=DM+Sans:wght@400;500&family=JetBrains+Mono:wght@400;500&display=swap'); + +/* bootstrap-multiselect overrides */ +button.multiselect.dropdown-toggle { + display: block; + width: 100%; + background: #080d19; + border: 1px solid #1c3050; + border-radius: .375rem; + color: #e2e8f0; + padding: .5rem .75rem; + font-family: 'JetBrains Mono', monospace; + font-size: .875rem; + text-align: left; + cursor: pointer; + transition: border-color .15s, box-shadow .15s; +} + +button.multiselect.dropdown-toggle:hover, +button.multiselect.dropdown-toggle:focus { + border-color: #38bdf8; + box-shadow: 0 0 0 3px rgba(56, 189, 248, .2); + outline: none; +} + +.multiselect-container.dropdown-menu { + display: block; + position: relative; + z-index: 10; + width: 100%; + background: #080d19; + border: 1px solid #1c3050; + border-radius: .375rem; + margin-top: 2px; + padding: 4px 0; + list-style: none; + max-height: 200px; + overflow-y: auto; +} + +.multiselect-container > li > a { + display: block; + padding: 0; + color: #e2e8f0; + text-decoration: none; +} + +.multiselect-container > li > a > label { + display: block; + padding: 5px 12px 5px 36px; + cursor: pointer; + color: #e2e8f0; + font-size: .875rem; + font-family: 'DM Sans', sans-serif; + margin: 0; +} + +.multiselect-container > li > a > label:hover { + background: #1c3050; + color: #38bdf8; +} + +.multiselect-container > li > a > label > input[type=checkbox] { + margin-right: 8px; + accent-color: #34d399; +} + +.input-group-addon { + background: #0d1628; + border: 1px solid #1c3050; + color: #94a3b8; + padding: .375rem .5rem; + font-size: .875rem; +} + +.multiselect-container .input-group input.form-control { + background: #080d19; + border: 1px solid #1c3050; + border-left: 0; + color: #e2e8f0; + padding: .375rem .5rem; + font-size: .875rem; +} + +button.btn.btn-default.multiselect-clear-filter { + background: #0d1628; + border: 1px solid #1c3050; + color: #94a3b8; + padding: .25rem .5rem; + border-radius: .25rem; + cursor: pointer; +} + +/* Pure CSS toggles — replaces bootstrap-toggle entirely */ +#generator input[type=checkbox] { + -moz-appearance: none; + appearance: none; + -webkit-appearance: none; + position: relative; + display: inline-block; + width: 44px; + min-width: 44px; + height: 24px; + background: #1c3050; + border: 1px solid #2d4a6e; + border-radius: 9999px; + cursor: pointer; + vertical-align: middle; + transition: background .2s, border-color .2s; +} + +#generator input[type=checkbox]::after { + content: ''; + position: absolute; + width: 18px; + height: 18px; + background: #94a3b8; + border-radius: 9999px; + top: 2px; + left: 2px; + transition: left .2s, background .2s; +} + +#generator input[type=checkbox]:checked { + background: #34d399; + border-color: #34d399; +} + +#generator input[type=checkbox]:checked::after { + left: 22px; + background: #fff; +} + +.hover\:text-\[\#38bdf8\]:hover { + --tw-text-opacity: 1; + color: rgb(56 189 248 / var(--tw-text-opacity, 1)); +} + +@media (min-width: 640px) { + + .sm\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .sm\:flex-row { + flex-direction: row; + } +} + +@media (min-width: 768px) { + + .md\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .md\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +@media (min-width: 1024px) { + + .lg\:col-span-1 { + grid-column: span 1 / span 1; + } + + .lg\:col-span-3 { + grid-column: span 3 / span 3; + } + + .lg\:grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } +} diff --git a/public/css/base.css b/public/css/base.css deleted file mode 100644 index ac6f053f..00000000 --- a/public/css/base.css +++ /dev/null @@ -1,207 +0,0 @@ -/***** Main styles *****/ - -body { - font-family : "Hind", sans-serif; - font-size : 1.8em; -} - -body, html { - height : 100%; -} - -#wrap { - min-height : calc(100% - 55px); -} - -a { - color : #df1c0d; - font-weight : bold !important; -} - -hr { - border-color : #df1c0d; - width : 90%; -} - -h1, h2, h3, h4, h5 { - font-weight : bold; -} - -.shadow { - -webkit-box-shadow : 0 6px 12px rgba(0, 0, 0, .175); - -moz-box-shadow : 0 6px 12px rgba(0, 0, 0, .175); - box-shadow : 0 6px 12px rgba(0, 0, 0, .175); -} - -.inner-shadow-top { - -moz-box-shadow : inset 0 5px 10px 0 #000; - -webkit-box-shadow : inset 0 5px 10px 0 #000; - box-shadow : inset 0 5px 10px 0 #000; -} - -.inner-shadow-bottom { - -moz-box-shadow : inset 0 -5px 10px 0 #000; - -webkit-box-shadow : inset 0 -5px 10px 0 #000; - box-shadow : inset 0 -5px 10px 0 #000; -} - -h3 { - display : block; -} - -/***** Section *****/ - -section { - padding : 0.5em 0; -} - -section#content { - padding : 1.5em !important; -} - -/***** Header *****/ -section#header { - border-radius : 0; - margin-bottom : 0; - padding-top : 0.5em; - padding-bottom : 0.5em; - padding-left : 1.5em; - text-shadow : 2px 2px 6px rgba(0, 0, 0, .7); - background-color : rgba(0, 0, 0, 0.64); - border-color : transparent; -} - -#header a h1 { - color : #fff; - font-weight : 900; - font-size : 32px; -} - -#header p { - color : #fff; -} - -/***** Footer *****/ - -footer { - padding-top : 1em; - padding-bottom : 1em; - background-color : rgba(0, 0, 0, 0.7); - height : 55px; -} - -footer .copyright, -footer a { - text-shadow : 2px 2px 6px rgba(0, 0, 0, .7); -} - -footer a { - color : white !important; -} - -footer a:hover { - cursor : pointer; - text-decoration : none; -} - -footer .share { - text-align : right; -} - -footer .github-link { - margin-left : 1em; -} - -/***** Forms *****/ - -form input[type=submit] { -} - -form .group { - border : 2px #444 solid; - border-radius : 5px; - margin-bottom : 1em; -} - -form .group .note { - font-style : italic; - font-size : 0.8em; - display : block; - clear : both; - padding-left : 15px; -} - -form .group h2 { - margin : 0 0 1em 0; -} - -form .group h3 { - margin : -15px -15px 0 -15px; - background-color : #444; - padding : 0.5em; - color : white; -} - -form .row { - margin-top: 15px; - margin-bottom: 5px; -} - -form .group h3:first-of-type { - margin-top : 0 !important; -} - -form .form-group { - min-height : 2em; -} - -.multiselect-container.dropdown-menu { - z-index : 10; - box-shadow : none; - width : 100%; - position : relative; -} - -.disabled { - color : #666; - font-style : italic; - display : none; -} - -label { - font-size : 0.9em; -} - -option:disabled { - background-color : #ccc; - font-style : italic; -} - -/***** Buttons *****/ - -.button-custom { - border-radius : 0; - -webkit-border-radius : 0; - -moz-border-radius : 0; - -webkit-transition : all 0.5s ease-in-out; - -moz-transition : all 0.5s ease-in-out; - -o-transition : all 0.5s ease-in-out; - transition : all 0.5s ease-in-out; - margin : 5px; -} - -.btn-custom-three { - color : #fff; - background-color : #777777; - border : 2px solid #4c4c4c; - font-size : 1em; - font-weight : bold; - padding : 0.5em; -} - -.btn-custom-three:hover { - border : 2px solid black; - text-decoration : none; - color : #fff; - background-color : #4c4c4c; -} diff --git a/public/css/dark.css b/public/css/dark.css deleted file mode 100644 index 0fffc679..00000000 --- a/public/css/dark.css +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2021 Luis Alberto Pabón Flores - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -@media (prefers-color-scheme : dark) { - :root { - --darkest : #191919; - --dark : #2a2a2a; - --less-dark : #444444; - --bright : #797979; - --brightest : #c2c2c2; - --dark-blue : #296292; - } - - * { - scrollbar-color : var(--darkest) var(--dark); - } - - section#header, - footer { - background-color : var(--darkest) !important; - } - - body { - color : var(--brightest); - background-color : var(--darkest); - } - - section#content { - background-color : var(--darkest); - } - - form .group h3 { - background-color : var(--dark); - color : var(--brightest); - } - - .btn-custom-three { - background-color : var(--dark); - } - - .form-control { - color : var(--brightest); - background-color : var(--darkest); - border-color : var(--dark); - } - - #header a, - #header p { - color : var(--brightest) !important; - } - - /** Multiselect **/ - .dropdown-menu { - background-color : var(--darkest); - border-color : var(--dark); - box-shadow : rgba(0, 0, 0, 0.18); - } - - .dropdown-menu > li > a { - color : var(--brightest); - font-size : 1.2em; - } - - .input-group-addon { - background-color : var(--dark); - color : var(--brightest); - border-color : var(--dark); - } - - ul.multiselect-container.dropdown-menu li a label.checkbox:hover, - .multiselect.dropdown-toggle:hover { - background-color : var(--dark) !important; - color : var(--brightest) !important; - } - - /** Toggles **/ - .btn-default, - .btn-default:active, - .open > .dropdown-toggle.btn-default, - button.btn.btn-default.multiselect-clear-filter { - color : var(--brightest); - background-color : var(--dark) !important; - border-color : var(--dark); - } - - label.btn.btn-default.btn-sm { - background-color : var(--dark); - color : var(--brightest); - } - - .btn-sm:hover { - border-color : var(--bright) !important; - } - - .toggle-on { - background-color : var(--dark-blue); - } - - .toggle-off { - background-color : var(--less-dark) !important; - } - - .toggle-handle { - background-color : var(--darkest) !important; - } -} - diff --git a/public/css/media-queries.css b/public/css/media-queries.css deleted file mode 100644 index bdb018b6..00000000 --- a/public/css/media-queries.css +++ /dev/null @@ -1,66 +0,0 @@ -/***** Media queries *****/ - -/*========== Mobile First Method ==========*/ - -/* Custom, iPhone Retina */ -@media only screen and (min-width : 320px) { - -} - -/* Extra Small Devices, Phones */ -@media only screen and (min-width : 480px) { - -} - -/* Extra Small Devices, Phones */ -@media only screen and (max-width : 480px) { - -} - -/* Small Devices, Tablets */ -@media only screen and (min-width : 768px) { -} - -/* Medium Devices, Desktops */ -@media only screen and (min-width : 992px) { -} - -/* Large Devices, Wide Screens */ -@media only screen and (min-width : 1200px) { -} - -/*========== Non-Mobile First Method ==========*/ - -/* Large Devices, Wide Screens */ -@media only screen and (max-width : 1200px) { -} - -/* Medium Devices, Desktops */ -@media only screen and (max-width : 1024px) { -} - -/* Small Devices, Tablets */ -@media only screen and (max-width : 800px) { - form .group { - border : 0 !important; - } -} - -/* Custom, iPhone Retina */ -@media only screen and (max-width : 480px) { -} - -/***** Custom footer *****/ -@media only screen and (max-width : 736px) { - #wrap { - min-height : calc(100% - 80px); - } - - footer { - height : 80px; - } - - footer .copyright { - text-align : center; - } -} diff --git a/public/js/main-form.js b/public/js/main-form.js index 54696755..e4f4799e 100644 --- a/public/js/main-form.js +++ b/public/js/main-form.js @@ -143,8 +143,4 @@ function doMainFormMagic () { gtag('send', 'event', 'builder-form', 'form-submission') }) - // Bootstrap toggles - $('#generator div.checkbox input[type=checkbox]').bootstrapToggle({ - size: 'small' - }) } diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000..3fd5bab1 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,23 @@ +module.exports = { + content: ['./templates/**/*.twig'], + theme: { + extend: { + colors: { + 'deep-bg': '#080d19', + 'panel-bg': '#0d1628', + 'panel-border': '#1c3050', + 'accent-sky': '#38bdf8', + 'accent-indigo': '#818cf8', + 'accent-emerald': '#34d399', + 'text-primary': '#e2e8f0', + 'text-secondary': '#94a3b8', + }, + fontFamily: { + display: ['Syne', 'sans-serif'], + body: ['DM Sans', 'sans-serif'], + mono: ['JetBrains Mono', 'monospace'], + }, + }, + }, + plugins: [], +} diff --git a/templates/form_layout.html.twig b/templates/form_layout.html.twig index 49a993be..435aea0e 100644 --- a/templates/form_layout.html.twig +++ b/templates/form_layout.html.twig @@ -1,66 +1,46 @@ -{% use "bootstrap_3_layout.html.twig" %} - -{% block form_start -%} - {% set attr = attr|merge({class: (attr.class|default('') ~ ' form-horizontal')|trim}) %} - {{- parent() -}} -{%- endblock form_start %} - -{# Labels #} - -{% block form_label -%} - - {% if label is same as(false) %} -
- {% else %} - {% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' ' ~ block('form_label_class'))|trim}) %} - {{- parent() -}} - {% endif %} - -{%- endblock form_label %} - -{% block form_label_class -%}col-lg-3 col-md-3{%- endblock form_label_class %} - -{% block form_group_class -%}col-lg-9 col-md-9{%- endblock form_group_class %} - -{# Rows #} +{% use "tailwind_2_layout.html.twig" %} {% block form_row -%} -
+
{{- form_label(form) -}} -
- {{- form_widget(form) -}} - {{- form_errors(form) -}} -
- {##}
+ {{- form_widget(form) -}} + {{- form_errors(form) -}} +
{%- endblock form_row %} {% block checkbox_row -%} - {{- block('checkbox_radio_row') -}} -{%- endblock checkbox_row %} - -{% block radio_row -%} - {{- block('checkbox_radio_row') -}} -{%- endblock radio_row %} - -{% block checkbox_radio_row -%} - -
-
-
- {{ form_widget(form) }} - {{ form_errors(form) }} +
+
+ {{- form_widget(form) -}} + {{- form_label(form) -}}
+ {{- form_errors(form) -}}
+{%- endblock checkbox_row %} -{%- endblock checkbox_radio_row %} - -{% block submit_row -%} +{% block form_label -%} + {% if label is not same as(false) %} + {% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' form-label')|trim}) %} + {{- parent() -}} + {% endif %} +{%- endblock form_label %} -
-
-
- {{ form_widget(form) }} -
-
+{% block form_errors -%} + {%- if errors|length > 0 -%} +
    + {%- for error in errors -%} +
  • {{ error.message }}
  • + {%- endfor -%} +
+ {%- endif -%} +{%- endblock form_errors %} + +{% block widget_attributes -%} + {%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-input')|trim}) -%} + {{- parent() -}} +{%- endblock widget_attributes %} -{% endblock submit_row %} +{% block choice_widget_collapsed -%} + {%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-select')|trim}) -%} + {{- parent() -}} +{%- endblock choice_widget_collapsed %} diff --git a/templates/generator.html.twig b/templates/generator.html.twig index b7f327b9..0e564ee5 100644 --- a/templates/generator.html.twig +++ b/templates/generator.html.twig @@ -4,86 +4,77 @@ {% set activePage = 'generator' %} {% block pageTitle %} - Generator{% endblock %} -{% set formGroupClass = 'group' %} - -{% set bigColumn = 'col col-lg-12 col-md-12 col-sm-12 col-xs-12' %} -{% set quarterColumn = 'col col-lg-3 col-md-3 col-sm-12 col-xs-12' %} - {% block body %}
-
- {{ form_errors(form) }} -
-
-
-

Global configuration

-
+ {{ form_errors(form) }} + + {# Global configuration #} +
+

Global configuration

+
+
{% for field in ['basePort', 'appPath', 'dockerWorkingDir'] %} -
{{ form_row(attribute(form.globalOptions, field)) }}
+
{{ form_row(attribute(form.globalOptions, field)) }}
{% endfor %}
-
-
-
Initial port for services exposed from docker to your machine
-
-
-
Location of your app's source code relative to docker-compose.yaml
-
-
-
Working directory for all containers
-
+
+

Initial port for services exposed from docker to your machine

+

Location of your app's source code relative to docker-compose.yaml

+

Working directory for all containers

-
-
-

PHP configuration

-
-
- {{ form_row(attribute(form.phpOptions, 'version')) }} - {{ form_row(attribute(form.phpOptions, 'frontControllerPath')) }} - {{ form_row(attribute(form.phpOptions, 'hasGit')) }} - -
-

Please note:

-
    -
  • Extensions already included on base image: APC, - cURL, JSON, Sodium, MBString, OPCache, Readline, XML and Zip. -
  • -
  • Each PHP version supports a different set of extensions to the others.
  • -
+ {# PHP + Zero-config row #} +
+
+

PHP configuration

+
+
+
+ {{ form_row(attribute(form.phpOptions, 'version')) }} + {{ form_row(attribute(form.phpOptions, 'frontControllerPath')) }} + {{ form_row(attribute(form.phpOptions, 'hasGit')) }} + +
+

Please note:

+
    +
  • Extensions already included on base image: APC, + cURL, JSON, Sodium, MBString, OPCache, Readline, XML and Zip. +
  • +
  • Each PHP version supports a different set of extensions to the others.
  • +
+
-
-
- {{ form_row(attribute(form.phpOptions, 'phpExtensions85')) }} - - {{ form_row(attribute(form.phpOptions, 'phpExtensions84')) }} - - {{ form_row(attribute(form.phpOptions, 'phpExtensions83')) }} - - {{ form_row(attribute(form.phpOptions, 'phpExtensions82')) }} +
+ {{ form_row(attribute(form.phpOptions, 'phpExtensions85')) }} + {{ form_row(attribute(form.phpOptions, 'phpExtensions84')) }} + {{ form_row(attribute(form.phpOptions, 'phpExtensions83')) }} + {{ form_row(attribute(form.phpOptions, 'phpExtensions82')) }} +
-
-

Zero-config Services

-

The following services take no additional configuration parameters.

- {% for field in ['hasMemcached', 'hasRedis', 'hasMailhog', 'hasClickhouse'] %} - {% if (attribute(form, field) is defined) %} -
{{ form_widget(attribute(form, field)) }}
- {% endif %} - {% endfor %} +
+

Zero-config Services

+
+

The following services take no additional configuration parameters.

+ {% for field in ['hasMemcached', 'hasRedis', 'hasMailhog', 'hasClickhouse'] %} + {% if (attribute(form, field) is defined) %} + {{ form_row(attribute(form, field)) }} + {% endif %} + {% endfor %} +
-
-
-

{{ form_widget(attribute(form.mysqlOptions, 'hasMysql')) }}

-
+ {# Database + Elasticsearch panels #} +
+
+

{{ form_widget(attribute(form.mysqlOptions, 'hasMysql')) }} MySQL

+
{% for field in ['version', 'rootPassword', 'databaseName', 'username', 'password'] %} {% if (attribute(form.mysqlOptions, field) is defined) %}
{{ form_row(attribute(form.mysqlOptions, field)) }}
@@ -92,9 +83,9 @@
-
-

{{ form_widget(attribute(form.mariadbOptions, 'hasMariadb')) }}

-
+
+

{{ form_widget(attribute(form.mariadbOptions, 'hasMariadb')) }} MariaDB

+
{% for field in ['version', 'rootPassword', 'databaseName', 'username', 'password'] %} {% if (attribute(form.mariadbOptions, field) is defined) %}
{{ form_row(attribute(form.mariadbOptions, field)) }}
@@ -103,9 +94,9 @@
-
-

{{ form_widget(attribute(form.postgresOptions, 'hasPostgres')) }}

-
+
+

{{ form_widget(attribute(form.postgresOptions, 'hasPostgres')) }} Postgres

+
{% for field in ['version', 'rootUser', 'rootPassword', 'databaseName'] %} {% if (attribute(form.postgresOptions, field) is defined) %}
{{ form_row(attribute(form.postgresOptions, field)) }}
@@ -114,9 +105,9 @@
-
-

{{ form_widget(attribute(form.elasticsearchOptions, 'hasElasticsearch')) }}

-
+
+

{{ form_widget(attribute(form.elasticsearchOptions, 'hasElasticsearch')) }} Elasticsearch

+
{{ form_row(attribute(form.elasticsearchOptions, 'version')) }}
@@ -124,13 +115,8 @@ {{ form_rest(form) }} -
-
-
- -
-
+
+
{% endblock %} diff --git a/templates/layout.html.twig b/templates/layout.html.twig index ae26b185..2be78148 100644 --- a/templates/layout.html.twig +++ b/templates/layout.html.twig @@ -15,59 +15,36 @@ {% include 'analytics.html.twig' %} - - - - + - - - + -
- - - +
+ +

PHPDocker.io

+
+

A PHP development environment generator built with Docker containers.

+
- -
-
- {% block body %}{% endblock %} -
-
- -
+
{% block body %}{% endblock %}
-