After adding the products dropdown (7 categories + 27 subcategory
links), the mobile menu was taller than typical phone screens
(~640px on iPhone SE). Without overflow handling, users on
short screens could not reach the bottom items (ผลงาน, ติดต่อเรา).
Added to mobile menu container:
- max-h-[calc(100vh-4rem)]: cap height at viewport minus header
- overflow-y-auto: enable internal scrollbar when content overflows
- overscroll-contain: prevent scroll chain to background page
(iOS Safari specific)
Menu is now fully scrollable within its own container — page
content underneath stays still while user scrolls through menu
items.
The mobile menu previously had only flat links (หน้าแรก, เกี่ยวกับเรา,
สินค้าทั้งหมด, ผลงาน, ติดต่อเรา) while the desktop menu had a mega
dropdown with 7 product categories (ระบบท่อ, ฉนวนหุ้มท่อ, เครื่องเชื่อมท่อ,
ระบบน้ำ, อุปกรณ์ปรับอากาศ, อุปกรณ์ดับเพลิง, ระบบรั้ว) and 27
subcategory links.
Updated mobile menu in BaseLayout.astro to mirror the desktop
structure: "สินค้าทั้งหมด" is now a collapsible button that
expands to show all 7 categories and their 27 subcategory links,
plus a "ดูสินค้าทั้งหมด →" CTA at the bottom.
Toggle behavior:
- Click button: opens submenu, rotates chevron 180°, sets
aria-expanded="true"
- Click again: closes submenu, returns chevron
- aria-controls="mobile-products-submenu" for accessibility
Reverted Header.astro changes — that file is not actually used
by the site (BaseLayout.astro has its own inline header with the
real desktop mega menu and mobile menu).
Mobile menu now has parity with desktop navigation structure.
pipe-coupling.astro has a FAQ UI section (4 Q&A) but was missing
the FAQPage structured data. Added faq prop to BaseLayout so the
schema renders automatically via the existing JsonLd.astro
component.
Now all 3 pages with FAQ UI (realflex, เทอร์โมเบรค-thermobreak,
pipe-coupling) have matching FAQPage JSON-LD schema, which helps
Google rich results + GEO (Google AI Overview, Perplexity, etc.)
surface the FAQ content.
FAQPage schema renders as:
{
"@type": "FAQPage",
"mainEntity": [
{"@type": "Question", "name": "...", "acceptedAnswer": {"@type": "Answer", "text": "..."}},
...
]
}
Two fixes:
1 Deleted 7 product photos user requested:
- rockwool/gallery-8.jpg
- microfiber/gallery-9.jpg
- maxflex/gallery-2.jpg
- aeroflex/gallery-7.jpg
- aeroflex/gallery-15.jpg
- armflex/gallery-6.jpg
- armflex/gallery-7.jpg
Also updated gallery HTML in 5 pages to skip the deleted image
numbers. After deletion: rockwool=10, microfiber=9, maxflex=8,
aeroflex=13, armflex=5.
2) Restored Product Details section for armflex, aeroflex, and
maxflex. These 3 pages had their content stripped earlier in
the session (only kept Hero + Gallery + CTA). Pulled the
original Product Details from commit 17f4eb7 (which had the
full data: features, specs, certifications, applications,
water-vapor resistance values, etc.).
armflex: 10.3KB restored
aeroflex: 9.6KB restored
maxflex: 10.1KB restored
EOF
)
User provided 61 additional product photos across 6 insulation
brands. Added a responsive image gallery section (before CTA)
to each of these product pages:
- armflex.astro: 7 photos
- aeroflex.astro: 15 photos
- maxflex.astro: 9 photos
- เทอร์โมเบรค-thermobreak.astro: 9 photos
- rockwool.astro: 11 photos
- microfiber.astro: 10 photos
Files renamed to gallery-1.jpg ... gallery-N.jpg format in
public/images/{brand}/. Each image is clickable (opens full
size in new tab), uses lazy loading, and has hover zoom.
Gallery section layout:
- 2 columns on mobile, 3 on tablet, 4 on desktop
- Title: "แกลอรี่ภาพสินค้า"
- Subtitle: "ภาพสินค้าจริงจากงานติดตั้ง — คลิกเพื่อดูภาพขนาดเต็ม"
Found 3 mismatches between all-products.astro card images and
the actual hero image of each product page:
- ROCKWOOL: prod_0.png → cool-n-comfort-rl.jpg (matches hero)
- MICROFIBER: prod_0.jpg → microfiber-enf.jpg (matches hero)
- SCG: prod_0.jpg → scg-crb-g.jpg (matches hero)
Other 22 products were already in sync. All 27 products now
show their canonical hero image on the all-products page.
User provided screenshot of RNT Smart Clamp MJG80A (with SUS304
material, NBR seal, 89.1mm pipe OD, 67.8-91.9mm range) as the
canonical hero image for this product.
Changes:
- public/images/pipe-coupling/mjg80a-hero.png: new hero image
(copied from user's Desktop screenshot)
- pipe-coupling.astro: hero <img src> updated to mjg80a-hero.png
- all-products.astro: card image updated to mjg80a-hero.png
Other 5 model images (mjg/mjh/mjd/mjer/mjcx/rnt-e009) unchanged
as those are individual model photos from ranotech.com.
Removed the spec table that was at the bottom of each product
card. Now each card just shows: image, name, tagline, and
description paragraphs.
Size: 35 products still showing, 0 spec tables.
- rockwool: 62KB → 53KB
- microfiber: 60KB → 55KB
- scg: 57KB → 53KB
Crawled full content from each of 35 product pages on supplier
site (3t-insulation.com). For each product card on the 3 brand
pages, now show:
- Full Thai product name (e.g. "ROCKDUCT (ProRox BL)" instead of
just "ROCKDUCT")
- Short tag-line describing use case
- Real product description (2 paragraphs from supplier, in Thai)
- Spec table (density, thickness, dimensions, fire rating, etc.)
filtered to remove product option noise
Each product card is now a real catalog entry instead of a name
+ image. Source data is /tmp/product_details.json (35 entries).
Stats per page:
- rockwool: 11 products, 41 spec entries, 62KB
- microfiber: 12 products, 24 spec entries, 60KB
- scg: 12 products, 17 spec entries, 57KB
Two fixes:
1) Header.astro menu items for ROCKWOOL/MICROFIBER/SCG were
placed AFTER the closing array bracket - not visible in dropdown.
Moved INSIDE the 'ฉนวนและรั้ว' items array.
2) Product images were generic logos/QR codes. Replaced hero
images with actual product photos (1200x800) from supplier
WooCommerce galleries.
Also added footer links.
Replace thermobreak-solarblock.png with new thermobreak-main.jpg
across product page, all-products, and homepage (6 refs total).
New image copied to public/images/thermobreak/.
Blog images (thermobreak-hero.jpg, etc.) left unchanged.
Old CTAs (e.g. 'สนใจสินค้าของเรา?', 'สอบถามราคาและสั่งซื้อ',
'sนใจรั้วเทวดา?') were still present above the canonical CTA
section added in 17f4eb7. Each page now has exactly one CTA.
Deleted section types:
- 12x section gradient (สนใจสินค้าของเรา?)
- 5x section gradient (สนใจสินค้านี้? — different buttons)
- 3x box bg-primary-50 (สอบถามราคาและสั่งซื้อ)
- 2x accent gradient sections
- 1x div-based (ตู้ดับเพลิง — special format)
Verified: new CTA intact, no duplicate headings, build 40/40 OK,
HTML render: 20/20 have correct single CTA with 2 buttons.
Two changes driven by content review:
1) @JPPSELECTION → JPPSELECTION in user-visible text only
- 19 page files: drop @ from inline JPPSELECTION in <p> tags
- BaseLayout.astro + Footer.astro: drop @ from companyInfo.line
(rendered as "LINE: @JPPSELECTION" in mobile CTA + footer)
- URL line.me/ti/p/~JPPSELECTION left unchanged (the @ belongs
in the URL per line.me convention)
2) Add missing CTA section to all 20 product pages
- 16 pages had no CTA at all
- 4 pages (armflex, aeroflex, maxflex, xy-lent) had bespoke
CTA variants; replaced with canonical template
- Template copied from ppr-thai-ppr
- CTA inserted before </main> in all 20 product pages
Verified rendered HTML:
- @JPPSELECTION in <p> text = 0 across all 20 pages
- "LINE: JPPSELECTION" rendered in footer / mobile CTA
- heading + contact + line buttons present in all 20
Files touched: 30
The SVG path used for the Line chat button in the canonical template
contained a malformed curve command — a stray '0' inserted into a
relative bezier segment that broke the path into an unintended
sub-path. Result: the icon rendered as a misaligned blob instead of
the LINE wordmark glyph.
Restored the canonical path from ท่อ-ppr-thai-ppr (the untouched
stash reference) for all 20 product hero pages:
วาล์ว-valve, ท่อ-syler, ตู้ดับเพลิง, armflex, grilles, aeroflex,
durgo-avvs, maxflex, pipe-coupling, realflex, water-pump,
water-treatment, ท่อ-xy-lent, ระบบรั้วไวน์แมน, รั้วเทวดา,
หัวจ่าย-ball-jet, เครื่องเชื่อม-hdpe, เครื่องเชื่อม-ppr,
เทอร์โมเบรค, เม็กกรู๊ฟ-คับปลิ้ง
Path length 1079 chars, byte-for-byte identical to the working
template (stash) version. Verified against rendered HTML: all 20
pages now have the correct path; no other markup changed.
Two prior commits (d8ff358, 9653fcb) claimed to rewrite heroes with a
TEXT-LEFT template, but the source-order check in the prior apply step
was misread. The committed heroes were still IMAGE-LEFT, with the
sticky wrapper around the image and the data-price-button still
rendering where the page has no #pricelist section.
This commit rewrites the hero section of 12 pages against the actual
HEAD~1 (9653fcb) source and the HEAD (d8ff358) source for วาล์ว-valve
to apply the canonical TEXT-LEFT template correctly:
- text container (pill, title, features, buttons) before image
- sticky wrapper moved to the image column
- data-price-button removed where id="pricelist" is missing
- max-w-md mx-auto lg:max-w-none classes restored on image + card
Pages: วาล์ว-valve, realflex, water-pump, water-treatment, ท่อ-xy-lent,
ระบบรั้วไวน์แมน, รั้วเทวดา, หัวจ่าย-ball-jet, เครื่องเชื่อม-hdpe,
เครื่องเชื่อม-ppr, เทอร์โมเบรค, เม็กกรู๊ฟ-คับปลิ้ง
Verified rendered HTML: all 12 pages have TEXT-LEFT order in DOM,
data-price-button present only where id="pricelist" exists.
- Extract data from each page (pill, title, image, features, hasPricelist)
- Generate hero from canonical template (text-LEFT, image-RIGHT, animated bg)
- Remove dead <Header slot=Footer slot= StickyBottomCTA slots (BaseLayout renders defaults)
- Remove dead data-price-button when id="pricelist" missing (auto-detect hides it)
- Drop legacy justify-center/max-w-md workarounds; use canonical classes
- Apply consistent TEXT-LEFT order across all product heroes
- Drop unused mobile-only sections in ตู้ดับเพลิง (page now follows template)
- Add overflow-x-clip on header/footer (submenu overflow fix)
- Add .submenu-anchor class for submenu positioning
Verified: 9 pages render with valid HTML, TEXT-LEFT, correct features, no dead links.
The previous doc assumed a Gitea Actions workflow (which requires a
self-hosted act_runner that we don't have, hence the 'No matching
online runner with label: ubuntu-latest' error).
The actual setup is much simpler: a Gitea Webhook pointing at the
deploy endpoint. No runner, no workflow file. Setup is one-time in
Settings -> Webhooks -> Add Webhook.
Documents:
- The push -> webhook -> deploy -> EasyPanel flow
- Exact payload URL, method, content type, events
- Test Delivery verification step
- Why Gitea Actions doesn't work without act_runner
- Troubleshooting: push not triggering, build failure modes
(nixpacks 'No start command', node 20 vs 22), and a curl recipe
for redeploying without a code change.
The workflows were never able to run — Gitea Actions has no managed
runners the way GitHub does, and 'ubuntu-latest' isn't a label this
self-hosted Gitea instance can match. Every push to main showed the
job as 'No matching online runner with label: ubuntu-latest' in
the Actions tab.
EasyPanel already watches the 'main' branch and rebuilds on push
(Dockerfile-based, git source). The CI step was duplicative and
produced noise in the Actions tab without running anything.
If a real CI step is needed later (lint, build artifact, test), a
Gitea act_runner has to be installed on a server, registered with
labels like 'self-hosted:host:linux', and the workflow has to use
those labels. Skipping that for now.
Files removed:
.gitea/workflows/build-and-deploy.yml
.gitea/workflows/lint.yml
.gitea/ (empty after removal)
Three mobile issues fixed:
1. Categories section: <640px (mobile) now 1 column. Previously it was
already 2 columns at the smallest breakpoint which made the tiles feel
cramped. Uses Tailwind's default sm: (640px) for the 1->2 transition,
not a custom min-[500px].
2. Footer mobile layout (<1024px): three centered rows inside the same
max-w-7xl container.
- Row 1: Company Info (1 col, max-w-md, centered)
- Row 2: Quick Links + สินค้ายอดนิยม (2 cols, max-w-2xl, centered)
- Row 3: ติดต่อเรา (1 col, max-w-sm outer, max-w-xs button column)
The narrow inner max-widths are deliberate: a full-width row of
contact buttons looks stretched, especially the bottom one with the
โทรเลย / แอดไลน์ buttons.
3. Horizontal overflow bug: data-animate='fade-left' and 'fade-right'
children sit at translateX(30px) / translateX(-30px) in their
initial state, before the IntersectionObserver fires. On small
viewports this pushes the page 30px wider than the viewport and
reveals a horizontal scrollbar as soon as the user loads the page.
Adding overflow-x-clip on <footer> keeps the off-screen translation
contained inside the footer.
Astro 6.x requires Node >=22.12.0. The previous Dockerfile used
node:20-alpine, which the Astro CLI rejected with:
Node.js v20.20.2 is not supported by Astro!
Please upgrade Node.js to a supported version: ">=22.12.0"
EasyPanel pulled the change, ran the build, and failed at
`RUN npm run build`. Bumping to node:22-alpine fixes it.
Also added two 'common failure' sections to docs/ci-setup.md
covering the nixpacks 'No start command' and Node version
mismatch errors we just hit.
Nixpacks auto-detect could not find a 'start' script in package.json
and bailed out. Astro builds to static files in dist/ — there is no
Node server to start. Switching to a Dockerfile + nginx fixes the
'No start command could be found' error from EasyPanel.
The workflow also pointed at the source-code branch, but the panel's
git source ref for the dealplustech-astro service is 'main', so the
trigger was firing for the wrong ref. Both workflows now run on push
to main.
- Dockerfile: multi-stage node:20-alpine build + nginx:1.27-alpine serve
- nginx.conf: gzip, security headers, 1-year cache for hashed assets,
try_files fallback for UTF-8 slugs (Astro file-based routing)
- .dockerignore: keep build context small (skip CI, docs, .gitea, IDE)
- build-and-deploy.yml + lint.yml: branch source-code -> main
- docs/ci-setup.md: corrected project + service names (customerwebsite
/ dealplustech-astro), documented the Dockerfile rationale, added a
note for the 'Failed to sync changes' server-side error
Replaces the old EASYPANEL_WEBHOOK_URL flow with a direct tRPC call
to the panel, using three minimal secrets the operator fills in:
EASYPANEL_TOKEN - bearer token from EasyPanel profile
EASYPANEL_PROJECT_NAME - project name in the dashboard
EASYPANEL_SERVICE_NAME - service name inside that project
The endpoint (https://panelwebsite.moreminimore.com/api/trpc/services.
app.deployService) is hardcoded because the panel URL does not change.
Payload uses tRPC's wrapped-json shape: {"json":{"projectName":...,
"serviceName":...}}.
The build still runs and the dist/ artifact still uploads when any
secret is empty — only the trigger step is skipped with a warning.
Also adds docs/ci-setup.md explaining the three secrets, the service
type requirement (must be 'app' / Dockerfile-based), and a curl recipe
for testing the payload shape locally before pushing.
Two workflows under .gitea/workflows/:
- build-and-deploy.yml: on push to source-code, install deps, run
astro build, then POST the dist/ SHA + ref to EASYPANEL_WEBHOOK_URL
(read from repo secret) so EasyPanel redeploys. Uploads dist/ as a
7-day artifact as a fallback. Gracefully warns if the secret is empty
so contributors can run the build job without breaking.
- lint.yml: lightweight build check on every push + PR so syntax /
missing-image errors surface before the deploy workflow runs.
To enable auto-deploy:
1. Set EASYPANEL_WEBHOOK_URL secret in Gitea repo settings
2. Configure EasyPanel service to source from this repo + branch
source-code, build command 'npm run build', output 'dist'
## homepage (index.astro)
- Drop '500+ รายการสินค้า' from stat badges and rebuild the trust-badges
section to show only 15+ ปีประสบการณ์, 400+ ลูกค้าทั่วประเทศ, 98%
ลูกค้าพึงพอใจ — bigger numbers (text-5xl/6xl), no icons, counter animation
- Add 'ทำไมเลือกเรา' section (4 cards: ส่งฟรี กทม./ปริมณฑล, Lead time 1-3
วัน, ราคาโรงงาน, ทีมช่างแนะนำ) — no icons, primary/accent border hover
- Add 'หมวดสินค้า' section (8 tiles: 7 categories + 'สินค้าทั้งหมด')
placed after 'สินค้าแนะนำ' — each tile is a real product photo with
dark gradient overlay and a CTA link to /all-products?filter=<id>
- Reorder: Hero → ทำไมเลือกเรา → สินค้าแนะนำ → หมวดสินค้า → Stats →
บทความล่าสุด → CTA
## all-products (filter from URL)
- Script now reads ?filter=<id> on load and applies it without rewriting
the URL, then on click updates both the filter and the URL via
history.replaceState so the back/forward buttons work
## footer (BaseLayout.astro)
- Replace productLinks with the curated 6 popular products: ไทยพีพีอาร์,
เทอร์โมเบรค, กริลแอร์, หัวจ่ายแอร์ Ball Jet, ท่อ HDPE, ท่อ Syler
## about-us
- Stats: 10+/1000+/500+ replaced with 15+ / 400+ + counter animation,
bigger numbers, rounded-3xl + shadow (matches home)
- Why Choose Us: rebuilt with the same 4 cards + same style as home's
'ทำไมเลือกเรา' (no icons, pill header, larger h2 + subtitle)
## all-products.astro
Remove 2 broken product links (Poloplast, PVC + fittings) and align the
remaining 24 products with the header main menu (BaseLayout.astro):
- Reorganise categories to match the 7 header categories (ท่อพีพีอาร์,
เครื่องเชื่อมท่อ, ระบบน้ำ, อุปกรณ์ปรับอากาศ, อุปกรณ์ดับเพลิง,
ฉนวนหุ้มท่อ, ระบบรั้ว) instead of the old ad-hoc split
- Add Ball Jet to "อุปกรณ์ปรับอากาศ" so the page matches the menu
- Re-point 6 product images to each product page's actual hero/feature
image so the cards show what the linked page shows:
- HDPE, Syler, HDPE welding, PPR welding, Ball Jet, Vineman
## index.astro (homepage)
Drop the <time>...</time> block from the "บทความล่าสุด" article cards
to match the blog index (no dates, just tag chips).
Bring in latest changes:
- feat: add price list PDFs and pricelist sections for pipe products
- fix(seo): hardcoded dealplustech.co.th URLs in JSON-LD
- refactor(ball-jet): add product page + cleanup
- fix(grilles): remove redundant hero text
- refactor: migrate blog from EmDash CMS to Astro content collections (no longer using EmDash)
- chore: remove orphan images and PDFs
The JSON-LD Product schema in 6 product pages had hardcoded
URLs to dealplustech.co.th, but astro.config.mjs configures the
site as dealplustech.com. When this project replaces the old
site, those URLs would 404.
Changes:
- Replace `https://dealplustech.co.th/images/...` with relative
`/images/...` paths (resolved by Astro at build time)
- Replace `https://dealplustech.co.th/<page>` with
`https://dealplustech.com/<page>` (canonical domain)
- Special case: vineman schema `image` referenced an .svg that
doesn't exist locally — switch to the .jpg version that does
(also used by the page body) at
/images/products-raw/vineman/ระบบรั้วไวน์แมน-Vineman-e1613286324569-1024x880.jpg
Files changed:
- realflex.astro
- วาล์ว-valve.astro
- water-treatment.astro
- เครื่องเชื่อม-hdpe.astro
- ระบบรั้วไวน์แมน.astro
- เทอร์โมเบรค-thermobreak.astro
The HTML tables for dimensions and airflow performance are less
complete than the user-supplied spec images (which include more
data: bigger size range, more flow rates, unit annotations).
Remove the tables — the spec images alone are clearer and more
informative for the customer.
The 7 product photos in commit 47f28cd were scraped from
sapaengineer.com without copyright clearance. Replace them
with 4 user-supplied photos from the LINE album:
- ball-jet-main.jpg (478x542) — original main product photo
- ball-jet-main-hd.jpg (1764x2000) — 4x upscale for hero
- ball-jet-front.jpg — front view of the diffuser
- ball-jet-specs.jpg — dimensions + parameters table
- ball-jet-performance.jpg — airflow performance table
Page now uses:
- Hero: ball-jet-main-hd (upscaled from user's photo)
- Gallery: ball-jet-main-hd + ball-jet-front
- New section: ขนาดและพารามิเตอร์ (Dimensions & Parameters)
- Spec image + readable HTML table (sizes 4"-10")
- D / A / B / C / E dimensions in mm
- New section: ตารางสมรรถนะการจ่ายลม (Airflow Performance)
- Performance image + HTML table (sizes 4"-10", 5 flow rates each)
- Columns: Air Volume (CMH), Outlet Velocity (m/s), Pressure
Loss (Pa), Throw Distance (m), Noise (dB(A))
New product page at /หัวจ่าย-ball-jet covering Ball Spout Jet
Diffuser (JD Series) — long-throw ceiling air diffuser for
high-ceiling commercial/industrial buildings.
Content sourced from sapamaket.com, sapaengineer.com (official),
superaircool.com technical specs, and the user's brief. The page
covers:
- Hero with full feature badges (360° rotation, 45° nozzle, sizes,
materials)
- Product description, features, technical specs, applications,
advantages
- Image gallery (7 photos scraped from the official SAPA source at
sapaengineer.com — public product marketing images, used to
illustrate the product)
- 5-question FAQ
- Contact CTA
Nav updated: added หัวจ่ายแอร์ Ball Jet as the 3rd subcategory under
'อุปกรณ์ปรับอากาศ' in BaseLayout.astro.
No PDF pricelist (none provided by source). No price data displayed
(per user request — pricing to be confirmed separately).
The กริลแอร์ floating card image remains in the homepage hero,
but the 'กริลแอร์คุณภาพสูง' text label that previously overlaid the
card has been removed.