1
0
mirror of https://github.com/tabler/tabler.git synced 2026-08-14 23:32:25 +04:00

init tabler website

This commit is contained in:
codecalm
2023-07-18 00:13:56 +02:00
parent 77ae29acef
commit 06579ec91d
1336 changed files with 47866 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
+10
View File
@@ -0,0 +1,10 @@
{
"extends": "next/core-web-vitals",
"rules": {
"react/no-unescaped-entities": "off",
"react/display-name": "off",
"@next/next/no-img-element": "off",
"react/jsx-no-target-blank": "off",
"jsx-a11y/alt-text": "off"
}
}
+50
View File
@@ -0,0 +1,50 @@
# dependencies
/node_modules
/.pnp
.pnp.js
.idea/
# testing
/coverage
# next.js
.next/
/out/
/public/sitemap*
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel
package-lock.json
# tmp files
/.tmp-emails
# yarn
.yarn
.yarnrc.yml
.pnp.loader.mjs
.pnp.cjs
.jekyll-cache/
_site
.contentlayer
public/static/icons/*
public/static/icons-png/*
+1
View File
@@ -0,0 +1 @@
v18
+6
View File
@@ -0,0 +1,6 @@
src/data/*
dist
node_modules
.next
build
.contentlayer
+1
View File
@@ -0,0 +1 @@
# Tabler website and Docs
@@ -0,0 +1,30 @@
// import Link from "next/link";
// import { useRouter } from "next/router";
// import { getCategory, getDocsMenu, getPrevNext } from "@/lib/docs";
import DocsMenu from '@/components/DocsMenu';
// import Icon from "@/components/Icon";
export default function DocsLayout({ children /*, meta = {}, pageProps*/ }) {
// const docsMenu = getDocsMenu(),
// router = useRouter(),
// category = getCategory(router.pathname),
// [prev, next] = getPrevNext(router.pathname)
return (
<div className="border-bottom border-top">
<div className="container">
<div className="row g-0">
<div className="md:col-auto docs-side">
{/*<input type="search" className="form-control w-100 mb-5" placeholder="Search&hellip;" />*/}
<DocsMenu />
</div>
<div className="md:col">
<div className="py-6 md:pl-6">{children}</div>
</div>
</div>
</div>
</div>
);
}
+167
View File
@@ -0,0 +1,167 @@
// import { DocsPageHeader } from "@/components/page-header"
// import { DocsPager } from "@/components/pager"
// import { DashboardTableOfContents } from "@/components/toc"
import { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { allDocs } from 'contentlayer/generated';
// import { getTableOfContents } from "@/lib/toc"
import Mdx from '@/components/MDX';
import TablerSponsorsBanner from '@/components/TablerSponsorsBanner';
// import { env } from "@/env.mjs"
// import { absoluteUrl } from "@/lib/utils"
interface DocPageProps {
params: {
slug: string[]
}
}
async function getDocFromParams(params) {
const slug = params.slug?.join('/') || '';
const doc = allDocs.find((doc) => doc.slugAsParams === slug);
if (!doc) {
null;
}
return doc;
}
export async function generateMetadata({
params,
}: DocPageProps): Promise<Metadata> {
const doc = await getDocFromParams(params);
if (!doc) {
return {};
}
// const url = env.NEXT_PUBLIC_APP_URL
// const ogUrl = new URL(`${url}/api/og`)
// ogUrl.searchParams.set("heading", doc.description ?? doc.title)
// ogUrl.searchParams.set("type", "Documentation")
// ogUrl.searchParams.set("mode", "dark")
return {
title: doc.title,
description: doc.description,
openGraph: {
title: doc.title,
description: doc.description,
type: 'article',
// url: absoluteUrl(doc.slug),
// images: [
// {
// url: ogUrl.toString(),
// width: 1200,
// height: 630,
// alt: doc.title,
// },
// ],
},
twitter: {
card: 'summary_large_image',
title: doc.title,
description: doc.description,
// images: [ogUrl.toString()],
},
};
}
export async function generateStaticParams(): Promise<
DocPageProps['params'][]
> {
return allDocs.map((doc) => ({
slug: doc.slugAsParams.split('/'),
}));
}
export default async function DocPage({ params }: DocPageProps) {
const doc = await getDocFromParams(params);
if (!doc) {
notFound();
}
// const toc = await getTableOfContents(doc.body.raw)
return (
<>
<div className="markdown">
{/* {category && (
<div className="h-subheader text-primary">{category}</div>
)} */}
{doc.title && <h1>{doc.title}</h1>}
{doc.description && <p className="lead">{doc.description}</p>}
<Mdx code={doc.body.code} />
</div>
<TablerSponsorsBanner className="mt-7" />
<div className="pt-7">
<div className="row">
<div className="md:col">
{/* {prev && (
<Link href={prev.url} className="card">
<div className="card-body p-3">
<div className="row items-center g-3">
<div className="col-auto">
<div className="card-chevron card-chevron-left">
<Icon name="chevron-left" />
</div>
</div>
<div className="col">
<div className="h-subheader mb-1">
{prev.category}
</div>
<div className="h5 m-0">{prev.title}</div>
</div>
</div>
</div>
</Link>
)} */}
</div>
<div className="md:col">
{/* {next && (
<Link href={next.url} className="card text-right">
<div className="card-body p-3">
<div className="row items-center g-3">
<div className="col">
<div className="h-subheader mb-1">
{next.category}
</div>
<div className="h5 m-0">{next.title}</div>
</div>
<div className="col-auto">
<div className="card-chevron">
<Icon name="chevron-right" />
</div>
</div>
</div>
</div>
</Link>
)} */}
</div>
</div>
</div>
{/* // <main className="relative py-6 lg:gap-10 lg:py-10 xl:grid xl:grid-cols-[1fr_300px]">
// <div className="mx-auto w-full min-w-0">
// {/* <DocsPageHeader heading={doc.title} text={doc.description} />
// <Mdx code={doc.body.code} />
// <hr className="my-4 md:my-6" />
// {/* <DocsPager doc={doc} />
// </div>
// <div className="hidden text-sm xl:block">
// <div className="sticky top-16 -mt-10 max-h-[calc(var(--vh)-4rem)] overflow-y-auto pt-10">
// {/* <DashboardTableOfContents toc={toc} />
// </div>
// </div>
// </main> */}
</>
);
}
+16
View File
@@ -0,0 +1,16 @@
import Header from '@/components/layout/Header';
import Footer from '@/components/layout/Footer';
export default function CoreLayout({
children
}: {
children: React.ReactNode,
}) {
return (
<>
<Header className="header-docs" />
<main className="main bg-white">{children}</main>
<Footer />
</>
);
}
+5
View File
@@ -0,0 +1,5 @@
export default function PreviewLayout({ children }) {
return (
<>{children}</>
);
}
+74
View File
@@ -0,0 +1,74 @@
'use client';
import { useState } from 'react';
import Link from 'next/link';
// import { PreviewLayout } from "@/layouts/PreviewLayout"
import clsx from 'clsx';
import { uiDemoUrl, uiDownloadUrl } from '@/config/site';
import Icon from '@/components/Icon';
const devices = [
{ name: 'mobile', width: 375, icon: 'device-mobile' },
{ name: 'tablet', width: 960, icon: 'device-tablet' },
{ name: 'desktop', width: '100%', icon: 'device-desktop' },
];
export default function PreviewPage() {
const [currentDevice, setCurrentDevice] = useState('desktop');
const [width, setWidth] = useState<string|number>('100%');
return (
<div className="preview">
<iframe
className="preview-iframe"
src={uiDemoUrl}
frameBorder="0"
style={{ width }}
/>
<div className="preview-navbar">
<div className="mr-auto">
<Link href="/" className="preview-navbar-link">
<span className="logo logo-white logo-square" aria-label="Tabler" />
</Link>
</div>
<div className="preview-navbar-devices">
{devices.map((device) => (
<button
key={device.name}
className={clsx('preview-navbar-link', {
active: device.name === currentDevice,
})}
title={`Preview template on ${device.name}`}
onClick={() => {
setCurrentDevice(device.name);
setWidth(device.width);
}}
>
<Icon name={device.icon} />
</button>
))}
</div>
<div className="ml-auto d-flex">
<a href={uiDownloadUrl} className="btn btn-primary btn-responsive-sm lemonsqueezy-button">
<Icon name="download" />
<span className="btn-responsive-text">Download Tabler</span>
</a>
<a href={uiDemoUrl} className="preview-navbar-link ml-3">
<Icon name="x" />
</a>
</div>
</div>
</div>
);
}
// export async function getStaticProps() {
// return {
// props: {
// meta: {
// bodyClassName: "o-auto",
// },
// },
// }
// }
+66
View File
@@ -0,0 +1,66 @@
'use client';
import { useState } from 'react';
import { useClipboard } from '@/hooks';
import clsx from 'clsx';
// import glob from 'glob';
const importFiles = (type) => {
return [];
//return glob.sync(`./public/samples/${type}/*.{jpg,png}`).map((file) => file.replace('./public', ''))
};
export default function SamplesPage() {
const clipboard = useClipboard();
const types = [
{
title: 'Avatars',
list: importFiles('avatars'),
},
{
title: 'Photos',
list: importFiles('photos'),
},
{
title: 'Products',
list: importFiles('products'),
},
{
title: 'Tracks',
list: importFiles('tracks'),
},
];
let [clicked, setClicked] = useState([]);
return (
<>
{types.map((type, i) => (
<section className={clsx('section', i % 2 === 0 ? '' : 'section-light')} key={type.title}>
<div className="container">
<div>
<h3 className="mb-4">{type.title}</h3>
<div className="row">
{type.list.map((item) => (
<div className="col-auto" key={item}>
<img
src={`${item}`}
alt=""
style={{ width: '80px', opacity: clicked.indexOf(item) >= 0 ? 0.2 : 1 }}
onClick={() => {
clipboard.copy(item);
setClicked([item, ...clicked]);
}}
/>
</div>
))}
</div>
</div>
</div>
</section>
))}
</>
);
}
+14
View File
@@ -0,0 +1,14 @@
export default function SingleLayout({
children
}: {
children: React.ReactNode,
}) {
return (
<section className="section">
<div className="container container-narrow">
{children}
</div>
</section>
);
}
+51
View File
@@ -0,0 +1,51 @@
import { notFound } from 'next/navigation';
import { allPages } from 'contentlayer/generated';
import Mdx from '@/components/MDX';
interface PageProps {
params: {
slug: string
}
}
async function getPageFromParams(params) {
const slug = params?.slug,
page = allPages.find((page) => page.slugAsParams === slug);
if (!page) {
null;
}
return page;
}
export async function generateStaticParams(): Promise<PageProps['params'][]> {
return allPages.map((page) => ({
slug: page.slugAsParams,
}));
}
export default async function PagePage({ params }: PageProps) {
const page = await getPageFromParams(params);
if (!page) {
notFound();
}
return (
<>
{page && page.title && (
<>
<div className="section-header">
<h1 className="section-title section-title-lg">{page.title}</h1>
</div>
</>
)}
<div className="markdown">
{page.description && <p className="lead">{page.description}</p>}
<Mdx code={page.body.code} />
</div>
</>
);
}
+44
View File
@@ -0,0 +1,44 @@
import Link from 'next/link';
import Script from 'next/script';
import Icon from '@/components/Icon';
export default function Custom404Page() {
return (
<>
<section className="section">
<div className="container">
<div className="py-6 text-center">
<img
src="/img/404.svg"
alt="404 - not found"
height={200}
className="mb-6 mx-auto"
/>
<div className="section-header">
<h1 className="section-title section-title-lg">
Oooops! Page Not Found
</h1>
<p className="section-description">
This page doesn&apos;t exist or was removed!
<br />
We suggest you back home
</p>
<div className="mt-5">
<Link href="/" className="btn btn-primary">
<Icon name="chevron-left" />
Back to home
</Link>
</div>
</div>
</div>
</div>
</section>
{/* <Script id="plausible">
{'window.plausible && window.plausible("404",{props:{path:document.location.pathname}})'}
</Script> */}
</>
);
}
+56
View File
@@ -0,0 +1,56 @@
import { notFound } from 'next/navigation';
import { allPosts } from 'contentlayer/generated';
import Mdx from '@/components/MDX';
interface PageProps {
params: {
slug: string
}
}
async function getPageFromParams(params) {
const slug = params?.slug,
page = allPosts.find((page) => page.slugAsParams === slug);
if (!page) {
null;
}
return page;
}
export async function generateStaticParams(): Promise<PageProps['params'][]> {
return allPosts.map((page) => ({
slug: page.slugAsParams,
}));
}
export default async function PostPage({ params }: PageProps) {
const post = await getPageFromParams(params);
if (!post) {
notFound();
}
return (
<>
{post && post.title && (
<div className="hero">
<div className="container container-narrow">
<div className="hero-subheader">{post.product}</div>
<h1 className="hero-title">{post.title}</h1>
</div>
</div>
)}
<section className="section pt-0">
<div className="container container-narrow">
<div className="markdown">
{post.description && <p className="lead">{post.description}</p>}
<Mdx code={post.body.code} />
</div>
</div>
</section>
</>
);
}
@@ -0,0 +1,18 @@
import { allPosts } from 'contentlayer/generated';
export default async function BlogArchivePage() {
const posts = allPosts.sort((a, b) => {
return new Date(a.date).getTime() - new Date(b.date).getTime();
}).reverse();
return (
<>
{posts.map((post, i) => (
<div key={post._id}>
{post._id}
<a href={post.slug}>{post.title}</a>
</div>
))}
</>
);
}
+26
View File
@@ -0,0 +1,26 @@
export default function CoreLayout({
children
}: {
children: React.ReactNode,
}) {
return (
<section className="section">
<div className="container">
<div className="row">
<div className="col">
<main className="main">{children}</main>
</div>
<div className="col-3">
<h1 className="section-title section-title-lg">Tabler Blog</h1>
<p className="section-description">
Stay in the loop with all things Tabler. We provide regular
updates on new features, changelogs, and news, ensuring you never
miss any of our software developments.
</p>
</div>
</div>
</div>
</section>
);
}
+94
View File
@@ -0,0 +1,94 @@
import Link from 'components/Link';
import { allPosts } from 'contentlayer/generated';
export const metadata = {
title: 'Blog - Tabler',
description: 'Stay in the loop with all things Tabler. We provide regular updates on new features, changelogs, and news, ensuring you never miss any of our software developments.',
};
export default async function BlogPage() {
return (
<>
<div className="sm:gx-6 xl:gx-7">
{allPosts.map((post, i) => (
<div
className="guide"
key={post.slug}
itemScope={true}
itemType="https://schema.org/NewsArticle"
>
<div className="guide-date">
{/* <meta
itemProp="datePublished"
content={format(new Date(post.date), "yyyy-MM-dd")}
/>
<div>{format(new Date(post.date), "d")}</div>
<div>{format(new Date(post.date), "MMM")}</div> */}
</div>
<div className="box">
{post.image && (
<Link href={post.slug} className="d-block mb-4">
<div className="border-light rounded lh-1">
<img
src={post.image}
width={660}
height={361}
className="rounded"
alt={post.title}
itemProp="image"
/>
</div>
</Link>
)}
<div>
{post.title && (
<h2>
<meta itemProp="headline" content={post?.title} />
<meta itemProp="url" content={post.slug} />
<Link href={post.slug}>{post?.title}</Link>
</h2>
)}
<div className="markdown text-muted">
<p itemProp="description">{post.summary}</p>
</div>
</div>
<div className="mt-4">
<div className="row items-center">
<div className="col">
<div
className="d-flex items-center"
itemProp="author"
itemScope={true}
itemType="https://schema.org/Person"
>
<div
className="avatar mr-3"
style={{
backgroundImage: 'url(/img/authors/codecalm.jpg)',
}}
/>
<span itemProp="name">Paweł Kuna</span>
<meta itemProp="url" content="https://tabler.io" />
</div>
</div>
<div className="col-auto">
{/* <Link
href={post.slug}
className="btn"
aria-label={`Read more about "${post.title}"`}
>
Read more
</Link> */}
</div>
</div>
</div>
</div>
</div>
))}
</div>
</>
);
}
+58
View File
@@ -0,0 +1,58 @@
import { allChangelogs } from '@/.contentlayer/generated';
import Mdx from '@/components/MDX';
import { dateTemplate, distanceToNow, format } from '@/lib/date';
export default function ChangelogPage() {
const changelogs = allChangelogs
.sort((a, b) => {
return new Date(a.date).getTime() - new Date(b.date).getTime();
})
.reverse();
return (
<>
<section className="section pb-0">
<div className="container">
<div className="section-header mb-0">
<h2 className="section-title section-title-lg">Changelog</h2>
<p className="section-description">
Most recent updates, bug fixes, and introduction of new features.
</p>
</div>
</div>
</section>
<section className="section">
<div className="container container-narrow">
<div className="timeline">
{changelogs.map((changelog) => (
<div className="row g-7 timeline-item" key={changelog.version}>
<div className="col-3 timeline-summary">
<div className="font-medium font-h4">v{changelog.version}</div>
<div
className="text-muted mb-3 font-h6"
itemProp="datePublished"
content={format(changelog.date, 'yyyy-MM-dd')}
>
Published{' '}
<time
dateTime={dateTemplate(changelog.date)}
className="text-muted"
>
{distanceToNow(changelog.date)}
</time>
</div>
</div>
<div className="col-9 timeline-description">
{changelog.title && <h3 className="mb-3">{changelog.title}</h3>}
<div className="markdown">
<Mdx code={changelog.body.code} />
</div>
</div>
</div>
))}
</div>
</div>
</section>
</>
);
}
@@ -0,0 +1,78 @@
import emails from '@/data/emails.json';
import Link from '@/components/Link';
import EmailImage from '@/components/EmailImage';
import Slider from '@/components/Slider';
import ResponsiveImage from '@/components/ResponsiveImage';
import { emailsCount } from '@/config/site';
import CTABannerEmails from '@/components/CTABAnnerEmails';
import clsx from 'clsx';
export default function EmailsGalleryPage() {
return (
<>
<section className="section pb-0">
<div className="container">
<div className="section-header">
<h2 className="section-title section-title-lg">Email templates gallery</h2>
<p className="section-description">
See how our emails look. Choose your favorite from among {emailsCount}
&nbsp;carefully prepared emails.
</p>
</div>
</div>
</section>
{emails.map((email, i) => (
<section key={email.descriptionShort} className={clsx('section py-6', i % 2 == 1 ? 'section-light' : '')}>
<div className="container container-narrow">
<div className={clsx('row g-6 items-center', i % 2 == 0 ? 'flex-row-reverse' : '')}>
<div className="col">
<h3 className="mb-4">{email.descriptionShort}</h3>
<p>
{email.descriptionLong}
</p>
</div>
<div className="col-5">
<div>
<div className="rounded img-gradient border">
<div className="o-hidden ratio-3x4 mx-auto ">
<ResponsiveImage
src={`/img/tabler-emails/screenshots/${email.screenshot}-full.png`}
width={540}
height={email.height / email.width * 540}
className="rounded mx-auto"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
))}
<section className="section">
<div className="container">
<div className="mt-7">
<CTABannerEmails />
</div>
</div>
</section>
</>
);
}
// export async function getStaticProps() {
// return {
// props: {
// brand: 'tabler-emails',
// menu: 'emails',
// meta: {
// bodyClassName: 'body-gradient',
// title: `Tabler Emails: ${emailsCount} unique HTML email designs`,
// description: `See how our emails look. Choose your favorite from among ${emailsCount} carefully prepared emails.`,
// },
// },
// }
// }
+312
View File
@@ -0,0 +1,312 @@
import HeroEmails from '@/components/layout/hero/UiEmails';
import CTABannerEmails from '@/components/CTABAnnerEmails';
import Link from '@/components/Link';
import SectionDivider from '@/components/SectionDivider';
import Features from '@/components/Features';
import Shape from '@/components/Shape';
import ResponsiveImage from '@/components/ResponsiveImage';
import React from 'react';
import Slider from '@/components/Slider';
export const metadata = {
title: 'Tabler Emails',
description: 'Tabler Emails is a set of responsive email templates for marketing, transactional and automated emails.',
};
const EmailsFeatures1 = () => {
return (
<section className="section">
<div className="container">
<div className="row xl:g-7">
<div className="lg:col-6">
<ResponsiveImage
src="/img/tabler-emails/features/emails.png"
width="564"
height="549"
className="mx-auto"
/>
</div>
<div className="lg:col-6 d-flex flex-column items-center">
<div className="section-header w-100">
<h4 className="section-title text-center lg:text-left">Promote your brand the right way</h4>
</div>
<div className="space-y-5">
<div data-aos="fade-up" data-aos-delay="0">
<div className="row">
<div className="col-auto">
<Shape size="md" color="primary" icon="target-arrow" />
</div>
<div className="col">
<h3>Achieve your marketing goals</h3>
<p className="text-muted m-0">
Prepare engaging email campaigns and newsletters, keep your recipients up to date with the latest
news, let them know about their order status or send out customer satisfaction surveys. Our set of
emails will help you with all that and much more!
</p>
</div>
</div>
</div>
<div data-aos="fade-up" data-aos-delay="150">
<div className="row">
<div className="col-auto">
<Shape size="md" color="primary" icon="brush" />
</div>
<div className="col">
<h3>Personalization is key</h3>
<p className="text-muted m-0">
Customize the templates to make them suitable for your target group. You can change every element
as you wish, including the background, colors, icons, spacers and images. And if you want to
present your data in an attractive way, make use of advanced reports, charts or progress bars.
</p>
</div>
</div>
</div>
<div data-aos="fade-up" data-aos-delay="300">
<div className="row">
<div className="col-auto">
<Shape size="md" color="primary" icon="device-mobile" />
</div>
<div className="col">
<h3>Great quality with little effort</h3>
<p className="text-muted m-0">
More than 50% of emails today are open on mobile devices, so weve made sure our templates look
great on any device and screen size. They are fully responsive and mobile-ready, helping you take
care of great user experience.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
};
const EmailsFeatures2 = () => {
return (
<section className="section">
<div className="container">
<div className="row xl:g-7">
<div className="lg:col-6 d-flex flex-column items-center">
<div className="section-header w-100">
<h4 className="section-title text-center lg:text-left">
Focus on your brand and well take care of the rest
</h4>
</div>
<div className="space-y-5">
<div data-aos="fade-up" data-aos-delay="0">
<div className="row">
<div className="col-auto">
<Shape size="md" color="primary" icon="brand-bootstrap" />
</div>
<div className="col">
<h3>Bootstrap-inspired design</h3>
<p className="text-muted m-0">
Based on Bootstrap and Material Design principles, our email templates are responsive and meet the
highest quality standards. Thanks to that, you can be sure the layout will look perfect in every
email client and on any device.
</p>
</div>
</div>
</div>
<div data-aos="fade-up" data-aos-delay="150">
<div className="row">
<div className="col-auto">
<Shape size="md" color="primary" icon="layout-dashboard" />
</div>
<div className="col">
<h3>No coding skills needed</h3>
<p className="text-muted m-0">
Our templates are ready-to-use. You dont need coding skills to prepare eye-catching emails and
boost your brand awareness. Have a basic knowledge of HTML? Design your own email using the
elements from different templates and make it even more customized.
</p>
</div>
</div>
</div>
<div data-aos="fade-up" data-aos-delay="300">
<div className="row">
<div className="col-auto">
<Shape size="md" color="primary" icon="tools" />
</div>
<div className="col">
<h3>Reliable solution</h3>
<p className="text-muted m-0">
Tabler Emails have been tested across more than 90 email clients and many devices. Thanks to that,
instead of worrying about any technical issues, you can focus on making the content of your
message exceptional.
</p>
</div>
</div>
</div>
</div>
</div>
<div className="lg:col-6">
<ResponsiveImage src="/img/tabler-emails/features/stats.png" width="564" height="762" className="mx-auto" />
</div>
</div>
</div>
</section>
);
};
const EmailsGallery = () => {
return (
<div className="section section-light">
<div className="container">
<div className="section-header">
<h2 className="section-title">See what you will get</h2>
<p className="section-description">Browse our selection of emails and see how they look.</p>
</div>
</div>
<div className="expandable expandable-emails" />
<div className="container">
<div className="text-center mt-2">
<Link href="/emails/gallery" className="btn btn-lg">
Browse emails gallery
</Link>
</div>
</div>
</div>
);
};
const EmailsDark = () => {
return (
<section className="section">
<div className="container">
<div className="row xl:g-7 items-center">
<div className="lg:col-6">
<Slider
slides={[
<ResponsiveImage
src="/img/tabler-emails/features/dark.png"
width="564"
height="585"
key="img-1"
className="mx-auto"
/>,
<ResponsiveImage
src="/img/tabler-emails/features/dark-light.png"
width="564"
height="585"
key="img-2"
className="mx-auto"
/>,
]}
/>
</div>
<div className="lg:col-6">
<div className="section-header text-left">
<h2 className="section-title">Dark mode? No problem!</h2>
<div className="section-description">
<p>
Dark mode is a darker color palette for low-light or nighttime environments. This inverted color
scheme uses light typography, UI elements and icons on a dark background - and is one of the hottest
trends in digital design in recent years. If your subscribers are making a conscious decision to view
Dark Mode emails, it&apos;s best to respect that!
</p>
<p>
Each email in Tabler Emails is available in two color versions: light and dark. It&apos;s up to you
which version suits your branding better!
</p>
</div>
</div>
</div>
</div>
<div className="mt-7">
<CTABannerEmails />
</div>
</div>
</section>
);
};
const EmailsKickItOff = () => {
return (
<section className="section section-sm section-light">
<div className="container">
<div className="row text-center">
<div className="md:col" data-aos="fade-up" data-aos-delay={0}>
<Shape placeholder={1} size="md" className="mb-2" color="primary" />
<div>Choose one of 54 email templates</div>
</div>
<div className="md:col" data-aos="fade-up" data-aos-delay={150}>
<Shape placeholder={2} size="md" className="mb-2" color="primary" />
<div>Add your own content to customize it</div>
</div>
<div className="md:col" data-aos="fade-up" data-aos-delay={300}>
<Shape placeholder={3} size="md" className="mb-2" color="primary" />
<div>Send it using one of the most popular email sending systems</div>
</div>
</div>
{/*<div className="mt-5 text-center">*/}
{/* <a href="#" className="btn btn-primary">Buy now for ${emailsPrice}</a>*/}
{/*</div>*/}
</div>
</section>
);
};
export default function EmailsPage() {
const features = [
{
icon: 'devices',
title: 'Mobile-optimized',
description:
'Our email templates are fully responsive, so you can be sure they will look great on any device and screen size.',
},
{
icon: 'mailbox',
title: 'Compatible with 90+ email clients',
description:
'Tested across 90+ email clients and devices, Tabler emails will help you make your email communication professional and reliable.',
},
{
icon: 'palette',
title: 'Unique, minimal design',
description:
'Draw recipients attention with beautiful, minimal email designs based on Bootstrap and Material Design principles.',
},
];
return (
<>
<HeroEmails />
<section className="section section-sm section-light">
<SectionDivider />
<div className="container">
<Features list={features} />
</div>
</section>
<EmailsFeatures1 />
<EmailsKickItOff />
<EmailsFeatures2 />
<EmailsGallery />
<EmailsDark />
</>
);
}
// export async function getStaticProps() {
// return {
// props: {
// brand: 'tabler-emails',
// menu: 'emails',
// meta: {
// bodyClassName: 'body-gradient',
// title: 'Tabler Emails: Responsive Newsletters and Email templates design',
// description:
// 'Look great in every inbox! Compose newsletter, e-commerce messages, reset password and any other email in less than 5 minutes',
// },
// },
// }
// }
+52
View File
@@ -0,0 +1,52 @@
import ResponsiveImage from '@/components/ResponsiveImage';
import features from '@/data/features';
export default function FeaturesPage() {
return (
<section className="section">
<div className="container">
<div className="section-header">
<h2 className="section-title section-title-lg">Some examples built with Tabler</h2>
<p className="section-description">Get everything you need for building amazing websites</p>
</div>
<div className="row g-3 md:g-4 xl:g-6" data-aos-id-blocks-features>
{features.map(
(feature, i) =>
!feature.hide && (
<div className="col-12 sm:col-6 md:col-4" key={i}>
<div data-aos="fade-up" data-aos-anchor="[data-aos-id-blocks-features]" data-aos-delay={i * 100}>
<div className="mb-3 shadow-card rounded">
<ResponsiveImage
src={`/img/tabler/features-small/${feature.image}`}
width={368}
height={276}
className="rounded d-block"
alt={feature.title}
/>
</div>
<h3 className="h4">{feature.title}</h3>
<p className="text-muted m-0">{feature.description}</p>
</div>
</div>
)
)}
</div>
{/*<div className="mt-7">*/}
{/* <CTABannerEmails />*/}
{/*</div>*/}
</div>
</section>
);
}
// export async function getStaticProps() {
// return {
// props: {
// menu: 'ui',
// meta: {
// bodyClassName: 'body-gradient',
// },
// },
// }
// }
+190
View File
@@ -0,0 +1,190 @@
'use client';
import { notFound, useRouter } from 'next/navigation';
import { useClipboard } from '@/hooks';
import clsx from 'clsx';
import { allGuides } from 'contentlayer/generated';
import { escapeHtml, uiUrl } from '@/config/site';
import { dateTemplate, distanceToNow, format } from '@/lib/date';
import CTABannerEmails from '@/components/CTABAnnerEmails';
import Icon from '@/components/Icon';
import TablerSponsorsBanner from '@/components/TablerSponsorsBanner';
import Mdx from '@/components/MDX';
interface GuidePageProps {
params: {
slug: string
}
}
async function getGuideFromParams(params) {
const slug = params.slug || '';
const guide = allGuides.find((guide) => guide.slugAsParams === slug);
if (!guide) {
null;
}
return guide;
}
export async function generateStaticParams(): Promise<
GuidePageProps['params'][]
> {
return allGuides.map((guide) => ({
slug: guide.slugAsParams,
}));
}
export default async function GuidePage({ params }: GuidePageProps) {
const guide = await getGuideFromParams(params);
if (!guide) {
notFound();
}
const url = `${uiUrl}${guide.slug}`;
// const router = useRouter(),
// currentPath = router.pathname,
// url = `${uiUrl}${guide.slug}`
// clipboard = useClipboard()
return (
<>
<section
className="section"
itemScope={true}
itemType="https://schema.org/NewsArticle"
>
<div className="container">
{/* {meta.date && (
<div
className="text-muted mb-3 font-h6"
itemProp="datePublished"
content={format(meta.date, "yyyy-MM-dd")}
>
Published{" "}
<time dateTime={dateTemplate(meta.date)} className="text-muted">
{distanceToNow(meta.date)}
</time>
</div>
)} */}
<h1 className="h0 mb-3" itemProp="headline">
{guide.title}
</h1>
<div className="row">
<div className="md:col-9 text-muted font-h4">{guide.summary}</div>
</div>
<div className="mt-6">
<div className="row">
<div className="md:col-8">
{guide.image && (
<div className="mb-6">
<img
src={guide.image}
alt={guide.title}
className="border-light rounded"
// lazy={true}
itemProp="image"
/>
</div>
)}
<article className="markdown">
<Mdx code={guide.body.code} />
</article>
<TablerSponsorsBanner className="mt-7" />
</div>
<div className="md:col-3 md:order-first">
{guide.tags && (
<div className="tags-list mt-3">
{guide.tags.map((tag) => (
<div className="tag" key={tag}>
{tag}
</div>
))}
</div>
)}
<div
itemProp="author"
itemScope={true}
itemType="https://schema.org/Person"
>
<div
className="avatar avatar-xl avatar-rounded mb-3"
style={{
backgroundImage: 'url(/img/authors/codecalm.jpg)',
}}
></div>
<div className="h4" itemProp="name">
Paweł Kuna
</div>
<div className="text-muted">Founder of Tabler</div>
<meta itemProp="url" content={uiUrl} />
</div>
<div className="btn-list mt-6">
<button
type="button"
className={clsx(
'btn btn-icon btn-circle'
// clipboard.copied ? "btn-green" : ""
)}
aria-label="Copy the Canonical link"
// onClick={() => clipboard.copy(url)}
>
{/* {clipboard.copied ? (
<Icon name="check" />
) : (
<Icon name="link" />
)} */}
</button>
<a
className="btn btn-icon btn-circle"
target="_blank"
rel="noopener"
href={`https://twitter.com/share?url=${escapeHtml(
url
)}&text=${escapeHtml(guide.title)}`}
>
<Icon name="brand-twitter" />
</a>
<a
className="btn btn-icon btn-circle"
target="_blank"
rel="noopener"
href={`https://www.facebook.com/sharer/sharer.php?u=${escapeHtml(
url
)}`}
>
<Icon name="brand-facebook" />
</a>
<a
className="btn btn-icon btn-circle"
target="_blank"
rel="noopener"
href={`https://www.linkedin.com/share?url=${escapeHtml(
url
)}`}
>
<Icon name="brand-linkedin" />
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<section className="section bg-light">
<div className="container">
<CTABannerEmails />
</div>
</section>
</>
);
}
+114
View File
@@ -0,0 +1,114 @@
import { allGuides } from 'contentlayer/generated';
import { format } from '@/lib/date';
import Link from '@/components/Link';
export default async function GuidesPage() {
return (
<section className="section">
<div className="container">
<div className="section-header">
<h2 className="section-title section-title-lg">Guides</h2>
<p className="section-description">
The most interesting articles to help you build better applications
</p>
</div>
<div className="guides sm:gx-6 xl:gx-7">
{allGuides.map((guide, i) => (
<div
className="guide"
key={guide.slug}
itemScope={true}
itemType="https://schema.org/NewsArticle"
>
<div className="guide-date">
<meta
itemProp="datePublished"
content={format(guide.date, 'yyyy-MM-dd')}
/>
<div>{format(guide.date, 'd')}</div>
<div>{format(guide.date, 'MMM')}</div>
</div>
<div className="box">
{guide.image && (
<Link href={guide.slug} className="d-block mb-4">
<div className="border-light rounded lh-1">
<img
src={guide.image}
width={660}
height={361}
className="rounded"
alt={guide.title}
itemProp="image"
/>
</div>
</Link>
)}
<div>
{guide.title && (
<h2>
<meta itemProp="headline" content={guide?.title} />
<meta itemProp="url" content={guide.slug} />
<Link href={guide.slug}>{guide?.title}</Link>
</h2>
)}
<div className="markdown text-muted">
<p itemProp="description">{guide.summary}</p>
</div>
</div>
<div className="mt-4">
<div className="row items-center">
<div className="col">
<div
className="d-flex items-center"
itemProp="author"
itemScope={true}
itemType="https://schema.org/Person"
>
<div
className="avatar mr-3"
style={{
backgroundImage: 'url(/img/authors/codecalm.jpg)',
}}
/>
<span itemProp="name">Paweł Kuna</span>
<meta itemProp="url" content="https://tabler.io" />
</div>
</div>
<div className="col-auto">
<Link
href={guide.slug}
className="btn"
aria-label={`Read more about "${guide.title}"`}
>
Read more
</Link>
</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</section>
);
}
// export async function getStaticProps() {
// const guides = await getAllGuides(['slug', 'title', 'summary', 'date', 'image'])
// return {
// props: {
// guides,
// menu: 'guides',
// meta: {
// bodyClassName: 'bg-light',
// title: 'Guides - The most interesting articles to help you build better applications',
// },
// },
// }
// }
+254
View File
@@ -0,0 +1,254 @@
import React from 'react';
import icons from '@/data/icons.json';
import { groupBy, sortByKeys } from '@/helpers';
import { IconType, IconsType } from '@/types';
import { figmaPluginUrl, iconsCount, iconsCountRounded, iconsUrl } from '@/config/site';
import Features from '@/components/Features';
import Icon from '@/components/Icon';
import IconSvg from '@/components/IconSvg';
import ResponsiveImage from '@/components/ResponsiveImage';
import SectionDivider from '@/components/SectionDivider';
import HeroIcons from '@/components/layout/hero/UiIcons';
// const IconsInstallation = () => {
// return (
// <section className="section section-light">
// <div className="container">
// <div className="section-header">
// <h2 className="section-title">Installation</h2>
// </div>
// </div>
// </section>
// )
// }
// const IconsFrameworks = () => {
// const frameworks = [
// { name: 'React', route: '/docs/icons/react', package: '@tabler/icons-react', icon: 'react' },
// { name: 'Svelte', route: '/docs/icons/svelte', package: '@tabler/icons-svelte', icon: 'svelte' },
// { name: 'Blade', route: '/docs/icons/blade', package: '@tabler/icons-blade', icon: 'blade' },
// { name: 'Vue 3', route: '/docs/icons/vue', package: '@tabler/icons-vue', icon: 'vue' },
// { name: 'Preact', route: '/docs/icons/preact', package: '@tabler/icons-preact', icon: 'preact' },
// { name: 'Figma', href: figmaPluginUrl, package: '@tabler/icons-figma', icon: 'figma' },
// ]
//
// return (
// <section className="section section-sm section-light">
// <div className="container">
// <div className="section-header">
// <h2 className="section-title">Frameworks</h2>
// </div>
//
// <div className="row justify-center g-4">
// {frameworks.map((framework) => (
// <div className="col" key={framework.icon}>
// {framework.route ?
// <Link href={framework.route} className="d-block text-center text-reset bg-white border rounded-lg py-3">
// <img src={`/img/tabler-icons/framework/${framework.icon}.svg`} alt={framework.name} className="mx-auto mb-2" />
// {framework.name}
// </Link>
// :
// <a href={framework.href} className="d-block text-center text-reset bg-white border rounded-lg py-3" target="_blank" rel="noopener noreferrer">
// <img src={`/img/tabler-icons/framework/${framework.icon}.svg`} alt={framework.name} className="mx-auto mb-2" />
// {framework.name}
// </a>}
// </div>
// ))}
// </div>
// </div>
// </section>
// )
// }
const IconsFigma = () => {
return (
<section className="section">
<div className="container">
<div className="row xl:g-7 items-center">
<div className="md:col-6">
<ResponsiveImage
src="/img/tabler-icons/features/figma.png"
width="564"
height="448"
/>
</div>
<div className="md:col-6">
<div className="section-header text-left">
<h2 className="section-title">
Do you need Figma plugin? No problem!
</h2>
<p className="section-description">
Tabler Icons offers a plugin for Figma, with which you can
easily find and customize the icons you just need. You will
always find the newest icons that you can quickly add to your
project!
</p>
</div>
<div className="btn-list mt-6">
<a
href={figmaPluginUrl}
className="btn btn-lg"
target="_blank"
rel="noopener noreferrer"
>
<Icon name="brand-figma" /> Get Figma plugin
</a>
</div>
</div>
</div>
</div>
</section>
);
};
const IconsFeatures = () => {
const features = [
{
icon: 'check',
title: 'Ready-to-use',
description:
'You can use the icons as HTML images, embed them in your HTML code, create an SVG sprite or render them in React.',
},
{
icon: 'brand-sketch',
title: 'Multiple formats',
description:
'Icons can be used in Sketch, Illustrator, XD and Figma - choose the tool you feel the most comfortable working with.',
},
{
icon: 'edit',
title: 'Customizable',
description:
'Every icon is designed on a 24x24 grid and a 2px stroke. You can easily customize them, changing the size, stroke or color.',
},
{
icon: 'brand-github',
title: 'Free and open source',
description:
'Tabler Icons is a free and open source solution, which is continuously developed. Feel free to request an icon you need!',
},
];
return (
<section className="section section-sm section-light">
<SectionDivider wave />
<div className="container">
{/*<div className="section-header">*/}
{/* <h2 className="section-title">*/}
{/* Icons tailored to your needs*/}
{/* </h2>*/}
{/*</div>*/}
<Features list={features} />
</div>
</section>
);
};
const IconsCategories = () => {
const iconsGroupedByCategory = ((icons) => {
return sortByKeys(groupBy(icons, 'category'));
})(icons);
delete iconsGroupedByCategory[''];
delete iconsGroupedByCategory['Gender'];
delete iconsGroupedByCategory['Zodiac'];
delete iconsGroupedByCategory['Database'];
delete iconsGroupedByCategory['Building'];
delete iconsGroupedByCategory['Logic'];
delete iconsGroupedByCategory['Animals'];
return (
<section className="section section-light">
<div className="container">
<div className="section-header">
<div className="section-title">Wide choice of categories</div>
<div className="section-description">
Search for icons by categories to find what you need easier and
faster. Tabler icons will help you make your design consistent and
eye-catching.
</div>
</div>
<div className="row" data-aos-id-blocks-icons>
{Object.entries<IconsType>(iconsGroupedByCategory).map(
([category, icons], i) => (
<div
className="sm:col-6 md:col-4 lg:col-3"
key={category}
data-aos="fade-up"
data-aos-anchor="[data-aos-id-blocks-icons]"
data-aos-delay={i * 50}
>
<a
href={`${iconsUrl}?category=${encodeURIComponent(category)}`}
className="icons-card"
target="_blank"
>
<strong className="icons-card-title">{category}</strong>
<div className="icons-card-list">
{icons
.filter((icon) => !icon.name.endsWith('-off'))
.map(
(icon, i) =>
i < 14 && (
<IconSvg
svg={icon.svg}
key={icon.name}
className="icons-card-icon"
/>
)
)}
{icons.length > 15 && (
<div className="icons-card-placeholder">
+{icons.length - 14}
</div>
)}
</div>
<span className="icons-card-layer">
<Icon name="search" /> Browse {icons.length} icons
</span>
</a>
</div>
)
)}
</div>
</div>
</section>
);
};
export default function IconsPage() {
return (
<>
<HeroIcons />
<IconsFeatures />
<IconsFigma />
{/*<IconsFrameworks />*/}
<IconsCategories />
{/*<IconsInstallation />*/}
</>
);
}
// export async function getStaticProps() {
// return {
// props: {
// brand: 'tabler-icons',
// menu: 'icons',
// meta: {
// bodyClassName: 'body-gradient',
// title: `Tabler Icons: over ${iconsCountRounded} free and open source vector icons for web design`,
// description: `${iconsCount} free and open source SVG icons designed with attention to detail to make your design stand out. Highly customizable. No attribution required. For commercial use.`,
// },
// },
// }
// }
+16
View File
@@ -0,0 +1,16 @@
import Header from '@/components/layout/Header';
import Footer from '@/components/layout/Footer';
export default function CoreLayout({
children
}: {
children: React.ReactNode,
}) {
return (
<>
<Header />
<main className="main">{children}</main>
<Footer />
</>
);
}
+716
View File
@@ -0,0 +1,716 @@
'use client';
import React, { useState } from 'react';
import Link from 'next/link';
import questions from '@/data/faq.json';
import { componentsCount, emailsPrice, iconsUrl } from '@/config/site';
import Features from '@/components/Features';
import Icon from '@/components/Icon';
import ResponsiveImage from '@/components/ResponsiveImage';
import SectionDivider from '@/components/SectionDivider';
import Shape from '@/components/Shape';
import Testimonials from '@/components/layout/Testimonials';
import TestimonialsShare from '@/components/layout/TestimonialsShare';
import HeroUi from '@/components/layout/hero/Ui';
const benefits = [
'Fully responsive',
'Based on Bootstrap 5',
'Built with Sass',
'Detailed documentation',
'MIT license',
'Customizable',
`${componentsCount}+ UI components`,
'Multiple layouts',
'Dark mode',
'Premium vector icons',
];
const Modal = () => {
const [modalVisible, setModalVisible] = useState(true);
return (
modalVisible && (
<div className="modal-backdrop">
<div className="modal modal-wide">
<div
className="modal-close"
onClick={() => setModalVisible(false)}
>
<Icon name="x" />
</div>
<div className="row g-0">
<div className="col-6">
<div
className="ratio ratio-1x1 rounded-left"
style={{
backgroundColor: '#fff',
backgroundImage: 'url(https://source.unsplash.com/random/478x478/?landscape)',
}}
/>
</div>
<div className="col">
<div className="modal-body d-flex flex-column h-100">
<h3 className="modal-title">Modal title</h3>
<div className="text-muted">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cum
eius eligendi error facilis fugiat laboriosam omnis quam
soluta? Adipisci aliquam iste numquam, optio perferendis
possimus quae ratione rerum soluta voluptatibus.
</div>
<a
href="#"
className="mt-auto btn btn-primary btn-block"
onClick={() => setModalVisible(false)}
>
Buy for $$
{emailsPrice}
</a>
</div>
</div>
</div>
</div>
</div>
)
);
};
const FAQ = () => {
return (
<section className="section section-light">
<div className="container">
<div className="row xl:g-6">
<div className="md:col-4" data-aos="fade-up">
<div className="section-header text-left sticky-top">
<div className="section-title">Frequently asked questions</div>
<p className="section-description">
Cant find the answer youre looking for? Reach out to our
customer support team.
</p>
</div>
</div>
<div className="col">
<div className="space-y-5">
{questions.map((question, i) => (
<div data-aos="fade-up" data-aos-delay={i * 150} key={i}>
<div className="h3 mb-1">{question.question}</div>
<div className="text-muted">{question.answer}</div>
</div>
))}
</div>
<div className="mt-5">
<Link href="/faq" className="btn">
Read more questions
</Link>
</div>
</div>
</div>
</div>
</section>
);
};
const Projects = () => {
return (
<section className="section">
<div className="container">
<div className="section-header">
<h3 className="section-title">Section title</h3>
<p className="section-description">
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</p>
</div>
<div className="row">
<div className="col">
<div className="card">
<div className="row g-0">
<div className="col">
<div className="card-body h-100 d-flex flex-column pr-0">
<div className="h-subheader text-primary">Tabler Icons</div>
<h3 className="section-title mb-4">
Brilliant Toolkit to Build Nextgen Website Faster.
</h3>
<div className="text-muted markdown">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing
elit. Illo perferendis, repellat! Asperiores ducimus
esse nobis quaerat sed! Delectus eius illum incidunt
minus neque, quos ratione reiciendis voluptatum. Odio
quia, similique.
</p>
</div>
<div className="mt-auto pt-5">
<div className="btn-list">
<a
href={iconsUrl}
className="btn btn-primary"
target="_blank"
>
Browse icons
</a>
<Link href="/icons" className="btn">
More info
</Link>
</div>
</div>
</div>
</div>
<div className="col-4">
<div
className="ratio ratio-1x1 rounded-right"
style={{
backgroundColor: '#fff',
backgroundImage: 'url(/img/tabler/icons-bg.png)',
}}
/>
</div>
</div>
</div>
</div>
<div className="col">
<div className="card">
<div className="row g-0">
<div className="col">
<div className="card-body h-100 d-flex flex-column pr-0">
<div className="h-subheader text-primary">
Tabler Emails
</div>
<h3 className="section-title mb-4">
Brilliant Toolkit to Build Nextgen Website Faster.
</h3>
<div className="text-muted markdown">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing
elit. Illo perferendis, repellat! Asperiores ducimus
esse nobis quaerat sed! Delectus eius illum incidunt
minus neque, quos ratione reiciendis voluptatum. Odio
quia, similique.
</p>
</div>
<div className="mt-auto pt-5">
<div className="btn-list">
<a href="#" className="btn btn-primary">
Buy emails for $29
</a>
<Link href="/icons" className="btn">
More info
</Link>
</div>
</div>
</div>
</div>
<div className="col-4">
<div
className="ratio ratio-1x1 rounded-right"
style={{
backgroundColor: '#fff',
backgroundImage: 'url(/img/tabler/icons-bg.png)',
}}
/>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
};
export default async function HomePage() {
const features = [
{
icon: 'brand-github',
title: 'Free and open source',
description:
'A big choice of free UI elements and layouts in one efficient, open source solution',
},
{
icon: 'brand-bootstrap',
title: 'Based on Bootstrap 5',
description:
'Based on the latest version of Bootstrap, Tabler is a UI Kit of the future',
},
{
icon: 'brand-html5',
title: 'Modern design',
description:
'Beautiful, fully responsive UI elements that will make your design modern and user-friendly',
},
];
const highlighCode = `<div className="col" data-aos="fade-up">
<h2 className="section-title">
Loving Tabler? Get to know our set of {iconsCount}&nbsp;free vector icons!
</h2>
<p className="section-description">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eligendi ex facere impedit nostrum
obcaecati. Ipsam, magnam nam nihil quisquam repellendus tempora. Dicta dignissimos ex laudantium
reiciendis sapiente ut voluptate voluptatibus?
</p>
<div className="mt-5">
<Link href="/icons" className="btn">
Read more about icons
</Link>
</div>
</div>`;
return (
<>
{/*<Modal />*/}
<HeroUi />
<div className="section section-light pt-6 pb-6">
<SectionDivider />
<div className="container img-overlap-padding">
<Features list={features} />
</div>
</div>
<section className="section" id="features">
<div className="container">
<div className="row items-center">
<div className="lg:col-6" data-aos="fade-up">
<div className="section-header w-100">
<h2 className="section-title text-center lg:text-left">
Benefit from Tablers top-notch features
</h2>
</div>
{/*<p className="section-description mb-5">*/}
{/* Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur*/}
{/* deleniti dicta, earum eligendi exercitationem itaque molestias nobis non optio perspiciatis*/}
{/* placeat possimus praesentium rerum tempora tempore totam vel. Autem, repudiandae!*/}
{/*</p>*/}
<div className="row">
{benefits.map((benefit, i) => (
<div className="sm:col-6 md:col-4 lg:col-6" key={i}>
<Shape
icon="check"
color="green"
className="mr-3"
size="sm"
rounded
/>
{benefit}
</div>
))}
</div>
</div>
<div className="lg:col-6" data-aos="fade-up">
<ResponsiveImage
src="/img/tabler/features/charts.png"
width="510"
height="524"
className="mx-auto"
/>
</div>
</div>
</div>
</section>
<section className="section section-light">
<div className="container">
<div className="section-header">
<h2 className="section-title">Multiple Demos</h2>
<p className="section-description">
6 Pre-built layout options to cater needs of modern web
applications. Ready-to-use UI elements enable to develop modern
web application with great speed
</p>
</div>
<div className="row" data-aos-id-blocks-previews>
<div className="col-6 md:col-4">
<a
href="https://preview.tabler.io?theme=light"
className="d-block text-center link text-reset"
data-aos="fade-up"
data-aos-anchor="[data-aos-id-blocks-previews]"
data-aos-delay={0}
target="_blank"
rel="noopener noreferrer"
>
<ResponsiveImage
src="/img/tabler/preview.png"
width="389"
height="243"
className="mx-auto rounded link-img"
/>
<div className="mt-3">Modern dashboard</div>
</a>
</div>
<div className="col-6 md:col-4">
<a
href="https://preview.tabler.io?theme=dark"
className="d-block text-center link text-reset"
data-aos="fade-up"
data-aos-anchor="[data-aos-id-blocks-previews]"
data-aos-delay={150}
target="_blank"
rel="noopener noreferrer"
>
<ResponsiveImage
src="/img/tabler/preview-dark.png"
width="389"
height="243"
className="mx-auto rounded link-img"
/>
<div className="mt-3">Dark mode</div>
</a>
</div>
<div className="col-6 md:col-4">
<a
href="https://preview.tabler.io/layout-vertical.html?theme=light"
className="d-block text-center link text-reset"
data-aos="fade-up"
data-aos-anchor="[data-aos-id-blocks-previews]"
data-aos-delay={300}
target="_blank"
rel="noopener noreferrer"
>
<ResponsiveImage
src="/img/tabler/preview-sidebar.png"
width="389"
height="243"
className="mx-auto rounded link-img"
/>
<div className="mt-3">With sidebar navigation</div>
</a>
</div>
<div className="col-6 md:col-4">
<a
href="https://preview.tabler.io/layout-navbar-overlap.html?theme=light"
className="d-block text-center link text-reset"
data-aos="fade-up"
data-aos-anchor="[data-aos-id-blocks-previews]"
data-aos-delay={450}
target="_blank"
rel="noopener noreferrer"
>
<ResponsiveImage
src="/img/tabler/preview-navbar-overlap.png"
width="389"
height="243"
className="mx-auto rounded link-img"
/>
<div className="mt-3">With overlap navbar</div>
</a>
</div>
<div className="col-6 md:col-4">
<a
href="https://preview.tabler.io/layout-vertical-transparent.html?theme=light"
className="d-block text-center link text-reset"
data-aos="fade-up"
data-aos-anchor="[data-aos-id-blocks-previews]"
data-aos-delay={600}
target="_blank"
rel="noopener noreferrer"
>
<ResponsiveImage
src="/img/tabler/preview-sidebar-transparent.png"
width="389"
height="243"
className="mx-auto rounded link-img"
/>
<div className="mt-3">With transparent navigation</div>
</a>
</div>
<div className="col-6 md:col-4">
<a
href="https://preview.tabler.io/layout-rtl.html?theme=light"
className="d-block text-center link text-reset"
data-aos="fade-up"
data-aos-anchor="[data-aos-id-blocks-previews]"
data-aos-delay={750}
target="_blank"
rel="noopener noreferrer"
>
<ResponsiveImage
src="/img/tabler/preview-rtl.png"
width="389"
height="243"
className="mx-auto rounded link-img"
/>
<div className="mt-3">RTL mode</div>
</a>
</div>
</div>
</div>
</section>
<section className="section">
<div className="container">
<div className="section-header">
<h2 className="section-title">
Create a perfect interface. Make your life easier.
</h2>
</div>
<div className="row items-center">
<div className="lg:col-6" data-aos="fade-up">
<ResponsiveImage
src="/img/tabler/features/forms.png"
width={510}
height={524}
className="mx-auto"
/>
</div>
<div className="lg:col-6">
<div className="space-y-5">
<div data-aos="fade-up" data-aos-delay="0">
<div className="row">
<div className="col-auto">
<Shape size="md" color="primary" icon="tools" />
</div>
<div className="col">
<h3>Designed with users in mind</h3>
<p className="text-muted 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 data-aos="fade-up" data-aos-delay="150">
<div className="row">
<div className="col-auto">
<Shape size="md" color="primary" icon="brand-bootstrap" />
</div>
<div className="col">
<h3>Built for developers</h3>
<p className="text-muted 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 data-aos="fade-up" data-aos-delay="300">
<div className="row">
<div className="col-auto">
<Shape size="md" color="primary" icon="paint" />
</div>
<div className="col">
<h3>Fully customizable</h3>
<p className="text-muted 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>
<section className="section section-dark">
<div className="container">
<div className="section-header">
<h2 className="section-title">
Dark theme whenever you need it
</h2>
</div>
<div className="row items-center">
<div className="lg:col-6">
<div className="space-y-5">
<div data-aos="fade-up" data-aos-delay="0">
<div className="row">
<div className="col-auto">
<Shape size="md" color="white" icon="sun-moon" />
</div>
<div className="col">
<h3>Change default variant when you need</h3>
<p className="text-muted m-0">
Tabler is a beautiful dashboard that comes in 2
versions: Dark and Light Mode. If you are looking for a
tool to manage and visualize data about your business,
this dashboard is the thing for you. It combines colors
that are easy on the eye, spacious cards, beautiful
typography, and graphics.
</p>
</div>
</div>
</div>
<div data-aos="fade-up" data-aos-delay="150">
<div className="row">
<div className="col-auto">
<Shape size="md" color="white" icon="tools" />
</div>
<div className="col">
<h3>All components available in dark mode</h3>
<p className="text-muted m-0">
Tabler contains a vast collection of assorted reusable
dark UI components, page layouts, charts, tables, UI
elements, and icons.
</p>
</div>
</div>
</div>
<div data-aos="fade-up" data-aos-delay="300">
<div className="row">
<div className="col-auto">
<Shape size="md" color="white" icon="paint" />
</div>
<div className="col">
<h3>A lot of reasons why dark theme are used widely</h3>
<p className="text-muted m-0">
Dark mode saves battery life and can reduce eye fatigue
in low-light conditions. The high contrast between text
and background reduces eye fatigue, and the dark screen
helps you focus your eyes longer and helps your brain
keep more attention on the screen.
</p>
</div>
</div>
</div>
</div>
</div>
<div className="lg:col-6" data-aos="fade-up">
<ResponsiveImage
src="/img/tabler/features/dark.png"
width={510}
height={524}
className="mx-auto"
/>
</div>
</div>
</div>
</section>
<section className="section">
<div className="container">
<div className="section-header">
<h2 className="section-title">Trusted by hundreds</h2>
<p className="section-description">
Our Users send us bunch of smilies with our services, and we love
them 😍
</p>
</div>
<div className="expandable">
<Testimonials limit={10} />
</div>
<TestimonialsShare />
</div>
</section>
{/*<section className="section section-light">*/}
{/* <div className="container">*/}
{/* <div className="row items-center">*/}
{/* <div className="col" data-aos="fade-up">*/}
{/* <ResponsiveImage*/}
{/* src="/img/features/code.png"*/}
{/* width={510}*/}
{/* height={276}*/}
{/* />*/}
{/* </div>*/}
{/* <div className="col" data-aos="fade-up">*/}
{/* <h2 className="section-title">*/}
{/* Loving Tabler? Get to know our set of {iconsCount}&nbsp;free vector icons!*/}
{/* </h2>*/}
{/* <p className="section-description">*/}
{/* Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eligendi ex facere impedit nostrum*/}
{/* obcaecati. Ipsam, magnam nam nihil quisquam repellendus tempora. Dicta dignissimos ex laudantium*/}
{/* reiciendis sapiente ut voluptate voluptatibus?*/}
{/* </p>*/}
{/* <div className="mt-5">*/}
{/* <Link href="/icons" className="btn">*/}
{/* Read more about icons*/}
{/* </Link>*/}
{/* </div>*/}
{/* </div>*/}
{/* </div>*/}
{/* </div>*/}
{/*</section>*/}
{/*<section className="section">*/}
{/* <div className="container text-center">*/}
{/* <blockquote className="font-h2 lh-h2 mb-5 font-medium">*/}
{/* “UI Prep has been instrumental in our agency work. UI Prep helps us start at 60% instead of 0%. Its comprehensive, organized, and very*/}
{/* thoughtfully designed. I could not recommend this more.”*/}
{/* </blockquote>*/}
{/* <div>*/}
{/* <span className="avatar avatar-xl" style={{ backgroundImage: "url(/img/authors/codecalm.jpg)"}} />*/}
{/* </div>*/}
{/* <div className="h4">Jon Moore</div>*/}
{/* <div className="text-muted">Principal Product Designer at Innovate map</div>*/}
{/* <div>*/}
{/* <Icon name="star" filled color="yellow" />*/}
{/* <Icon name="star" filled color="yellow" />*/}
{/* <Icon name="star" filled color="yellow" />*/}
{/* <Icon name="star" filled color="yellow" />*/}
{/* <Icon name="star" filled color="yellow" />*/}
{/* </div>*/}
{/* </div>*/}
{/*</section>*/}
{/*<section className="section section-light">*/}
{/* <div className="container">*/}
{/* <div className="row items-center">*/}
{/* <div className="col-6" data-aos="fade-up">*/}
{/* <h2 className="section-title">*/}
{/* Loving Tabler? Get to know our set of {iconsCount}&nbsp;free vector icons!*/}
{/* </h2>*/}
{/* <p className="section-description">*/}
{/* Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eligendi ex facere impedit nostrum*/}
{/* obcaecati. Ipsam, magnam nam nihil quisquam repellendus tempora. Dicta dignissimos ex laudantium*/}
{/* reiciendis sapiente ut voluptate voluptatibus?*/}
{/* </p>*/}
{/* <div className="mt-5">*/}
{/* <Link href="/icons" className="btn">*/}
{/* Read more about icons*/}
{/* </Link>*/}
{/* </div>*/}
{/* </div>*/}
{/* <div className="col-6" data-aos="fade-up">*/}
{/* <div className="highlight highlight-readonly" data-language="html">*/}
{/* <SyntaxHighlighter language={"xml"} useInlineStyles={false}>*/}
{/* {highlighCode}*/}
{/* </SyntaxHighlighter>*/}
{/* </div>*/}
{/* </div>*/}
{/* </div>*/}
{/* </div>*/}
{/*</section>*/}
{/*<News />*/}
{/*<Projects />*/}
<FAQ />
</>
);
}
// export async function getStaticProps() {
// return {
// props: {
// menu: "ui",
// meta: {
// bodyClassName: "body-gradient",
// title:
// "Tabler: Premium dashboard template with responsive and high quality UI",
// description:
// "Tabler comes with tons of well-designed components and features. Start your adventure with Tabler and make your dashboard great again. For free!",
// },
// },
// }
// }
+172
View File
@@ -0,0 +1,172 @@
import { pricingPlansPersonal, pricingPlanTeam } from '@/config/pricing';
import clsx from 'clsx';
import Icon from '@/components/Icon';
const PricingCards = () => {
return (
<div className="pricing">
{pricingPlansPersonal.map(plan => (
<div
key={plan.name}
className={clsx('pricing-card', {
featured: plan.featured
})}
>
{plan.featured && (
<div className="pricing-label">
<div className="label label-primary">Popular</div>
</div>
)}
<h4 className="pricing-title">{plan.name}</h4>
<div className="pricing-price">
<span className="pricing-price-currency">$</span>
{plan.price}
<div className="pricing-price-description">
<div>per user</div>
<div>per year</div>
</div>
</div>
<ul className="pricing-features">
{pricingPlanTeam.features.map(feature => (
<li key={feature}>
<Icon name="check" className="text-green mr-2" />
{feature}
</li>
))}
</ul>
<div className="pricing-btn">
<a
href="#"
className={clsx('btn btn-block', {
'btn-primary': plan.featured
})}
>
Get started
</a>
</div>
</div>
))}
</div>
);
};
const PricingTeam = ({ className }) => {
return (
<div className={clsx('pricing-banner', className)}>
<div className="row g items-center">
<div className="lg:col">
<h3>{pricingPlanTeam.name}</h3>
<p className="m-0">{pricingPlanTeam.description}</p>
</div>
<div className="lg:col">
<ul className="pricing-features m-0">
{pricingPlanTeam.features.map(feature => (
<li key={feature}>
<Icon name="check" className="text-green mr-2" />
{feature}
</li>
))}
</ul>
</div>
<div className="sm:col-6 lg:col">
<div className="pricing-price m-0">
<span className="pricing-price-currency">$</span>
{pricingPlanTeam.price}
<div className="pricing-price-description">
<div>per team</div>
<div>per year</div>
</div>
</div>
</div>
<div className="sm:col-6 lg:col-auto">
<a href="#" className="btn btn-primary btn-block">
Get started
</a>
</div>
</div>
</div>
);
};
export default function Page() {
return (
<>
<section className="section">
<div className="container">
<div className="section-header">
<h2 className="page-title">Simple, transparent pricing</h2>
<p className="section-description">
Get early access to 100+ components and free updates every month. Make it yours today!
</p>
</div>
<PricingCards />
<PricingTeam className="mt-5" />
</div>
</section>
<section className="section section-light">
<div className="container">
<div className="section-header">
<h2 className="section-title">Frequently Asked Questions</h2>
</div>
<div className="row gy">
<div className="md:col-4 markdown">
<h3>How is Tabler UI Pro different from Tabler UI?</h3>
<p>
Tabler UI provides the basic functional components you&apos;ll need to compose together to create your
app or website. Pro components are assembled, building blocks and page templates you can drop-in your
app to save time.
</p>
</div>
<div className="md:col-4 markdown">
<h3>Is this a yearly subscription?</h3>
<p>
No, you have a lifetime access to all our components. This means that you&apos;ll get new components and
updates every month till we&apos;ve exhausted our component inspiration.
</p>
</div>
<div className="md:col-4 markdown">
<h3>I want to buy this but I can&apos;t afford it. Is there a discount?</h3>
<p>
If you&apos;re a student or if the price in your local currency is too high, kindly send an email to
support@tabler.io stating your situation and we&apos;ll consider giving you a discount.
</p>
</div>
<div className="md:col-4 markdown">
<h3>What can I do with this license?</h3>
<ul>
<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 className="md:col-4 markdown">
<h3>What version of Tabler UI is used?</h3>
<p>
The components in PRO are authored using Tabler UI v1.2+. If you&apos;re on v0.8, we recommend upgrading
to the most recent version to use Pro components.
</p>
</div>
<div className="md:col-4 markdown">
<h3>What restrictions does this license have?</h3>
<ul>
<li>Create a clone of Tabler UI 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>
</>
);
}
+76
View File
@@ -0,0 +1,76 @@
import Shape from '@/components/Shape';
export default function Support() {
return (
<section className="section">
<div className="container">
<div className="section-header">
<h1 className="section-title section-title-lg">Tabler Support</h1>
<p className="section-description">
If you have any questions regarding our theme, feel free to contact us using one of the methods below. We
usually reply within 24 hours.
</p>
</div>
<div className="row xl:g-6">
<div className="sm:col-6 lg:col-4">
<div className="box text-center">
<Shape icon="message" color="primary" size="md" className="mb-4" />
<h3>General Inquiry</h3>
<p className="text-muted">
Have a question? Something is not clear? Or maybe you just want to say Hi! We usually reply within 24
hours.
</p>
<a href="mailto:hello@tabler.io" className="btn">
Send a Message
</a>
</div>
</div>
<div className="sm:col-6 lg:col-4">
<div className="box text-center">
<Shape icon="settings" color="primary" size="md" className="mb-4" />
<h3>Technical Support</h3>
<p className="text-muted">
Something is wrong with one of our theme? Found a bug or have a feature request?
</p>
<a
href="https://github.com/tabler/tabler/issues/new/choose"
className="btn"
target="_blank"
rel="noopener noreferrer"
>
Open a new issue
</a>
</div>
</div>
<div className="sm:col-6 lg:col-4">
<div className="box text-center">
<Shape icon="adjustments" color="primary" size="md" className="mb-4" />
<h3>Customization</h3>
<p className="text-muted">
Need one of theme customized? Let us know exactly what you need and well get back to you with a quote.
</p>
<a href="mailto:support@tabler.io" className="btn">
Get a Quote
</a>
</div>
</div>
</div>
</div>
</section>
);
}
// export async function getStaticProps() {
// return {
// props: {
// menu: 'ui',
// meta: {
// bodyClassName: 'body-gradient',
// title: 'Support',
// },
// },
// }
// }
@@ -0,0 +1,18 @@
import Testimonials from '@/components/layout/Testimonials';
export default function TestimonialsPage() {
return <>
<section className="section">
<div className="container">
<div className="section-header">
<h2 className="section-title section-title-lg">Our Wall Of Love</h2>
<p className="section-description">
Reviews and feedback from our satisfied users who have experienced our products.
</p>
</div>
<Testimonials />
</div>
</section>
</>;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

+94
View File
@@ -0,0 +1,94 @@
import '@/styles/website.scss';
import { creator, description, name, uiUrl } from '@/config/site';
import PageProgress from '@/components/PageProgress';
export const metadata = {
title: {
default: name,
template: `%s | ${name}`,
},
description: description,
keywords: [
'css',
'html',
'jekyll',
'sass',
'bootstrap',
'modular',
'html5',
'dashboard',
'sponsors',
'uikit',
'boilerplate-template',
'scss',
'admin-dashboard',
'themes',
'dashboards',
'ui-kit',
'adminpanel',
'dashboard-templates',
'bootstrap4-theme',
'bootstrap5',
'bootstrap',
],
authors: [
{
name: creator,
url: uiUrl,
},
],
creator: creator,
themeColor: [
{ media: '(prefers-color-scheme: light)', color: 'white' },
{ media: '(prefers-color-scheme: dark)', color: 'black' },
],
openGraph: {
type: 'website',
locale: 'en_US',
url: uiUrl,
siteName: name,
},
twitter: {
card: 'summary_large_image',
images: [`${uiUrl}/og.jpg`],
creator: `@${creator}`,
},
icons: {
icon: '/favicon.ico',
shortcut: '/favicon-16x16.png',
apple: '/apple-touch-icon.png',
},
// manifest: `${uiUrl}/site.webmanifest`,
};
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<script
defer
data-api="/stats/api/event"
data-domain="tabler.io"
src="/stats/js/script.js"
/>
<script>
{
'window.plausible=window.plausible||function(){(window.plausible.q=window.plausible.q||[]).push(arguments)}'
}
</script>
</head>
<body className="body-gradient">
<PageProgress />
{children}
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
{/* <script src="https://cdn.paritydeals.com/banner.js" defer /> */}
<script src="https://assets.lemonsqueezy.com/lemon.js" defer />
</body>
</html>
);
}
+12
View File
@@ -0,0 +1,12 @@
import { uiUrl } from '@/config/site';
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
},
sitemap: `${uiUrl}/sitemap.xml`,
};
}
+43
View File
@@ -0,0 +1,43 @@
import { MetadataRoute } from 'next';
import { allDocs, allGuides, allPages, allPosts } from '@/.contentlayer/generated';
import { uiUrl } from '@/config/site';
const pages = [
'testimonials',
'support',
'icons',
'guides',
'features',
'emails',
'emails/gallery',
'docs',
'blog'
];
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: uiUrl,
lastModified: new Date(),
},
...pages.map((page) => ({
url: `${uiUrl}/${page}`,
lastModified: new Date(),
})),
...allPages.map((page) => ({
url: `${uiUrl}/${page.slugAsParams}`,
lastModified: new Date(),
})),
...[...allDocs, ...allGuides, ...allPosts].map((doc) => ({
url: `${uiUrl}${doc.slug}`,
lastModified: new Date(),
})),
];
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

+47
View File
@@ -0,0 +1,47 @@
const iconsPkg = require("../node_modules/@tabler/icons/package.json")
const icons = require("../node_modules/@tabler/icons/tags.json")
const fs = require("fs-extra")
const path = require("path")
const prepareSvgFile = (svg) => {
return svg.replace(/\n/g, "").replace(/>\s+</g, "><")
}
let svgList = []
for (let iconName in icons) {
let iconData = icons[iconName]
svgList.push({
name: iconName,
version: iconData.version,
category: iconData.category,
tags: iconData.tags,
unicode: iconData.unicode,
svg: prepareSvgFile(
fs
.readFileSync(
path.join(
__dirname,
`../node_modules/@tabler/icons/icons/${iconName}.svg`
)
)
.toString()
),
})
}
fs.writeFileSync(
path.join(__dirname, `../data/icons.json`),
JSON.stringify(svgList)
)
fs.writeFileSync(
path.join(__dirname, `../data/icons-info.json`),
JSON.stringify({
version: iconsPkg.version,
count: svgList.length,
})
)
fs.copySync(path.join(__dirname, '../node_modules/@tabler/icons/icons'), path.join(__dirname, '../public/static/tabler-icons/icons'), { overwrite: true })
fs.copySync(path.join(__dirname, '../node_modules/@tabler/icons-png/icons'), path.join(__dirname, '../public/static/tabler-icons/icons-png'), { overwrite: true })
+24
View File
@@ -0,0 +1,24 @@
const fs = require('fs')
const path = require('path')
const glob = require('glob')
const { html: beautifyHtml } = require('js-beautify')
const files = glob(path.join(__dirname, '../content/{docs,blog}/**/*.mdx'), {}, (err, files) => {
files.forEach((file) => {
let content = fs.readFileSync(file, 'utf-8')
content = content.replace(/\n\n+/g, '\n\n')
content = content.replace(/(?<=```html [^\n]+\n)([^`]+)(?=\n```)/g, (m, code) => {
code = code.trim()
code = beautifyHtml(code, {
indent_size: 2,
})
return code
})
fs.writeFileSync(file, content, 'utf-8')
})
})
+37
View File
@@ -0,0 +1,37 @@
import { uiDemoUrl } from '@/config/site';
import Icon from '@/components/Icon';
import ResponsiveImage from '@/components/ResponsiveImage';
import clsx from 'clsx';
export default function Browser({ icon = 'lock', url = uiDemoUrl, noresize = false, className, children, ...props }:{
icon?: string,
url?: string,
noresize?: boolean,
className?: string,
children?: React.ReactNode
}) {
return (
<div className={clsx('browser', noresize && 'browser-noresize', className)} {...props}>
<div className="browser-header">
<div className="row items-center">
<div className="col-auto md:col-2">
<div className="browser-dots">
<div className="browser-dot" />
<div className="browser-dot" />
<div className="browser-dot" />
</div>
</div>
<div className="col-8">
<div className="tooltip" data-title="Open preview of Tabler dashboard!">
<a href={url} className="browser-input" target="_blank" rel="noopener noreferrer">
<Icon name={icon} />
{url}
</a>
</div>
</div>
</div>
</div>
<div className="browser-image">{children}</div>
</div>
);
}
+44
View File
@@ -0,0 +1,44 @@
export default function CTABanner({
title,
description,
buttonHref,
buttonText,
buttonSecondaryHref,
buttonSecondaryText
}) {
return (
<div className="bg-primary text-white rounded p-5 lg:p-6" data-aos="zoom-y-out">
<div className="row items-center text-center md:text-left">
<div className="lg:col">
<h3 className="h1 text-reset font-black">{title}</h3>
<p className="font-h4 m-0">{description}</p>
</div>
<div className="lg:col-auto">
<div className="row g-2">
{buttonText &&
buttonHref && (
<div className="col-auto">
<a href={buttonHref} className="btn btn-lg btn-white" target="_blank" rel="noopener noreferrer">
{buttonText}
</a>
</div>
)}
{buttonSecondaryText &&
buttonSecondaryHref && (
<div className="col-auto">
<a
href={buttonSecondaryHref}
className="btn btn-lg btn-white btn-outline"
target="_blank"
rel="noopener noreferrer"
>
{buttonSecondaryText}
</a>
</div>
)}
</div>
</div>
</div>
</div>
);
}
+15
View File
@@ -0,0 +1,15 @@
import { emailsDownloadUrl, emailsPrice, emailsSampleDownloadUrl } from '@/config/site';
import CTABanner from '@/components/CTABAnner';
export default function CTABannerEmails() {
return (
<CTABanner
title="Ready to download?"
description="Look like a PRO in every inbox. Start with one of our templates!"
buttonHref={emailsDownloadUrl}
buttonText={`Download for $${emailsPrice}`}
buttonSecondaryHref={emailsSampleDownloadUrl}
buttonSecondaryText="Get free sample"
/>
);
}
+93
View File
@@ -0,0 +1,93 @@
'use client';
import React from 'react';
import { useClipboard } from '@/hooks';
import clsx from 'clsx';
import { html as beautifyHtml } from 'js-beautify';
import SyntaxHighlighter from 'react-syntax-highlighter';
import Icon from '@/components/Icon';
export default function CodeBlock({
html,
children,
className,
language = 'xml',
copyable = true,
beautify = false,
hideLinks = false,
}:{
html?: string,
children?: React.ReactNode,
className?: string,
language?: string,
copyable?: boolean,
beautify?: boolean,
hideLinks?: boolean,
}) {
let code = html ?? (children || '').toString();
const clipboard = useClipboard();
if (hideLinks) {
code = code
.replace(/url\([^\)]+\)/g, 'url(...)')
.replace(/img src="[^"]+"/g, 'img src="..."')
.replace(
/(\n?)(\s*)<svg[^>]+icon-tabler-([^"]+).*?<\/svg>/gms,
'$1$2<!-- SVG icon from http://tabler-icons.io/i/$3 -->\n$2<svg>...</svg>'
);
}
if (beautify) {
code = beautifyHtml(code, {
inline: 'strong',
indent_size: 2,
});
}
const languageNames = {
js: 'JavaScript',
ts: 'TypeScript',
javascript: 'JavaScript',
typescript: 'TypeScript',
php: 'PHP',
python: 'Python',
ruby: 'Ruby',
go: 'Go',
};
if (language === 'js') {
language = 'javascript';
} else if (language === 'html') {
language = 'xml';
}
return (
<div className="codeblock">
{copyable && (
<div className="codeblock-copy">
<button
className={clsx('btn btn-icon', clipboard.copied ? 'btn-green' : 'btn-dark')}
onClick={() => clipboard.copy(html || '')}
>
{clipboard.copied ? <Icon name="check" /> : <Icon name="clipboard" />}
</button>
</div>
)}
<SyntaxHighlighter
className={clsx(`language-${language}`, className)}
language={language}
useInlineStyles={false}
>
{code}
</SyntaxHighlighter>
</div>
);
}
+50
View File
@@ -0,0 +1,50 @@
'use client';
import Link from '@/components/Link';
import { usePathname } from 'next/navigation';
import { DocsConfigType } from '@/types';
import clsx from 'clsx';
import { docsConfig } from '@/config/docs';
export default function DocsMenu() {
const pathname = usePathname();
return (
<ul role="list" className="docs-menu scrollbar">
{docsConfig.map((item, index) => (
<li className="docs-menu-group" key={index}>
<span className="docs-menu-header">{item.title}</span>
{item.items && (
<div className="docs-menu-submenu">
{item.items.map((page, j) => (
<Link
href={page.href}
className={clsx(
'docs-menu-item',
pathname === page.href && 'active'
)}
exact
key={j}
>
{page.title}
{page.label && (
<>
<span className="badge badge-primary ml-2">
{page.label}
</span>
</>
)}
</Link>
))}
</div>
)}
</li>
))}
</ul>
);
}
+21
View File
@@ -0,0 +1,21 @@
import ResponsiveImage from '@/components/ResponsiveImage';
export default function EmailImage({ email, dark = false, full = false, ...props }) {
const width = full ? email.widthFull : email.width;
const height = full ? email.heightFull : email.height;
return (
<ResponsiveImage
src={`/img/tabler-emails/screenshots/${email.screenshot}${dark ? '-dark' : ''}${full ? '-full' : ''}.png`}
width={width}
height={height}
{...props}
/>
);
// return (
// <div className="rounded bg-white border-light" style={{ position: 'relative', paddingTop: `${height / width * 100}%`, overflow: 'hidden'}}>
// <div style={{ background: `url() no-repeat top center/cover`, position: 'absolute', top: -2, left: -2, right: -2, bottom: -2 }} />
// </div>
// )
}
+149
View File
@@ -0,0 +1,149 @@
'use client';
import { useState } from 'react';
import clsx from 'clsx';
import { uiCdnUrl, uiUrl } from '@/config/site';
const previewHtml = (
example,
{
background = '',
vertical = false,
scrollable = false,
columns = 0,
centered = false,
vcentered = false,
separated = false,
vendors = false,
overview = false,
fullpage = false,
plugins = [],
libs = [],
}: {
vertical?: boolean
background?: string
scrollable?: boolean
columns?: number
centered?: boolean
vcentered?: boolean
separated?: boolean
vendors?: boolean
overview?: boolean
fullpage?: boolean
plugins?: string[]
libs?: string[]
}
) => {
let assetsUrl = uiCdnUrl;
if (process.env.TABLER_LOCAL) {
assetsUrl = uiUrl;
}
let content = example;
if (!fullpage) {
content = `<main class="min-vh-100 ${vertical ? 'p-4' : 'py-4 px-4'}${
centered
? ' d-flex justify-content-center align-items-center flex-wrap'
: ''
}${vcentered ? ' d-flex justify-content-center flex-column' : ''}">
${
columns
? `<div class="mx-auto w-100" style="max-width: ${columns * 20}rem">`
: ''
}
${
separated
? vertical
? '<div class="space-y">'
: '<div class="space-x">'
: ''
}
${example}
${separated ? '</div>' : ''}
${columns ? '</div>' : ''}
</main>`;
}
example = example
.replace(/a href="[^"]+"/g, 'a href="javascript:void(0)"')
.replace(/action="[^"]+"/g, 'action="javascript:void(0)"');
return `<html lang="en">
<head>
<title>Example</title>
<link rel="stylesheet" href="${assetsUrl}/dist/css/tabler.css">
${
plugins
? plugins.map(
(plugin) =>
` <link rel="stylesheet" href="${assetsUrl}/dist/css/tabler-${plugin}.css" />`
)
: ''
}
</head>
<body class="h-100${background ? ` bg-${background}` : ''}${
scrollable || fullpage ? ' auto-scroll' : ' no-scroll'
}"${!background && ' style="--tblr-body-bg: #fbfcfd"'}>
${content}
${
vendors
? `<link rel="stylesheet" href="${assetsUrl}/dist/css/tabler-vendors.css" />`
: ''
}
<script src="${assetsUrl}/dist/js/tabler.js"></script>
</body>
</html>`;
};
export default function Example({
height = 200,
vertical = false,
background = '',
scrollable = false,
columns = 0,
centered = false,
vcentered = false,
separated = false,
vendors = false,
overview = false,
fullpage = false,
plugins = '',
resizable = false,
libs = '',
html,
}) {
const [iframeHeight, setIframeHeight] = useState(height);
const srcDoc = previewHtml(html, {
vertical,
background,
scrollable,
columns,
centered,
vcentered,
separated,
vendors,
overview,
fullpage,
plugins: plugins ? plugins.split(',') : [],
libs: libs ? libs.split(',') : [],
});
return (
<div className="example">
<iframe className={clsx('example-frame', {
'example-frame-resizable': resizable,
})} srcDoc={srcDoc} style={{ height: iframeHeight }} />
</div>
);
}
+61
View File
@@ -0,0 +1,61 @@
'use client';
import React, { useState } from 'react';
import clsx from 'clsx';
import { uiPackageName, uiVersion } from '@/config/site';
import { generateIframeContent } from '@/lib/components';
export default function ExampleIframe({
html,
height = 15,
wrapper,
backgroundColor = '',
plugins,
resizabe = false,
className
}) {
const iframeRef = React.useRef<HTMLIFrameElement>(null);
const [contentHeight, setContentHeight] = useState(0);
const iframeLoaded = e => {
setContentHeight(e.target.contentWindow.document.body.scrollHeight);
};
function resizeIframe(obj) {
obj.style.height = obj.contentWindow.document.documentElement.scrollHeight + 'px';
}
const srcDoc = generateIframeContent({
html,
wrapper,
plugins,
backgroundColor
});
// React.useEffect(() => {
// const iframe = iframeRef.current
// // const listener = e => console.log(e)
// // iframe && iframe.addEventListener("load", listener)
// // return () => {
// // iframe && iframe.removeEventListener("load", listener)
// // }
// })
return (
<iframe
ref={iframeRef}
className={clsx('example-frame', resizabe && 'example-frame-resizable', className)}
srcDoc={srcDoc}
style={{ minHeight: `${height}rem`, height: `${contentHeight}px` }}
onLoad={iframeLoaded}
/>
);
}
+15
View File
@@ -0,0 +1,15 @@
import Shape from '@/components/Shape';
export default function Features({ list }) {
return (
<div className="row items-center text-center lg:g-6">
{list.map((feature, i) => (
<div className="md:col-6 lg:col" key={i} data-aos="fade-up" data-aos-delay={i * 150}>
<Shape icon={feature.icon} size="md" className="mb-3" color="primary" />
<h2 className="h3">{feature.title}</h2>
<p className="text-muted">{feature.description}</p>
</div>
))}
</div>
);
}
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
import icons from '@/data/icons.json';
import clsx from 'clsx';
export default function IconSvg({ svg, className }) {
return <span className={clsx('icon-svg', className)} dangerouslySetInnerHTML={{ __html: svg }} />;
}
+40
View File
@@ -0,0 +1,40 @@
'use client';
import { default as NextLink } from 'next/link';
import { usePathname } from 'next/navigation';
import clsx from 'clsx';
export default function Link({
href,
children,
className,
prefetch = false,
exact = false,
onClick = () => {},
...props
}: {
href: string
children?: React.ReactNode
prefetch?: boolean
className?: string
exact?: boolean
onClick?: (event: React.MouseEvent) => void
}): JSX.Element {
const pathname = usePathname();
return (
<NextLink
href={href}
className={clsx(className, [
(exact ? pathname === href : pathname.startsWith(href)) ? 'active' : '',
])}
{...props}
>
{children}
</NextLink>
);
}
+209
View File
@@ -0,0 +1,209 @@
import * as React from 'react';
import type { MDXComponents } from 'mdx';
import { useMDXComponent } from 'next-contentlayer/hooks';
import Link from '@/components/Link';
import TablerSponsorsBanner from '@/components/TablerSponsorsBanner';
import Callout from '@/components/mdx/Callout';
import { Card, Cards } from '@/components/mdx/Cards';
import { Code, Pre } from '@/components/mdx/Code';
import ColorsTable from '@/components/mdx/ColorsTable';
import EmailsCount from '@/components/mdx/EmailsCount';
import FlagsTable from '@/components/mdx/FlagsTable';
import GuideImage from '@/components/mdx/GuideImage';
import IconsCount from '@/components/mdx/IconsCount';
import Image from '@/components/mdx/Image';
import PaymentsTable from '@/components/mdx/PaymentsTable';
import TablerLogos from '@/components/mdx/TablerLogos';
import { Tab, Tabs, TabsPackage } from '@/components/mdx/Tabs';
import { TipBad, TipGood, TipChanges } from '@/components/mdx/Tips';
import { OptionDescription, OptionTitle, OptionsTable } from '@/components/mdx/OptionsTable';
const components: MDXComponents = {
// h1: ({ className, ...props }) => (
// <h1
// className={cn(
// "mt-2 scroll-m-20 text-4xl font-bold tracking-tight",
// className
// )}
// {...props}
// />
// ),
// h2: ({ className, ...props }) => (
// <h2
// className={cn(
// "mt-10 scroll-m-20 border-b pb-1 text-3xl font-semibold tracking-tight first:mt-0",
// className
// )}
// {...props}
// />
// ),
// h3: ({ className, ...props }) => (
// <h3
// className={cn(
// "mt-8 scroll-m-20 text-2xl font-semibold tracking-tight",
// className
// )}
// {...props}
// />
// ),
// h4: ({ className, ...props }) => (
// <h4
// className={cn(
// "mt-8 scroll-m-20 text-xl font-semibold tracking-tight",
// className
// )}
// {...props}
// />
// ),
// h5: ({ className, ...props }) => (
// <h5
// className={cn(
// "mt-8 scroll-m-20 text-lg font-semibold tracking-tight",
// className
// )}
// {...props}
// />
// ),
// h6: ({ className, ...props }) => (
// <h6
// className={cn(
// "mt-8 scroll-m-20 text-base font-semibold tracking-tight",
// className
// )}
// {...props}
// />
// ),
// a: ({ className, ...props }) => (
// <a
// className={cn("font-medium underline underline-offset-4", className)}
// {...props}
// />
// ),
// p: ({ className, ...props }) => (
// <p
// className={cn("leading-7 [&:not(:first-child)]:mt-6", className)}
// {...props}
// />
// ),
// ul: ({ className, ...props }) => (
// <ul className={cn("my-6 ml-6 list-disc", className)} {...props} />
// ),
// ol: ({ className, ...props }) => (
// <ol className={cn("my-6 ml-6 list-decimal", className)} {...props} />
// ),
// li: ({ className, ...props }) => (
// <li className={cn("mt-2", className)} {...props} />
// ),
// blockquote: ({ className, ...props }) => (
// <blockquote
// className={cn(
// "mt-6 border-l-2 pl-6 italic [&>*]:text-muted-foreground",
// className
// )}
// {...props}
// />
// ),
// img: ({
// className,
// alt,
// ...props
// }: React.ImgHTMLAttributes<HTMLImageElement>) => (
// // eslint-disable-next-line @next/next/no-img-element
// <img className={cn("rounded-md border", className)} alt={alt} {...props} />
// ),
// hr: ({ ...props }) => <hr className="my-4 md:my-8" {...props} />,
// table: ({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) => (
// <div className="my-6 w-full overflow-y-auto">
// <table className={cn("w-full", className)} {...props} />
// </div>
// ),
// tr: ({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) => (
// <tr
// className={cn("m-0 border-t p-0 even:bg-muted", className)}
// {...props}
// />
// ),
// th: ({ className, ...props }) => (
// <th
// className={cn(
// "border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right",
// className
// )}
// {...props}
// />
// ),
// td: ({ className, ...props }) => (
// <td
// className={cn(
// "border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right",
// className
// )}
// {...props}
// />
// ),
// pre: ({ className, ...props }) => (
// <pre
// className={cn(
// "mb-4 mt-6 overflow-x-auto rounded-lg border bg-black py-4",
// className
// )}
// {...props}
// />
// ),
// code: ({ className, ...props }) => (
// <code
// className={cn(
// "relative rounded border px-[0.3rem] py-[0.2rem] font-mono text-sm",
// className
// )}
// {...props}
// />
// ),
// Image,
// Callout,
// Card: MdxCard,
Link,
TablerLogos,
PaymentsTable,
FlagsTable,
ColorsTable,
EmailsCount,
IconsCount,
GuideImage,
Callout,
Tabs,
TabsPackage,
Tab,
Card,
Cards,
TipGood,
TipBad,
TipChanges,
pre: Pre,
code: Code,
a: (props) => {
return <Link {...props} />;
},
img: Image,
TablerSponsorsBanner,
OptionDescription,
OptionTitle,
OptionsTable,
};
export default function Mdx({ code }: { code: string }) {
const Component = useMDXComponent(code);
return (
<>
<Component components={components} />
</>
);
}
+39
View File
@@ -0,0 +1,39 @@
import Icon from '@/components/Icon';
import { useCallback, useEffect, useState } from 'react';
export function Modal({ children }) {
const [isOpen, setIsOpen] = useState(false);
const handleEscape = useCallback(e => {
if (e.keyCode === 27) {
setIsOpen(false);
}
}, []);
useEffect(() => {
if (isOpen) {
document.addEventListener('keydown', handleEscape, false);
}
return () => {
document.removeEventListener('keydown', handleEscape, false);
};
});
const hideModal = e => {
setIsOpen(false);
};
return isOpen ? (
<div className="modal-backdrop" tabIndex={-1} role="dialog" onClick={hideModal} onKeyDown={hideModal}>
<div className="modal">
<a href="#" className="modal-close" data-dismiss="modal" aria-label="Close modal" onClick={hideModal}>
<Icon name="x" />
</a>
<div className="modal-body">{children}</div>
</div>
</div>
) : null;
}
export default Modal;
+16
View File
@@ -0,0 +1,16 @@
import Link from '@/components/Link';
import clsx from 'clsx';
function NavLink({ href, active, children, ...props }) {
if (active) {
props.className = clsx(props.className, 'active');
}
return (
<Link href={href} {...props}>
{children}
</Link>
);
}
export default NavLink;
+8
View File
@@ -0,0 +1,8 @@
'use client';
import { color } from '@/config/site';
import NextTopLoader from 'nextjs-toploader';
export default function ProgressBar() {
return <NextTopLoader color={color} height={2} />;
}
+21
View File
@@ -0,0 +1,21 @@
import Link from '@/components/Link';
import clsx from 'clsx';
import BlogAuthors from '@/components/blog/Authors';
export default function PostItem({ title, category, slug, date, children, authors, wide = false }) {
return (
<div>
<div className="row gx-5 justify-center">
<div className="col-3">
<BlogAuthors authors={authors} />
</div>
<article className="col-6">
<Link href={`/blog/${slug}`} className="h3 mb-3">
{title}
</Link>
<div className="markdown">{children}</div>
</article>
</div>
</div>
);
}
+41
View File
@@ -0,0 +1,41 @@
import { pricingPlanTeam as plan } from '@/config/pricing';
import Icon from '@/components/Icon';
import clsx from 'clsx';
export default function PricingCardTeam({ className }) {
return (
<div className={clsx('pricing-banner', className)}>
<div className="row g items-center">
<div className="lg:col">
<h3>{plan.name}</h3>
<p className="m-0">{plan.description}</p>
</div>
<div className="lg:col">
<ul className="pricing-features m-0">
{plan.features.map(feature => (
<li key={feature}>
<Icon name="check" className="text-green mr-2" />
{feature}
</li>
))}
</ul>
</div>
<div className="sm:col-6 lg:col">
<div className="pricing-price m-0">
<span className="pricing-price-currency">$</span>
{plan.price}
<div className="pricing-price-description">
<div>per team</div>
<div>per year</div>
</div>
</div>
</div>
<div className="sm:col-6 lg:col-auto">
<a href="#" className="btn btn-primary btn-block">
Get started
</a>
</div>
</div>
</div>
);
}
+50
View File
@@ -0,0 +1,50 @@
import { pricingPlansPersonal as plans } from '@/config/pricing';
import clsx from 'clsx';
import Icon from '@/components/Icon';
export default function PricingCards() {
return (
<div className="pricing">
{plans.map(plan => (
<div key={plan.name} className={clsx('pricing-card', { featured: plan.featured })}>
{plan.featured && (
<div className="pricing-label">
<div className="label label-primary label-sm">Popular</div>
</div>
)}
<h4 className="pricing-title">{plan.name}</h4>
<div className="pricing-price">
<span className="pricing-price-currency">$</span>
{plan.price}
<div className="pricing-price-description">
<div>per user</div>
<div>per year</div>
</div>
</div>
<ul className="pricing-features">
{plan.features.map(feature => (
<li key={feature}>
<Icon name="check" className="text-green mr-2" />
{feature}
</li>
))}
</ul>
<div className="pricing-btn">
<a
href="#"
className={clsx('btn btn-block', {
'btn-primary': plan.featured
})}
>
Get started
</a>
</div>
</div>
))}
</div>
);
}
+32
View File
@@ -0,0 +1,32 @@
import clsx from 'clsx';
import Image from 'next/image';
export default function ResponsiveImage(props) {
if (props.url) {
return (
<img
src={props.url}
className={clsx('img-fluid', props.className)}
width={props.width}
height={props.height}
loading="lazy"
alt={props.alt || ''}
/>
);
}
const src2x = props.src;
return (
<Image
className={clsx(props.className)}
src={src2x}
alt={props.alt || ''}
width={props.width}
height={props.height}
quality={85}
srcSet={[props.width, props.width * 2]}
{...props}
/>
);
}
+17
View File
@@ -0,0 +1,17 @@
import React from 'react';
import Head from 'next/head';
const SEO = (props) => {
const { title, description, image } = props;
return (
<Head>
<title>{title} | App</title>
<meta name="description" content={description} />
<meta itemProp="name" content={title} />
<meta itemProp="description" content={description} />
<meta itemProp="image" content={image} />
</Head>
);
};
export default SEO;
+22
View File
@@ -0,0 +1,22 @@
export default function SectionDivider({ wave = false }) {
if (wave) {
return (
<svg className="section-divider section-divider-auto" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 80">
<path d="M1920,80 L0,80 L0,0 C0,0 387,59 960,59 C1533,59 1920,0 1920,0 L1920,80 Z" />
</svg>
);
}
return (
<svg
className="section-divider"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 24 150 28"
preserveAspectRatio="none"
>
<path className="wave-1" d="M-110 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
<path className="wave-2" d="M-110 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
<path className="wave-3" d="M-110 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
</svg>
);
}
+36
View File
@@ -0,0 +1,36 @@
import clsx from 'clsx';
import Icon from '@/components/Icon';
export default function Shape({
icon,
placeholder,
color,
size,
rounded,
className,
}: {
icon?: string
placeholder?: string | number
color?: string
size?: string
rounded?: boolean
className?: string
}) {
return (
<div
className={clsx(
'shape',
{
[`shape-${color}`]: color,
[`shape-${size}`]: size,
'shape-rounded': rounded,
},
className
)}
>
{icon && <Icon name={icon} />}
{placeholder && placeholder}
</div>
);
}
+60
View File
@@ -0,0 +1,60 @@
'use client';
import { useEffect, useRef } from 'react';
import Glide from '@glidejs/glide';
import Icon from '@/components/Icon';
const sliderConfiguration = {
gap: 0,
perView: 1,
type: 'carousel',
autoplay: 7000,
animationDuration: 1000,
};
export default function Slider({
slides = [],
style = {},
}: {
slides: React.ReactNode[]
style?: React.CSSProperties
}) {
const wrapper = useRef<HTMLDivElement>(null);
useEffect(() => {
const glide = new Glide(wrapper.current, sliderConfiguration).mount();
return () => glide.destroy();
}, []);
return (
<div ref={wrapper} className="glide" style={style}>
<div className="glide__track" data-glide-el="track">
<ul className="glide__slides">
{slides.map((slide, i) => (
<li className="glide__slide slider" key={i}>
{slide}
</li>
))}
</ul>
</div>
<div className="glide__arrows" data-glide-el="controls">
<button
className="glide__arrow glide__arrow--prev"
data-glide-dir="<"
aria-label="Previous slide"
>
<Icon name="chevron-left" />
</button>
<button
className="glide__arrow glide__arrow--next"
data-glide-dir=">"
aria-label="Next slide"
>
<Icon name="chevron-right" />
</button>
</div>
</div>
);
}
+16
View File
@@ -0,0 +1,16 @@
export default function Svg({ width = 20, height = 20, className }) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
className={className}
width={width}
height={height}
viewBox={`0 0 ${width} ${height}`}
stroke="#b8cef1"
>
<rect x=".5" y=".5" width={width - 1} height={height - 1} fill="#fff" rx="2" />
<line x1="1" y1="1" x2={width - 1} y2={height - 1} />
<line x1="1" y1={height - 1} x2={width - 1} y2="1" />
</svg>
);
}
File diff suppressed because one or more lines are too long
+21
View File
@@ -0,0 +1,21 @@
export default function BlogAuthors({ authors }) {
return (
<>
{authors.map(author => (
<div key={author.twitter} className="row gx-3 items-center">
<div className="col-auto">
<img src={author.avatar} alt="" className="avatar" />
</div>
<div className="col">
<div>{author.name}</div>
<div>
<a href={`https://twitter.com/${author.twitter}`} target="_blank" rel="noopener noreferrer">
@{author.twitter}
</a>
</div>
</div>
</div>
))}
</>
);
}
+10
View File
@@ -0,0 +1,10 @@
// import CTABanner from '@/components/CTABAnner'
// import CTABannerEmails from '@/components/CTABAnnerEmails'
export default function CTA() {
return (
<section className="section">
<div className="container" />
</section>
);
}
+132
View File
@@ -0,0 +1,132 @@
import clsx from 'clsx';
import { footerMenu, socialLinks } from '@/config/site';
import Icon from '@/components/Icon';
import Link from '@/components/Link';
const FooterMenu = ({
border = false
}: {
border?: boolean
}) => (
<footer className="footer">
<div className="container">
<div className={clsx('py-6', border && 'border-top')}>
<div className="row">
<div className="lg:col-7">
<div className="row">
{footerMenu.map((column) => (
<div className="sm:col-6 md:col" key={column.title}>
<div className="h-subheader mb-3">{column.title}</div>
<ul className="list-unstyled list-separated">
{column.items.map((item) => (
<li key={item.title}>
{item.route ? (
<Link href={item.route} className="link-muted">
{item.title}
</Link>
) : (
<a href={item.href} className="link-muted" target="_blank" rel="noopener noreferrer">
{item.title}
</a>
)}
</li>
))}
</ul>
</div>
))}
</div>
</div>
<div className="lg:col-4 ml-auto">
<div className="logo logo-gray mb-4" />
<div className="text-muted">
Tabler comes with tons of well-designed components and features. Start your adventure with Tabler and make
your dashboard great again. For free!
</div>
<div className="mt-4 lg:mt-6">
<div className="row gx-3">
{socialLinks.map((social) => (
<div className="col-auto" key={social.icon}>
<a
href={social.url}
className="link-muted"
aria-label="social.label"
target="_blank"
rel="noopener noreferrer"
>
<Icon name={social.icon} className="icon-md" />
</a>
</div>
))}
</div>
</div>
</div>
</div>
</div>
</div>
</footer>
);
const FooterMain = () => (
<footer className="footer">
<div className="container">
<div className="py-5 text-center lg:text-left border-top">
<div className="row">
<div className="lg:col-auto lg:text-right lg:order-last">
<div className="row justify-center">
<div className="col-auto">
©
<a
href="https://codecalm.net"
className="link-muted"
target="_blank"
rel="noopener noreferrer"
>
codecalm.net
</a>
</div>
<div className="col-auto">
<div className="list-inline-dots">
<Link
href="/terms-of-service"
className="link-muted"
prefetch={false}
>
Terms of service
</Link>
<Link
href="/privacy-policy"
className="link-muted"
prefetch={false}
>
Privacy policy
</Link>
</div>
</div>
</div>
</div>
<div className="lg:col">
Made with <Icon name="heart" color="red" filled /> in Poland.
</div>
</div>
</div>
</div>
</footer>
);
export default function Footer() {
return (
<>
<FooterMenu />
<FooterMain />
</>
);
}
+37
View File
@@ -0,0 +1,37 @@
import clsx from 'clsx';
import Icon from '@/components/Icon';
import { useEffect, useState } from 'react';
export default function GoToTop() {
const [goToTopVisible, setGoToTopVisible] = useState(false);
const pop = () => {
setGoToTopVisible(window.pageYOffset > window.innerHeight / 2);
};
const scrollToTop = e => {
window.scroll({
top: 0,
behavior: 'smooth'
});
e.preventDefault();
return false;
};
useEffect(() => {
window.addEventListener('scroll', pop);
return () => window.removeEventListener('scroll', pop);
}, []);
return (
<button
className={clsx('go-to-top', goToTopVisible && 'go-to-top-visible')}
aria-label="Go to top"
onClick={scrollToTop}
>
<Icon name="chevron-up" />
</button>
);
}
+346
View File
@@ -0,0 +1,346 @@
'use client';
import { Fragment, PropsWithChildren, useEffect, useState } from 'react';
import { Dialog, Popover } from '@headlessui/react';
import clsx from 'clsx';
import { componentsRounded, iconsCountRounded, sponsorsUrl, uiGithubUrl } from '@/config/site';
import Icon from '@/components/Icon';
import GoToTop from '@/components/layout/GoToTop';
import Link from '@/components/Link';
import NavLink from '@/components/NavLink';
import Shape from '@/components/Shape';
// import { useRouter } from 'next/router'
const NavDropdown = ({ title, children, active, footer = false }) => {
return (
<Popover className="navbar-dropdown">
{({ open }) => (
<>
<Popover.Button className={clsx('navbar-link', active && 'active')}>{title}</Popover.Button>
<Popover.Panel className="navbar-dropdown-menu">
<div className="navbar-dropdown-menu-content">{children}</div>
{footer && <div className="navbar-dropdown-menu-footer">{footer}</div>}
</Popover.Panel>
</>
)}
</Popover>
);
};
const menuLinks = [
{
title: 'UI Kit',
menu: 'ui',
children: [
{
icon: 'home',
href: '/',
title: 'About',
description: 'Develop beautiful web apps with Tabler',
},
{
icon: 'layout-dashboard',
href: '/preview',
title: 'Preview template',
description: 'See what Tabler looks like and offers',
},
{
icon: 'script',
href: '/docs',
title: 'Documentation',
description: 'Read how to develop apps with Tabler',
},
{
icon: 'lego',
href: '/features',
title: 'Features',
description: 'See what kind of features you can find here',
},
{
icon: 'lifebuoy',
href: '/support',
title: 'Support',
description: 'Write to us if you need anything!',
},
{
icon: 'brand-github',
href: uiGithubUrl,
title: 'Source code',
description: 'View Tabler\'s source code ',
props: {
target: '_blank',
rel: 'nofollow',
},
},
],
},
{
href: '/emails',
menu: 'emails',
title: 'Email templates',
},
{
href: '/icons',
menu: 'icons',
title: (
<>
<span className="d-none lg:d-inline">Over {iconsCountRounded} </span>
Icons
</>
),
},
{
href: '/blog',
menu: 'blog',
title: (
<>
Blog
</>
),
},
{
href: '/docs',
menu: 'docs',
title: 'Documentation',
},
// {
// href: '/guides',
// menu: 'guides',
// title: 'Guides',
// },
{
menu: 'sponsors',
href: sponsorsUrl,
type: 'button',
title: (
<span>
Sponsor<span className="d-none lg:d-inline"> project</span>
</span>
),
icon: <Icon name="heart" filled color="red" />,
},
];
const NavbarLink = (link, menu) => {
// const router = useRouter()
if (link.type === 'button') {
return (
<div className="navbar-item">
<a href={link.href} className="btn" target="_blank" rel="noopener noreferrer">
{link.icon}
{link.title}
</a>
</div>
);
} else if (link.children) {
return (
<NavDropdown title={link.title} active={menu === link.menu}>
{link.children.map((link) => (
<Popover.Button
as={Link}
href={link.href || ''}
className="navbar-dropdown-menu-link"
key={link.title}
onClick={() => true}
{...link.props}
>
<div className="row g-3">
<div className="col-auto">
<Shape icon={link.icon} />
</div>
<div className="col">
<h5 className="mb-1">{link.title}</h5>
<p className="font-h6 m-0 text-muted">{link.description}</p>
</div>
</div>
</Popover.Button>
))}
</NavDropdown>
);
}
return (
// router.pathname.replace(/^\//, '').startsWith(link.menu)
<NavLink href={link.href} className="navbar-link" active={false}>
{link.title}
</NavLink>
);
};
const SidebarLink = (link, menu, onClick) => {
if (link.type === 'button') {
return (
<div className="aside-menu-item mt-4">
<a href={link.href} className="btn btn-block" target="_blank" rel="noopener noreferrer" onClick={onClick}>
{link.icon}
{link.title}
</a>
</div>
);
} else if (link.children) {
return (
<div className="aside-menu-item">
<div className={clsx('aside-menu-title', { active: menu === link.menu })}>{link.title}</div>
<div className="aside-menu-children">
{link.children.map((link) => (
<Link href={link.href || ''} key={link.title} className="aside-menu-link" onClick={onClick} {...link.props}>
{link.title}
</Link>
))}
</div>
</div>
);
}
return (
<Link href={link.href} className={clsx('aside-menu-link', { active: menu === link.menu })} onClick={onClick}>
{link.title}
</Link>
);
};
const Navbar = ({
menu,
opened,
onClick,
...props
}: {
menu?: string
opened?: boolean
onClick?: (event: React.MouseEvent) => void,
className?: string,
}) => {
return (
<div className={clsx('navbar', opened && 'opened', props.className)}>
{menuLinks.map((link) => (
<Fragment key={link.menu}>
{NavbarLink(link, menu)}
</Fragment>
))}
</div>
);
};
export default function Header({ headerStatic, className, pageProps, ...props }:{
headerStatic?: boolean,
className?: string,
pageProps?: any,
}) {
const bannerId = 'tabler-icons-v2';
const [sticky, setSticky] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [showBanner, setShowBanner] = useState(false);
const pop = () => {
setSticky(window.pageYOffset > 0);
};
function closeModal() {
setIsOpen(false);
}
function toggleModal() {
setIsOpen(!isOpen);
}
function closeBanner() {
localStorage.setItem(`banner-${bannerId}`, '1');
setShowBanner(false);
}
useEffect(() => {
window.addEventListener('scroll', pop);
if (window.localStorage.getItem(`banner-${bannerId}`) !== '1') {
setShowBanner(true);
}
return () => window.removeEventListener('scroll', pop);
}, []);
// const router = useRouter()
return (
<>
{/* {showBanner && (
<div className="banner">
<div className="container">
<div className="text-truncate">
🎉 Tabler Icons v2.0 has been released: filled icons, new packages: React, Vue, Preact, Svelte, SolidJS
and more!
</div>
<a href="https://tabler-icons.io" className="ml-5 banner-link">
Learn more
</a>
</div>
<a onClick={closeBanner} className="banner-close">
<Icon name="x" />
</a>
</div>
)} */}
<header
className={clsx(
'header',
// router.pathname.startsWith('/docs') && 'header-bordered',
headerStatic ? 'header-static' : '',
sticky && 'header-sticky',
className
)}
>
<div className="container" data-aos="fade-down">
<nav className="row items-center">
<div className="col-auto">
<Link
href="/"
className={clsx('logo'/*, pageProps.brand ? `logo-${pageProps.brand}` : ''*/)}
aria-label="Tabler"
/>
</div>
<div className="col-auto ml-auto">
<div className="d-none md:d-block">
{/* <Navbar menu={pageProps.menu} /> */}
<Navbar />
</div>
<div className="md:d-none">
<button
className={clsx('navbar-toggle', {
active: isOpen,
})}
onClick={toggleModal}
>
<span />
<span />
<span />
<span />
</button>
</div>
</div>
</nav>
</div>
</header>
<Dialog open={isOpen} onClose={closeModal} className="modal-backdrop">
<Dialog.Panel className="modal modal-side">
<div className={clsx('aside-menu mt-4')}>
{/* {menuLinks.map((link) => (
// <Fragment key={link.menu}>{SidebarLink(link, pageProps.menu, closeModal)}</Fragment>
))} */}
</div>
</Dialog.Panel>
</Dialog>
<GoToTop />
</>
);
}
+57
View File
@@ -0,0 +1,57 @@
import Link from '@/components/Link';
import tinytime from 'tinytime';
import CTABannerEmails from '@/components/CTABAnnerEmails';
export default function News() {
const changelogs = [];
const dateTemplate = tinytime('{MM} {DD}, {YYYY}');
return (
<section className="section section-light">
<div className="container">
<div className="section-header">
<h2 className="section-title">Refreshing posts from our blog</h2>
</div>
<div className="row xl:g-5">
{/* {changelogs.map(({ slug, module: { default: Component, meta } }, i) => (
<div className="col-12 md:col-6 lg:col-4" key={i} data-aos="zoom-y-out" data-aos-delay={i * 150}>
<Link href={`/changelog/${slug}`} className="d-block text-reset">
<div
className="ratio-16x9 mb-4 border-light rounded-lg"
style={{
backgroundColor: '#fff',
backgroundImage: meta?.image && `url(/img/changelog/${meta.image})`
}}
/>
<h3 className="mb-2">{meta?.title}</h3>
<p className="text-muted">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua.
</p>
<div className="row g-3 items-center">
<div className="col-auto">
<div
className="avatar"
style={{
backgroundImage: `url(/img/authors/codecalm.jpg)`
}}
/>
</div>
<div className="col">
Paweł Kuna
<span className="text-muted"> - {dateTemplate.render(new Date(meta?.date.replace(' ', 'T')))}</span>
</div>
</div>
</Link>
</div>
))} */}
</div>
<div className="mt-7">
<CTABannerEmails />
</div>
</div>
</section>
);
}
+61
View File
@@ -0,0 +1,61 @@
import Image from 'next/image';
import testimonials from '@/data/testimonials.json';
import clsx from 'clsx';
import TestimonialsShare from './TestimonialsShare';
export default function Testimonials({ limit = 0 }) {
let testimonialsList = testimonials;
if (limit) {
testimonialsList = testimonials.slice(0, limit);
}
return (
<>
<div className="row" data-aos-id-blocks-testimonials>
{testimonialsList.map((column, id) => (
<div
className={clsx('col-12 sm:col', id === 2 && 'd-none lg:d-block')}
key={id}
>
{column.map((testimonial, id2) => (
<a
href={testimonial.url}
className="testimonial"
target="_blank"
rel="noopener noreferrer"
key={id2}
data-aos="fade-up"
data-aos-anchor="[data-aos-id-blocks-testimonials]"
data-aos-delay={id2 * 150 + id * 50}
>
<div className="row g-3 items-center">
<div className="col-auto">
<Image
className="avatar avatar-lg d-block"
src={`/img/testimonials/${testimonial.avatar}`}
width={48}
height={48}
alt={testimonial.name}
/>
</div>
<div className="col">
<div className="font-bold">{testimonial.name}</div>
<div className="text-muted">{testimonial.job}</div>
</div>
</div>
<div className="mt-3">{testimonial.description}</div>
</a>
))}
</div>
))}
</div>
<div className="mt-5">
<TestimonialsShare />
</div>
</>
);
}
@@ -0,0 +1,17 @@
import { escapeHtml, uiUrl } from '@/config/site';
import Icon from '@/components/Icon';
export default function TestimonialsShare() {
const twitterUrl = `https://twitter.com/intent/tweet?url=${escapeHtml(
uiUrl
)}&via=codecalm&text=Tabler+-+Premium+dashboard+template+with+responsive+and+high+quality+UI`;
return <>
<div className="text-center mt-2">
<a href={twitterUrl} className="btn btn-lg" target="_blank" rel="noopener noreferrer">
<Icon name="heart" className="text-red" />
Share the love with us!
</a>
</div>
</>;
}
+71
View File
@@ -0,0 +1,71 @@
import Head from 'next/head';
import { uiUrl } from '@/config/site';
import { useRouter } from 'next/router';
export default function Title({ meta = {
title: '',
image: '',
description: '',
}}) {
const router = useRouter(),
path = router.pathname;
let section = '';
if (path.match(/\/docs/)) {
section = 'Documentation';
}
const title = meta.title
? `${meta.title} - ${section ? `${section} - ` : ''}Tabler`
: 'Tabler: Premium dashboard template with responsive and high quality UI';
const image = `${meta.image ? meta.image : `${uiUrl}/img/tabler/og.png?2`}`;
const description = meta.description
? meta.description
: 'Tabler comes with tons of well-designed components and features. Start your adventure with Tabler and make your dashboard great again. For free!';
const canonical = `${uiUrl}${(path === '/' ? '' : path).split('?')[0]}`;
return (
<Head>
<link rel="canonical" href={canonical} />
<title key="title">{title}</title>
<meta key="og:type" property="og:type" content="website" />
<meta key="og:url" property="og:url" content={canonical} />
<meta key="og:title" property="og:title" content={title} />
<meta key="twitter:title" name="twitter:title" content={title} />
<meta key="description" name="description" content={description} />
<meta key="og:description" property="og:description" content={description} />
<meta key="og:image" property="og:image" content={`${image}`} />
<meta key="twitter:image" name="twitter:image" content={`${image}`} />
<meta key="og:image:width" property="og:image:width" content="1200" />
<meta key="og:image:height" property="og:image:height" content="630" />
<meta key="twitter:card" name="twitter:card" content="summary_large_image" />
<meta key="twitter:site" name="twitter:site" content="@codecalm" />
<meta key="twitter:creator" name="twitter:creator" content="@codecalm" />
<link rel="preconnect" href="https://rsms.me/" />
<link rel="preconnect" href="https://vitals.vercel-insights.com/" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicons/favicon-16x16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="48x48" href="/favicons/favicon-48x48.png" />
<link rel="manifest" href="/favicons/manifest.json" />
<meta name="theme-color" content="#fff" />
<meta name="application-name" content="tabler" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon-180x180.png" />
<meta name="msapplication-TileColor" content="#206bc4" />
<meta httpEquiv="X-UA-Compatible" content="ie=edge" />
<meta httpEquiv="pragma" content="no-cache" />
</Head>
);
}
+41
View File
@@ -0,0 +1,41 @@
import Icon from '@/components/Icon';
import { escapeHtml, iconsCountRounded, iconsUrl } from '@/config/site';
const twitterUrl = `https://twitter.com/intent/tweet?url=${escapeHtml(
iconsUrl
)}&via=codecalm&text=Over%20${iconsCountRounded}%20free%20and%20open%20source%20icons%20for%20web%20design%3A%20Tabler%20Icons&hashtags=opensource,icons,iconfont,freebie`;
const fbUrl = `https://www.facebook.com/sharer/sharer.php?u=${escapeHtml(iconsUrl)}`;
export default function LayoutHeroIcons() {
return (
<div>
<header className="hero pb-8">
<div className="container">
<h1 className="hero-title">Over {iconsCountRounded} pixel-perfect icons for web design</h1>
<p className="hero-description mt-4">
Free and open source icons designed to make your website or app attractive, visually consistent and simply
beautiful.
</p>
<div className="mt-5">
<div className="row g-3 justify-center">
<div className="col-auto">
<a href={twitterUrl} className="btn btn-twitter" target="_blank" rel="noopener noreferrer">
<Icon name="brand-twitter" />
Tweet me
</a>
</div>
<div className="col-auto">
<a href={fbUrl} className="btn btn-facebook" target="_blank" rel="noopener noreferrer">
<Icon name="brand-facebook" />
Share me
</a>
</div>
</div>
</div>
</div>
</header>
</div>
);
}
+42
View File
@@ -0,0 +1,42 @@
import Browser from '@/components/Browser';
import ResponsiveImage from '@/components/ResponsiveImage';
import { uiDownloadUrl } from '@/config/site';
export default function LayoutHeroUi() {
return (
<>
<header className="hero pt-10 pb-0">
<div className="container">
<h1 className="hero-title" data-aos="zoom-y-out">
Develop beautiful web apps with&nbsp;Tabler
</h1>
<p className="hero-description mt-4" data-aos="zoom-y-out" data-aos-delay="150">
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 className="mt-5" data-aos="zoom-y-out" data-aos-delay="300">
<div className="row g-3 justify-center">
<div className="col-auto">
<a href={uiDownloadUrl} className="btn btn-lg btn-primary lemonsqueezy-button">
Download template
</a>
</div>
<div className="col-auto">
<a href="/preview" className="btn btn-lg" target="_blank" rel="noopener noreferrer">
Preview template
</a>
</div>
</div>
</div>
<div className="hero-img img-overlap-margin">
<Browser data-aos="zoom-y-out" data-aos-delay="450">
<ResponsiveImage src="/img/tabler/preview.png" width={1040} height={760} priority />
</Browser>
</div>
</div>
</header>
</>
);
}
@@ -0,0 +1,43 @@
import { componentsCount, componentsRounded, emailsCount, emailsPrice } from '@/config/site';
import Svg from '@/components/Svg';
import Link from '@/components/Link';
import ResponsiveImage from '@/components/ResponsiveImage';
export default function LayoutHeroUiComponents() {
return (
<header className="hero pb-8">
<div className="container">
<div className="row items-center">
<div className="col text-left" data-aos="fade-up">
<div className="hero-subheader">Tabler Components</div>
<h1 className="hero-title">{componentsRounded}+ responsive components built with Tabler</h1>
<p className="hero-description mt-4">
Build your next website even faster with premade responsive components designed and built by Tabler
maintainers and community. All components are free forever for everyone.
</p>
<div className="mt-7">
<div className="row g-3">
<div className="col-auto">
<a href="#" className="btn btn-lg btn-primary">
Buy now for ${emailsPrice}
</a>
</div>
<div className="col-auto">
<Link href="/emails/gallery" className="btn btn-lg">
Browse gallery
</Link>
</div>
</div>
</div>
</div>
<div className="col" data-aos="fade-up">
<div className="hero-img-side pl-5">
<ResponsiveImage src="/img/components/hero.png" class="hero-image" width="552" height="420" alt="" />
</div>
</div>
</div>
</div>
</header>
);
}
+99
View File
@@ -0,0 +1,99 @@
'use client';
import { emailsCount, emailsDownloadUrl, emailsPrice } from '@/config/site';
import Link from '@/components/Link';
import Slider from '@/components/Slider';
import ResponsiveImage from '@/components/ResponsiveImage';
export default function LayoutHeroUiEmails() {
return (
<header className="hero pb-8">
<div className="container">
<div className="row items-center">
<div className="md:col-6 text-center md:text-left" data-aos="fade-up">
<div className="hero-subheader">Tabler Emails</div>
<h1 className="hero-title">Better email communication, less effort.</h1>
<p className="hero-description mt-4">
{emailsCount} eye-catching, customizable and responsive email templates to improve your email
communication. No coding skills needed.
</p>
<div className="mt-6 lg:mt-7">
<div className="row justify-center md:justify-start">
<div className="col-auto">
<a
href={emailsDownloadUrl}
className="btn btn-lg btn-primary"
target="_blank"
rel="noopener noreferrer"
>
Buy for ${emailsPrice}
</a>
</div>
<div className="col-auto">
<Link href="/emails/gallery" className="btn btn-lg">
Browse gallery
</Link>
</div>
</div>
</div>
</div>
<div className="md:col-6" data-aos="fade-up">
<div className="lg:my-n6">
<div className="hero-img-side">
<Slider
style={{
background: 'url(/img/emails/hero-bg.svg) no-repeat center/contain'
}}
slides={[
<ResponsiveImage
src="/img/emails/hero-5.png"
className="mx-auto"
width="604"
height="590"
alt=""
key="hero-1"
priority
/>,
<ResponsiveImage
src="/img/emails/hero-1.png"
className="mx-auto"
width="604"
height="590"
alt=""
key="hero-2"
/>,
<ResponsiveImage
src="/img/emails/hero-2.png"
className="mx-auto"
width="604"
height="590"
alt=""
key="hero-3"
/>,
<ResponsiveImage
src="/img/emails/hero-3.png"
className="mx-auto"
width="604"
height="590"
alt=""
key="hero-4"
/>,
<ResponsiveImage
src="/img/emails/hero-4.png"
className="mx-auto"
width="604"
height="590"
alt=""
key="hero-5"
/>
]}
/>
</div>
</div>
</div>
</div>
</div>
</header>
);
}
+89
View File
@@ -0,0 +1,89 @@
import { iconsCountRounded, iconsGithubUrl, iconsUrl } from '@/config/site';
import ResponsiveImage from '@/components/ResponsiveImage';
import Icon from '@/components/Icon';
import React from 'react';
import Slider from '@/components/Slider';
export default function LayoutHeroUiIcons() {
return (
<header className="hero">
<div className="container">
<div className="row items-center xl:g-6">
<div className="md:col-6 md:text-left" data-aos="fade-up">
<div className="hero-subheader">Tabler Icons</div>
<h1 className="hero-title">Pixel-perfect icons that match your design</h1>
<p className="hero-description mt-4">
Over {iconsCountRounded} free, open source icons designed to make your website or app attractive, visually
consistent and simply beautiful.
</p>
<div className="mt-5 lg:mt-7">
<div className="row justify-center md:justify-start g-3">
<div className="col-auto">
<a href={iconsUrl} className="btn btn-lg btn-primary" target="_blank">
<Icon name="search" /> Browse icons
</a>
</div>
<div className="col-auto">
<a href={iconsGithubUrl} className="btn btn-lg" target="_blank" rel="noopener noreferrer">
See on GitHub
</a>
</div>
</div>
</div>
</div>
<div className="md:col-6 md:order-first" data-aos="fade-up">
<div className="hero-img-side">
<Slider
style={{
background: 'url(/img/icons/hero-bg.svg) no-repeat center/contain'
}}
slides={[
<ResponsiveImage
src="/img/icons/hero-1.png"
className="mx-auto"
width="552"
height="420"
alt=""
key="hero-1"
/>,
<ResponsiveImage
src="/img/icons/hero-2.png"
className="mx-auto"
width="552"
height="420"
alt=""
key="hero-2"
/>,
<ResponsiveImage
src="/img/icons/hero-3.png"
className="mx-auto"
width="552"
height="420"
alt=""
key="hero-3"
/>,
<ResponsiveImage
src="/img/icons/hero-4.png"
className="mx-auto"
width="552"
height="420"
alt=""
key="hero-4"
/>,
<ResponsiveImage
src="/img/icons/hero-5.png"
className="mx-auto"
width="552"
height="420"
alt=""
key="hero-5"
/>
]}
/>
</div>
</div>
</div>
</div>
</header>
);
}
+8
View File
@@ -0,0 +1,8 @@
export default function Callout({ children, title = 'Important' }) {
return (
<div className="callout">
<div className="callout-title">{title}</div>
{children}
</div>
);
}
+36
View File
@@ -0,0 +1,36 @@
import Link from '@/components/Link';
import Icon from '@/components/Icon';
export function Cards({ children, ...props }) {
return <div className="cards">{children}</div>;
}
export function Card({ children, title, icon, href, ...props }) {
let Component: typeof Link | string = Link;
if (!href) {
Component = 'div';
}
return (
<Component className="card" href={href}>
<div className="card-body">
<div className="row items-center">
<div className="col">
{icon && <Icon name={icon} className="card-icon" />}
{title && <div className="card-title">{title}</div>}
{children}
</div>
{href && (
<div className="col-auto">
<div className="card-chevron">
<Icon name="chevron-right" />
</div>
</div>
)}
</div>
</div>
</Component>
);
}
+25
View File
@@ -0,0 +1,25 @@
import Example from '@/components/Example';
import CodeBlock from '@/components/CodeBlock';
import { iconsVersion, uiCdnUrl } from '@/config/site';
export function Code({ children, ...props }) {
return <code {...props}>{children}</code>;
}
export function Pre({ children, ...props }) {
const language = (children.props.className || '').replace(/^language-/, ''),
html = ([...children.props.children].join('') || '')
.replace(/\$TABLER_CDN/g, uiCdnUrl)
.replace(/\$ICONS_VERSION/g, iconsVersion);
if (props.example) {
return (
<>
<Example html={html} {...props} />
{props.code && <CodeBlock html={html} language={language} hideLinks />}
</>
);
}
return <CodeBlock html={html} language={language} />;
}
+41
View File
@@ -0,0 +1,41 @@
import { colors } from '@/config/tabler';
type Color = {
name: string
value: string
variable?: string
}
export default function ColorsTable({ name }: { name: string }) {
if (!colors[name]) {
return null;
}
return (
<div className="colors-table mt-5 mb-6">
<div className="row">
{colors[name].map((color: Color, i: number) => (
<div className="col-3" key={i}>
<div className="row g-3 items-center">
<div className="col-auto">
<div
className="avatar avatar-lg"
style={{ backgroundColor: color.value }}
></div>
</div>
<div className="col">
<div className="font-bold">{color.name}</div>
<div>
<code>{color.value}</code>
</div>
</div>
{/*<div className="col-auto">*/}
{/* <code>{color.variable}</code>*/}
{/*</div>*/}
</div>
</div>
))}
</div>
</div>
);
}
+5
View File
@@ -0,0 +1,5 @@
import { emailsCount } from '@/config/site';
export default function EmailsCount() {
return emailsCount;
}
+36
View File
@@ -0,0 +1,36 @@
import { flags } from '@/config/tabler';
import { uiCdnUrl } from '@/config/site';
type Flag = {
flag: string
name: string
}
export default function FlagsTable () {
return (
<table className="table">
<tbody>
{flags.map((flag: Flag) => (
<tr key={flag.flag}>
<td>
<img
src={`${uiCdnUrl}/dist/img/flags/${flag.flag}.svg`}
height="40"
alt={flag.name}
className="rounded border"
/>
</td>
<td className="d-none lg:d-table-cell">{flag.name}</td>
<td>
<code>{flag.flag}</code>
</td>
<td className="d-none lg:d-table-cell">
<code>.flag-country-{flag.flag}</code>
</td>
</tr>
))}
</tbody>
</table>
);
}
+17
View File
@@ -0,0 +1,17 @@
import ResponsiveImage from '@/components/ResponsiveImage';
import clsx from 'clsx';
export default function GuideImage({ src, width, height, description, float }) {
return (
<figure className={clsx('guide-image', { [`guide-image-${float}`]: float })}>
<ResponsiveImage
src={src}
width={width}
height={height}
alt={description}
className="rounded bg-white shadow-card"
/>
{description && <figcaption>{description}</figcaption>}
</figure>
);
}
+9
View File
@@ -0,0 +1,9 @@
import { iconsCount, iconsCountRounded } from '@/config/site';
export default function IconsCount({ rounded = false }) {
if (rounded) {
return iconsCountRounded;
}
return iconsCount;
}
+8
View File
@@ -0,0 +1,8 @@
export default function Image(props) {
return (
<figure>
<img className={'border rounded'} alt="" {...props} />
<figcaption>{props.alt}</figcaption>
</figure>
);
}
+25
View File
@@ -0,0 +1,25 @@
import { FC, ReactNode } from 'react';
export function OptionsTable({ children }) {
return (
<div className="options-table">
{children}
</div>
);
}
export function OptionTitle({ children }) {
return (
<div className="options-table-title not-markdown">
{children}
</div>
);
}
export function OptionDescription({ children }) {
return <div className="options-table-description">{children}</div>;
}
+38
View File
@@ -0,0 +1,38 @@
import { payments } from '@/config/tabler';
import { uiCdnUrl } from '@/config/site';
export default function PaymentsTable() {
return (
<table className="table">
<tbody>
{payments.map((payment) => (
<tr key={payment.logo}>
<td>
<img
src={`${uiCdnUrl}/dist/img/payments/${payment.logo}.svg`}
height="40"
alt={payment.name}
className="rounded border"
/>
</td>
<td className="d-none lg:d-table-cell">
<img
src={`${uiCdnUrl}/dist/img/payments/${payment.logo}-dark.svg`}
height="40"
alt={payment.name}
className="rounded border"
/>
</td>
<td className="d-none lg:d-table-cell">{payment.name}</td>
<td>
<code>{payment.logo}</code>
</td>
<td className="d-none lg:d-table-cell">
<code>.payment-provider-{payment.logo}</code>
</td>
</tr>
))}
</tbody>
</table>
);
}
+31
View File
@@ -0,0 +1,31 @@
import clsx from 'clsx';
export default function TablerLogos() {
const logos = [
{ src: '/img/favicon.svg' },
{ src: '/img/logo-tabler.svg' },
{ src: '/img/logo-tabler-gray.svg', className: 'bg-light' },
{ src: '/img/logo-tabler-white.svg', className: 'bg-dark' }
];
return (
<div className="row g-6">
{logos.map(logo => (
<div className="md:col-6" key={logo.src}>
<div className="row g-3">
<div className="col-12">
<div className={clsx('card p-5 d-flex justify-center', logo.className)}>
<img src={logo.src} alt="" />
</div>
</div>
<div className="col-12">
<a href={logo.src} className="btn btn-block" download={true}>
Download SVG
</a>
</div>
</div>
</div>
))}
</div>
);
}
+47
View File
@@ -0,0 +1,47 @@
'use client';
import clsx from 'clsx';
import { Tab as HTab } from '@headlessui/react';
import { Fragment } from 'react';
import { Pre } from '@/components/mdx/Code';
export function Tabs({ items, children }) {
return (
<HTab.Group>
<HTab.List className="tabs">
{items.map((item, i) => (
<HTab as={Fragment} key={item}>
{({ selected }) => <div className={clsx('tab', selected && 'active')}>{item}</div>}
</HTab>
))}
</HTab.List>
<HTab.Panels>{children}</HTab.Panels>
</HTab.Group>
);
}
export function Tab({ children }) {
return <HTab.Panel className="tab-content">{children}</HTab.Panel>;
}
export function TabsPackage({ name }) {
return (
<Tabs items={['yarn', 'npm', 'pnpm']}>
<Tab>
<Pre>
<code className="language-plaintext">yarn add {name}</code>
</Pre>
</Tab>
<Tab>
<Pre>
<code className="language-plaintext">npm install {name}</code>
</Pre>
</Tab>
<Tab>
<Pre>
<code className="language-plaintext">pnpm install {name}</code>
</Pre>
</Tab>
</Tabs>
);
}
+28
View File
@@ -0,0 +1,28 @@
import Icon from '@/components/Icon';
export function TipBad({ children }) {
return (
<div className="tip font-medium">
<Icon name="circle-x-filled" color="red" />
{children}
</div>
);
}
export function TipGood({ children }) {
return (
<div className="tip font-medium">
<Icon name="circle-check-filled" color="green" />
{children}
</div>
);
}
export function TipChanges({ children }) {
return (
<div className="tip font-medium">
<Icon name="alert-circle-filled" color="violet" />
{children}
</div>
);
}

Some files were not shown because too many files have changed in this diff Show More