Render Modal as real markup; drain scripts via CaptureScript (#2742)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Paweł Kuna
2026-08-03 00:55:32 +02:00
committed by GitHub
co-authored by StarDev
parent 66dc336726
commit 575d68572f
200 changed files with 10670 additions and 10096 deletions
@@ -1,49 +1,56 @@
---
// The "active" class is hardcoded on the Home link in the Liquid source — it is
// NOT derived from the current page, so every marketing page marks Home active.
// The relative base is "../" (page|relative for the one-level-deep marketing pages).
import NavbarLogo from '../navbar/NavbarLogo.astro'
// "active" is hardcoded on Home — not derived from the current page.
// Relative base is "../" for one-level-deep marketing pages.
import NavbarLogo from '../navbar/NavbarLogo.astro';
const base = '..'
const base = '..';
---
<!-- BEGIN MARKETING NAVBAR -->
<header class="navbar navbar-expand-lg navbar-transparent py-3">
<div class="container">
<NavbarLogo href={base} />
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle primary navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarTogglerDemo01">
<nav aria-label="Primary">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link active" href={`${base}/marketing`}><span class="nav-link-title">Home</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/testimonials.html`}><span class="nav-link-title">Testimonials</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/pricing.html`}><span class="nav-link-title">Pricing</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/about.html`}><span class="nav-link-title">About</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/text.html`}><span class="nav-link-title">Text</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/hero.html`}><span class="nav-link-title">App</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/real-estate.html`}><span class="nav-link-title">Real estate</span></a>
</li>
<li class="nav-item ms-4">
<a href="#" class="btn btn-primary">Buy now</a>
</li>
</ul>
</nav>
</div>
</div>
<div class="container">
<NavbarLogo href={base} />
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarTogglerDemo01"
aria-controls="navbarTogglerDemo01"
aria-expanded="false"
aria-label="Toggle primary navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarTogglerDemo01">
<nav aria-label="Primary">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link active" href={`${base}/marketing`}><span class="nav-link-title">Home</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/testimonials.html`}><span class="nav-link-title">Testimonials</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/pricing.html`}><span class="nav-link-title">Pricing</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/about.html`}><span class="nav-link-title">About</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/text.html`}><span class="nav-link-title">Text</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/hero.html`}><span class="nav-link-title">App</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href={`${base}/marketing/real-estate.html`}><span class="nav-link-title">Real estate</span></a>
</li>
<li class="nav-item ms-4">
<a href="#" class="btn btn-primary">Buy now</a>
</li>
</ul>
</nav>
</div>
</div>
</header>
<!-- END MARKETING NAVBAR -->
+44 -43
View File
@@ -1,50 +1,51 @@
---
// Inlines ui/marketing/browser.html (the browser chrome) and
// ui/responsive-image.html (the preview image). site.previewUrl is the browser
// input URL; the "../" asset base matches the marketing pages' depth (page|relative = "..").
import Icon from '@ui/Icon.astro'
import { site } from '@shared/lib/site'
import Icon from '@ui/Icon.astro';
import { site } from '@shared/lib/site';
---
<!-- BEGIN HERO -->
<header class="hero pb-0">
<div class="container">
<h1 class="hero-title">Develop beautiful web apps with&nbsp;Tabler</h1>
<p class="hero-description mt-4">Tabler is a free and open source web application UI kit based on Bootstrap&nbsp;5, with hundreds responsive components and multiple layouts.</p>
<div class="my-5">
<div class="row g-3 justify-content-center">
<div class="col-auto">
<a href="#" class="btn btn-lg">See features</a>
</div>
<div class="col-auto">
<a href="#" class="btn btn-lg btn-primary" target="_blank" rel="noopener noreferrer">Preview template</a>
</div>
</div>
</div>
<div class="hero-img img-overlap-margin">
<div class="browser">
<div class="browser-header">
<div class="row align-items-center">
<div class="col-auto col-md-2">
<div class="browser-dots browser-dots-colored">
<div class="browser-dot"></div>
<div class="browser-dot"></div>
<div class="browser-dot"></div>
</div>
</div>
<div class="col-8">
<a href={site.previewUrl} class="browser-input" target="_blank" rel="noopener noreferrer" data-bs-toggle="tooltip" data-bs-placement="top" title="Open preview of Tabler dashboard!">
<Icon name="lock" color="green" size="sm" class="me-2" />
{site.previewUrl}
</a>
</div>
</div>
</div>
<picture>
<img src="../static/marketing/preview.png" srcset="../static/marketing/preview.png 1x, ../static/marketing/preview@2x.png 2x" alt="" class="img-fluid" width="1040" height="760" loading="lazy" />
</picture>
</div>
</div>
</div>
<div class="container">
<h1 class="hero-title">Develop beautiful web apps with&nbsp;Tabler</h1>
<p class="hero-description mt-4">
Tabler is a free and open source web application UI kit based on Bootstrap&nbsp;5, with hundreds responsive
components and multiple layouts.
</p>
<div class="my-5">
<div class="row g-3 justify-content-center">
<div class="col-auto">
<a href="#" class="btn btn-lg">See features</a>
</div>
<div class="col-auto">
<a href="#" class="btn btn-lg btn-primary" target="_blank" rel="noopener noreferrer">Preview template</a>
</div>
</div>
</div>
<div class="hero-img img-overlap-margin">
<div class="browser">
<div class="browser-header">
<div class="row align-items-center">
<div class="col-auto col-md-2">
<div class="browser-dots browser-dots-colored">
<div class="browser-dot"></div>
<div class="browser-dot"></div>
<div class="browser-dot"></div>
</div>
</div>
<div class="col-8">
<a href={site.previewUrl} class="browser-input" target="_blank" rel="noopener noreferrer"
data-bs-toggle="tooltip" data-bs-placement="top" title="Open preview of Tabler dashboard!">
<Icon name="lock" color="green" size="sm" class="me-2" />
{site.previewUrl}
</a>
</div>
</div>
</div>
<picture>
<img src="../static/marketing/preview.png" srcset="../static/marketing/preview.png 1x, ../static/marketing/preview@2x.png 2x" alt="" class="img-fluid" width="1040" height="760" loading="lazy" />
</picture>
</div>
</div>
</div>
</header>
<!-- END HERO -->
+64 -65
View File
@@ -1,78 +1,77 @@
---
// Port of marketing/hero/side.html.
// Inlines ui/typed.html: renders the seed span (first string) and the Typed.js init
// (page-libs: [typed.js] loads the library), rendered directly here.
import Icon from '@ui/Icon.astro'
import Illustration from '@ui/Illustration.astro'
import Icon from '@ui/Icon.astro';
import Illustration from '@ui/Illustration.astro';
import CaptureScript from '../../CaptureScript.astro';
// ui/typed.html: strings = include.strings | split: '|'; id defaults to "typed".
const strings = ['more effective', 'more efficient', 'more productive']
const typedId = 'typed'
const strings = ['more effective', 'more efficient', 'more productive'];
const typedId = 'typed';
---
<!-- BEGIN HERO -->
<header class="hero">
<div class="container">
<div class="row g-lg-8 align-items-center">
<div class="col-md-6 text-center text-md-start">
<div class="hero-subheader">Tabler Emails</div>
<h1 class="hero-title">
Better email communication,<br />
<span class="text-primary" id={typedId}>{strings[0]}</span>
</h1>
<p class="hero-description mt-4">54 eye-catching, customizable and responsive email templates to improve your email communication. No coding skills needed.</p>
<div class="mt-6 mt-lg-7">
<div class="row justify-content-center justify-content-md-start">
<div class="col-auto"><a href="#" class="btn btn-lg btn-primary">Buy for $29</a></div>
<div class="col-auto"><a href="#" class="btn btn-lg">Browse gallery</a></div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="hero-img-side">
<div id="carousel-controls" class="carousel slide" data-bs-ride="carousel" data-interval="4000">
<div class="carousel-inner">
<div class="carousel-item active">
<Illustration image="boy-with-key.svg" class="d-block mx-auto" height="350" />
</div>
<div class="carousel-item">
<Illustration image="boy-girl.svg" class="d-block mx-auto" height="350" />
</div>
<div class="carousel-item">
<Illustration image="computer-fix.svg" class="d-block mx-auto" height="350" />
</div>
</div>
<a class="carousel-control-prev text-secondary" href="#carousel-controls" role="button" data-bs-slide="prev">
<Icon name="chevron-left" class="icon-md" />
<span class="visually-hidden">Previous</span>
</a>
<a class="carousel-control-next text-secondary" href="#carousel-controls" role="button" data-bs-slide="next">
<Icon name="chevron-right" class="icon-md" />
<span class="visually-hidden">Next</span>
</a>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row g-lg-8 align-items-center">
<div class="col-md-6 text-center text-md-start">
<div class="hero-subheader">Tabler Emails</div>
<h1 class="hero-title">
Better email communication,<br />
<span class="text-primary" id={typedId}>{strings[0]}</span>
</h1>
<p class="hero-description mt-4">54 eye-catching, customizable and responsive email templates to improve your email communication. No coding skills needed.</p>
<div class="mt-6 mt-lg-7">
<div class="row justify-content-center justify-content-md-start">
<div class="col-auto"><a href="#" class="btn btn-lg btn-primary">Buy for $29</a></div>
<div class="col-auto"><a href="#" class="btn btn-lg">Browse gallery</a></div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="hero-img-side">
<div id="carousel-controls" class="carousel slide" data-bs-ride="carousel" data-interval="4000">
<div class="carousel-inner">
<div class="carousel-item active">
<Illustration image="boy-with-key.svg" class="d-block mx-auto" height="350" />
</div>
<div class="carousel-item">
<Illustration image="boy-girl.svg" class="d-block mx-auto" height="350" />
</div>
<div class="carousel-item">
<Illustration image="computer-fix.svg" class="d-block mx-auto" height="350" />
</div>
</div>
<a class="carousel-control-prev text-secondary" href="#carousel-controls" role="button" data-bs-slide="prev">
<Icon name="chevron-left" class="icon-md" />
<span class="visually-hidden">Previous</span>
</a>
<a class="carousel-control-next text-secondary" href="#carousel-controls" role="button" data-bs-slide="next">
<Icon name="chevron-right" class="icon-md" />
<span class="visually-hidden">Next</span>
</a>
</div>
</div>
</div>
</div>
</div>
</header>
<!-- END HERO -->
<CaptureScript>
<!-- BEGIN TYPED -->
<script define:vars={{ typedId, strings }}>
function initTyped() {
const typed = new Typed(`#${typedId}`, {
strings,
typeSpeed: 100,
backSpeed: 50,
backDelay: 1000,
startDelay: 1000,
loop: true,
fade: true,
})
}
function initTyped() {
const typed = new Typed(`#${typedId}`, {
strings,
typeSpeed: 100,
backSpeed: 50,
backDelay: 1000,
startDelay: 1000,
loop: true,
fade: true,
});
}
// Typed.js loads via a deferred page-lib <script>, which only runs once parsing
// finishes — this inline script (positioned mid-body) would otherwise run first.
document.readyState !== 'loading' ? initTyped() : document.addEventListener('DOMContentLoaded', initTyped, { once: true })
// Typed.js loads via a deferred page-lib <script>, which only runs once parsing
// finishes — this inline script (positioned mid-body) would otherwise run first.
document.readyState !== 'loading' ? initTyped() : document.addEventListener('DOMContentLoaded', initTyped, { once: true });
</script>
<!-- END TYPED -->
</CaptureScript>
@@ -1,39 +1,37 @@
---
// The ui/shape.html include is inlined: <div class="shape shape-md ..."><Icon /></div>
// (shape class order: shape, shape-{size}, shape-{color}, {class}, rounded-circle).
import SectionDivider from '../SectionDivider.astro'
import Icon from '@ui/Icon.astro'
import SectionDivider from '../SectionDivider.astro';
import Icon from '@ui/Icon.astro';
interface Props {
background?: string
class?: string
divider?: string
background?: string;
class?: string;
divider?: string;
}
const { background, class: className, divider } = Astro.props
const { background, class: className, divider } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
---
<section class:list={sectionClass}>
<SectionDivider divider={divider} />
<div class="container">
<div class="row items-center text-center g-lg-10">
<div class="col-md-6 col-lg">
<div class="shape shape-md mb-3"><Icon name="devices" /></div>
<h2 class="h2">Mobile-optimized</h2>
<p class="text-secondary">Our email templates are fully responsive, so you can be sure they will look great on any device and screen size.</p>
</div>
<div class="col-md-6 col-lg">
<div class="shape shape-md mb-3"><Icon name="mailbox" /></div>
<h2 class="h2">Compatible with 90+ email clients</h2>
<p class="text-secondary">Tested across 90+ email clients and devices, Tabler emails will help you make your email communication professional and reliable.</p>
</div>
<div class="col-md-6 col-lg">
<div class="shape shape-md mb-3"><Icon name="palette" /></div>
<h2 class="h2">Unique, minimal design</h2>
<p class="text-secondary">Draw recipients attention with beautiful, minimal email designs based on Bootstrap and Material Design principles.</p>
</div>
</div>
</div>
<SectionDivider divider={divider} />
<div class="container">
<div class="row items-center text-center g-lg-10">
<div class="col-md-6 col-lg">
<div class="shape shape-md mb-3"><Icon name="devices" /></div>
<h2 class="h2">Mobile-optimized</h2>
<p class="text-secondary">Our email templates are fully responsive, so you can be sure they will look great on any device and screen size.</p>
</div>
<div class="col-md-6 col-lg">
<div class="shape shape-md mb-3"><Icon name="mailbox" /></div>
<h2 class="h2">Compatible with 90+ email clients</h2>
<p class="text-secondary">Tested across 90+ email clients and devices, Tabler emails will help you make your email communication professional and reliable.</p>
</div>
<div class="col-md-6 col-lg">
<div class="shape shape-md mb-3"><Icon name="palette" /></div>
<h2 class="h2">Unique, minimal design</h2>
<p class="text-secondary">Draw recipients attention with beautiful, minimal email designs based on Bootstrap and Material Design principles.</p>
</div>
</div>
</div>
</section>
@@ -1,73 +1,77 @@
---
// The ui/svg.html placeholder (width=500 height=400 border=true) is inlined,
// and ui/shape.html (size="md") as <div class="shape shape-md"><Icon /></div>.
import SectionDivider from '../SectionDivider.astro'
import Icon from '@ui/Icon.astro'
import SectionDivider from '../SectionDivider.astro';
import Icon from '@ui/Icon.astro';
interface Props {
background?: string
class?: string
divider?: string
background?: string;
class?: string;
divider?: string;
}
const { background, class: className, divider } = Astro.props
const { background, class: className, divider } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
---
<section class:list={sectionClass}>
<SectionDivider divider={divider} />
<div class="container">
<div class="section-header">
<h2 class="section-title">Everything you need to deploy your app</h2>
<div class="section-description">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
</div>
<SectionDivider divider={divider} />
<div class="container">
<div class="section-header">
<h2 class="section-title">Everything you need to deploy your app</h2>
<div class="section-description">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
</div>
<div class="row g-lg-10">
<div class="col-lg-6 mb-3 mb-lg-0">
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" width="500" height="400" viewBox="0 0 500 400" fill="transparent" stroke="var(--tblr-border-color, #b8cef1)" style="width: 100%; height: auto">
<rect x=".5" y=".5" width="499" height="399" rx="2"></rect>
<line x1="0" y1="0" x2="500" y2="400"></line>
<line x1="0" y1="400" x2="500" y2="0"></line>
</svg>
</div>
<div class="col-lg-6">
<div class="space-y-6">
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="tools" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Designed with users in mind</h3>
<p class="text-secondary m-0">Tabler is fully responsive and compatible with all modern browsers. Thanks to its modern, user-friendly design you can create a fully functional interface that users will love. Every UI element has been created with attention to detail to make your interface beautiful!</p>
</div>
</div>
</div>
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="brand-bootstrap" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Built for developers</h3>
<p class="text-secondary m-0">Having in mind what it takes to write high-quality code, we want to help you speed up the development process and keep your code clean. Based on Bootstrap 5, Tabler is a cutting-edge solution, compatible with all modern browsers and fully responsive.</p>
</div>
</div>
</div>
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="paint" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Fully customizable</h3>
<p class="text-secondary m-0">You can easily customize the UI elements to make them fit the needs of your project. And dont worry if you dont have much experience - Tabler is easy to get started!</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-lg-10">
<div class="col-lg-6 mb-3 mb-lg-0">
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" width="500" height="400" viewBox="0 0 500 400" fill="transparent" stroke="var(--tblr-border-color, #b8cef1)" style="width: 100%; height: auto">
<rect x=".5" y=".5" width="499" height="399" rx="2"></rect>
<line x1="0" y1="0" x2="500" y2="400"></line>
<line x1="0" y1="400" x2="500" y2="0"></line>
</svg>
</div>
<div class="col-lg-6">
<div class="space-y-6">
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="tools" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Designed with users in mind</h3>
<p class="text-secondary m-0">
Tabler is fully responsive and compatible with all modern browsers. Thanks to its modern, user-friendly design you can create a fully functional interface that users will love. Every UI element has been created with
attention to detail to make your interface beautiful!
</p>
</div>
</div>
</div>
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="brand-bootstrap" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Built for developers</h3>
<p class="text-secondary m-0">
Having in mind what it takes to write high-quality code, we want to help you speed up the development process and keep your code clean. Based on Bootstrap 5, Tabler is a cutting-edge solution, compatible with all modern
browsers and fully responsive.
</p>
</div>
</div>
</div>
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="paint" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Fully customizable</h3>
<p class="text-secondary m-0">You can easily customize the UI elements to make them fit the needs of your project. And dont worry if you dont have much experience - Tabler is easy to get started!</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
@@ -1,72 +1,77 @@
---
// placeholder svg on the right). ui/svg.html and ui/shape.html inlined.
import SectionDivider from '../SectionDivider.astro'
import Icon from '@ui/Icon.astro'
import SectionDivider from '../SectionDivider.astro';
import Icon from '@ui/Icon.astro';
interface Props {
background?: string
class?: string
divider?: string
background?: string;
class?: string;
divider?: string;
}
const { background, class: className, divider } = Astro.props
const { background, class: className, divider } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
---
<section class:list={sectionClass}>
<SectionDivider divider={divider} />
<div class="container">
<div class="section-header">
<h2 class="section-title">Everything you need to deploy your app</h2>
<div class="section-description">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
</div>
<SectionDivider divider={divider} />
<div class="container">
<div class="section-header">
<h2 class="section-title">Everything you need to deploy your app</h2>
<div class="section-description">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
</div>
<div class="row g-lg-10">
<div class="col-lg-6">
<div class="space-y-6">
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="tools" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Designed with users in mind</h3>
<p class="text-secondary m-0">Tabler is fully responsive and compatible with all modern browsers. Thanks to its modern, user-friendly design you can create a fully functional interface that users will love. Every UI element has been created with attention to detail to make your interface beautiful!</p>
</div>
</div>
</div>
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="brand-bootstrap" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Built for developers</h3>
<p class="text-secondary m-0">Having in mind what it takes to write high-quality code, we want to help you speed up the development process and keep your code clean. Based on Bootstrap 5, Tabler is a cutting-edge solution, compatible with all modern browsers and fully responsive.</p>
</div>
</div>
</div>
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="paint" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Fully customizable</h3>
<p class="text-secondary m-0">You can easily customize the UI elements to make them fit the needs of your project. And dont worry if you dont have much experience - Tabler is easy to get started!</p>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mt-3 mt-lg-0">
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" width="500" height="400" viewBox="0 0 500 400" fill="transparent" stroke="var(--tblr-border-color, #b8cef1)" style="width: 100%; height: auto">
<rect x=".5" y=".5" width="499" height="399" rx="2"></rect>
<line x1="0" y1="0" x2="500" y2="400"></line>
<line x1="0" y1="400" x2="500" y2="0"></line>
</svg>
</div>
</div>
</div>
<div class="row g-lg-10">
<div class="col-lg-6">
<div class="space-y-6">
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="tools" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Designed with users in mind</h3>
<p class="text-secondary m-0">
Tabler is fully responsive and compatible with all modern browsers. Thanks to its modern, user-friendly design you can create a fully functional interface that users will love. Every UI element has been created with
attention to detail to make your interface beautiful!
</p>
</div>
</div>
</div>
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="brand-bootstrap" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Built for developers</h3>
<p class="text-secondary m-0">
Having in mind what it takes to write high-quality code, we want to help you speed up the development process and keep your code clean. Based on Bootstrap 5, Tabler is a cutting-edge solution, compatible with all modern
browsers and fully responsive.
</p>
</div>
</div>
</div>
<div>
<div class="row">
<div class="col-auto">
<div class="shape shape-md"><Icon name="paint" /></div>
</div>
<div class="col">
<h3 class="h2 mb-2">Fully customizable</h3>
<p class="text-secondary m-0">You can easily customize the UI elements to make them fit the needs of your project. And dont worry if you dont have much experience - Tabler is easy to get started!</p>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mt-3 mt-lg-0">
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" width="500" height="400" viewBox="0 0 500 400" fill="transparent" stroke="var(--tblr-border-color, #b8cef1)" style="width: 100%; height: auto">
<rect x=".5" y=".5" width="499" height="399" rx="2"></rect>
<line x1="0" y1="0" x2="500" y2="400"></line>
<line x1="0" y1="400" x2="500" y2="0"></line>
</svg>
</div>
</div>
</div>
</section>
@@ -1,88 +1,89 @@
---
// Marketing pages live one level deep, so the avatar asset base is ".."
// (reference uses "../static/avatars/...") — passed to Avatar via `base`.
import testimonials from '@data/testimonials.json'
import people from '@data/people.json'
import Avatar from '@ui/Avatar.astro'
import testimonials from '@data/testimonials.json';
import people from '@data/people.json';
import Avatar from '@ui/Avatar.astro';
interface Person {
full_name?: string
photo?: string
job_title?: string
[key: string]: unknown
full_name?: string;
photo?: string;
job_title?: string;
[key: string]: unknown;
}
interface Props {
background?: string
class?: string
limit?: number
hideHeader?: boolean
background?: string;
class?: string;
limit?: number;
hideHeader?: boolean;
}
const { background, class: className, limit = 99, hideHeader } = Astro.props
const { background, class: className, limit = 99, hideHeader } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
// Liquid: testimonials | slice: 0, limit | split_to_n: 3
const list = (testimonials as string[]).slice(0, limit)
const n = 3
const chunkSize = Math.round(list.length / n)
const groups: string[][] = []
// Slice testimonials and split into 3 columns.
const list = (testimonials as string[]).slice(0, limit);
const n = 3;
const chunkSize = Math.round(list.length / n);
const groups: string[][] = [];
for (let i = 0; i < list.length; i += chunkSize) {
groups.push(list.slice(i, i + chunkSize))
groups.push(list.slice(i, i + chunkSize));
}
// Liquid: {% assign i = 1 %} — a global counter incremented per testimonial,
// used to index people[i] (people[0] is intentionally skipped).
let i = 1
// Global counter starting at 1 — indexes people[i] (people[0] is intentionally skipped).
let i = 1;
const cards = groups.map((group) =>
group.map((testimonial) => {
const person = (people as Person[])[i] ?? {}
i += 1
return { testimonial, person }
}),
)
group.map((testimonial) => {
const person = (people as Person[])[i] ?? {};
i += 1;
return { testimonial, person };
}),
);
---
<section class:list={sectionClass}>
<div class="container">
{
!hideHeader && (
<div class="section-header">
<h2 class="section-title">Trusted by hundreds</h2>
<p class="section-description">Our Users send us bunch of smilies with our services, and we love them 😍</p>
</div>
)
}
<div class="container">
{
!hideHeader && (
<div class="section-header">
<h2 class="section-title">Trusted by hundreds</h2>
<p class="section-description">Our Users send us bunch of smilies with our services, and we love them 😍</p>
</div>
)
}
<div class="row g-lg-6">
{
cards.map((group) => (
<div class="col-md-6 col-lg-4">
<div class="row g-lg-6">
{group.map(({ testimonial, person }) => (
<div class="col-12">
<a href="#" class="card bg-surface-secondary">
<div class="card-body">
<div class="row mb-3">
<div class="col-auto">
<Avatar person={person} size="md" base=".." />
</div>
<div class="col">
<h3 class="h3 m-0">{person.full_name}</h3>
<div class="text-secondary">{person.job_title}</div>
</div>
</div>
<div class="row g-lg-6">
{
cards.map((group) => (
<div class="col-md-6 col-lg-4">
<div class="row g-lg-6">
{group.map(({ testimonial, person }) => (
<div class="col-12">
<a href="#" class="card bg-surface-secondary">
<div class="card-body">
<div class="row mb-3">
<div class="col-auto">
<Avatar person={person} size="md" base=".." />
</div>
<div class="col">
<h3 class="h3 m-0">{person.full_name}</h3>
<div class="text-secondary">{person.job_title}</div>
</div>
</div>
<p>{testimonial}</p>
</div>
</a>
</div>
))}
</div>
</div>
))
}
</div>
</div>
<p>
{testimonial}
</p>
</div>
</a>
</div>
))}
</div>
</div>
))
}
</div>
</div>
</section>