docs: client-approved public-site redesign — PRD 1.4, UX spec v2.0, architecture §6.2, tasks 24-x Ready for Dev
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
---
|
||||
id: 24-1
|
||||
title: 24-1 Public Design Foundation (Stylesheet, Script, Fonts, Layout)
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Create the shared foundation every later redesign subtask builds on. It must be loaded only by
|
||||
the public layout (and, for the stylesheet only, by the auth layouts in task 24-9), and every rule
|
||||
must be scoped under `body.site` so the admin and client dashboards are unaffected.
|
||||
|
||||
The approved visual reference is the mockup file `docs/ux-mockup.html` (committed in `caec396`).
|
||||
Where this task says "port lines X–Y", copy those CSS rules from that file and prefix every
|
||||
selector with `body.site ` (for example `.btn-gold` → `body.site .btn-gold`; `:root{…}` →
|
||||
`body.site{…}`; `body{…}` → `body.site{…}`; `html[dir=ltr] .x` → `html[dir=ltr] body.site .x`;
|
||||
`html[lang=en] .x` → `html[lang=en] body.site .x`). The mockup's lines contain no images, so line
|
||||
numbers are exact.
|
||||
|
||||
### Files to create
|
||||
|
||||
1. **`resources/css/public.css`** — contains, in this order:
|
||||
- Tokens on `body.site` (from mockup lines 12–29):
|
||||
`--forest:#2D3624; --forest-2:#232A1C; --gold:#A68966; --gold-ink:#8A7555; --gold-lt:#C4A882;
|
||||
--cream:#F4F1EA; --olive:#4A5D23; --ink:#1E2219; --muted:#5B6152; --line:rgba(45,54,36,.14);
|
||||
--display:"Markazi Text","Times New Roman",serif; --body:"IBM Plex Sans Arabic",system-ui,sans-serif;
|
||||
--r:10px; --ease:cubic-bezier(.2,.7,.2,1);
|
||||
--shadow-1:0 1px 2px rgba(30,34,25,.06),0 4px 14px rgba(30,34,25,.06);
|
||||
--shadow-2:0 2px 4px rgba(30,34,25,.08),0 18px 40px -12px rgba(30,34,25,.28);`
|
||||
- Page ground and type on `body.site` (port lines 32–39): `font-family:var(--body);
|
||||
color:var(--ink); font-size:17px; line-height:1.75; background-color:var(--cream)` plus the
|
||||
linen weave `background-image: repeating-linear-gradient(0deg, rgba(45,54,36,.025) 0 1px,
|
||||
transparent 1px 3px), repeating-linear-gradient(90deg, rgba(45,54,36,.022) 0 1px, transparent
|
||||
1px 4px)`. This overrides the inline `style="font-family: var(--font-…)"` on the body, so the
|
||||
layout's inline style is removed (see layout changes below).
|
||||
- Port lines 40–50 (img, links, `.wrap`, skip link, focus-visible, h1–h3, `.eyebrow`,
|
||||
`.art-no`). `.wrap` = `max-width:1200px; margin-inline:auto; padding-inline:28px`.
|
||||
Focus = `outline:2px solid var(--gold); outline-offset:3px; border-radius:4px`.
|
||||
- Buttons: port lines 52–68 (`.btn`, `.btn-gold` with shimmer `::after`, `.btn-ghost`,
|
||||
`.on-dark .btn-ghost`, `.btn .arr` and LTR mirroring). Class names `.btn`, `.btn-gold`,
|
||||
`.btn-ghost` do not exist in `resources/css/app.css` (which uses `.btn-primary`,
|
||||
`.btn-secondary`), and they are scoped under `body.site`, so there is no collision.
|
||||
- Progress rule: port lines 70–73 (`#hem` → rename to `.site-progress`; fixed, top 0, z 60,
|
||||
height 2px, gradient `linear-gradient(90deg,#8A7555,#E2CDA4,#A68966)`, `transform:scaleX(0)`,
|
||||
origin right; `html[dir=ltr]` origin left).
|
||||
- Sections: port lines 139–144 (`section{position:relative}`, `.sec{padding:120px 0}`,
|
||||
`.sec-head`, `.sec-head h2`, `.sec-head p`).
|
||||
- Reveal: port lines 286–290, changed so content is hidden only when JavaScript runs:
|
||||
`body.site.js [data-reveal]{opacity:0;transform:translateY(28px);transition:opacity .9s
|
||||
var(--ease),transform .9s var(--ease)}`, `body.site.js [data-reveal].in{opacity:1;transform:none}`,
|
||||
and the `data-d` 1–5 delays (.08s, .16s, .24s, .32s, .4s).
|
||||
- Responsive base: at `max-width:760px`: `body.site{font-size:16px}`,
|
||||
`body.site .wrap{padding-inline:18px}`, `body.site .sec{padding:80px 0}`.
|
||||
- Reduced motion (port lines 324–327): under `@media (prefers-reduced-motion:reduce)`,
|
||||
`body.site *, body.site *::before, body.site *::after{animation:none!important;
|
||||
transition:none!important; scroll-behavior:auto!important}` and
|
||||
`body.site [data-reveal]{opacity:1;transform:none}`.
|
||||
- `html:has(body.site){scroll-behavior:smooth}`.
|
||||
2. **`resources/js/public.js`** — imports `./site/reveal.js` and `./site/progress.js`, and calls
|
||||
each module's `init()` on the `livewire:navigated` document event (Livewire 3 dispatches it on
|
||||
the first page load and after every `wire:navigate`), and each module's `destroy()` on
|
||||
`livewire:navigating`. On init it adds the class `js` to `document.body`.
|
||||
3. **`resources/js/site/reveal.js`** — exports `init()`/`destroy()`. If
|
||||
`matchMedia('(prefers-reduced-motion: reduce)').matches`, add class `in` to every
|
||||
`[data-reveal]` and return. Otherwise create one `IntersectionObserver` with
|
||||
`rootMargin: '0px 0px -8% 0px'`; when an observed element intersects, add class `in` and
|
||||
unobserve it. `destroy()` disconnects the observer.
|
||||
4. **`resources/js/site/progress.js`** — exports `init()`/`destroy()`. Adds a passive `scroll`
|
||||
listener on `window` that sets `.site-progress` `style.transform = scaleX(p)` where
|
||||
`p = max > 0 ? scrollY / max : 1` and `max = document.documentElement.scrollHeight - innerHeight`,
|
||||
and toggles class `scrolled` on `#site-nav` when `scrollY > 8` (if that element exists; it is
|
||||
added in task 24-2). Runs once on init. `destroy()` removes the listener.
|
||||
5. **`resources/views/partials/site-fonts.blade.php`** — exactly:
|
||||
```html
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Markazi+Text:wght@400;500;600;700&family=IBM+Plex+Sans+Arabic:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||||
```
|
||||
6. **`lang/ar/site.php`** and **`lang/en/site.php`** — each `<?php return [ ... ];` with the
|
||||
keys `progress_label` (ar `'تقدّم القراءة'`, en `'Reading progress'`). Later subtasks add keys
|
||||
to these files.
|
||||
|
||||
### Files to modify
|
||||
|
||||
7. **`vite.config.js`** — `input` becomes
|
||||
`['resources/css/app.css', 'resources/js/app.js', 'resources/css/public.css', 'resources/js/public.js']`.
|
||||
8. **`resources/views/components/layouts/public.blade.php`**:
|
||||
- After `@include('partials.head')` add `@include('partials.site-fonts')` and
|
||||
`@vite(['resources/css/public.css', 'resources/js/public.js'])`.
|
||||
- `<body>` becomes `<body class="site min-h-screen flex flex-col">` (remove `bg-background`
|
||||
and the inline `style="font-family: …"`).
|
||||
- Immediately after the skip link add
|
||||
`<div class="site-progress" aria-hidden="true"></div>`.
|
||||
- Remove the spacer `<div class="h-16"></div>` (the navigation becomes sticky in 24-2; until
|
||||
then the existing fixed navigation may overlap the first 64px — acceptable only between
|
||||
24-1 and 24-2).
|
||||
- `<main>` keeps `id="main-content" role="main" class="flex-1" tabindex="-1"` but its child
|
||||
`<div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 py-6 sm:py-8">` is removed, so
|
||||
`{{ $slot }}` is rendered directly inside `<main>`.
|
||||
9. Because the wrapper is gone, wrap the root content of each existing public page that is not
|
||||
yet redesigned in `<div class="wrap py-8">…</div>` so these pages keep a contained width until
|
||||
their own subtask restyles them:
|
||||
- `resources/views/livewire/pages/home.blade.php`
|
||||
- `resources/views/livewire/pages/about.blade.php` (also remove the negative margins
|
||||
`-mx-4 sm:-mx-6 lg:-mx-8 -mt-6 sm:-mt-8` from its first `<section>`)
|
||||
- `resources/views/livewire/pages/booking.blade.php`
|
||||
- `resources/views/livewire/pages/booking-success.blade.php`
|
||||
- `resources/views/livewire/pages/posts/index.blade.php`
|
||||
- `resources/views/livewire/pages/posts/show.blade.php`
|
||||
- `resources/views/pages/legal.blade.php`
|
||||
- `resources/views/pages/terms.blade.php`
|
||||
- `resources/views/pages/privacy.blade.php`
|
||||
(`resources/views/pages/booking.blade.php` is a dead placeholder — `/booking` is served by the
|
||||
Volt page — and is left untouched.)
|
||||
For a Volt page whose root is a single element, put the wrapper inside the root element so the
|
||||
component keeps one root.
|
||||
10. **`resources/views/partials/head.blade.php`** — change
|
||||
`<meta name="theme-color" content="#4A4A42">` to `<meta name="theme-color" content="#2D3624">`.
|
||||
Change nothing else in this file (the dashboards share it).
|
||||
|
||||
Do not modify `resources/css/app.css` or any file under `resources/views/livewire/admin/`,
|
||||
`resources/views/livewire/client/`, `resources/views/components/layouts/app*`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `npm run build` succeeds and `public/build/manifest.json` contains entries for
|
||||
`resources/css/public.css` and `resources/js/public.js`.
|
||||
- [ ] Every selector in `resources/css/public.css` is scoped under `body.site` (or
|
||||
`html[...] body.site`, or `html:has(body.site)`), verify:
|
||||
`grep -nE '^[^@/ }].*\{' resources/css/public.css | grep -v 'body.site'` returns nothing.
|
||||
- [ ] The HTML of `/` contains `<body class="site`, the `Markazi+Text` font link, a
|
||||
`public.css` and a `public.js` asset, and `<div class="site-progress"`.
|
||||
- [ ] The HTML of `/admin/dashboard` (logged in as admin) and `/client/dashboard` (logged in as a
|
||||
client) contains neither `public.css`, `public.js`, `Markazi` nor `class="site`.
|
||||
- [ ] `resources/css/app.css` is unchanged: `git diff --quiet BASE -- resources/css/app.css`.
|
||||
- [ ] On `/` with the browser at 390px wide, the document has no horizontal scroll, and every
|
||||
public page listed in item 9 still renders its content inside a 1200px-max container.
|
||||
- [ ] Scrolling `/` changes the `.site-progress` element's transform from `scaleX(0)` toward
|
||||
`scaleX(1)`; with `prefers-reduced-motion: reduce` emulated, every `[data-reveal]` element
|
||||
is visible without scrolling.
|
||||
- [ ] `partials/head.blade.php` contains `content="#2D3624"` and no `#4A4A42`.
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: 24-10
|
||||
title: 24-10 Redesign Integration Verification
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Verify the finished redesign as a whole before it is offered for deployment, and fix any defect
|
||||
found within the files touched by tasks 24-1 to 24-9. This task adds no feature. Build the assets
|
||||
(`npm run build`) first so the pages are not rendered from stale CSS.
|
||||
|
||||
Check, on the local site (`https://libra.test` via Valet, or `php artisan serve`), with at least
|
||||
three published posts in the database and working hours configured so slots exist:
|
||||
|
||||
1. **Pages** — `/`, `/about`, `/posts`, one `/posts/{post}`, `/booking`, `/booking/success`,
|
||||
`/page/terms`, `/page/privacy`, `/login`, `/forgot-password`: each in Arabic (RTL) and English
|
||||
(LTR), each at 1440, 768 and 390px wide.
|
||||
2. **Booking end-to-end** — one guest booking from the home card and one from `/booking`, each
|
||||
reaching `/booking/success` and each appearing in the admin's pending bookings
|
||||
(`/admin/bookings/pending`).
|
||||
3. **Unchanged areas** — `/admin/dashboard`, `/admin/bookings/pending`, `/admin/posts`,
|
||||
`/client/dashboard`, `/client/consultations/book`, `/forms/nablus-workshop`.
|
||||
4. **Motion** — load `/` with and without `prefers-reduced-motion: reduce` emulated.
|
||||
5. **Navigation** — move between public pages with the navigation links (`wire:navigate`) and back
|
||||
to `/`.
|
||||
|
||||
Fix defects in the redesign's own files only: `resources/css/public.css`, `resources/js/public.js`,
|
||||
`resources/js/site/*.js`, `resources/views/components/site/*.blade.php`,
|
||||
`resources/views/components/navigation.blade.php`, `resources/views/components/footer.blade.php`,
|
||||
`resources/views/components/layouts/public.blade.php`,
|
||||
`resources/views/components/layouts/auth/*.blade.php`, `resources/views/partials/site-fonts.blade.php`,
|
||||
`resources/views/livewire/pages/home.blade.php`, `about.blade.php`, `booking.blade.php`,
|
||||
`booking-success.blade.php`, `posts/index.blade.php`, `posts/show.blade.php`,
|
||||
`resources/views/livewire/availability-calendar.blade.php`, `resources/views/pages/legal.blade.php`,
|
||||
`terms.blade.php`, `privacy.blade.php`, `lang/ar/site.php`, `lang/en/site.php`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Every page in item 1, in both languages and at all three widths, has no horizontal scroll
|
||||
(`document.documentElement.scrollWidth <= innerWidth`), no console error, and no missing
|
||||
translation key (no raw `site.` or `home.` key text visible).
|
||||
- [ ] Each page in item 1 has exactly one `<h1>`, every `<img>` has a non-empty `alt`, and every
|
||||
interactive element in the navigation, footer and booking card is reachable by Tab with a
|
||||
visible gold focus ring.
|
||||
- [ ] Both bookings in item 2 succeed and appear in `/admin/bookings/pending`.
|
||||
- [ ] The pages in item 3 contain no `public.css`, `public.js`, `class="site` or `site-auth`, and
|
||||
`git diff BASE -- resources/css/app.css resources/views/livewire/admin resources/views/livewire/client resources/views/components/layouts/app.blade.php resources/views/components/layouts/app resources/views/livewire/pages/forms`
|
||||
(BASE = the commit recorded before task 24-1) is empty.
|
||||
- [ ] With reduced motion emulated, all `[data-reveal]` content is visible on load and every
|
||||
balance is level; without it, the hero balance settles and the finale levels on scroll.
|
||||
- [ ] After five `wire:navigate` hops ending on `/`, the hero balance and reveal still work and the
|
||||
finale still levels.
|
||||
- [ ] Contrast: body text on cream, `--gold-lt` text on forest, and the gold button text meet
|
||||
WCAG AA (4.5:1 for body text, 3:1 for large text) — measured, values noted in the task's QA
|
||||
record.
|
||||
- [ ] No page contains the text "Unsplash" or "mockup".
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,146 @@
|
||||
---
|
||||
id: 24-2
|
||||
title: 24-2 Navigation and Footer
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Restyle the public navigation and footer to the approved redesign. Both components are used only
|
||||
by `resources/views/components/layouts/public.blade.php`, so they are restyled in place. Keep all
|
||||
existing behaviour: the Alpine `x-data="{ mobileMenuOpen: false }"` menu with its
|
||||
`x-trap.inert.noscroll`, `@click.away` and `@keydown.escape.window` handling, the `@auth` branch
|
||||
(Dashboard link to `route('admin.dashboard')` or `route('client.dashboard')` by
|
||||
`auth()->user()->isAdmin()`, and the logout `<form method="POST" action="{{ route('logout') }}">`),
|
||||
the language toggle's `/language/{locale}` links, and `wire:navigate` on internal links.
|
||||
|
||||
All CSS goes in `resources/css/public.css` (created in 24-1), every selector prefixed with
|
||||
`body.site `. Port the CSS from `docs/ux-mockup.html`: navigation lines 75–98, footer lines
|
||||
273–284, and the responsive nav/footer rules inside lines 293–323 (`.links` hidden and
|
||||
`.menu-btn` shown at ≤1100px; `.nav .btn` and `.login` hidden at ≤760px; footer grid 2 columns at
|
||||
≤1100px and 1 column at ≤760px).
|
||||
|
||||
### Navigation — `resources/views/components/navigation.blade.php`
|
||||
|
||||
- Root: `<header class="nav" id="site-nav">` — sticky (`position:sticky; top:0; z-index:50`),
|
||||
height 72px, background `rgba(244,241,234,.82)`, `backdrop-filter: blur(14px) saturate(1.2)`
|
||||
(with `-webkit-` prefix), bottom border transparent; with class `scrolled` (toggled by
|
||||
`resources/js/site/progress.js` from 24-1 when `scrollY > 8`) the border becomes
|
||||
`1px solid var(--line)` and the shadow `0 8px 24px -18px rgba(30,34,25,.5)`. Remove the old
|
||||
fixed positioning and forest background.
|
||||
- Inner `<div class="wrap">` laid out as flex, `align-items:center; gap:28px; height:72px`:
|
||||
1. Brand link to `route('home')`: `<span class="seal">` (46×46px, background
|
||||
`#fff url('/images/logo.png') center/cover no-repeat`, `border:2px solid #1A1A1A`,
|
||||
`box-shadow:3px 3px 5px rgba(26,26,26,.35)`) then a two-line wordmark: `<b>` =
|
||||
`__('site.brand_name')` (display font, 1.35rem, line-height 1) and `<small>` =
|
||||
`__('site.brand_sub')` (.72rem, `--muted`; letter-spacing .12em in English).
|
||||
`aria-label="{{ __('site.brand_label') }}"`.
|
||||
2. `<nav class="links" aria-label="{{ __('site.nav_main') }}">` with links: Home →
|
||||
`route('home')`, About → `route('about')`, Services → `route('home').'#services'`,
|
||||
Articles → `route('posts.index')`, Booking → `route('booking')`. Labels from `site.nav_*`.
|
||||
The current route's link gets `aria-current="page"` (home for `home`, about for `about`,
|
||||
articles for `posts.*`, booking for `booking*`). Link style: padding 10px 14px, weight 500,
|
||||
.95rem, radius 8px; hover colour `--olive`; `::after` underline — `inset-inline:14px;
|
||||
bottom:4px; height:2px; background:repeating-linear-gradient(90deg,var(--gold) 0 4px,
|
||||
transparent 4px 7px); transform:scaleX(0)`, origin right (left in LTR), transition
|
||||
`.35s var(--ease)`; `scaleX(1)` on hover and on `[aria-current]`.
|
||||
3. `.nav-tools` (flex, gap 10px): replace both `<x-language-toggle />` usages in this file
|
||||
(desktop and mobile) with a plain link
|
||||
`<a class="lang" href="{{ url('/language/'.(app()->getLocale() === 'ar' ? 'en' : 'ar')) }}" aria-label="{{ __('site.lang_switch') }}">`
|
||||
— a pill (min 48×44px, inline-grid centred, radius 999px, `1.5px solid var(--line)`, white,
|
||||
weight 600 .85rem, no underline; hover gold border and lift 1px) whose text is `EN` when the
|
||||
locale is `ar` and `ع` when it is `en`. Do not edit
|
||||
`resources/views/components/language-toggle.blade.php` (the auth layouts and the dashboard
|
||||
sidebar use it); for guests a `.login` link (`__('site.nav_login')` →
|
||||
`route('login')`, .92rem, min-height 44px, hover olive); for authenticated users the
|
||||
existing Dashboard link and logout button styled like `.login`; then
|
||||
`<a class="btn btn-gold" href="{{ route('home') }}#book">{{ __('site.nav_book') }}</a>`
|
||||
(in the nav: min-height 44px, padding 10px 20px, .92rem); then the mobile menu button
|
||||
`.menu-btn` (44×44px, radius 10px, `1.5px solid var(--line)`, white, hidden above 1100px)
|
||||
carrying the existing Alpine toggle, `:aria-expanded`, and
|
||||
`aria-label="{{ __('site.nav_menu') }}"`.
|
||||
- Mobile menu sheet (the existing `x-show="mobileMenuOpen"` panel): cream background
|
||||
(`var(--cream)`), directly under the nav, full width, each link a 48px-high row with a
|
||||
`1px solid var(--line)` bottom border; contains the five links, the login (or Dashboard and
|
||||
logout) and the gold Book button full width.
|
||||
|
||||
### Footer — `resources/views/components/footer.blade.php`
|
||||
|
||||
- `<footer class="site-footer">`: background `var(--forest-2)`, colour `var(--gold-lt)`,
|
||||
margin-top 120px, padding 72px 0 28px, .92rem, position relative. First child
|
||||
`<span class="foot-band" aria-hidden="true">` — absolute, top 0, full width, height 1px,
|
||||
`linear-gradient(90deg,transparent,rgba(196,168,130,.7),transparent)`.
|
||||
- `<div class="wrap"><div class="foot">` grid `1.4fr 1fr 1fr 1fr`, gap 40px:
|
||||
1. The brand mark (same seal + wordmark as the nav; wordmark `<b>` cream, `<small>` gold-lt)
|
||||
and `<p>` = `__('home.tagline')` (margin-top 16px, max-width 26em).
|
||||
2. `<h4>{{ __('site.footer_explore') }}</h4>` then links About → `route('about')`, Services →
|
||||
`route('home').'#services'`, Articles → `route('posts.index')`, Booking → `route('booking')`.
|
||||
3. `<h4>{{ __('site.footer_clients') }}</h4>` then Client login → `route('login')`, Terms →
|
||||
`route('terms')` with `__('site.footer_terms')`, Privacy → `route('privacy')` with
|
||||
`__('site.footer_privacy')`.
|
||||
4. `<h4>{{ __('site.footer_contact') }}</h4>` then `<a href="tel:+970599353502" dir="ltr">`
|
||||
`{{ __('footer.phone') }}`, `<a href="mailto:{{ __('footer.email') }}">`, and the address
|
||||
`{{ __('footer.address') }}` as plain text.
|
||||
- `h4`: display font, 1.15rem, cream, margin 0 0 14px. Links: block, padding 10px 0, hover
|
||||
colour cream and `translateX(-3px)` (RTL) / `translateX(3px)` (LTR).
|
||||
- `.legal` row: flex, space-between, wrap, `border-top:1px solid rgba(244,241,234,.1)`,
|
||||
margin-top 48px, padding-top 22px, .8rem, colour `rgba(196,168,130,.75)`; content
|
||||
`© {{ date('Y') }} {{ __('footer.copyright') }}`. No photography credit.
|
||||
|
||||
### Language keys — add to `lang/ar/site.php` and `lang/en/site.php`
|
||||
|
||||
| Key | ar | en |
|
||||
|---|---|---|
|
||||
| `brand_name` | ليبرا | Libra |
|
||||
| `brand_sub` | للحقوق | FOR RIGHTS |
|
||||
| `brand_label` | ليبرا للحقوق | Libra for Rights |
|
||||
| `nav_main` | القائمة الرئيسية | Main |
|
||||
| `nav_home` | الرئيسية | Home |
|
||||
| `nav_about` | من نحن | About |
|
||||
| `nav_services` | الخدمات | Services |
|
||||
| `nav_articles` | المقالات | Articles |
|
||||
| `nav_booking` | الحجز | Booking |
|
||||
| `nav_login` | دخول العملاء | Client login |
|
||||
| `nav_book` | احجز استشارة | Book a consultation |
|
||||
| `nav_menu` | القائمة | Menu |
|
||||
| `lang_switch` | English | العربية |
|
||||
| `footer_explore` | تصفّح | Explore |
|
||||
| `footer_clients` | العملاء | Clients |
|
||||
| `footer_contact` | تواصل | Contact |
|
||||
| `footer_terms` | شروط الاستخدام | Terms of use |
|
||||
| `footer_privacy` | سياسة الخصوصية | Privacy policy |
|
||||
|
||||
Do not edit `lang/*/navigation.php` or `lang/*/footer.php` (the dashboards use `navigation.php`).
|
||||
|
||||
### Files
|
||||
|
||||
- Modify: `resources/views/components/navigation.blade.php`,
|
||||
`resources/views/components/footer.blade.php`, `resources/css/public.css`,
|
||||
`lang/ar/site.php`, `lang/en/site.php`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] On `/` at 1440px the navigation is 72px high, stays at the top of the viewport while
|
||||
scrolling, shows brand, five links, language pill, Client login and the gold Book button,
|
||||
and gains a bottom border once the page is scrolled past 8px.
|
||||
- [ ] On `/about` the About link has `aria-current="page"`; on `/posts` the Articles link does.
|
||||
- [ ] At ≤1100px the five links are hidden and the menu button opens a sheet containing all five
|
||||
links, login and Book; Escape closes it; at 390px there is no horizontal scroll.
|
||||
- [ ] Logged in as a client, the navigation shows Dashboard (to `/client/dashboard`) and a working
|
||||
Log out instead of Client login; logged in as admin, Dashboard goes to `/admin/dashboard`.
|
||||
- [ ] The language pill reads `EN` on Arabic pages and `ع` on English pages and switches locale;
|
||||
`resources/views/components/language-toggle.blade.php` is unchanged against BASE.
|
||||
- [ ] The footer shows four columns at 1440px with the phone, email and address from
|
||||
`lang/*/footer.php`, links to `/terms` and `/privacy`, and `© <current year>`; it contains no
|
||||
"Unsplash" text.
|
||||
- [ ] Every key in the table exists in both `lang/ar/site.php` and `lang/en/site.php`, and
|
||||
`lang/*/navigation.php` and `lang/*/footer.php` are unchanged against BASE.
|
||||
- [ ] The admin and client dashboards' navigation is unchanged (they do not render
|
||||
`components/navigation.blade.php`): verify `grep -rn "x-navigation" resources/views` lists
|
||||
only `components/layouts/public.blade.php`.
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
id: 24-3
|
||||
title: 24-3 Signature Balance Component
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Build the redesign's signature: an engraved-gold balance (scales of justice) rendered as an
|
||||
inline SVG, with three behaviours — `hero` (settles on load, weighed by the pointer), `finale`
|
||||
(comes level as the reader scrolls to the booking card) and `static` (always level). Pages place
|
||||
it in later subtasks (24-4 hero and vision card, 24-5 finale, 24-6 success page).
|
||||
|
||||
### Files to create
|
||||
|
||||
1. **`resources/views/components/site/balance.blade.php`** — props: `mode` (`hero` | `finale` |
|
||||
`static`, default `static`), `label` (default null), `size` (integer px, default null; when set,
|
||||
the SVG gets `width` and `height` of that many px). Renders
|
||||
`<svg class="site-balance" data-balance="{{ $mode }}" viewBox="0 0 400 400" …>` with
|
||||
`overflow:visible`; when `label` is set: `role="img" aria-label="{{ $label }}"`, otherwise
|
||||
`aria-hidden="true"`. Pass through `$attributes` (class, id, style).
|
||||
2. **`resources/js/site/balance.js`** — exports `init()` and `destroy()`; imported and wired in
|
||||
`resources/js/public.js` exactly like `reveal.js` (init on `livewire:navigated`, destroy on
|
||||
`livewire:navigating`). It contains:
|
||||
- `build(svg)` — fills the SVG with the markup from `docs/ux-mockup.html` lines 566–595
|
||||
(the `scales()` function's template: four gradients `gd`, `gc`, `gb`, `gh`, two filters
|
||||
`sh` (drop shadow dy 8, stdDeviation 7, flood `#0d1009` opacity .45) and `bl` (blur 6), the
|
||||
ground shadow ellipse, base, pillar, olive-leaf finial, the `.beam` group, the pivot, and two
|
||||
`.pan` groups). Gradient and filter ids must be unique per instance (suffix a running
|
||||
counter) so several balances on one page do not share ids. Returns `tilt(deg)` (mockup lines
|
||||
597–602): `beam.setAttribute('transform', rotate(deg 200 110))`; with
|
||||
`r = deg·π/180, c = cos(r)·142, s = sin(r)·142`, pan 0 at `translate(200−c, 110−s)` and pan 1
|
||||
at `translate(200+c, 110+s)`.
|
||||
- `spring(tilt, start)` (mockup lines 605–610): state `a = start, v = 0, target = 0`; each
|
||||
animation frame `v += (target − a)·0.028; v ·= 0.935; a += v; tilt(a)`; keep requesting
|
||||
frames while `|v| > 0.002` or `|target − a| > 0.01`. Exposes `set(target)`.
|
||||
- Behaviour per `data-balance`:
|
||||
- `static`: `tilt(0)`.
|
||||
- `hero`: `tilt(14)`, create a spring from 14, after 450ms `set(0)`. If
|
||||
`matchMedia('(pointer:fine)').matches`, find the closest ancestor `.frame` (the hero frame,
|
||||
built in 24-4); on `pointermove` over it: `x = (clientX − rect.left) / rect.width`,
|
||||
`set(clamp((x − 0.5)·2.4, −1, 1)·9)`; move the frame's `.glow` element's `left`/`top` to
|
||||
the pointer position within the frame; set the frame's `img` transform to
|
||||
`scale(1.08) translate(${(clientX − rect.left − rect.width/2)/−40}px, ${(clientY − rect.top − rect.height/2)/−40}px)`.
|
||||
On `pointerleave`: `set(0)` and clear the image transform.
|
||||
- `finale`: `tilt(−12)`, spring from −12; on a passive window `scroll` listener (and once on
|
||||
init): `p = scrollY / (scrollHeight − innerHeight)` (1 if the denominator is ≤ 0),
|
||||
`q = clamp((p − 0.7) / 0.25, 0, 1)`, `set(−12·(1 − q))`.
|
||||
- If `matchMedia('(prefers-reduced-motion: reduce)').matches`: every balance is built and
|
||||
`tilt(0)`; no spring, no listeners.
|
||||
- `destroy()` removes every listener added and cancels pending animation frames.
|
||||
3. CSS in **`resources/css/public.css`**: `body.site .site-balance{display:block;overflow:visible}`.
|
||||
|
||||
### Files to modify
|
||||
|
||||
- `resources/js/public.js` (import and wire `./site/balance.js`), `resources/css/public.css`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `<x-site.balance mode="hero" label="ميزان العدالة" />` renders an `<svg>` with
|
||||
`data-balance="hero"`, `viewBox="0 0 400 400"`, `role="img"` and the given `aria-label`;
|
||||
without `label` it renders `aria-hidden="true"`.
|
||||
- [ ] With two balances on one page, every `id` inside the SVGs is unique
|
||||
(`document.querySelectorAll('[id]')` has no duplicate values).
|
||||
- [ ] A `hero` balance is drawn tilted on load and its beam's `transform` reaches `rotate(0…)`
|
||||
(|angle| < 0.05) within 4 seconds without pointer input.
|
||||
- [ ] Moving a fine pointer to the right edge of the hero frame tips the beam toward +9° (in the
|
||||
browser, read the beam's transform); leaving the frame returns it toward 0°.
|
||||
- [ ] A `finale` balance's beam is at −12° at the top of the page and within 0.5° of 0° when the
|
||||
page is scrolled to the bottom.
|
||||
- [ ] With `prefers-reduced-motion: reduce` emulated, every balance's beam transform is
|
||||
`rotate(0 200 110)` and no animation frame is requested after load.
|
||||
- [ ] Navigating between public pages with `wire:navigate` and back to `/` re-initialises the
|
||||
hero balance (it renders and settles) and leaves no duplicate scroll listeners (the finale
|
||||
still levels correctly after three navigations).
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,196 @@
|
||||
---
|
||||
id: 24-4
|
||||
title: 24-4 Home Page Sections (Hero to Latest Articles)
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Rebuild `resources/views/livewire/pages/home.blade.php` as the approved redesign, sections 1–7
|
||||
(hero, pillars, founder, services, vision, values, latest articles). Section 8, the booking card,
|
||||
is task 24-5; leave a placeholder comment `{{-- booking card: task 24-5 --}}` where it goes. Keep
|
||||
the component's PHP class as it is (`#[Layout('components.layouts.public')]`, `with()` returning
|
||||
`latestPosts` = `Post::published()->latest('published_at')->take(3)->get()`). Remove the
|
||||
temporary `<div class="wrap py-8">` wrapper added in 24-1: each section is full-bleed and holds a
|
||||
`<div class="wrap">`.
|
||||
|
||||
The visual reference is `docs/ux-mockup.html` (commit `caec396`). Port the CSS for each section
|
||||
from the line ranges below into `resources/css/public.css`, every selector prefixed with
|
||||
`body.site `, and port the matching responsive rules from lines 293–323. Put `data-reveal` and
|
||||
`data-d` attributes on the same elements as the mockup (lines 358–506).
|
||||
|
||||
### Photography — create `public/images/site/`
|
||||
|
||||
Extract these JPEG data URIs from `docs/ux-mockup.html` and save them, decoded, as files (a short
|
||||
script reading the file and base64-decoding the `src="data:image/jpeg;base64,…"` value on each
|
||||
line is enough; do not commit the script):
|
||||
|
||||
| Mockup line | `<img>` | Save as |
|
||||
|---|---|---|
|
||||
| 377 | hero olive tree | `public/images/site/olive-tree.jpg` |
|
||||
| 447 | embroidery hoop | `public/images/site/embroidery-hoop.jpg` |
|
||||
| 455 | olives on a branch | `public/images/site/olives.jpg` |
|
||||
| 459 | hills and road | `public/images/site/hills.jpg` |
|
||||
|
||||
The founder portrait uses the existing `public/images/huda-armouche.jpg`. The images are from
|
||||
Unsplash (licence permits commercial use without attribution); show no credit line.
|
||||
|
||||
### Sections (in order, inside the root `<div>`)
|
||||
|
||||
1. **Hero** — `<section class="hero" id="top">`; CSS lines 100–125. Two-column grid
|
||||
(`1fr 1.08fr`, gap 56px; one column ≤1100px). Start column: `.eyebrow` = `site.hero_eyebrow`;
|
||||
`<h1>` = `{{ __('site.hero_title_a') }}<em>{{ __('site.hero_title_em') }}</em>{{ __('site.hero_title_b') }}`
|
||||
(the `em` is upright, `--olive`, with `text-decoration: underline dashed var(--gold) .07em;
|
||||
text-underline-offset:.28em`); `<p class="lede">` = `home.intro`; CTA row: gold button
|
||||
`home.cta_book` → `#book` with the arrow SVG (mockup line 366), ghost button
|
||||
`home.cta_services` → `#services`; `.trust` strip with three items, each
|
||||
`<strong>` + `<span>`: (`site.trust_1_title`, `site.trust_1_text`), (`site.trust_2_title`,
|
||||
`site.trust_2_text`), (`site.trust_3_title`, `site.trust_3_text`). End column `.hero-art`:
|
||||
`<figure class="frame">` (aspect 4/4.6, radius `999px 999px 18px 18px`, forest ground,
|
||||
gradient veil `::before` from `rgba(35,42,28,.35)` to `.9`), containing
|
||||
`<img src="/images/site/olive-tree.jpg" alt="{{ __('site.alt_olive_tree') }}">` (filter
|
||||
`saturate(.75) contrast(1.05)`, `scale(1.08)`), `<span class="glow">` (420px radial gold
|
||||
glow), `<x-site.balance mode="hero" :label="__('site.balance_label')" id="scales" />`
|
||||
positioned `inset:10% 8% 12%`, and `<figcaption>` = `site.frame_caption` (display italic,
|
||||
cream .78). Then `<div class="tag">` with `<span class="dot">` (olive, pulsing) and
|
||||
`site.frame_tag`.
|
||||
2. **Pillars band** — `<section class="band on-dark" aria-label="{{ __('site.pillars_label') }}">`;
|
||||
CSS lines 127–137. Three `.pillar` columns: (`site.pillar_justice`, `site.pillar_justice_text`),
|
||||
(`site.pillar_dignity`, `site.pillar_dignity_text`), (`site.pillar_advocacy`,
|
||||
`site.pillar_advocacy_text`), each title preceded by `<span class="gem">` (CSS line 210).
|
||||
3. **Founder** — `<section class="sec" id="founder">`; CSS lines 146–157. Portrait
|
||||
`/images/huda-armouche.jpg` (alt `home.lawyer_name`) with `.namecard`
|
||||
(`<b>` `home.lawyer_name`, `<span>` `site.founder_role`). Text column: `.art-no`
|
||||
`site.art_founder`; `<h2>` `home.about_title`; `<blockquote>` `site.founder_quote`;
|
||||
paragraphs `home.lawyer_bio` and `home.lawyer_bio_2`; ghost button `site.founder_cta` →
|
||||
`route('about')`.
|
||||
4. **Services docket** — `<section class="sec" id="services" style="padding-top:40px">`;
|
||||
CSS lines 159–174. `x-site.section-head` (see below) with label `site.art_services`, title
|
||||
`home.services_subtitle`, lede `site.services_lede`. Four `<a class="row" href="#book">` rows:
|
||||
number `01`–`04` (`.n`), `<h3>` title, `.chips` of the items, `.go` arrow circle. Rows in order:
|
||||
(`home.service_consultation_title`, `home.service_consultation_items`),
|
||||
(`home.service_family_title`, `home.service_family_items`),
|
||||
(`home.service_civil_title`, `home.service_civil_items`),
|
||||
(`home.service_business_title`, `home.service_business_items`). Items are arrays — render each
|
||||
as `<span class="chip">`.
|
||||
5. **Vision** — `<section class="sec fabric" id="mission">`; CSS lines 176–197. Text column:
|
||||
`.art-no` `site.art_vision`, `<h2>` `site.vision_title`, `<p class="big">` `site.vision_text`;
|
||||
beside it `.hoop` with `/images/site/embroidery-hoop.jpg` (alt `site.alt_hoop`; filter
|
||||
`hue-rotate(-140deg) saturate(.55) sepia(.25)`). Below, `.three` grid of `<article class="card">`:
|
||||
(a) `.ph.motif-ph` containing `<x-site.balance mode="static" />` (150×150px) and label
|
||||
`site.card_institution_label`, title `site.card_institution_title`, text
|
||||
`site.card_institution_text`; (b) `.ph` with `/images/site/olives.jpg` (alt `site.alt_olives`),
|
||||
label `site.card_society_label`, title `site.card_society_title`, text `site.card_society_text`;
|
||||
(c) `.ph` with `/images/site/hills.jpg` (alt `site.alt_hills`), label
|
||||
`site.card_diaspora_label`, title `site.card_diaspora_title`, text `site.card_diaspora_text`.
|
||||
6. **Values** — `<section class="sec" id="values">`; CSS lines 199–212. Section head: label
|
||||
`site.art_values`, title `home.values_title`, lede `home.values_subtitle`. `.sampler` grid of six
|
||||
`.val` cards, each `<span class="medal">` with the line icon and `<b>` =
|
||||
`home.values.<key>.title`, keys in order `integrity`, `justice`, `knowledge`, `empowerment`,
|
||||
`professionalism`, `innovation`. Icons: the inline SVGs on mockup lines 474–479 in the same
|
||||
order (24×24 viewBox, `aria-hidden="true"`, stroke `--gold-ink` 1.5, no fill). Replace the
|
||||
current `flux:icon` usage.
|
||||
7. **Latest articles** — `<section class="sec" id="posts" style="padding-top:20px">`; CSS lines
|
||||
214–234. Head: label `site.art_articles`, title `home.posts_title`, and in place of the lede a
|
||||
ghost button `home.view_all_posts` → `route('posts.index')`. If `$latestPosts` is not empty:
|
||||
`.posts` grid of `<x-site.post-card :post="$post" />`; otherwise a `<p>` with
|
||||
`home.posts_empty` (muted, centred).
|
||||
|
||||
### Components to create
|
||||
|
||||
- **`resources/views/components/site/section-head.blade.php`** — props `label`, `title`,
|
||||
`lede` (nullable); renders
|
||||
`<div class="sec-head"><div><span class="art-no" data-reveal>{{ $label }}</span><h2 data-reveal data-d="1">{{ $title }}</h2></div>`
|
||||
then either `<p data-reveal data-d="2">{{ $lede }}</p>` or the `$slot` (for the button), then
|
||||
`</div>`.
|
||||
- **`resources/views/components/site/post-card.blade.php`** — prop `post` (App\Models\Post);
|
||||
`<a class="post" href="{{ route('posts.show', $post) }}" wire:navigate data-reveal>` →
|
||||
`<div class="bd">` with `<span class="meta">` = the published date
|
||||
(`$post->published_at?->translatedFormat('j F Y')`), `<h3>` = `$post->getTitle()`, `<p>` = an
|
||||
excerpt of `strip_tags($post->getBody())` limited to 140 characters (`Str::limit`), and
|
||||
`<span class="more">` = `home.read_more`. Text-only: no image element.
|
||||
|
||||
### Language keys — add to `lang/ar/site.php` and `lang/en/site.php`
|
||||
|
||||
| Key | ar | en |
|
||||
|---|---|---|
|
||||
| `hero_eyebrow` | ليبرا للحقوق · فلسطين | Libra for Rights · Palestine |
|
||||
| `hero_title_a` | العدالة␠ | Justice is a␠ |
|
||||
| `hero_title_em` | ممارسةٌ يومية | daily practice |
|
||||
| `hero_title_b` | ، لا مبدأٌ نظري. | , not a theory. |
|
||||
| `trust_1_title` | أفراد وشركات | Individuals & companies |
|
||||
| `trust_1_text` | استشارات وتمثيل | Consultations and representation |
|
||||
| `trust_2_title` | المرأة والأسرة | Women & family |
|
||||
| `trust_2_text` | دعم قانوني متخصص | Specialised legal support |
|
||||
| `trust_3_title` | عربي · English | Arabic · English |
|
||||
| `trust_3_text` | خدمة بلغتين | Bilingual service |
|
||||
| `alt_olive_tree` | شجرة زيتون معمّرة بين صخور كلسية | An ancient olive tree among limestone rocks |
|
||||
| `balance_label` | ميزان العدالة | The scales of justice |
|
||||
| `frame_caption` | لكلّ حقٍّ وزنُه | Every right carries its weight |
|
||||
| `frame_tag` | استشارات حضورية أو عن بُعد | Consultations in person or remotely |
|
||||
| `pillars_label` | ركائزنا | Our pillars |
|
||||
| `pillar_justice` | العدالة | Justice |
|
||||
| `pillar_justice_text` | الإنصاف، والمساءلة، وسيادة القانون. | Fairness, accountability and the rule of law. |
|
||||
| `pillar_dignity` | الكرامة | Dignity |
|
||||
| `pillar_dignity_text` | القيمة الأصيلة لكل إنسان. | The inherent worth of every person. |
|
||||
| `pillar_advocacy` | الدفاع | Advocacy |
|
||||
| `pillar_advocacy_text` | انخراطٌ فاعل، وقولُ الحق في وجه السلطة. | Active engagement, and speaking truth to power. |
|
||||
| `art_founder` | المادة ٠١ — المؤسِّسة | Article 01 — The founder |
|
||||
| `founder_role` | المؤسِّسة · محامية | Founder · Attorney at Law |
|
||||
| `founder_quote` | «العدالة ممارسة يومية، وليست مجرد مبدأ نظري.» | “Justice is a daily practice, not merely a theoretical principle.” |
|
||||
| `founder_cta` | اقرأ قصتنا | Read our story |
|
||||
| `art_services` | المادة ٠٢ — الخدمات | Article 02 — Services |
|
||||
| `services_lede` | ممارسة قانونية أصيلة، تقوم على البحث والمعرفة الميدانية. | Traditional legal practice, combined with research-driven insight. |
|
||||
| `art_vision` | المادة ٠٣ — الرؤية | Article 03 — Vision |
|
||||
| `vision_title` | منسوجةٌ من نسيج المجتمع | Woven from the fabric of society |
|
||||
| `vision_text` | ليبرا نسيجٌ أصيل من المجتمع، تتقصّى مشكلاته وتوثّقها وتكشف جذورها، وتقدّم حلولاً عملية لرأب أوجاعه مهما صغرت، عبر العمل التشاركي والبحث الميداني الحقيقي. | Libra investigates society's problems, documents them, uncovers their roots, and offers practical solutions to mend social pains — however small — through collaborative work and genuine field research. |
|
||||
| `alt_hoop` | تطريز بغرزة الصليب مشدود على طارة خشبية | Cross-stitch embroidery stretched on a wooden hoop |
|
||||
| `card_institution_label` | لمؤسستنا | For our institution |
|
||||
| `card_institution_title` | القانون والبحث والميدان | Law, research and fieldwork |
|
||||
| `card_institution_text` | نلتقط نبض المجتمع ونحوّل تحدياته إلى معرفة وحلول قانونية مبتكرة. | Capturing society's pulse and turning its challenges into knowledge and innovative legal solutions. |
|
||||
| `alt_olives` | ثمار زيتون على غصن | Olives ripening on a branch |
|
||||
| `card_society_label` | للمجتمع | For society |
|
||||
| `card_society_title` | شريكٌ موثوق للقضاء | A trusted partner to the judiciary |
|
||||
| `card_society_text` | نعيد وصل المجتمع بتاريخه وإرثه القانوني. | Reconnecting society with its history and legal heritage. |
|
||||
| `alt_hills` | تلال وطريق متعرّج عند الغروب | Hills and a winding road at sunset |
|
||||
| `card_diaspora_label` | لفلسطينيي الشتات | For Palestinians in the diaspora |
|
||||
| `card_diaspora_title` | عودةٌ إلى الأرض والعائلة | Back to the land and the family |
|
||||
| `card_diaspora_text` | نساعد الفلسطينيين في الخارج على البحث في عائلاتهم وتاريخهم وأراضيهم. | Helping Palestinians abroad research their families, their history and their land. |
|
||||
| `art_values` | المادة ٠٤ — القيم | Article 04 — Values |
|
||||
| `art_articles` | المادة ٠٥ — المقالات | Article 05 — Articles |
|
||||
|
||||
`␠` marks a trailing space that must be kept in the value.
|
||||
|
||||
### Files
|
||||
|
||||
- Create: `public/images/site/olive-tree.jpg`, `public/images/site/embroidery-hoop.jpg`,
|
||||
`public/images/site/olives.jpg`, `public/images/site/hills.jpg`,
|
||||
`resources/views/components/site/section-head.blade.php`,
|
||||
`resources/views/components/site/post-card.blade.php`.
|
||||
- Modify: `resources/views/livewire/pages/home.blade.php`, `resources/css/public.css`,
|
||||
`lang/ar/site.php`, `lang/en/site.php`.
|
||||
- Do not edit `lang/*/home.php`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `/` renders, in order, sections with ids `top`, (the pillars band), `founder`, `services`,
|
||||
`mission`, `values`, `posts`, each with its content from the keys above in both Arabic and
|
||||
English (switch with `/language/en`).
|
||||
- [ ] `/` has exactly one `<h1>`, and every `<img>` has a non-empty `alt` in both languages.
|
||||
- [ ] The four files in `public/images/site/` exist, are valid JPEGs (`file` reports JPEG image
|
||||
data) and load with HTTP 200 on `/`.
|
||||
- [ ] The hero balance renders inside the hero frame and settles level (task 24-3 behaviour).
|
||||
- [ ] Each services row links to `#book`; each row shows the item chips from `home.php`.
|
||||
- [ ] With three or more published posts, three post cards show date, title, excerpt and "Read
|
||||
more", link to `/posts/{post}`, and contain no `<img>`; with no published posts, the
|
||||
`home.posts_empty` text shows instead of the grid.
|
||||
- [ ] At 1440, 768 and 390px wide, `/` has no horizontal scroll (`document.documentElement.scrollWidth <= innerWidth`).
|
||||
- [ ] Hovering a service row fills it forest with cream text; hovering a value card lifts it and
|
||||
rotates its medallion; hovering a post card lifts it.
|
||||
- [ ] The page contains no "Unsplash" text and `lang/*/home.php` is unchanged against BASE.
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
id: 24-5
|
||||
title: 24-5 Home Booking Card (Compact Booking and Day Strip)
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Add section 8 of the home page: a forest booking card that embeds the existing guest-booking
|
||||
component in a one-screen "compact" mode, with a 14-day strip of bookable days. The booking rules
|
||||
must not change: name, email and phone required; case summary required, minimum 20 characters;
|
||||
the math captcha (`App\Services\CaptchaService`); one booking per email per day; slots from
|
||||
`App\Services\AvailabilityService`; the existing confirm step (`showConfirmation`); and the
|
||||
existing `submit()` that redirects to `route('booking.success')`. Logged-in visitors see the
|
||||
existing logged-in message instead of the form.
|
||||
|
||||
### 1. Availability calendar — `resources/views/livewire/availability-calendar.blade.php`
|
||||
|
||||
- Add `public string $variant = 'month';` (settable from the tag: `variant="strip"`). The default
|
||||
`month` must render exactly as today, because
|
||||
`resources/views/livewire/client/consultations/book.blade.php` also uses this component.
|
||||
- When `$variant === 'strip'`:
|
||||
- Compute `$stripDays`: starting today, step one day at a time up to 60 days ahead and collect
|
||||
the first 14 dates for which `AvailabilityService::getDateStatus($date)` returns
|
||||
`'available'` or `'partial'` (the same two values `selectDate()` accepts today), each with
|
||||
its `getAvailableSlots($date)`.
|
||||
- On mount, select the first strip day (`$selectedDate`) and load its slots with the existing
|
||||
`loadAvailableSlots()`.
|
||||
- Render a day strip: `<div class="days" role="group" aria-label="{{ __('site.booking_day') }}">`
|
||||
of `<button type="button" class="day" aria-pressed="true|false" wire:click="selectDate('Y-m-d')">`
|
||||
with the weekday name (`translatedFormat('l')`) and `<b>` the day number. Then a slot row:
|
||||
`<div class="slots" role="group" aria-label="{{ __('site.booking_time') }}">` of
|
||||
`<button type="button" class="slot" dir="ltr" aria-pressed=…>` per slot, clicking calls the
|
||||
existing `$parent.selectSlot('<date>', '<slot>')`, and the button for the parent's current
|
||||
`selectedTime` on the selected date is pressed. Slot labels use the same time format as the
|
||||
month view.
|
||||
- No strip day available within 60 days → show `site.booking_none` (ar «لا توجد مواعيد
|
||||
متاحة حالياً»; en "No times are available at the moment") in place of the strip and slots.
|
||||
- CSS (in `resources/css/public.css`, scoped `body.site`; mockup `docs/ux-mockup.html` lines
|
||||
256–265): `.days` flex, gap 8px, `overflow-x:auto`, `scrollbar-width:none`; `.day` 66×72px min,
|
||||
radius 14px, `1.5px solid rgba(45,54,36,.15)`, white, .78rem muted, `<b>` display font 1.35rem
|
||||
ink; hover gold border and lift 2px; `[aria-pressed=true]` forest background, `--gold-lt` text,
|
||||
cream number, shadow `0 10px 22px -10px rgba(45,54,36,.8)`. `.slots` flex-wrap gap 8px;
|
||||
`.slot` min-height 44px, padding 8px 16px, pill, same border, white; hover gold border;
|
||||
`[aria-pressed=true]` gold fill, gold border, ink text.
|
||||
|
||||
### 2. Booking component — `resources/views/livewire/pages/booking.blade.php`
|
||||
|
||||
- Add `public bool $compact = false;` and accept it in `mount(bool $compact = false)` (keep the
|
||||
existing mount logic). The `#[Layout]` attribute stays; it is ignored when the component is
|
||||
embedded.
|
||||
- When `$compact` is true, render (instead of the page markup) a
|
||||
`<form class="book-r" wire:submit="showConfirm">` (mockup CSS lines 247–267: cream, padding
|
||||
44px 44px 40px, margin 12px, radius 20px) containing, in order:
|
||||
1. `.f2` two-column row: full name (`guestName`, `autocomplete="name"`) and phone
|
||||
(`guestPhone`, `type="tel" dir="ltr" autocomplete="tel"`), labels from the existing
|
||||
`booking.*` keys with ` *`;
|
||||
2. email (`guestEmail`, `type="email" dir="ltr" autocomplete="email"`);
|
||||
3. `<livewire:availability-calendar variant="strip" />` — the strip variant itself renders a
|
||||
visible label `site.booking_day` (.85rem, weight 600, margin-bottom 6px) above `.days` and
|
||||
`site.booking_time` above `.slots`;
|
||||
4. case summary textarea (`problemSummary`, rows 3, label `booking.problem_summary` + ` *`,
|
||||
help text `booking.problem_summary_help`);
|
||||
5. the captcha question and input (`captchaAnswer`, `inputmode="numeric" dir="ltr"`,
|
||||
max-width 140px) exactly as the page version renders it;
|
||||
6. `<button type="submit" class="btn btn-gold">` `site.booking_submit`, full width;
|
||||
7. `<p class="note">` `booking.limit_message`.
|
||||
Validation errors render under each field as in the page version. Submitting without a
|
||||
selected slot shows the existing `selectedTime` error.
|
||||
- When `$compact` and `$showConfirmation` are true, the same `.book-r` panel shows the existing
|
||||
confirmation summary (date, time, name, email, phone, summary) with the existing Confirm
|
||||
(`submit`) and Back (`$set('showConfirmation', false)`) actions, styled `btn-gold` and
|
||||
`btn-ghost`.
|
||||
- When `$compact` and the visitor is logged in, the panel shows the existing
|
||||
`booking.logged_in_title`, `booking.logged_in_message` and the `booking.go_to_dashboard` link
|
||||
(`route('client.consultations.book')`) styled as `btn-gold`.
|
||||
- Inputs and textarea (scoped `body.site .book-r`): min-height 48px, padding 12px 16px, radius
|
||||
12px, `1.5px solid rgba(45,54,36,.18)`, white, `font:400 1rem var(--body)`; focus border
|
||||
`--gold` and `box-shadow:0 0 0 4px rgba(166,137,102,.2)`; labels .85rem weight 600. Flux inputs
|
||||
may be replaced by plain inputs in compact mode, keeping the same `wire:model` names.
|
||||
- The non-compact (page) rendering is unchanged by this task.
|
||||
|
||||
### 3. Home page — `resources/views/livewire/pages/home.blade.php`
|
||||
|
||||
Replace `{{-- booking card: task 24-5 --}}` with
|
||||
`<section id="book"><div class="wrap"><div class="book" data-reveal>` (mockup CSS lines 236–246:
|
||||
forest, radius 28px, two columns `1fr 1.1fr`, one column ≤1100px, shadow
|
||||
`0 50px 90px -40px rgba(30,34,25,.8)`), containing:
|
||||
- `<div class="book-l on-dark">` (padding 56px 52px; 40px 24px ≤760px): `.eyebrow`
|
||||
`site.art_booking` (colour `--gold-lt`), `<h2>` `site.booking_title` (cream), `<p>`
|
||||
`site.booking_lede` (`--gold-lt`), `.contact` list — phone link `tel:+970599353502` with
|
||||
`<span dir="ltr">{{ __('footer.phone') }}</span>`, email link `mailto:` `footer.email`, and the
|
||||
address `footer.address`, each with the 20px gold line icon from mockup lines 517–519 — and
|
||||
`<x-site.balance mode="finale" style="width:190px;height:190px;margin-top:22px" />`.
|
||||
- `<livewire:pages.booking :compact="true" />`.
|
||||
|
||||
### Language keys — add to `lang/ar/site.php` and `lang/en/site.php`
|
||||
|
||||
| Key | ar | en |
|
||||
|---|---|---|
|
||||
| `art_booking` | المادة ٠٦ — الاستشارة | Article 06 — Consultation |
|
||||
| `booking_title` | احجز استشارة | Book a consultation |
|
||||
| `booking_lede` | اختر يوماً ووقتاً متاحَين، وأخبرنا باختصار عن قضيتك. نراجع كل طلب ونؤكّد الموعد بالبريد الإلكتروني — دون الحاجة إلى حساب. | Choose an available day and time and tell us briefly about your case. We review every request and confirm by email — no account needed. |
|
||||
| `booking_day` | اليوم | Day |
|
||||
| `booking_time` | الوقت | Time |
|
||||
| `booking_submit` | اطلب هذا الموعد | Request this appointment |
|
||||
| `booking_none` | لا توجد مواعيد متاحة حالياً | No times are available at the moment |
|
||||
|
||||
### Files
|
||||
|
||||
- Modify: `resources/views/livewire/availability-calendar.blade.php`,
|
||||
`resources/views/livewire/pages/booking.blade.php`,
|
||||
`resources/views/livewire/pages/home.blade.php`, `resources/css/public.css`,
|
||||
`lang/ar/site.php`, `lang/en/site.php`.
|
||||
- Do not modify `app/Services/AvailabilityService.php`, `app/Services/CaptchaService.php`,
|
||||
`resources/views/livewire/client/consultations/book.blade.php`, or any migration.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `/` shows the booking card with id `book`: the forest panel (title, lede, phone, email,
|
||||
address, finale balance) and the cream form with fields in the order name, phone, email,
|
||||
day strip, slots, summary, captcha, submit, one-per-day note.
|
||||
- [ ] The day strip lists up to 14 dates, all of which have at least one slot in
|
||||
`AvailabilityService::getAvailableSlots()`; the first is pressed on load and its slots show;
|
||||
clicking another day loads that day's slots.
|
||||
- [ ] A guest who fills valid data, picks a slot, answers the captcha and confirms creates exactly
|
||||
one guest consultation (same attributes as a booking made on `/booking`) and lands on
|
||||
`/booking/success`.
|
||||
- [ ] A summary of fewer than 20 characters, a wrong captcha answer, a missing slot, or a second
|
||||
booking with the same email on the same day each produce the same error as on `/booking`,
|
||||
and no consultation is created.
|
||||
- [ ] Logged in as a client, `/` shows the logged-in message with a link to
|
||||
`/client/consultations/book` and no form.
|
||||
- [ ] `/booking` and `/client/consultations/book` render the month calendar as before this task
|
||||
(`variant` defaults to `month`).
|
||||
- [ ] The finale balance is tilted at the top of `/` and level when scrolled to the booking card at
|
||||
the end of the page.
|
||||
- [ ] At 390px the card is one column, the day strip scrolls horizontally inside the card, and the
|
||||
page has no horizontal scroll.
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
id: 24-6
|
||||
title: 24-6 Booking Page and Booking Success
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Restyle `/booking` (the non-compact rendering of `resources/views/livewire/pages/booking.blade.php`)
|
||||
and `/booking/success` (`resources/views/livewire/pages/booking-success.blade.php`) to the
|
||||
redesign. Behaviour does not change: the month calendar, the guest fields, the captcha, the
|
||||
confirm step, the one-per-day rule, the logged-in message, and the redirect to `/booking/success`.
|
||||
Task 24-5 already added `$compact`, the strip variant and the `.book`, `.book-l`, `.book-r`,
|
||||
input and label styles in `resources/css/public.css`; reuse them.
|
||||
|
||||
### `/booking` (non-compact branch of `booking.blade.php`)
|
||||
|
||||
Replace the page markup (keeping every `wire:` binding, error output, and the
|
||||
`@if($isLoggedIn)` / step logic) with:
|
||||
|
||||
`<section class="sec" style="padding-top:56px"><div class="wrap">` →
|
||||
`<x-site.section-head :label="__('site.art_booking')" :title="__('booking.request_consultation')" :lede="__('site.booking_lede')" />` →
|
||||
`<div class="book">`:
|
||||
- `.book-l.on-dark`: `.contact` list (phone `tel:+970599353502` with
|
||||
`<span dir="ltr">{{ __('footer.phone') }}</span>`, `mailto:` `footer.email`, address
|
||||
`footer.address`, same 20px gold icons as the home card) and
|
||||
`<x-site.balance mode="static" style="width:190px;height:190px;margin-top:22px" />`.
|
||||
- `.book-r` (cream inset): for a logged-in visitor, the existing logged-in title, message and
|
||||
`booking.go_to_dashboard` link (`route('client.consultations.book')`) as `btn btn-gold`.
|
||||
For a guest: step 1 — `booking.select_date_time` then `<livewire:availability-calendar />`
|
||||
(month variant); step 2 — the selected date/time summary with the existing "change" action,
|
||||
the fields name, email, phone, case summary, captcha, the gold submit; step 3 — the existing
|
||||
confirmation summary with Confirm (`btn-gold`) and Back (`btn-ghost`). The existing
|
||||
`session('success')` callout stays at the top of `.book-r`.
|
||||
|
||||
Below the card, inside the same `.wrap`, keep `<x-booking-expectations class="mt-10" />`
|
||||
unchanged.
|
||||
|
||||
### Month calendar restyle (CSS only, scoped to the public site)
|
||||
|
||||
In `resources/css/public.css`, under `body.site`, style the month grid rendered by
|
||||
`resources/views/livewire/availability-calendar.blade.php` (month variant) without editing its
|
||||
markup: day cells min 44×44px, radius 10px; available and partial days white with a 6px gold dot
|
||||
below the number (`::after`, `background:var(--gold)`); the selected day `background:var(--forest)`
|
||||
with cream text; unavailable, closed, blocked and past days `--muted` text at 50% opacity, no
|
||||
hover; month navigation buttons as 44px pills with `1.5px solid var(--line)`. Read the template
|
||||
to find the exact classes or `wire:click` attributes the selectors must target; if the template
|
||||
has no class to hook onto, add a class attribute only (e.g. `site-cal-day`, plus
|
||||
`is-available`, `is-selected`) without changing structure or behaviour, so the client dashboard
|
||||
(which has no `body.site`) renders as before.
|
||||
|
||||
### `/booking/success` — `booking-success.blade.php`
|
||||
|
||||
`<section class="sec"><div class="wrap">` → a centred cream card (max-width 560px, margin-inline auto,
|
||||
`background:var(--cream)`, `1px solid var(--line)` border, radius 20px, `--shadow-2`, padding
|
||||
48px 40px, text-align center) containing
|
||||
`<x-site.balance mode="static" style="width:120px;height:120px;margin:0 auto 18px" />`, `<h1>`
|
||||
`booking.success_title` (display font, `clamp(2rem,3.4vw,2.6rem)`), `<p>`
|
||||
`booking.success_message` (muted), and `<a class="btn btn-ghost" href="{{ route('home') }}" wire:navigate>`
|
||||
`site.nav_home`. Remove the `flux:icon` check-circle, `flux:heading` and `flux:button`.
|
||||
|
||||
### Files
|
||||
|
||||
- Modify: `resources/views/livewire/pages/booking.blade.php`,
|
||||
`resources/views/livewire/pages/booking-success.blade.php`, `resources/css/public.css`, and
|
||||
(class attributes only, if needed) `resources/views/livewire/availability-calendar.blade.php`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `/booking` as a guest shows the section head, the forest card with contact details and a
|
||||
level balance, and the month calendar inside the cream panel; selecting an available day and
|
||||
a slot reveals the fields; completing the form and confirming creates one guest consultation
|
||||
and redirects to `/booking/success`.
|
||||
- [ ] Every validation rule behaves as before this task (required fields, 20-character summary,
|
||||
captcha, one booking per email per day), each error rendered under its field.
|
||||
- [ ] `/booking` logged in as a client shows the logged-in message and the link to
|
||||
`/client/consultations/book`, and no form.
|
||||
- [ ] In the month calendar on `/booking`, available days show a gold dot, the selected day is
|
||||
forest with cream text, and unavailable days are dimmed; day cells are at least 44×44px.
|
||||
- [ ] `/client/consultations/book` (logged in as a client) renders the calendar as before
|
||||
(no `body.site` styles apply there).
|
||||
- [ ] `/booking/success` shows the balance, title, message and a Home button, and contains no
|
||||
`flux:` markup output (`data-flux-` attributes) in its main content.
|
||||
- [ ] `/booking` and `/booking/success` have no horizontal scroll at 1440, 768 and 390px.
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
id: 24-7
|
||||
title: 24-7 About Page
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Restyle `/about` (`resources/views/livewire/pages/about.blade.php`) with the redesign's components,
|
||||
using only the page's existing content from `lang/*/about.php` (no new copy beyond the article
|
||||
labels below). Keep the Volt class and layout attribute. Remove the temporary
|
||||
`<div class="wrap py-8">` from 24-1; each section is full-bleed with its own `.wrap`. The
|
||||
Scholarship section stays removed (it was taken out on 2026-01-11 at Naser's request).
|
||||
|
||||
Sections, in order (all CSS classes already exist in `resources/css/public.css` from 24-1 to 24-5;
|
||||
add only what is listed as new):
|
||||
|
||||
1. **Hero** — `<section class="sec" style="padding-bottom:64px">`, `.wrap`, max-width 52em:
|
||||
`.eyebrow` = `about.tagline`; `<h1>` = `about.title` (display font,
|
||||
`clamp(2.6rem,4.6vw,4.1rem)`, line-height 1.12); `<p class="lede">` = `about.identity`.
|
||||
2. **Vision and mission** — `<section class="sec fabric">`: `.fabric-grid` with the text column
|
||||
(`.art-no` `site.about_art_vision`, `<h2>` `about.vision_title`, `<p class="big">`
|
||||
`about.vision_text`, then `<h3>` `about.mission_title` and `<p>` `about.mission_intro`) and the
|
||||
`.hoop` photo `/images/site/embroidery-hoop.jpg` (alt `site.alt_hoop`); below, `.three` cards
|
||||
exactly as on the home page but with the about texts: (a) static balance panel, label
|
||||
`site.card_institution_label`, title `about.mission_institution_title`, text
|
||||
`about.mission_institution_text`; (b) `/images/site/olives.jpg`, label
|
||||
`site.card_society_label`, title `about.mission_society_title`, text
|
||||
`about.mission_society_text`; (c) `/images/site/hills.jpg`, label `site.card_diaspora_label`,
|
||||
title `about.mission_diaspora_title`, text `about.mission_diaspora_text`.
|
||||
3. **Values** — `<section class="sec">`: `<x-site.section-head :label="__('site.about_art_values')" :title="__('about.values_title')" :lede="__('about.values_intro')" />`,
|
||||
then the `.sampler` of six `.val` medallion cards with the same six icons and order as the home
|
||||
page (inline SVGs from `docs/ux-mockup.html` lines 474–479), names `about.value_integrity`,
|
||||
`about.value_justice`, `about.value_knowledge`, `about.value_women`,
|
||||
`about.value_professionalism`, `about.value_innovation`.
|
||||
4. **Goals** — `<section class="sec" style="padding-top:20px">`: section head with label
|
||||
`site.about_art_goals`, title `about.goals_title`; then a `.docket` list (`<ol>`, no bullets)
|
||||
with one `.row.row-static` per item of `about.goals` (an array of 7 strings): `.n` = the
|
||||
two-digit number (`01`–`07`) and a `<p>` with the goal text (1.1rem, ink). New CSS:
|
||||
`body.site .row-static{grid-template-columns:90px 1fr}` (52px 1fr at ≤760px) and
|
||||
`body.site .row-static:hover{background:none;color:inherit;transform:none;box-shadow:none}`,
|
||||
`body.site .row-static::before{display:none}`.
|
||||
5. **Legal services** — `<section class="sec" id="services" style="padding-top:20px">`: section
|
||||
head with label `site.about_art_services`, title `about.services_title`, lede
|
||||
`about.services_intro`; four `<a class="row">` rows linking to `route('booking')`, as on the
|
||||
home page, with titles and chips from `about.service_consultation_title/items`,
|
||||
`about.service_family_title/items`, `about.service_civil_title/items`,
|
||||
`about.service_business_title/items`.
|
||||
6. **Closing CTA** — `<section class="band on-dark">` with a `.wrap` centred column, padding
|
||||
72px 0: `<h2>` `site.about_cta_title` (cream, display font) and
|
||||
`<a class="btn btn-gold" href="{{ route('booking') }}" wire:navigate>` `about.services_cta`.
|
||||
|
||||
All elements that reveal on the home page carry `data-reveal` here too.
|
||||
|
||||
### Language keys — add to `lang/ar/site.php` and `lang/en/site.php`
|
||||
|
||||
| Key | ar | en |
|
||||
|---|---|---|
|
||||
| `about_art_vision` | المادة ٠١ — الرؤية والرسالة | Article 01 — Vision and mission |
|
||||
| `about_art_values` | المادة ٠٢ — القيم | Article 02 — Values |
|
||||
| `about_art_goals` | المادة ٠٣ — الأهداف | Article 03 — Goals |
|
||||
| `about_art_services` | المادة ٠٤ — الخدمات | Article 04 — Services |
|
||||
| `about_cta_title` | لكلّ حقٍّ وزنُه | Every right carries its weight |
|
||||
|
||||
### Files
|
||||
|
||||
- Modify: `resources/views/livewire/pages/about.blade.php`, `resources/css/public.css`,
|
||||
`lang/ar/site.php`, `lang/en/site.php`. Do not edit `lang/*/about.php`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `/about` renders the six sections in order with all existing `about.*` content in Arabic and
|
||||
English: identity, vision, mission intro and three mission cards, six values, seven goals,
|
||||
four service groups with their items.
|
||||
- [ ] `/about` has exactly one `<h1>`; every `<img>` has a non-empty `alt`.
|
||||
- [ ] Goal rows have no hover fill; service rows have the forest hover fill and link to `/booking`.
|
||||
- [ ] No Scholarship content appears (`grep -i scholarship resources/views/livewire/pages/about.blade.php` returns nothing).
|
||||
- [ ] `/about` has no horizontal scroll at 1440, 768 and 390px.
|
||||
- [ ] `lang/*/about.php` is unchanged against BASE.
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
id: 24-8
|
||||
title: 24-8 Articles and Legal Pages
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Restyle the articles index, the article page and the legal pages. Behaviour does not change:
|
||||
search (`wire:model.live.debounce.300ms="search"`), pagination (`paginate(10)`), result counts,
|
||||
empty states, the 404 for unpublished posts, and the CMS content of legal pages. Remove the
|
||||
temporary `<div class="wrap py-8">` wrappers added in 24-1.
|
||||
|
||||
### `/posts` — `resources/views/livewire/pages/posts/index.blade.php`
|
||||
|
||||
`<section class="sec" style="padding-top:56px"><div class="wrap">`:
|
||||
- `<x-site.section-head :label="__('site.hero_eyebrow')" :title="__('site.nav_articles')">`
|
||||
(the h2 reads «المقالات» / "Articles"; the existing `posts.posts` key reads "Posts" in English, so
|
||||
it is not used here) with,
|
||||
in the slot, the search field: a pill input (`.search`: min-height 48px, radius 999px, padding
|
||||
12px 20px, `1.5px solid rgba(45,54,36,.18)`, white, width min(360px, 100%); focus gold border
|
||||
plus `0 0 0 4px rgba(166,137,102,.2)`), same `wire:model` and placeholder
|
||||
`posts.search_placeholder`, with an accessible label (`sr-only` text
|
||||
`posts.search_placeholder`).
|
||||
- The existing result-count / no-result lines (`posts.search_results`, `posts.no_results`) as a
|
||||
muted paragraph, and the existing clear-search action as `btn btn-ghost`.
|
||||
- The posts as `<x-site.post-card :post="$post" />` in a `.posts` grid (3 columns; 2 at ≤1100px;
|
||||
1 at ≤760px — the grid CSS exists from 24-4; at this page the last card does not span two
|
||||
columns: add `body.site .posts-index .post:last-child{grid-column:auto}` and give the grid the
|
||||
extra class `posts-index`).
|
||||
- Empty states `posts.no_posts` as before.
|
||||
- Pagination: `{{ $posts->links() }}` kept; style its links under `body.site .pagination-wrap`
|
||||
(wrap the call in `<div class="pagination-wrap">`): 44px pill buttons, `1.5px solid var(--line)`,
|
||||
current page `background:var(--forest)` with cream text, disabled at 50% opacity.
|
||||
|
||||
### `/posts/{post}` — `resources/views/livewire/pages/posts/show.blade.php`
|
||||
|
||||
`<section class="sec" style="padding-top:56px"><article class="wrap" style="max-width:768px">`
|
||||
(720px content + padding):
|
||||
- `<span class="meta">` the published date (existing `translatedFormat('l, d F Y')` expression),
|
||||
colour `--gold-ink`, .85rem, weight 600.
|
||||
- `<h1>` = `$post->getTitle()` — display font, `clamp(2rem,3.4vw,3rem)`, margin 10px 0 28px.
|
||||
- Body `<div class="prose prose-lg prose-brand max-w-none site-prose">{!! $post->getBody() !!}</div>`
|
||||
(keep the existing output exactly). New CSS: `body.site .site-prose :is(h2,h3,h4){font-family:var(--display)}`,
|
||||
`body.site .site-prose a{color:var(--olive)}`, `body.site .site-prose{font-size:1.06rem;line-height:1.85}`.
|
||||
- Footer: `<a class="btn btn-ghost" href="{{ route('posts.index') }}" wire:navigate>`
|
||||
`posts.back_to_posts`, preceded by a hairline `border-top:1px solid var(--line)` with 48px
|
||||
margin-top and 24px padding-top. Remove `flux:heading`.
|
||||
|
||||
### Legal pages
|
||||
|
||||
- `resources/views/pages/legal.blade.php` — inside `<x-layouts.public>`:
|
||||
`<section class="sec" style="padding-top:56px"><div class="wrap" style="max-width:768px">`,
|
||||
`<h1>` `$page->getTitle()` (same h1 style as the article page), the existing
|
||||
`prose prose-brand` block with the class `site-prose` added and its card styling replaced by
|
||||
white background, radius 16px, `--shadow-1`, padding 40px (24px ≤760px); the existing
|
||||
"last updated" line as muted .85rem text. Keep the `clean()` call and the
|
||||
`pages.content_coming_soon` fallback unchanged.
|
||||
- `resources/views/pages/terms.blade.php` and `resources/views/pages/privacy.blade.php` — the same
|
||||
structure with their existing title and placeholder text. (`/terms` and `/privacy` redirect to
|
||||
`/page/terms` and `/page/privacy`; these two views are kept in case they are rendered
|
||||
directly.)
|
||||
|
||||
### Language keys
|
||||
|
||||
None new; `site.hero_eyebrow` (24-4) and `site.nav_articles` (24-2) are reused.
|
||||
|
||||
### Files
|
||||
|
||||
- Modify: `resources/views/livewire/pages/posts/index.blade.php`,
|
||||
`resources/views/livewire/pages/posts/show.blade.php`, `resources/views/pages/legal.blade.php`,
|
||||
`resources/views/pages/terms.blade.php`, `resources/views/pages/privacy.blade.php`,
|
||||
`resources/css/public.css`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `/posts` shows the section head, a working search (typing filters results after the
|
||||
debounce and shows the count line), text-only post cards and styled pagination when there
|
||||
are more than 10 published posts.
|
||||
- [ ] `/posts/{post}` for a published post shows date, a display-font `<h1>`, the body and a Back
|
||||
button to `/posts`; an unpublished post still returns 404.
|
||||
- [ ] `/page/terms` and `/page/privacy` show the title, the sanitised CMS content (or the
|
||||
coming-soon text) and the last-updated line.
|
||||
- [ ] Each of these pages has exactly one `<h1>` and no horizontal scroll at 1440, 768 and 390px.
|
||||
- [ ] The admin posts screens (`/admin/posts`) are unchanged (they do not use the public layout).
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
id: 24-9
|
||||
title: 24-9 Auth Pages Type and Controls
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: 24
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Apply the redesign's type and form controls to the auth pages (login, forgot password, reset
|
||||
password, confirm password, verify email, two-factor challenge) without changing their
|
||||
composition. The split layout (forest panel with the logo on the start side at ≥1024px, cream form
|
||||
panel with the existing `auth-pattern` background, the language toggle at the top end, and the
|
||||
mobile logo above the form) stays exactly as it is. No public script is loaded on auth pages.
|
||||
|
||||
### Layouts
|
||||
|
||||
In each of `resources/views/components/layouts/auth/split.blade.php`,
|
||||
`resources/views/components/layouts/auth/card.blade.php` and
|
||||
`resources/views/components/layouts/auth/simple.blade.php`:
|
||||
- After `@include('partials.head')` add `@include('partials.site-fonts')` and
|
||||
`@vite(['resources/css/public.css'])`.
|
||||
- Add the class `site-auth` to `<body>` and remove the inline
|
||||
`style="font-family: var(--font-…)"` from `<body>`.
|
||||
|
||||
### CSS — `resources/css/public.css`, scoped under `body.site-auth`
|
||||
|
||||
- `body.site-auth{font-family:"IBM Plex Sans Arabic",system-ui,sans-serif;color:#1E2219}`.
|
||||
- Headings (`h1, h2, [data-flux-heading]`): `font-family:"Markazi Text","Times New Roman",serif;
|
||||
font-weight:700`.
|
||||
- Text inputs (`input[type=email], input[type=password], input[type=text]`) — including those
|
||||
rendered by `flux:input`: min-height 48px, radius 12px, border `1.5px solid rgba(45,54,36,.18)`,
|
||||
white background; focus border `#A68966` and `box-shadow:0 0 0 4px rgba(166,137,102,.2)`, no
|
||||
default outline.
|
||||
- Primary submit buttons (`[data-flux-button][type=submit]` and `button[type=submit]`): radius
|
||||
999px, min-height 48px, background `#A68966`, text `#1E2219`, weight 600, shadow
|
||||
`0 1px 0 rgba(255,255,255,.35) inset, 0 8px 22px -8px rgba(166,137,102,.8)`; hover lift 2px.
|
||||
- Links inside the form panel: colour `#4A5D23`, underline on hover.
|
||||
- Focus ring for every control: `outline:2px solid #A68966; outline-offset:3px`.
|
||||
- Reduced motion: no transitions under `prefers-reduced-motion: reduce`.
|
||||
Inspect the rendered login page to confirm which attributes Flux outputs before writing the
|
||||
selectors; target only elements inside `body.site-auth`.
|
||||
|
||||
### Files
|
||||
|
||||
- Modify: `resources/views/components/layouts/auth/split.blade.php`,
|
||||
`resources/views/components/layouts/auth/card.blade.php`,
|
||||
`resources/views/components/layouts/auth/simple.blade.php`, `resources/css/public.css`.
|
||||
- Do not modify any file under `resources/views/livewire/auth/` or `app/Actions/Fortify/`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `/login` renders in IBM Plex Sans Arabic with the heading in Markazi Text, 48px inputs with a
|
||||
gold focus ring, and a gold pill submit button; the forest logo panel and the cream pattern
|
||||
panel are unchanged in layout.
|
||||
- [ ] Logging in with valid credentials still works for an admin and a client (redirect to their
|
||||
dashboard), and invalid credentials still show the existing error.
|
||||
- [ ] `/forgot-password` shows the same styles and still sends the reset link for a known email.
|
||||
- [ ] The auth pages' HTML contains `public.css` and `class="site-auth`, and does not contain
|
||||
`public.js`.
|
||||
- [ ] The admin and client dashboards contain neither `public.css` nor `site-auth`.
|
||||
- [ ] `/login` has no horizontal scroll at 1440, 768 and 390px.
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
None.
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
id: 24
|
||||
title: 24 Public-Site Redesign (PRD 1.4)
|
||||
status: Ready for Dev
|
||||
date: 2026-10-31
|
||||
parent: null
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Container for the public-site redesign the client approved on 2026-10-31 (mockup v3,
|
||||
`docs/ux-mockup.html`, commit `caec396`). The redesign is presentation-only: no route, model,
|
||||
migration, service, mail or job changes. It restyles the public pages (`/`, `/about`, `/posts`,
|
||||
`/posts/{post}`, `/booking`, `/booking/success`, `/page/{slug}`, `/terms`, `/privacy`) and the
|
||||
auth pages' type and controls. The admin and client dashboards, emails, PDFs and
|
||||
`/forms/nablus-workshop` must not change.
|
||||
|
||||
This parent carries no implementation of its own. Execute the subtasks in ID order.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Subtasks 24-1, 24-2, 24-3, 24-4, 24-5, 24-6, 24-7, 24-8, 24-9 and 24-10 are all Done.
|
||||
|
||||
## Sub-tasks
|
||||
|
||||
- 24-1 Public design foundation (stylesheet, script, fonts, layout)
|
||||
- 24-2 Navigation and footer
|
||||
- 24-3 Signature balance component
|
||||
- 24-4 Home page sections (hero to latest articles)
|
||||
- 24-5 Home booking card (compact booking and day strip)
|
||||
- 24-6 Booking page and booking success
|
||||
- 24-7 About page
|
||||
- 24-8 Articles and legal pages
|
||||
- 24-9 Auth pages type and controls
|
||||
- 24-10 Redesign integration verification
|
||||
@@ -0,0 +1,143 @@
|
||||
# Task Index: Libra
|
||||
**Generated:** 2026-10-31
|
||||
|
||||
| ID | Title | Status | Parent |
|
||||
|----|-------|--------|--------|
|
||||
| 1 | 1 Core Foundation & Infrastructure | Done | — |
|
||||
| 1-1 | 1-1 Project Setup & Database Schema | Done | 1 |
|
||||
| 1-2 | 1-2 Authentication & Role System | Done | 1 |
|
||||
| 1-3 | 1-3 Bilingual Infrastructure (Arabic/English) | Done | 1 |
|
||||
| 1-4 | 1-4 Base UI & Navigation | Done | 1 |
|
||||
| 2 | 2 User Management System | Done | — |
|
||||
| 2-1 | 2-1 Individual Client Account Management | Done | 2 |
|
||||
| 2-2 | 2-2 Company/Corporate Client Account Management | Done | 2 |
|
||||
| 2-3 | 2-3 Account Type Conversion | Done | 2 |
|
||||
| 2-4 | 2-4 Account Lifecycle Management | Done | 2 |
|
||||
| 2-5 | 2-5 Account Creation Email Notification | Done | 2 |
|
||||
| 3 | 3 Booking & Consultation System | Done | — |
|
||||
| 3-1 | 3-1 Working Hours Configuration | Done | 3 |
|
||||
| 3-2 | 3-2 Time Slot Blocking | Done | 3 |
|
||||
| 3-3 | 3-3 Availability Calendar Display | Done | 3 |
|
||||
| 3-4 | 3-4 Booking Request Submission | Done | 3 |
|
||||
| 3-5 | 3-5 Admin Booking Review & Approval | Done | 3 |
|
||||
| 3-6 | 3-6 Calendar File Generation (.ics) | Done | 3 |
|
||||
| 3-7 | 3-7 Consultation Management | Done | 3 |
|
||||
| 3-8 | 3-8 Consultation Reminders | Done | 3 |
|
||||
| 3-9 | 3-9 Guest Booking Request | Done | 3 |
|
||||
| 4 | 4 Case Timeline System | Done | — |
|
||||
| 4-1 | 4-1 Timeline Creation | Done | 4 |
|
||||
| 4-2 | 4-2 Timeline Updates Management | Done | 4 |
|
||||
| 4-3 | 4-3 Timeline Archiving | Done | 4 |
|
||||
| 4-4 | 4-4 Admin Timeline Dashboard | Done | 4 |
|
||||
| 4-5 | 4-5 Client Timeline View | Done | 4 |
|
||||
| 4-6 | 4-6 Timeline Update Notifications | Done | 4 |
|
||||
| 5 | 5 Posts/Blog System | Done | — |
|
||||
| 5-1 | 5-1 Post Creation & Editing | Done | 5 |
|
||||
| 5-2 | 5-2 Post Management Dashboard | Done | 5 |
|
||||
| 5-3 | 5-3 Post Deletion | Done | 5 |
|
||||
| 5-4 | 5-4 Public Posts Display | Done | 5 |
|
||||
| 5-5 | 5-5 Post Search | Done | 5 |
|
||||
| 6 | 6 Admin Dashboard | Done | — |
|
||||
| 6-1 | 6-1 Dashboard Overview & Statistics | Done | 6 |
|
||||
| 6-2 | 6-2 Analytics Charts | Done | 6 |
|
||||
| 6-3 | 6-3 Quick Actions Panel | Done | 6 |
|
||||
| 6-4 | 6-4 Data Export - User Lists | Done | 6 |
|
||||
| 6-5 | 6-5 Data Export - Consultation Records | Done | 6 |
|
||||
| 6-6 | 6-6 Data Export - Timeline Reports | Done | 6 |
|
||||
| 6-7 | 6-7 Monthly Statistics Report | Done | 6 |
|
||||
| 6-8 | 6-8 System Settings | Done | 6 |
|
||||
| 6-9 | 6-9 Legal Pages Editor | Done | 6 |
|
||||
| 6-10 | 6-10 Audit Log Viewer | Done | 6 |
|
||||
| 7 | 7 Client Dashboard | Done | — |
|
||||
| 7-1 | 7-1 Client Dashboard Overview | Done | 7 |
|
||||
| 7-2 | 7-2 My Consultations View | Done | 7 |
|
||||
| 7-3 | 7-3 My Cases/Timelines View (Dashboard Integration) | Done | 7 |
|
||||
| 7-4 | 7-4 My Profile View | Done | 7 |
|
||||
| 7-5 | 7-5 New Booking Interface | Done | 7 |
|
||||
| 7-6 | 7-6 Booking Limit Indicator | Done | 7 |
|
||||
| 8 | 8 Email Notification System | Done | — |
|
||||
| 8-1 | 8-1 Email Infrastructure Setup | Done | 8 |
|
||||
| 8-2 | 8-2 Welcome Email (Account Created) | Done | 8 |
|
||||
| 8-3 | 8-3 Booking Submitted Confirmation | Done | 8 |
|
||||
| 8-4 | 8-4 Booking Approved Email | Done | 8 |
|
||||
| 8-5 | 8-5 Booking Rejected Email | Done | 8 |
|
||||
| 8-6 | 8-6 Consultation Reminder (24 Hours) | Done | 8 |
|
||||
| 8-7 | 8-7 Consultation Reminder (2 Hours) | Done | 8 |
|
||||
| 8-8 | 8-8 Timeline Update Notification | Done | 8 |
|
||||
| 8-9 | 8-9 Admin Notification - New Booking | Done | 8 |
|
||||
| 8-10 | 8-10 Admin Notification - System Events | Done | 8 |
|
||||
| 9 | 9 Design & Branding Implementation | Done | — |
|
||||
| 9-1 | 9-1 Color System Implementation | Done | 9 |
|
||||
| 9-2 | 9-2 Typography System | Done | 9 |
|
||||
| 9-3 | 9-3 Logo Integration | Done | 9 |
|
||||
| 9-4 | 9-4 Component Styling - Buttons | Done | 9 |
|
||||
| 9-5 | 9-5 Component Styling - Forms | Done | 9 |
|
||||
| 9-6 | 9-6 Component Styling - Cards & Containers | Done | 9 |
|
||||
| 9-7 | 9-7 Navigation & Footer Styling | Done | 9 |
|
||||
| 9-8 | 9-8 RTL/LTR Layout Perfection | Done | 9 |
|
||||
| 9-9 | 9-9 Responsive Design Implementation | Done | 9 |
|
||||
| 9-10 | 9-10 Accessibility Compliance | Done | 9 |
|
||||
| 9-11 | 9-11 Animations & Micro-interactions | Done | 9 |
|
||||
| 10 | 10 Brand Color Refresh | Done | — |
|
||||
| 10-1 | 10-1 Core CSS Theme Update | Done | 10 |
|
||||
| 10-2 | 10-2 Blade Component Color Migration | Done | 10 |
|
||||
| 10-3 | 10-3 Email Template Color Update | Done | 10 |
|
||||
| 10-4 | 10-4 PDF Template Color Update | Done | 10 |
|
||||
| 10-5 | 10-5 Logo and SVG Assets Update | Done | 10 |
|
||||
| 10-6 | 10-6 Documentation Update | Done | 10 |
|
||||
| 11 | 11 Guest Booking | Done | — |
|
||||
| 11-1 | 11-1 Database Schema & Model Updates | Done | 11 |
|
||||
| 11-2 | 11-2 Public Booking Form with Custom Captcha | Done | 11 |
|
||||
| 11-3 | 11-3 Guest Email Notifications & Admin Integration | Done | 11 |
|
||||
| 11-4 | 11-4 Documentation Updates | Done | 11 |
|
||||
| 12 | 12 Branding Refresh (Logo + Color Scheme) | Done | — |
|
||||
| 12-1 | 12-1 Logo Asset Deployment and CSS Layout Updates | Done | 12 |
|
||||
| 12-2 | 12-2 Core CSS Theme Update - Dark Charcoal & Warm Gold Palette | Done | 12 |
|
||||
| 12-3 | 12-3 Blade Component Color Migration - Dark Charcoal & Warm Gold | Done | 12 |
|
||||
| 12-4 | 12-4 Email Template Color Update - Dark Charcoal & Warm Gold | Done | 12 |
|
||||
| 12-5 | 12-5 PDF Template Color Update - Dark Charcoal & Warm Gold | Done | 12 |
|
||||
| 12-6 | 12-6 Brand Documentation Update - Dark Charcoal & Warm Gold | Done | 12 |
|
||||
| 13 | 13 Authentication Pages Design Enhancement | Done | — |
|
||||
| 13-1 | 13-1 Language Toggle Visibility Enhancement | Done | 13 |
|
||||
| 13-2 | 13-2 Auth Layout Split Design Update | Done | 13 |
|
||||
| 13-3 | 13-3 Subtle Background Pattern Implementation | Done | 13 |
|
||||
| 13-4 | 13-4 Auth Pages Migration to Split Layout | Done | 13 |
|
||||
| 13-5 | 13-5 Visual QA and Refinement | Done | 13 |
|
||||
| 14 | 14 Home Page Redesign | Done | — |
|
||||
| 14-1 | 14-1 Hero Section Implementation | Done | 14 |
|
||||
| 14-2 | 14-2 About Section with Lawyer Profile | Done | 14 |
|
||||
| 14-3 | 14-3 Services Section | Done | 14 |
|
||||
| 14-4 | 14-4 Values Section | Done | 14 |
|
||||
| 14-5 | 14-5 Latest Posts Section | Done | 14 |
|
||||
| 14-6 | 14-6 Footer Contact Information Update | Done | 14 |
|
||||
| 15 | 15 Potential Clients Management | Done | — |
|
||||
| 15-1 | 15-1 Database Schema & Model Setup | Done | 15 |
|
||||
| 15-2 | 15-2 Potential Clients List with Type Filter | Done | 15 |
|
||||
| 15-3 | 15-3 CRUD Operations for Potential Clients | Done | 15 |
|
||||
| 16 | 16 About Us Page | Done | — |
|
||||
| 16-1 | 16-1 About Page Layout & Hero Section | Done | 16 |
|
||||
| 16-2 | 16-2 Vision & Mission Section | Done | 16 |
|
||||
| 16-3 | 16-3 Values Section | Done | 16 |
|
||||
| 16-4 | 16-4 Goals Section | Done | 16 |
|
||||
| 16-5 | 16-5 Legal Services Section | Done | 16 |
|
||||
| 16-6 | 16-6 Scholarship Aspiration Section (REMOVED from production 2026-01-11 — do not re-implement) | Done | 16 |
|
||||
| 17 | 17 Nablus Workshop Registration Form | Done | — |
|
||||
| 17-1 | 17-1 Registration mailable and email template | Done | 17 |
|
||||
| 17-2 | 17-2 Standalone registration page, form, and submit wiring | Done | 17 |
|
||||
| 18 | 18 Nablus Workshop Form - Image Sizing Fix | Done | — |
|
||||
| 19 | 19 Nablus Workshop Form - Remove Logo, Shrink Flyer Further | Done | — |
|
||||
| 20 | 20 Nablus Workshop Form - Match Site Background and Card Styling | Done | — |
|
||||
| 21 | 21 Nablus Workshop Form - Flyer Size Adjustment | Done | — |
|
||||
| 22 | 22 Fix Footer Address - Add Missing Street Name | Done | — |
|
||||
| 23 | 23 Fix AdminNotificationService Carbon TypeError Masking Exceptions | Done | — |
|
||||
| 24 | 24 Public-Site Redesign (PRD 1.4) | Ready for Dev | — |
|
||||
| 24-1 | 24-1 Public Design Foundation (Stylesheet, Script, Fonts, Layout) | Ready for Dev | 24 |
|
||||
| 24-2 | 24-2 Navigation and Footer | Ready for Dev | 24 |
|
||||
| 24-3 | 24-3 Signature Balance Component | Ready for Dev | 24 |
|
||||
| 24-4 | 24-4 Home Page Sections (Hero to Latest Articles) | Ready for Dev | 24 |
|
||||
| 24-5 | 24-5 Home Booking Card (Compact Booking and Day Strip) | Ready for Dev | 24 |
|
||||
| 24-6 | 24-6 Booking Page and Booking Success | Ready for Dev | 24 |
|
||||
| 24-7 | 24-7 About Page | Ready for Dev | 24 |
|
||||
| 24-8 | 24-8 Articles and Legal Pages | Ready for Dev | 24 |
|
||||
| 24-9 | 24-9 Auth Pages Type and Controls | Ready for Dev | 24 |
|
||||
| 24-10 | 24-10 Redesign Integration Verification | Ready for Dev | 24 |
|
||||
@@ -5,6 +5,7 @@
|
||||
**Last synced:** 2026-09-28 — 19 QA passed (logo removed, flyer max-h-40 confirmed, 7/7 tests), Done
|
||||
**Last synced:** 2026-09-28 — 20 QA passed (auth-pattern/bg-background/card/text-body confirmed in compiled CSS and Blade, 7/7 tests), Done
|
||||
**Last synced:** 2026-09-28 — 21 QA passed (flyer max-h-56 confirmed in Blade and compiled CSS, HTTP 200, 7/7 tests), Done
|
||||
**Last synced:** 2026-10-31 — added tasks 24, 24-1…24-10 (public-site redesign, PRD 1.4); readiness review same day: 6 task-level fixes, all 11 promoted to Ready for Dev
|
||||
|
||||
| ID | Title | Status |
|
||||
|----|-------|--------|
|
||||
@@ -135,3 +136,14 @@
|
||||
| 21 | 21 Nablus Workshop Form - Flyer Size Adjustment | Done |
|
||||
| 22 | 22 Fix Footer Address - Add Missing Street Name | Done |
|
||||
| 23 | 23 Fix AdminNotificationService Carbon TypeError Masking Exceptions | Done |
|
||||
| 24 | 24 Public-Site Redesign (PRD 1.4) | Ready for Dev |
|
||||
| 24-1 | 24-1 Public Design Foundation (Stylesheet, Script, Fonts, Layout) | Ready for Dev |
|
||||
| 24-2 | 24-2 Navigation and Footer | Ready for Dev |
|
||||
| 24-3 | 24-3 Signature Balance Component | Ready for Dev |
|
||||
| 24-4 | 24-4 Home Page Sections (Hero to Latest Articles) | Ready for Dev |
|
||||
| 24-5 | 24-5 Home Booking Card (Compact Booking and Day Strip) | Ready for Dev |
|
||||
| 24-6 | 24-6 Booking Page and Booking Success | Ready for Dev |
|
||||
| 24-7 | 24-7 About Page | Ready for Dev |
|
||||
| 24-8 | 24-8 Articles and Legal Pages | Ready for Dev |
|
||||
| 24-9 | 24-9 Auth Pages Type and Controls | Ready for Dev |
|
||||
| 24-10 | 24-10 Redesign Integration Verification | Ready for Dev |
|
||||
|
||||
Reference in New Issue
Block a user