Restructure shared Astro sources and import aliases (#2737)

This commit is contained in:
Paweł Kuna
2026-07-30 23:58:48 +02:00
committed by GitHub
parent 0f8dcb0a3c
commit ad2ed849dd
492 changed files with 1469 additions and 1714 deletions
@@ -0,0 +1,38 @@
---
import SectionDivider from '../SectionDivider.astro';
import Baremetrics from '../brands/Baremetrics.astro';
import Cgi from '../brands/Cgi.astro';
import Docplanner from '../brands/Docplanner.astro';
import Flow from '../brands/Flow.astro';
import Fubotv from '../brands/Fubotv.astro';
import SixFlags from '../brands/SixFlags.astro';
import Vocus from '../brands/Vocus.astro';
interface Props {
background?: string;
class?: string;
divider?: string;
}
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 mb-6">
<h2 class="section-title text-secondary">Trusted by over 3,000 companies</h2>
</div>
<div class="row g-lg-8 align-items-center justify-content-center">
<div class="col-auto"><a href="#" class="link-secondary"><Baremetrics /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Cgi /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Docplanner /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Flow /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Fubotv /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><SixFlags /></a></div>
<div class="col-auto"><a href="#" class="link-secondary"><Vocus /></a></div>
</div>
</div>
</section>
@@ -0,0 +1,44 @@
---
interface Props {
background?: string;
class?: string;
}
const { background, class: className } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
---
<section class:list={sectionClass}>
<div class="container">
<div class="row justify-content-lg-center">
<div class="col-sm-6 col-lg-3">
<div class="text-center">
<h2 class="display-5 m-0 fw-bold">48</h2>
<p class="text-secondary m-0">templates</p>
</div>
</div>
<div class="col-sm-6 col-lg-3">
<div class="text-center">
<h2 class="display-5 m-0 fw-bold">12</h2>
<p class="text-secondary m-0">years in business</p>
</div>
</div>
<div class="col-sm-6 col-lg-3">
<div class="text-center">
<h2 class="display-5 m-0 fw-bold">2,5k+</h2>
<p class="text-secondary m-0">copies sold</p>
</div>
</div>
<div class="col-sm-6 col-lg-3">
<div class="text-center">
<h2 class="display-5 m-0 fw-bold">99%</h2>
<p class="text-secondary m-0">happy customers</p>
</div>
</div>
</div>
</div>
</section>
@@ -0,0 +1,24 @@
---
import Button from '@ui/Button.astro';
import ButtonList from '@ui/ButtonList.astro';
interface Props {
background?: string;
class?: string;
}
const { background, class: className } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
---
<section class:list={sectionClass}>
<div class="container-narrow text-center">
<h3 class="h1">Enhance your efficiency with our application,<br />available for use immediately.</h3>
<p class="text-secondary">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sunt, ipsa? Voluptates sunt, ipsum esse quis obcaecati atque placeat consectetur beatae, tenetur ducimus iure minima expedita recusandae doloribus nam. Pariatur, facilis?</p>
<ButtonList class="justify-content-center mt-6">
<Button text="Get started" color="primary" />
<Button text="Learn more" ghost iconEnd="chevron-right" />
</ButtonList>
</div>
</section>
@@ -0,0 +1,53 @@
---
import { site } from '@shared/lib/site';
interface Props {
background?: string;
class?: string;
}
const { background, class: className } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
---
<section class:list={sectionClass}>
<div class="container">
<div class="section-header">
<h2 class="section-title">Frequently Asked Questions</h2>
</div>
<div class="row g-lg-4">
<div class="col-md-4 prose">
<h3 class="h2">How is Tabler Pro different from Tabler?</h3>
<p class="text-secondary">Tabler offers fundamental components that you can piece together to build your app or website. However, Tabler Pro offers an elevated convenience by providing pre-assembled components and page templates, acting as ready-to-use building blocks that can be swiftly integrated into your app, thereby saving development time.</p>
</div>
<div class="col-md-4 prose">
<h3 class="h2">Is this a yearly subscription?</h3>
<p class="text-secondary">Certainly, you have lifelong access to all our components. This implies that you will receive new components and updates every month, continuing as long as we have new component ideas to share.</p>
</div>
<div class="col-md-4 prose">
<h3 class="h2">I want to buy this but I can't afford it. Is there a discount?</h3>
<p class="text-secondary">Should you be a student or find the cost excessively high in your local currency, please reach out to us at {site.email} detailing your circumstances, and we will contemplate offering you a discount.</p>
</div>
<div class="col-md-4 prose">
<h3 class="h2">What can I do with this license?</h3>
<ul class="text-secondary">
<li>To build your websites or SaaS project that end-users need to pay</li>
<li>To build an open-source tool or documentation website</li>
</ul>
</div>
<div class="col-md-4 prose">
<h3 class="h2">What version of Tabler is used?</h3>
<p class="text-secondary">The elements in Tabler Pro are created using Tabler v1.2 and later versions. If your current version is v0.8, we advise you to update to the latest version to make the most of the Pro components.</p>
</div>
<div class="col-md-4 prose">
<h3 class="h2">What restrictions does this license have?</h3>
<ul class="text-secondary">
<li>Create a clone of Tabler PRO to sell</li>
<li>Create products like templates, themes, Figma or Sketch UI kits, page builders based on the PRO components</li>
<li>Recreate the components for other UI libraries or CSS frameworks</li>
</ul>
</div>
</div>
</div>
</section>
@@ -0,0 +1,44 @@
---
interface Props {
background?: string;
class?: string;
}
const { background, class: className } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
---
<section class:list={sectionClass}>
<div class="container">
<div class="row g-xl-6">
<div class="col-lg-4">
<div class="section-header text-start sticky-top">
<div class="section-title">Frequently asked questions</div>
<p class="section-description">Cant find the answer youre looking for? Reach out to our customer support team.</p>
</div>
</div>
<div class="col-lg">
<div class="space-y-5">
<div>
<div class="h3 mb-1">Can I use Tabler in commercial projects?</div>
<div class="text-secondary">Of course! Tabler is under MIT license, so you can confidently use it in commercial projects. However, remember to include a note that your project uses Tabler.</div>
</div>
<div>
<div class="h3 mb-1">How do I get notified of new Tabler versions?</div>
<div class="text-secondary">You may watch the releases on GitHub or follow me on Twitter.</div>
</div>
<div>
<div class="h3 mb-1">Can Tabler be used with WordPress?</div>
<div class="text-secondary">
Tabler is an HTML template that can be used for any purpose. However, it is not made to be easily installed on WordPress. It will require some effort and enough knowledge of the WordPress script to do so.
</div>
</div>
</div>
<div class="mt-5">
<a class="btn" href="#">Read more questions</a>
</div>
</div>
</div>
</div>
</section>
@@ -0,0 +1,39 @@
---
// 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';
interface Props {
background?: string;
class?: string;
divider?: string;
}
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>
</section>
@@ -0,0 +1,79 @@
---
// 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';
interface Props {
background?: string;
class?: string;
divider?: string;
}
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>
<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>
@@ -0,0 +1,78 @@
---
// placeholder svg on the right). ui/svg.html and ui/shape.html inlined.
import SectionDivider from '../SectionDivider.astro';
import Icon from '@ui/Icon.astro';
interface Props {
background?: string;
class?: string;
divider?: string;
}
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>
<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>
@@ -0,0 +1,95 @@
---
import Icon from '@ui/Icon.astro';
interface Props {
background?: string;
class?: string;
}
const { background, class: className } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
---
<section class:list={sectionClass}>
<div class="container">
<div class="pricing">
<div class="pricing-card">
<h4 class="pricing-title">Free</h4>
<div class="pricing-price">
<span class="pricing-price-currency">$</span>99
<div class="pricing-price-description">
<div>per user</div>
<div>per year</div>
</div>
</div>
<ul class="pricing-features my-5">
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Up to 5 developers
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />All marketing + app components
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Figma UI Kit
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Lifetime free updates
</li>
</ul>
<div class="pricing-btn"><a href="#" class="btn w-100">Get started</a></div>
</div>
<div class="pricing-card featured">
<div class="pricing-label"><div class="badge bg-primary text-primary-fg">Popular</div></div>
<h4 class="pricing-title">All features</h4>
<div class="pricing-price">
<span class="pricing-price-currency">$</span>199
<div class="pricing-price-description">
<div>per user</div>
<div>per year</div>
</div>
</div>
<ul class="pricing-features my-5">
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Up to 5 developers
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />All marketing + app components
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Figma UI Kit
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Lifetime free updates
</li>
</ul>
<div class="pricing-btn"><a href="#" class="btn w-100 btn-primary">Get started</a></div>
</div>
<div class="pricing-card">
<h4 class="pricing-title">Other</h4>
<div class="pricing-price">
<span class="pricing-price-currency">$</span>99
<div class="pricing-price-description">
<div>per user</div>
<div>per year</div>
</div>
</div>
<ul class="pricing-features my-5">
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Up to 5 developers
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />All marketing + app components
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Figma UI Kit
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Lifetime free updates
</li>
</ul>
<div class="pricing-btn"><a href="#" class="btn w-100">Get started</a></div>
</div>
</div>
</div>
</section>
@@ -0,0 +1,50 @@
---
import Icon from '@ui/Icon.astro';
interface Props {
background?: string;
}
const { background } = Astro.props;
const sectionClass = ['section', background && `section-${background}`];
---
<section class:list={sectionClass}>
<div class="container">
<div class="bg-body-tertiary p-6 rounded-4">
<div class="row g-4 align-items-center">
<div class="col-lg">
<h3 class="h2">Team License</h3>
<p class="m-0 text-secondary">Get Marketing + Application UI for you and your team</p>
</div>
<div class="col-lg">
<ul class="list-unstyled m-0">
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Up to 5 developers
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />All marketing + app components
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Figma UI Kit
</li>
<li>
<Icon name="check" color="green" class="icon-inline me-1" />Lifetime free updates
</li>
</ul>
</div>
<div class="col-6-sm col-lg">
<div class="pricing-price m-0">
<span class="pricing-price-currency">$</span>599
<div class="pricing-price-description">
<div>per team</div>
<div>per year</div>
</div>
</div>
</div>
<div class="col-6-sm col-lg-auto"><a href="#" class="btn btn-primary w-100">Get started</a></div>
</div>
</div>
</div>
</section>
@@ -0,0 +1,32 @@
---
import Icon from '@ui/Icon.astro';
interface Props {
background?: string;
class?: string;
}
const { background, class: className } = Astro.props;
const sectionClass = ['section', background && `section-${background}`, className]
---
<section class:list={sectionClass}>
<div class="container">
<div class="section-header mb-6">
<h2 class="section-title">Subscribe on our newsletter</h2>
<p class="section-description">Get daily news on upcoming offers from many suppliers all over the world</p>
</div>
</div>
<div class="container-tight">
<div class="row">
<div class="col">
<input class="w-100 form-control" placeholder="Your Email" type="email" />
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary"><Icon name="mail" /> Subscribe</button>
</div>
</div>
</div>
</section>
@@ -0,0 +1,90 @@
---
// 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';
interface Person {
full_name?: string;
photo?: string;
job_title?: string;
[key: string]: unknown;
}
interface Props {
background?: string;
class?: string;
limit?: number;
hideHeader?: boolean;
}
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[][] = [];
for (let i = 0; i < list.length; 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;
const cards = groups.map((group) =>
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="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>
</section>