Skip to content

Commit f96849e

Browse files
luispabonclaude
andauthored
Replace Bootstrap 3 with Tailwind CSS — dark-mode redesign (#388)
* Replace Bootstrap 3 with Tailwind CSS — dark-mode redesign - 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 <noreply@anthropic.com> * Fix a few behaviour test failures * Alignments * Alignments --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 71eade7 commit f96849e

15 files changed

Lines changed: 2098 additions & 584 deletions

Dockerfile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ COPY yarn.lock .
7171

7272
RUN yarn install --immutable
7373

74+
COPY tailwind.config.js postcss.config.js ./
75+
COPY assets/ ./assets/
76+
COPY templates/ ./templates/
77+
78+
RUN yarn build:css
79+
7480
## Actual deployable frontend image
7581
FROM nginx:alpine AS frontend-deployment
7682

@@ -84,6 +90,6 @@ RUN sed -i "s/# %DEPLOYMENT //g" /etc/nginx/conf.d/default.conf \
8490
&& sed -i "s/ssl_/#ssl_/g" /etc/nginx/conf.d/default.conf
8591

8692
COPY --from=frontend-installer node_modules/@bower_components public/vendor
93+
COPY --from=frontend-installer /public/css public/css
8794

88-
COPY public/css public/css
8995
COPY public/js public/js

Makefile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,16 @@ yarn-install:
7070
node:alpine \
7171
sh -c "yarn install --immutable"
7272

73-
install-dependencies: composer-install yarn-install
73+
build-css:
74+
docker run \
75+
--rm \
76+
-t \
77+
-v "`pwd`:/workdir" \
78+
-w /workdir \
79+
node:alpine \
80+
sh -c "yarn install && yarn build:css"
81+
82+
install-dependencies: composer-install yarn-install build-css
7483

7584
composer-update:
7685
$(PHP_RUN) composer update --no-scripts

assets/css/app.css

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+
5+
@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');
6+
7+
@layer base {
8+
html {
9+
background-color: #080d19;
10+
color: #e2e8f0;
11+
font-family: 'DM Sans', sans-serif;
12+
}
13+
14+
body {
15+
min-height: 100vh;
16+
background-color: #080d19;
17+
background-image: radial-gradient(circle, rgba(56, 189, 248, 0.06) 1px, transparent 1px);
18+
background-size: 28px 28px;
19+
}
20+
21+
h1, h2, h3, h4, h5 {
22+
font-family: 'Syne', sans-serif;
23+
font-weight: 700;
24+
}
25+
26+
a {
27+
color: #38bdf8;
28+
font-weight: 600;
29+
}
30+
31+
* {
32+
scrollbar-color: #1c3050 #0d1628;
33+
scrollbar-width: thin;
34+
}
35+
}
36+
37+
@layer components {
38+
/* form-panel: glass-like dark card */
39+
.form-panel {
40+
background: #0d1628;
41+
border: 1px solid #1c3050;
42+
border-radius: .5rem;
43+
box-shadow: 0 0 0 1px rgba(56, 189, 248, 0.08), 0 4px 24px rgba(8, 13, 25, .6);
44+
overflow: hidden;
45+
margin-bottom: 1rem;
46+
}
47+
48+
/* panel-header: dark bar + left 3px sky accent stripe */
49+
.panel-header {
50+
background: #0a1220;
51+
border-bottom: 1px solid #1c3050;
52+
border-left: 3px solid #38bdf8;
53+
padding: .625rem 1rem;
54+
display: flex;
55+
align-items: center;
56+
gap: .5rem;
57+
font-family: 'Syne', sans-serif;
58+
font-weight: 700;
59+
font-size: 1rem;
60+
color: #e2e8f0;
61+
margin: 0;
62+
}
63+
64+
.panel-body {
65+
padding: 1.25rem;
66+
}
67+
68+
.panel-body.disabled {
69+
opacity: 0.35;
70+
pointer-events: none;
71+
}
72+
73+
/* form inputs / selects */
74+
.form-input,
75+
.form-select {
76+
background: #080d19;
77+
border: 1px solid #1c3050;
78+
border-radius: .375rem;
79+
color: #e2e8f0;
80+
padding: .5rem .75rem;
81+
width: 100%;
82+
font-family: 'JetBrains Mono', monospace;
83+
font-size: .875rem;
84+
transition: border-color .15s, box-shadow .15s;
85+
}
86+
87+
.form-input:focus,
88+
.form-select:focus {
89+
outline: none;
90+
border-color: #38bdf8;
91+
box-shadow: 0 0 0 3px rgba(56, 189, 248, .2);
92+
}
93+
94+
.form-label {
95+
display: block;
96+
color: #94a3b8;
97+
font-size: .8125rem;
98+
font-weight: 500;
99+
margin-bottom: .25rem;
100+
}
101+
102+
.form-note {
103+
font-style: italic;
104+
font-size: .75rem;
105+
color: #94a3b8;
106+
}
107+
108+
.form-error {
109+
color: #f87171;
110+
font-size: .75rem;
111+
margin-top: .25rem;
112+
}
113+
114+
/* submit button */
115+
.btn-generate {
116+
background: linear-gradient(135deg, #0ea5e9, #6366f1);
117+
color: #fff;
118+
font-family: 'Syne', sans-serif;
119+
font-weight: 700;
120+
font-size: 1rem;
121+
padding: .875rem 2.5rem;
122+
border-radius: .5rem;
123+
border: none;
124+
cursor: pointer;
125+
box-shadow: 0 0 20px rgba(56, 189, 248, .25);
126+
transition: opacity .2s, box-shadow .2s;
127+
letter-spacing: .025em;
128+
}
129+
130+
.btn-generate:hover {
131+
opacity: .9;
132+
box-shadow: 0 0 30px rgba(56, 189, 248, .4);
133+
}
134+
}
135+
136+
/* bootstrap-multiselect overrides */
137+
button.multiselect.dropdown-toggle {
138+
display: block;
139+
width: 100%;
140+
background: #080d19;
141+
border: 1px solid #1c3050;
142+
border-radius: .375rem;
143+
color: #e2e8f0;
144+
padding: .5rem .75rem;
145+
font-family: 'JetBrains Mono', monospace;
146+
font-size: .875rem;
147+
text-align: left;
148+
cursor: pointer;
149+
transition: border-color .15s, box-shadow .15s;
150+
}
151+
152+
button.multiselect.dropdown-toggle:hover,
153+
button.multiselect.dropdown-toggle:focus {
154+
border-color: #38bdf8;
155+
box-shadow: 0 0 0 3px rgba(56, 189, 248, .2);
156+
outline: none;
157+
}
158+
159+
.multiselect-container.dropdown-menu {
160+
display: block;
161+
position: relative;
162+
z-index: 10;
163+
width: 100%;
164+
background: #080d19;
165+
border: 1px solid #1c3050;
166+
border-radius: .375rem;
167+
margin-top: 2px;
168+
padding: 4px 0;
169+
list-style: none;
170+
max-height: 200px;
171+
overflow-y: auto;
172+
}
173+
174+
.multiselect-container > li > a {
175+
display: block;
176+
padding: 0;
177+
color: #e2e8f0;
178+
text-decoration: none;
179+
}
180+
181+
.multiselect-container > li > a > label {
182+
display: block;
183+
padding: 5px 12px 5px 36px;
184+
cursor: pointer;
185+
color: #e2e8f0;
186+
font-size: .875rem;
187+
font-family: 'DM Sans', sans-serif;
188+
margin: 0;
189+
}
190+
191+
.multiselect-container > li > a > label:hover {
192+
background: #1c3050;
193+
color: #38bdf8;
194+
}
195+
196+
.multiselect-container > li > a > label > input[type=checkbox] {
197+
margin-right: 8px;
198+
accent-color: #34d399;
199+
}
200+
201+
.input-group-addon {
202+
background: #0d1628;
203+
border: 1px solid #1c3050;
204+
color: #94a3b8;
205+
padding: .375rem .5rem;
206+
font-size: .875rem;
207+
}
208+
209+
.multiselect-container .input-group input.form-control {
210+
background: #080d19;
211+
border: 1px solid #1c3050;
212+
border-left: 0;
213+
color: #e2e8f0;
214+
padding: .375rem .5rem;
215+
font-size: .875rem;
216+
}
217+
218+
button.btn.btn-default.multiselect-clear-filter {
219+
background: #0d1628;
220+
border: 1px solid #1c3050;
221+
color: #94a3b8;
222+
padding: .25rem .5rem;
223+
border-radius: .25rem;
224+
cursor: pointer;
225+
}
226+
227+
/* Pure CSS toggles — replaces bootstrap-toggle entirely */
228+
#generator input[type=checkbox] {
229+
appearance: none;
230+
-webkit-appearance: none;
231+
position: relative;
232+
display: inline-block;
233+
width: 44px;
234+
min-width: 44px;
235+
height: 24px;
236+
background: #1c3050;
237+
border: 1px solid #2d4a6e;
238+
border-radius: 9999px;
239+
cursor: pointer;
240+
vertical-align: middle;
241+
transition: background .2s, border-color .2s;
242+
}
243+
244+
#generator input[type=checkbox]::after {
245+
content: '';
246+
position: absolute;
247+
width: 18px;
248+
height: 18px;
249+
background: #94a3b8;
250+
border-radius: 9999px;
251+
top: 2px;
252+
left: 2px;
253+
transition: left .2s, background .2s;
254+
}
255+
256+
#generator input[type=checkbox]:checked {
257+
background: #34d399;
258+
border-color: #34d399;
259+
}
260+
261+
#generator input[type=checkbox]:checked::after {
262+
left: 22px;
263+
background: #fff;
264+
}

package.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
{
22
"dependencies": {
3-
"@bower_components/bootstrap": "twbs/bootstrap#^3.3.6",
43
"@bower_components/bootstrap-multiselect": "davidstutz/bootstrap-multiselect#0.9.13",
5-
"@bower_components/bootstrap-toggle": "minhur/bootstrap-toggle#^2.2.2",
6-
"@bower_components/font-awesome": "FortAwesome/Font-Awesome#^4.5.0",
4+
"@bower_components/font-awesome": "FortAwesome/Font-Awesome#^4.5.0",
75
"@bower_components/jquery": "jquery/jquery-dist#^2.2.2",
86
"@bower_components/jquery-ui": "components/jqueryui#^1.11.4"
97
},
8+
"devDependencies": {
9+
"tailwindcss": "^3.4",
10+
"postcss": "^8.4",
11+
"postcss-cli": "^11",
12+
"autoprefixer": "^10.4"
13+
},
14+
"scripts": {
15+
"build:css": "postcss assets/css/app.css -o public/css/app.css"
16+
},
1017
"engines": {
1118
"yarn": ">= 1.0.0"
1219
}

postcss.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = { plugins: { tailwindcss: {}, autoprefixer: {} } }

0 commit comments

Comments
 (0)