diff --git a/Dockerfile b/Dockerfile index 0daeb3d..d4f4019 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ git \ unzip \ locales \ + curl \ + && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs \ && rm -rf /var/lib/apt/lists/* RUN docker-php-ext-configure gd --with-freetype --with-jpeg && \ @@ -33,7 +36,9 @@ WORKDIR /var/www/html # To use ../drupal instead, add it as a path repository in composer.json: # "repositories": [{"type": "path", "url": "../drupal/core", "options": {"symlink": false}}] # then bump drupal/core-recommended to "11.x-dev@dev" and rebuild. -COPY composer.json ./ +COPY composer.json package.json tailwind.config.js ./ + +RUN npm install --include=dev RUN composer config repositories.drupal composer https://packages.drupal.org/8 @@ -59,6 +64,8 @@ COPY web/sites/default/settings.php web/sites/default/settings.php COPY web/sites/default/files/ web/sites/default/files/ COPY web/modules/custom/ web/modules/custom/ +RUN npm run build + ARG FULLCALENDAR_VERSION=6.1.15 RUN curl -fsSL "https://cdn.jsdelivr.net/npm/fullcalendar@${FULLCALENDAR_VERSION}/index.global.min.js" \ -o web/modules/custom/riverside_pt/js/fullcalendar.min.js diff --git a/docker-compose.yml b/docker-compose.yml index ac5445c..220b5b4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,8 +14,10 @@ services: ADMIN_PASS: "${ADMIN_PASS:-admin}" HASH_SALT: "${HASH_SALT:-replace-this-in-production-with-a-long-random-string}" POSTMARK_API_KEY: "${POSTMARK_API_KEY:-}" + BASE_URL: "${BASE_URL:-http://localhost:8080}" volumes: - ./web/sites/default/files:/var/www/html/web/sites/default/files + - ./web/modules/custom:/var/www/html/web/modules/custom depends_on: postgres: condition: service_healthy diff --git a/docker/php/entrypoint.sh b/docker/php/entrypoint.sh index 8eb8383..046cbe1 100644 --- a/docker/php/entrypoint.sh +++ b/docker/php/entrypoint.sh @@ -65,6 +65,8 @@ else echo "[entrypoint] No config to import, continuing." fi +npm run build --prefix /var/www/html >/dev/null 2>&1 && echo "[entrypoint] Tailwind built." || echo "[entrypoint] WARNING: Tailwind build failed." + $DRUSH cache:rebuild >/dev/null 2>&1 && echo "[entrypoint] Cache rebuilt." echo "[entrypoint] Starting services..." diff --git a/package.json b/package.json new file mode 100644 index 0000000..fd35f92 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "riverside-therapeutics", + "private": true, + "scripts": { + "watch": "tailwindcss -i ./web/modules/custom/riverside_pt/css/tailwind.css -o ./web/modules/custom/riverside_pt/css/app.css --watch", + "build": "tailwindcss -i ./web/modules/custom/riverside_pt/css/tailwind.css -o ./web/modules/custom/riverside_pt/css/app.css --minify" + }, + "devDependencies": { + "tailwindcss": "^3.4.17" + } +} diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..db8befb --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './web/modules/custom/riverside_pt/templates/**/*.twig', + './web/modules/custom/riverside_pt/src/**/*.php', + ], + theme: { + extend: {}, + }, + plugins: [], +} diff --git a/web/modules/custom/riverside_pt/css/app.css b/web/modules/custom/riverside_pt/css/app.css new file mode 100644 index 0000000..0597b91 --- /dev/null +++ b/web/modules/custom/riverside_pt/css/app.css @@ -0,0 +1 @@ +*,:after,:before{--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:rgba(59,130,246,.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:rgba(59,130,246,.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*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}body{padding-top:80px}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}@media (max-width:767px){#rpt-main-nav{flex:none;position:absolute;top:5rem;left:0;right:0;background:#fff;box-shadow:0 4px 8px rgba(0,0,0,.1);max-height:0;overflow:hidden;opacity:0;transition:max-height .3s ease,opacity .25s ease}#rpt-main-nav.is-open{max-height:500px;opacity:1}#rpt-main-nav ul{flex-direction:column;align-items:stretch}}.rpt-header__hamburger[aria-expanded=true] span:first-child{width:100%!important;transform:translateY(10px) rotate(45deg)}.rpt-header__hamburger[aria-expanded=true] span:nth-child(2){opacity:0}.rpt-header__hamburger[aria-expanded=true] span:nth-child(3){width:100%!important;transform:translateY(-10px) rotate(-45deg)}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.left-0{left:0}.right-0{right:0}.top-0{top:0}.z-50{z-index:50}.m-0{margin:0}.mx-auto{margin-left:auto;margin-right:auto}.mb-1\.5{margin-bottom:.375rem}.mb-12{margin-bottom:3rem}.ml-auto{margin-left:auto}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-11{height:2.75rem}.h-20{height:5rem}.h-full{height:100%}.min-h-\[560px\]{min-height:560px}.w-11{width:2.75rem}.w-\[45\%\]{width:45%}.w-full{width:100%}.min-w-0{min-width:0}.max-w-\[1040px\]{max-width:1040px}.max-w-\[1200px\]{max-width:1200px}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.grow-\[2\]{flex-grow:2}.basis-\[12\%\]{flex-basis:12%}.basis-\[34\%\]{flex-basis:34%}.basis-\[38\%\]{flex-basis:38%}.basis-\[50\%\]{flex-basis:50%}.basis-\[58\%\]{flex-basis:58%}.basis-\[8\%\]{flex-basis:8%}.cursor-pointer{cursor:pointer}.list-none{list-style-type:none}.grid-cols-\[repeat\(auto-fit\2c minmax\(220px\2c 1fr\)\)\]{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.self-end{align-self:flex-end}.self-stretch{align-self:stretch}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-\[3px\]{border-radius:3px}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-0{border-width:0}.border-\[\#1e3a5f\]{--tw-border-opacity:1;border-color:rgb(30 58 95/var(--tw-border-opacity,1))}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-white\/60{border-color:hsla(0,0%,100%,.6)}.bg-\[\#1e3a5f\]{--tw-bg-opacity:1;background-color:rgb(30 58 95/var(--tw-bg-opacity,1))}.bg-\[\#4a7a8a\]{--tw-bg-opacity:1;background-color:rgb(74 122 138/var(--tw-bg-opacity,1))}.bg-\[\#aac6c6\]{--tw-bg-opacity:1;background-color:rgb(170 198 198/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-2{padding:.5rem}.p-6{padding:1.5rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.text-center{text-align:center}.font-serif{font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[17px\]{font-size:17px}.text-\[clamp\(2rem\2c 3\.5vw\2c 3\.25rem\)\]{font-size:clamp(2rem,3.5vw,3.25rem)}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.text-\[\#1e3a5f\]{--tw-text-opacity:1;color:rgb(30 58 95/var(--tw-text-opacity,1))}.text-\[\#1e3a8a\]{--tw-text-opacity:1;color:rgb(30 58 138/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-blue-900{--tw-text-opacity:1;color:rgb(30 58 138/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/80{color:hsla(0,0%,100%,.8)}.no-underline{text-decoration-line:none}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.transition-\[transform\2c opacity\]{transition-property:transform,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-\[250ms\]{transition-duration:.25s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.hover\:border-\[\#152a45\]:hover{--tw-border-opacity:1;border-color:rgb(21 42 69/var(--tw-border-opacity,1))}.hover\:bg-\[\#152a45\]:hover{--tw-bg-opacity:1;background-color:rgb(21 42 69/var(--tw-bg-opacity,1))}.hover\:bg-\[\#3a6a7a\]:hover{--tw-bg-opacity:1;background-color:rgb(58 106 122/var(--tw-bg-opacity,1))}.hover\:bg-blue-500:hover{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.hover\:bg-white\/10:hover{background-color:hsla(0,0%,100%,.1)}.hover\:text-\[\#1e3a8a\]:hover{--tw-text-opacity:1;color:rgb(30 58 138/var(--tw-text-opacity,1))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}@media (min-width:768px){.md\:hidden{display:none}} \ No newline at end of file diff --git a/web/modules/custom/riverside_pt/css/front.css b/web/modules/custom/riverside_pt/css/front.css deleted file mode 100644 index 23ba79f..0000000 --- a/web/modules/custom/riverside_pt/css/front.css +++ /dev/null @@ -1,147 +0,0 @@ -/* Hide Drupal's default page-title block on the front page — our H1 is inside the hero */ -.path-frontpage .block-page-title-block { - display: none; -} - -.page-wrapper { - max-width: none; -} - -/* ── Hero ───────────────────────────────────────────────────── */ -.rpt-hero { - background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); - padding: 5rem 1.5rem; - text-align: center; -} - -.rpt-hero__inner { - max-width: 680px; - margin: 0 auto; -} - -.rpt-hero__heading { - font-size: clamp(2rem, 5vw, 3.25rem); - font-weight: 700; - color: #1e3a8a; - line-height: 1.15; - margin-bottom: 1rem; -} - -.rpt-hero__body { - font-size: 1.125rem; - color: #4b5563; - line-height: 1.7; - margin-bottom: 2rem; -} - -.rpt-hero__actions { - display: flex; - gap: 1rem; - justify-content: center; - flex-wrap: wrap; -} - -/* ── Shared buttons ─────────────────────────────────────────── */ -.rpt-btn { - display: inline-block; - padding: 0.75rem 1.5rem; - border-radius: 999px; - font-weight: 600; - font-size: 0.9375rem; - text-decoration: none; - transition: background 0.15s, color 0.15s, border-color 0.15s; - cursor: pointer; -} - -.rpt-btn--primary { - background: #3b82f6; - color: #fff; - border: 2px solid #3b82f6; -} - -.rpt-btn--primary:hover, -.rpt-btn--primary:focus { - background: #1d4ed8; - border-color: #1d4ed8; - color: #fff; -} - -.rpt-btn--secondary { - background: transparent; - color: #3b82f6; - border: 2px solid #3b82f6; -} - -.rpt-btn--secondary:hover, -.rpt-btn--secondary:focus { - background: #3b82f6; - color: #fff; -} - -.rpt-btn--outline { - background: transparent; - color: #3b82f6; - border: 1px solid #3b82f6; - border-radius: 4px; - font-size: 0.875rem; - padding: 0.5rem 1rem; -} - -.rpt-btn--outline:hover, -.rpt-btn--outline:focus { - background: #3b82f6; - color: #fff; -} - -/* ── Services section ───────────────────────────────────────── */ -.rpt-services { - padding: 4rem 1.5rem; - background: #f3f4f6; -} - -.rpt-services__header { - text-align: center; - margin-bottom: 3rem; -} - -.rpt-services__heading { - font-size: 2rem; - font-weight: 700; - color: #1e3a8a; - margin-bottom: 0.375rem; -} - -.rpt-services__subtitle { - font-size: 1.0625rem; - color: #6b7280; -} - -.rpt-services__grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); - gap: 1.5rem; - max-width: 1040px; - margin: 0 auto; -} - -.rpt-service-card { - display: flex; - flex-direction: column; - gap: 0.75rem; - border: 1px solid #e5e7eb; - border-radius: 8px; - padding: 1.5rem; -} - -.rpt-service-card__title { - font-size: 1.0625rem; - font-weight: 600; - color: #111827; -} - -.rpt-service-card__body { - font-size: 0.9375rem; - color: #6b7280; - line-height: 1.6; - flex: 1; -} diff --git a/web/modules/custom/riverside_pt/css/nav.css b/web/modules/custom/riverside_pt/css/nav.css deleted file mode 100644 index a107ab4..0000000 --- a/web/modules/custom/riverside_pt/css/nav.css +++ /dev/null @@ -1,198 +0,0 @@ -/* ── Hide Olivero's built-in header entirely ─────────────── */ -.site-header, -.sticky-header-toggle, -.social-bar { - display: none !important; -} - -/* Push page content below the fixed header */ -body { - padding-top: 80px; -} - -/* ── Custom header shell ─────────────────────────────────── */ -.rpt-header { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - height: 80px; - background: #fff; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); -} - -.rpt-header__inner { - display: flex; - align-items: center; - height: 100%; - max-width: 1200px; - margin: 0 auto; - padding: 0 1.5rem; - gap: 2rem; -} - -/* ── Brand / site name ───────────────────────────────────── */ -.rpt-header__brand { - font-size: 1.125rem; - font-weight: 700; - color: #1e3a5f; - text-decoration: none; - white-space: nowrap; - flex-shrink: 0; -} - -.rpt-header__brand:hover { - color: #1e3a8a; -} - -/* ── Nav list ────────────────────────────────────────────── */ -.rpt-header__nav { - flex: 1; - min-width: 0; -} - -.rpt-header__list { - display: flex; - align-items: center; - list-style: none; - margin: 0; - padding: 0; - gap: 0.25rem; -} - -.rpt-header__items--cta { - margin-left: auto; - display: flex; - gap: 0.25rem; -} - -/* ── Nav links ───────────────────────────────────────────── */ -.rpt-header__link { - display: block; - font-size: 0.9375rem; - font-weight: 400; - color: #374151; - text-decoration: none; - padding: 0.25rem 0.875rem; -} - -.rpt-header__link:hover, -.rpt-header__link:focus { - color: #1e3a8a; -} - -.rpt-header__link.is-active { - color: #1e3a8a; - font-weight: 500; -} - -/* ── CTA button ──────────────────────────────────────────── */ -.rpt-header__cta { - display: inline-block; - padding: 0.5rem 1.25rem; - background: #1e3a5f; - color: #fff; - font-size: 0.9rem; - font-weight: 500; - text-decoration: none; - border-radius: 4px; - border: 1.5px solid #1e3a5f; - transition: background 0.15s, border-color 0.15s; - white-space: nowrap; -} - -.rpt-header__cta:hover, -.rpt-header__cta:focus { - background: #152a45; - border-color: #152a45; - color: #fff; -} - -.rpt-header__item--cta { - padding: 0.5rem 1.5rem; -} - - -/* ── Hamburger button (hidden on desktop) ────────────────── */ -.rpt-header__hamburger { - display: none; - flex-direction: column; - justify-content: center; - gap: 6px; - width: 44px; - height: 44px; - padding: 8px; - background: none; - border: none; - cursor: pointer; - flex-shrink: 0; - margin-left: auto; -} - -.rpt-header__hamburger span { - display: block; - height: 4px; - background: #1e3a5f; - border-radius: 3px; - transition: transform 0.25s ease, opacity 0.2s ease, width 0.25s ease; -} - -.rpt-header__hamburger span:nth-child(1) { width: 45%; } -.rpt-header__hamburger span:nth-child(2) { width: 100%; } -.rpt-header__hamburger span:nth-child(3) { width: 45%; align-self: flex-end; } - -/* Animate to X when open */ -.rpt-header__hamburger[aria-expanded="true"] span:nth-child(1) { - width: 100%; - transform: translateY(10px) rotate(45deg); -} -.rpt-header__hamburger[aria-expanded="true"] span:nth-child(2) { - opacity: 0; -} -.rpt-header__hamburger[aria-expanded="true"] span:nth-child(3) { - width: 100%; - transform: translateY(-10px) rotate(-45deg); -} - -/* ── Mobile layout ───────────────────────────────────────── */ -@media (max-width: 768px) { - .rpt-header__hamburger { - display: flex !important; - } - - .rpt-header__nav { - position: absolute; - top: 80px; - left: 0; - right: 0; - background: #fff; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - max-height: 0; - overflow: hidden; - opacity: 0; - transition: max-height 0.3s ease, opacity 0.25s ease; - } - - .rpt-header__nav.is-open { - max-height: 500px; - opacity: 1; - } - - .rpt-header__list { - flex-direction: column; - align-items: stretch; - gap: 0; - } - - - .rpt-header__link { - padding: 0.75rem 1.5rem; - font-size: 1rem; - } - - .rpt-header__cta { - display: block; - text-align: center; - } -} diff --git a/web/modules/custom/riverside_pt/css/tailwind.css b/web/modules/custom/riverside_pt/css/tailwind.css new file mode 100644 index 0000000..5dffcb3 --- /dev/null +++ b/web/modules/custom/riverside_pt/css/tailwind.css @@ -0,0 +1,60 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + body { + padding-top: 80px; + } + /* Neutralise any theme container constraints */ + .page-wrapper { + max-width: none; + padding-inline: 0; + } + /* Hide Olivero/theme chrome we don't use */ + .site-header, + .sticky-header-toggle, + .social-bar { + display: none !important; + } +} + +@layer components { + /* Mobile nav: max-height slide can't be expressed with utilities alone */ + @media (max-width: 767px) { + #rpt-main-nav { + flex: none; + position: absolute; + top: 5rem; + left: 0; + right: 0; + background: #fff; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + max-height: 0; + overflow: hidden; + opacity: 0; + transition: max-height 0.3s ease, opacity 0.25s ease; + } + #rpt-main-nav.is-open { + max-height: 500px; + opacity: 1; + } + #rpt-main-nav ul { + flex-direction: column; + align-items: stretch; + } + } + + /* Hamburger open-state animation */ + .rpt-header__hamburger[aria-expanded="true"] span:nth-child(1) { + width: 100% !important; + transform: translateY(10px) rotate(45deg); + } + .rpt-header__hamburger[aria-expanded="true"] span:nth-child(2) { + opacity: 0; + } + .rpt-header__hamburger[aria-expanded="true"] span:nth-child(3) { + width: 100% !important; + transform: translateY(-10px) rotate(-45deg); + } +} diff --git a/web/modules/custom/riverside_pt/riverside_pt.libraries.yml b/web/modules/custom/riverside_pt/riverside_pt.libraries.yml index e483c43..0d5adc7 100644 --- a/web/modules/custom/riverside_pt/riverside_pt.libraries.yml +++ b/web/modules/custom/riverside_pt/riverside_pt.libraries.yml @@ -1,12 +1,7 @@ -front: +app: css: theme: - css/front.css: {} - -navigation: - css: - theme: - css/nav.css: {} + css/app.css: {} js: js/nav.js: {} diff --git a/web/modules/custom/riverside_pt/riverside_pt.module b/web/modules/custom/riverside_pt/riverside_pt.module index d05d8e5..187205d 100644 --- a/web/modules/custom/riverside_pt/riverside_pt.module +++ b/web/modules/custom/riverside_pt/riverside_pt.module @@ -5,7 +5,7 @@ use Drupal\Core\Link; use Drupal\Core\Routing\RouteMatchInterface; function riverside_pt_page_attachments(array &$attachments): void { - $attachments['#attached']['library'][] = 'riverside_pt/navigation'; + $attachments['#attached']['library'][] = 'riverside_pt/app'; } function riverside_pt_theme(): array { @@ -18,6 +18,9 @@ function riverside_pt_theme(): array { 'current_path' => NULL, ], ], + 'riverside_pt_home' => [ + 'variables' => [], + ], ]; } diff --git a/web/modules/custom/riverside_pt/src/Controller/HomeController.php b/web/modules/custom/riverside_pt/src/Controller/HomeController.php index 425d08f..92950f9 100644 --- a/web/modules/custom/riverside_pt/src/Controller/HomeController.php +++ b/web/modules/custom/riverside_pt/src/Controller/HomeController.php @@ -7,55 +7,7 @@ use Drupal\Core\Controller\ControllerBase; class HomeController extends ControllerBase { public function page(): array { - return [ - '#type' => 'inline_template', - '#template' => self::template(), - '#attached' => ['library' => ['riverside_pt/front']], - ]; - } - - private static function template(): string { - return <<<'TWIG' -
-
-

Heal your body

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

- -
-
- -
-
-

Bringing Relief

-

Our wide range of services

-
-
-
-

Diagnostic Evaluation

-

Comprehensive assessment to identify the root cause of your pain and build a personalized recovery plan.

- More Info -
-
-

Sports Rehabilitation

-

Targeted programs to help athletes recover from injury and return to peak performance safely.

- More Info -
-
-

Pre/Post-Surgical Rehab

-

Expert care before and after surgery to maximize recovery outcomes and restore full function.

- More Info -
-
-

Neurological Physical Therapy

-

Specialized therapy for nervous system conditions, helping you regain strength and independence.

- More Info -
-
-
-TWIG; + return ['#theme' => 'riverside_pt_home']; } } diff --git a/web/modules/custom/riverside_pt/templates/riverside-pt-header.html.twig b/web/modules/custom/riverside_pt/templates/riverside-pt-header.html.twig index adfae06..313f001 100644 --- a/web/modules/custom/riverside_pt/templates/riverside-pt-header.html.twig +++ b/web/modules/custom/riverside_pt/templates/riverside-pt-header.html.twig @@ -1,14 +1,15 @@ -