mirror of
https://github.com/tabler/tabler.git
synced 2026-08-29 13:21:29 +04:00
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:
@@ -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 -->
|
||||
|
||||
@@ -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 Tabler</h1>
|
||||
<p class="hero-description mt-4">Tabler is a free and open source web application UI kit based on Bootstrap 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 Tabler</h1>
|
||||
<p class="hero-description mt-4">
|
||||
Tabler is a free and open source web application UI kit based on Bootstrap 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 -->
|
||||
|
||||
@@ -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 don’t worry if you don’t 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 don’t worry if you don’t 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 don’t worry if you don’t 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 don’t worry if you don’t 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>
|
||||
|
||||
Reference in New Issue
Block a user