bootstrap: swap BS4 (alexwine) CSS for bootstrap@5 npm

Completes the Bootstrap 4->5 migration now that every jQuery/BS4 widget is React
(navbar, carousel, dropdowns) — plus the feedback toggle here (Feedback.js:
global `$('#feedback-form').toggle()` -> React state).

- Load Bootstrap 5 CSS from the `bootstrap` npm package in client/index.js
  (imported first so app + component styles and react-bootstrap override it).
- Remove the `alexwine:bootstrap-4` meteor package (BS4 CSS + jQuery + BS4 JS).
  jQuery for jquery-validation still comes from the npm `jquery` dep.
- Utility renames to BS5: ml-auto->ms-auto, float-right->float-end,
  btn-block->w-100, data-toggle->data-bs-toggle (FromNow tooltip).
- forms.scss `.form-label` is no longer a shim (BS5 ships it); comment updated.

Full-app build boots clean; server suite 36 passing. Needs a visual staging pass
across all pages (BS4->5 shifts grid gutters/typography); forms should improve
since react-bootstrap v2 already emitted BS5 markup.
This commit is contained in:
vjrj 2026-07-22 05:55:34 +02:00
parent 9ff9abacc3
commit bddfb392c1
12 changed files with 63 additions and 38 deletions

View file

@ -1,4 +1,8 @@
/* global */
// Bootstrap 5 CSS (npm) replaces the old `alexwine:bootstrap-4` meteor package.
// Import it first so the app + component stylesheets below (and react-bootstrap,
// which targets BS5) override it.
import 'bootstrap/dist/css/bootstrap.css';
import React from 'react';
import { createRoot } from 'react-dom/client';
import { HelmetProvider } from 'react-helmet-async';

View file

@ -18,6 +18,7 @@ import './Feedback.scss';
class Feedback extends Component {
constructor(props) {
super(props);
this.state = { open: false };
this.handleSubmit = this.handleSubmit.bind(this);
this.onTabClick = this.onTabClick.bind(this);
}
@ -50,7 +51,9 @@ class Feedback extends Component {
}
onTabClick() {
$('#feedback-form').toggle('slide');
// Was `$('#feedback-form').toggle('slide')` — global jQuery from the BS4
// meteor package. React state instead, so nothing depends on that global.
this.setState(s => ({ open: !s.open }));
}
handleSubmit() {
@ -76,7 +79,7 @@ class Feedback extends Component {
<div>
{ !this.props.isHome &&
<div id="feedback">
<div id="feedback-form" ref={formdiv => (this.formdiv = formdiv)} style={{ display: 'none' }} className="card">
<div id="feedback-form" ref={formdiv => (this.formdiv = formdiv)} style={{ display: this.state.open ? 'block' : 'none' }} className="card">
<form
ref={form => (this.form = form)}
className="form card-body"
@ -109,7 +112,7 @@ class Feedback extends Component {
/>
<Form.Control.Feedback />
</Form.Group>
<Button type="submit" variant="success" className="float-right" id={testId('sendFeedbackBtn')} >
<Button type="submit" variant="success" className="float-end" id={testId('sendFeedbackBtn')} >
{t('Enviar')}
</Button>
</form>

View file

@ -33,7 +33,7 @@ class FromNow extends Component {
render() {
return (
<span data-toggle="tooltip" className="from-now" title={this.thatIs()}>{this.state.when}</span>
<span data-bs-toggle="tooltip" className="from-now" title={this.thatIs()}>{this.state.when}</span>
);
}
}

View file

@ -37,7 +37,7 @@ const Navigation = ({ name = '', ...props }) => {
</button>
<div className={`collapse navbar-collapse${open ? ' show' : ''}`} id="navbarNavDropdown">
{/* onClick closes the mobile menu when a main nav link is tapped */}
<ul className="navbar-nav ml-auto " onClick={close}>
<ul className="navbar-nav ms-auto " onClick={close}>
{/* <LinkContainer className="nav-item" anchorClassName="nav-link" to="/sandbox">
<NavItem eventKey={1.1} href="/sandbox">Sandbox</NavItem>
</LinkContainer> */}

View file

@ -45,7 +45,7 @@ const defaultCallback = (error) => {
const OAuthLoginButton = ({ service, callback = defaultCallback }) => (
<button
className={`btn btn-block btn-raised btn-danger OAuthLoginButton OAuthLoginButton-${service}`}
className={`btn w-100 btn-raised btn-danger OAuthLoginButton OAuthLoginButton-${service}`}
type="button"
onClick={() => handleLogin(service, callback)}
>

View file

@ -132,7 +132,7 @@ class Signup extends React.Component {
{ Meteor.settings.public.telegramAuth &&
<Col xs={12}>
<button
className="btn btn-block btn-raised btn-primary OAuthLoginButtonDis OAuthLoginButton-telegram"
className="btn w-100 btn-raised btn-primary OAuthLoginButtonDis OAuthLoginButton-telegram"
type="button"
onClick={this.onTelegramAuth}
>

View file

@ -1,11 +1,10 @@
@use './mixins' as *;
@use './colors' as *;
// react-bootstrap v2 emits Bootstrap 5 form markup (`.form-label`) while we
// still ship the Bootstrap 4 stylesheet (alexwine:bootstrap-4), which has no
// `.form-label`. Shim it until the Bootstrap 4 -> 5 CSS jump lands (tracked as
// debt in UPGRADE.md). v2's Form.Group is a plain div, so restore the old
// per-field bottom margin the removed `.form-group` used to give.
// Bootstrap 5 now provides `.form-label` natively, so this is no longer a shim
// we keep it only for the explicit `display: block` (v2's Form.Group is a plain
// div and some fields render the label inline otherwise). The bottom margin
// matches BS5's own `.form-label`.
.form-label {
display: block;
margin-bottom: 0.5rem;