Skip to content

Commit 20f3c4a

Browse files
Merge remote-tracking branch 'origin/main' into hetzner
2 parents e3c5107 + 350af44 commit 20f3c4a

18 files changed

Lines changed: 1154 additions & 74 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
<!-- version list -->
9+
10+
## v1.0.0 (2026-06-23)
11+
12+
### Chores
13+
14+
- Release v0.1.30 [skip ci]
15+
([`8740166`](https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/commit/87401665003a8863d28f7c583bc0ac57fdf1f8cb))
16+
17+
### Continuous Integration
18+
19+
- Add semantic-release workflow and conventional commit enforcement
20+
([#203](https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/pull/203),
21+
[`e9ab2ad`](https://github.com/Promptly-Technologies-LLC/fastapi-jinja2-postgres-webapp/commit/e9ab2ad60e1a06b20fc3fe1bcdb91fb958b50e6b))

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "fastapi-jinja2-postgres-webapp"
3-
version = "0.1.30"
3+
version = "1.0.0"
44
description = "A template webapp with a pure-Python FastAPI backend, frontend templating with Jinja2, and a Postgres database to power user auth"
55
readme = "README.md"
66
package-mode = false

static/css/extras.css

Lines changed: 344 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
/* Constrain top-level regions to the viewport and allow flex children to
2+
shrink below their content size, so wide content wraps instead of widening
3+
the document. */
4+
html,
5+
body {
6+
width: 100%;
7+
max-width: 100%;
8+
}
9+
10+
body,
11+
body > header,
12+
body > main,
13+
body > footer,
14+
main {
15+
min-width: 0;
16+
max-width: 100%;
17+
}
18+
119
.invalid-feedback {
220
display: none;
321
color: red;
@@ -7,7 +25,290 @@ input:invalid:not(:placeholder-shown) + .invalid-feedback {
725
display: block;
826
}
927

10-
/* Align pending-invitation Cancel buttons with card-header actions (e.g. Invite Member). */
28+
/* Organization page header. */
29+
.organization-page-header {
30+
min-width: 0;
31+
max-width: 100%;
32+
}
33+
34+
.organization-page-header-title {
35+
flex: 1 1 20rem;
36+
min-width: 0;
37+
max-width: 100%;
38+
overflow-wrap: anywhere;
39+
word-break: break-word;
40+
}
41+
42+
.organization-page-header-actions {
43+
flex: 0 0 auto;
44+
}
45+
46+
@media (max-width: 767.98px) {
47+
.organization-page-header-actions {
48+
width: 100%;
49+
}
50+
}
51+
52+
/* Dashboard organization selector. */
53+
.dashboard-org-selector {
54+
display: flex;
55+
flex-wrap: wrap;
56+
align-items: center;
57+
gap: 0.5rem 0.75rem;
58+
min-width: 0;
59+
max-width: 100%;
60+
}
61+
62+
.dashboard-org-selector-label {
63+
white-space: nowrap;
64+
}
65+
66+
.dashboard-org-selector-name {
67+
min-width: 0;
68+
flex: 1 1 auto;
69+
overflow-wrap: anywhere;
70+
word-break: break-word;
71+
}
72+
73+
.dashboard-org-selector-control .dropdown-toggle {
74+
max-width: 18rem;
75+
overflow: hidden;
76+
text-overflow: ellipsis;
77+
white-space: nowrap;
78+
}
79+
80+
.dashboard-resources-card-title {
81+
overflow-wrap: anywhere;
82+
word-break: break-word;
83+
}
84+
85+
.dashboard-resource-item-header {
86+
display: flex;
87+
justify-content: space-between;
88+
align-items: flex-start;
89+
gap: 0.5rem 1rem;
90+
min-width: 0;
91+
}
92+
93+
.dashboard-resource-item-title {
94+
min-width: 0;
95+
overflow-wrap: anywhere;
96+
word-break: break-word;
97+
}
98+
99+
.dashboard-resource-item-date {
100+
flex-shrink: 0;
101+
white-space: nowrap;
102+
}
103+
104+
.dashboard-resource-item-description {
105+
overflow-wrap: anywhere;
106+
word-break: break-word;
107+
}
108+
109+
@media (max-width: 767.98px) {
110+
/* Multi-org picker: stack label above full-width dropdown. */
111+
.dashboard-org-selector:has(.dashboard-org-selector-control) {
112+
flex-direction: column;
113+
align-items: stretch;
114+
}
115+
116+
.dashboard-org-selector-control {
117+
width: 100%;
118+
}
119+
120+
.dashboard-org-selector-control .dropdown-toggle {
121+
max-width: 100%;
122+
width: 100%;
123+
}
124+
125+
.dashboard-resource-item-header {
126+
flex-direction: column;
127+
align-items: flex-start;
128+
}
129+
}
130+
131+
/* Profile page. */
132+
.profile-email-list-item-body {
133+
display: flex;
134+
flex-wrap: wrap;
135+
align-items: center;
136+
justify-content: space-between;
137+
gap: 0.5rem 0.75rem;
138+
min-width: 0;
139+
}
140+
141+
.profile-email-leading {
142+
display: flex;
143+
flex-wrap: wrap;
144+
align-items: center;
145+
gap: 0.35rem 0.5rem;
146+
min-width: 0;
147+
}
148+
149+
.profile-email-address {
150+
overflow-wrap: anywhere;
151+
word-break: break-word;
152+
}
153+
154+
.profile-email-actions {
155+
display: flex;
156+
flex-wrap: wrap;
157+
gap: 0.5rem;
158+
}
159+
160+
.profile-organizations-card-title {
161+
overflow-wrap: anywhere;
162+
word-break: break-word;
163+
}
164+
165+
.profile-organizations-create-btn {
166+
flex-shrink: 0;
167+
}
168+
169+
.profile-organization-item-header {
170+
display: flex;
171+
justify-content: space-between;
172+
align-items: flex-start;
173+
gap: 0.5rem 1rem;
174+
min-width: 0;
175+
}
176+
177+
.profile-organization-item-name {
178+
min-width: 0;
179+
overflow-wrap: anywhere;
180+
word-break: break-word;
181+
}
182+
183+
.profile-organization-item-date {
184+
flex-shrink: 0;
185+
white-space: nowrap;
186+
}
187+
188+
.profile-form-actions {
189+
display: flex;
190+
flex-wrap: wrap;
191+
gap: 0.5rem;
192+
}
193+
194+
.profile-form-actions .profile-form-cancel-btn {
195+
margin-left: 0;
196+
}
197+
198+
@media (max-width: 767.98px) {
199+
.profile-email-list-item-body {
200+
flex-direction: column;
201+
align-items: stretch;
202+
}
203+
204+
.profile-email-leading {
205+
flex-direction: column;
206+
align-items: flex-start;
207+
}
208+
209+
.profile-email-actions {
210+
width: 100%;
211+
flex-direction: column;
212+
align-items: stretch;
213+
}
214+
215+
.profile-email-action-form {
216+
width: 100%;
217+
}
218+
219+
.profile-email-action-form .btn {
220+
width: 100%;
221+
}
222+
223+
.profile-organizations-card-header {
224+
flex-direction: column;
225+
align-items: stretch;
226+
}
227+
228+
.profile-organizations-create-btn {
229+
width: 100%;
230+
align-self: stretch;
231+
}
232+
233+
.profile-organization-item-header {
234+
flex-direction: column;
235+
align-items: flex-start;
236+
}
237+
238+
.profile-form-actions {
239+
flex-direction: column;
240+
align-items: stretch;
241+
}
242+
243+
.profile-form-actions .btn {
244+
width: 100%;
245+
}
246+
247+
.profile-add-email-form .input-group {
248+
flex-direction: column;
249+
align-items: stretch;
250+
}
251+
252+
.profile-add-email-form .input-group > .form-control,
253+
.profile-add-email-form .input-group > .btn {
254+
width: 100%;
255+
border-radius: var(--bs-border-radius);
256+
}
257+
258+
.profile-add-email-form .input-group > .form-control {
259+
border-bottom-right-radius: var(--bs-border-radius);
260+
border-bottom-left-radius: var(--bs-border-radius);
261+
}
262+
263+
.profile-add-email-form .input-group > .btn {
264+
margin-top: 0.5rem;
265+
}
266+
}
267+
268+
/* Site navbar: long brand text must not crowd the mobile toggler. */
269+
.site-navbar-brand {
270+
min-width: 0;
271+
max-width: 100%;
272+
overflow-wrap: anywhere;
273+
word-break: break-word;
274+
}
275+
276+
@media (max-width: 991.98px) {
277+
.site-navbar-brand {
278+
flex: 1 1 auto;
279+
max-width: calc(100% - 3.5rem);
280+
font-size: 1rem;
281+
line-height: 1.25;
282+
}
283+
}
284+
285+
/* Pending invitations in organization members card. */
286+
.invitation-list-item-body {
287+
display: flex;
288+
flex-wrap: wrap;
289+
align-items: center;
290+
gap: 0.5rem 0.75rem;
291+
}
292+
293+
.invitation-list-leading {
294+
display: flex;
295+
flex-wrap: wrap;
296+
align-items: center;
297+
gap: 0.25rem 0.35rem;
298+
min-width: 0;
299+
}
300+
301+
.invitation-list-email {
302+
word-break: break-word;
303+
}
304+
305+
.invitation-actions-cell {
306+
display: flex;
307+
flex-wrap: wrap;
308+
gap: 0.5rem;
309+
}
310+
311+
/* Desktop: bleed list to card edges so actions align with Invite Member. */
11312
.card-body .invitation-list.list-group-flush {
12313
margin-left: calc(-1 * var(--bs-card-spacer-x));
13314
margin-right: calc(-1 * var(--bs-card-spacer-x));
@@ -18,11 +319,50 @@ input:invalid:not(:placeholder-shown) + .invalid-feedback {
18319
padding-right: var(--bs-card-spacer-x);
19320
}
20321

322+
.invitation-resend-form .btn-invitation-resend,
21323
.invitation-cancel-form .btn {
22324
min-width: 6.75rem;
23325
}
24326

25-
.invitation-resend-form .btn-invitation-resend,
26-
.invitation-cancel-form .btn {
27-
min-width: 6.75rem;
327+
@media (max-width: 767.98px) {
328+
.card-body .invitation-list.list-group-flush {
329+
margin-left: 0;
330+
margin-right: 0;
331+
}
332+
333+
.card-body .invitation-list .invitation-list-item {
334+
padding-left: 0;
335+
padding-right: 0;
336+
}
337+
338+
.invitation-list-item + .invitation-list-item {
339+
margin-top: 0.25rem;
340+
padding-top: 0.75rem;
341+
}
342+
343+
.invitation-list-item-body {
344+
flex-direction: column;
345+
align-items: stretch;
346+
}
347+
348+
.invitation-list-leading {
349+
flex-direction: column;
350+
align-items: flex-start;
351+
gap: 0.35rem;
352+
}
353+
354+
.invitation-actions-cell {
355+
width: 100%;
356+
}
357+
358+
.invitation-resend-form,
359+
.invitation-cancel-form {
360+
flex: 1 1 0;
361+
}
362+
363+
.invitation-resend-form .btn-invitation-resend,
364+
.invitation-cancel-form .btn {
365+
min-width: 0;
366+
width: 100%;
367+
}
28368
}

0 commit comments

Comments
 (0)