Compare commits
43 Commits
3c5c541881
...
replit-ai
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
226f5f15cc | ||
|
|
75e46ed41e | ||
|
|
c0d1d517ae | ||
|
|
85d955fdad | ||
|
|
f7df852a00 | ||
|
|
43112c4584 | ||
|
|
621229e1fb | ||
|
|
d1ab497ad7 | ||
|
|
d0b7a9a90d | ||
|
|
8804d671a2 | ||
|
|
f0c6e1601b | ||
|
|
fe0c56a5df | ||
|
|
e1bb749c80 | ||
|
|
867cc5681f | ||
|
|
8c9d17d465 | ||
| 01443deb1c | |||
| 81579a82ed | |||
| 313e5ee462 | |||
| df0daa33ed | |||
| 1ea05002f7 | |||
| 0a24dffc35 | |||
| 3406096623 | |||
| 0b897235e1 | |||
| be8278453b | |||
| 9c4232cbe0 | |||
| c520e3858c | |||
| 666f336910 | |||
| 1c2a8f8a8c | |||
| 9a9fbbe9ea | |||
| 152acd5854 | |||
| fbe791e07f | |||
|
|
d5fe9ad5c4 | ||
|
|
7206cec8d2 | ||
| bd0bc40029 | |||
| cce9b95a0e | |||
| 855be9a4c3 | |||
|
|
56c3b70b87 | ||
|
|
b4276fc9f9 | ||
|
|
7b0ea4669e | ||
|
|
c7d969a606 | ||
|
|
24a6e6d34b | ||
|
|
f4706c0dec | ||
|
|
5ebbcadd62 |
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
dist
|
||||
.DS_Store
|
||||
server/public
|
||||
vite.config.ts.*
|
||||
*.tar.gz
|
||||
42
.replit
Normal file
@@ -0,0 +1,42 @@
|
||||
modules = ["nodejs-20", "web", "postgresql-16"]
|
||||
run = "npm run dev"
|
||||
hidden = [".config", ".git", "generated-icon.png", "node_modules", "dist"]
|
||||
|
||||
[nix]
|
||||
channel = "stable-24_05"
|
||||
|
||||
[[ports]]
|
||||
localPort = 5000
|
||||
externalPort = 80
|
||||
|
||||
[env]
|
||||
PORT = "5000"
|
||||
|
||||
[deployment]
|
||||
deploymentTarget = "autoscale"
|
||||
run = ["node", "./dist/index.cjs"]
|
||||
build = ["npm", "run", "build"]
|
||||
|
||||
[workflows]
|
||||
runButton = "Project"
|
||||
|
||||
[[workflows.workflow]]
|
||||
name = "Project"
|
||||
mode = "parallel"
|
||||
author = "agent"
|
||||
|
||||
[[workflows.workflow.tasks]]
|
||||
task = "workflow.run"
|
||||
args = "Start application"
|
||||
|
||||
[[workflows.workflow]]
|
||||
name = "Start application"
|
||||
author = "agent"
|
||||
|
||||
[[workflows.workflow.tasks]]
|
||||
task = "shell.exec"
|
||||
args = "npm run dev"
|
||||
waitForPort = 5000
|
||||
|
||||
[agent]
|
||||
expertMode = true
|
||||
187
404.html
@@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
|
||||
<head>
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
@@ -7,34 +8,21 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<meta name="author" content="Awaiken">
|
||||
<meta name="author" content="Keshav Anand">
|
||||
<!-- Page Title -->
|
||||
<title>Avenix - Church HTML Template</title>
|
||||
<title>Error</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.png">
|
||||
<!-- Google Fonts Css-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
|
||||
<!-- Bootstrap Css -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<!-- SlickNav Css -->
|
||||
<link href="css/slicknav.min.css" rel="stylesheet">
|
||||
<!-- Swiper Css -->
|
||||
<link rel="stylesheet" href="css/swiper-bundle.min.css">
|
||||
<!-- Font Awesome Icon Css-->
|
||||
<link href="css/all.css" rel="stylesheet" media="screen">
|
||||
<!-- Animated Css -->
|
||||
<link href="css/animate.css" rel="stylesheet">
|
||||
<!-- Magnific Popup Core Css File -->
|
||||
<link rel="stylesheet" href="css/magnific-popup.css">
|
||||
<!-- Mouse Cursor Css File -->
|
||||
<link rel="stylesheet" href="css/mousecursor.css">
|
||||
<!-- Audio Css File -->
|
||||
<link rel="stylesheet" href="css/plyr.css">
|
||||
<!-- Main Custom Css -->
|
||||
<link href="css/custom.css" rel="stylesheet" media="screen">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
||||
rel="stylesheet">
|
||||
<!-- Bundled CSS -->
|
||||
<link href="css/bundle.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- Preloader Start -->
|
||||
@@ -53,7 +41,7 @@
|
||||
<div class="container">
|
||||
<!-- Logo Start -->
|
||||
<a class="navbar-brand" href="./">
|
||||
<img src="images/logo.svg" alt="Logo">
|
||||
<img src="images/logo.png" alt="Logo" style="width: 60px; height: auto;">
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
@@ -61,38 +49,22 @@
|
||||
<div class="collapse navbar-collapse main-menu">
|
||||
<div class="nav-menu-wrapper">
|
||||
<ul class="navbar-nav mr-auto" id="menu">
|
||||
<li class="nav-item submenu"><a class="nav-link" href="./">Home</a>
|
||||
<ul class="sub-menu">
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home - Image</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-video.html">Home - Video</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-slider.html">Home - Slider</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="about.html">About Us</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="service.html">Services</a></li>
|
||||
<li class="nav-item submenu"><a class="nav-link" href="#">Pages</a>
|
||||
<ul>
|
||||
<li class="nav-item"><a class="nav-link" href="service-single.html">Service Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog.html">Blog</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog-single.html">Blog Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons.html">Sermons</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons-single.html">Sermons Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign.html">Campaigns</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign-single.html">Campaign Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministries.html">Ministries</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministry-single.html">Ministries Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="pastor.html">pastor</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="gallery.html">Gallery</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="404.html">404</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="dallas.html">Dallas Regionals</a></li>
|
||||
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="austin.html">Austin Regionals</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="contact.html">Contact Us</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="#">donate now</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="sponsors.html">Our
|
||||
Partners</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Let’s Start Button Start -->
|
||||
<div class="header-btn d-inline-flex">
|
||||
<a href="#" class="btn-default">donate now</a>
|
||||
<a href="sponsors.html" class="btn-default">Our Partners</a>
|
||||
</div>
|
||||
<!-- Let’s Start Button End -->
|
||||
</div>
|
||||
@@ -105,6 +77,7 @@
|
||||
</header>
|
||||
<!-- Header End -->
|
||||
|
||||
|
||||
<!-- Page Header Start -->
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
@@ -131,9 +104,7 @@
|
||||
<div class="error-page">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="error-page-image wow fadeInUp" data-wow-delay="0.25s">
|
||||
<img src="images/404-error-img.png" alt="">
|
||||
</div>
|
||||
|
||||
<div class="error-page-content">
|
||||
<div class="error-page-content-heading">
|
||||
<h2 class="text-anime-style-2" data-cursor="-opaque"><span>Oops!</span> Page Not Found</h2>
|
||||
@@ -148,6 +119,7 @@
|
||||
</div>
|
||||
<!-- error section end -->
|
||||
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer class="main-footer">
|
||||
<div class="container">
|
||||
@@ -157,21 +129,41 @@
|
||||
<div class="about-footer">
|
||||
<!-- Footer Logo Start -->
|
||||
<div class="footer-logo">
|
||||
<img src="images/footer-logo.svg" alt="">
|
||||
<img src="images/logo.png" alt="Footer Logo" style="width: 100px; height: auto;">
|
||||
</div>
|
||||
<!-- Footer Logo End -->
|
||||
|
||||
<!-- About Footer Content Start -->
|
||||
<div class="about-footer-content">
|
||||
<p>Lorem Ipsum is simply dummy text of printing and typesetting industry. Lorem Ipsum has been the industry's.</p>
|
||||
<p id="age-text">Loading...</p>
|
||||
|
||||
<script>
|
||||
const foundingDate = new Date("2025-12-29");
|
||||
const now = new Date();
|
||||
|
||||
const months = (now.getFullYear() - foundingDate.getFullYear()) * 12
|
||||
+ (now.getMonth() - foundingDate.getMonth());
|
||||
|
||||
const years = Math.floor(months / 12);
|
||||
const remainingMonths = months % 12;
|
||||
|
||||
let duration = "";
|
||||
if (years > 0) duration += `${years} year${years > 1 ? "s" : ""}`;
|
||||
if (years > 0 && remainingMonths > 0) duration += " and ";
|
||||
if (remainingMonths > 0) duration += `${remainingMonths} month${remainingMonths > 1 ? "s" : ""}`;
|
||||
if (months === 0) duration = "less than a month";
|
||||
|
||||
document.getElementById("age-text").textContent =
|
||||
`TSCB has been proudly serving its community for ${duration}`;
|
||||
</script>
|
||||
</div>
|
||||
<!-- Footer Social Links Start -->
|
||||
<div class="footer-social-links">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-x-twitter"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-linkedin-in"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
<li><a href="https://www.instagram.com/texasscholasticcricketboard/"><i
|
||||
class="fa-brands fa-instagram"></i></a></li>
|
||||
<li><a href="https://www.youtube.com/channel/UCdFfqkVWDJyFlFEEKfq27wg"><i class="fa-brands fa-youtube"></i></a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Links End -->
|
||||
@@ -185,11 +177,10 @@
|
||||
<div class="footer-links">
|
||||
<h3>quick links</h3>
|
||||
<ul>
|
||||
<li><a href="#">home</a></li>
|
||||
<li><a href="#">our chruch</a></li>
|
||||
<li><a href="#">services</a></li>
|
||||
<li><a href="#">event</a></li>
|
||||
<li><a href="#">news</a></li>
|
||||
<li><a href="/">home</a></li>
|
||||
<li><a href="/about.html">about</a></li>
|
||||
<li><a href="/sponsors.html">sponsors</a></li>
|
||||
<li><a href="/contact.html">contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
@@ -198,13 +189,12 @@
|
||||
<div class="col-lg-3 col-md-4 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>our services</h3>
|
||||
<h3>our cricket</h3>
|
||||
<ul>
|
||||
<li><a href="#">support groups</a></li>
|
||||
<li><a href="#">special events</a></li>
|
||||
<li><a href="#">online services</a></li>
|
||||
<li><a href="#">pastoral care</a></li>
|
||||
<li><a href="#">sunday worship</a></li>
|
||||
<li><a href="/dallas.html">dallas regionals</a></li>
|
||||
<li><a href="/austin.html">austin regionals</a></li>
|
||||
<li><a href="https://cricclubs.com/TexasScholasticCricketBoard">dallas cricclubs league</a></li>
|
||||
<li><a href="https://cricclubs.com/USHSC/series-list/QKoRw7aJTppHXMxmRSTXmg?seriesName=USAHSC%25202026">austin cricclubs league</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
@@ -219,10 +209,10 @@
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-phone.svg" alt="">
|
||||
<img loading="lazy" src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>(+0) 789 345 012</p>
|
||||
<p>(+1) (945) 900-1148</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
@@ -230,24 +220,15 @@
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-mail.svg" alt="">
|
||||
<img loading="lazy" src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>domain@gmail.com</p>
|
||||
<p>texasscholasticcricketboard@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-location.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>24/11 Robert Road,New York,USA</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
</div>
|
||||
<!-- Footer Contact Details End -->
|
||||
</div>
|
||||
@@ -261,7 +242,7 @@
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Copyright Start -->
|
||||
<div class="footer-copyright-text">
|
||||
<p>Copyright 2024 Avenix. All Rights Reserved.</p>
|
||||
<p>Copyright 2026 Texas Scholastic Cricket Board. All Rights Reserved.</p>
|
||||
</div>
|
||||
<!-- Footer Copyright End -->
|
||||
</div>
|
||||
@@ -270,9 +251,8 @@
|
||||
<!-- Footer Social Link Start -->
|
||||
<div class="footer-privacy-policy">
|
||||
<ul>
|
||||
<li><a href="#">term & condition</a></li>
|
||||
<li><a href="#">support</a></li>
|
||||
<li><a href="#">privacy policy</a></li>
|
||||
<li><a href="https://docs.google.com/document/d/10jrcqdHfUYqF6YBHKVqBewxep7vsUbvrIDLX7ednoCc/edit?tab=t.0#heading=h.xzi71qd5vfcz">policies</a></li>
|
||||
<li><a href="/liability.html">liability</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Link End -->
|
||||
@@ -284,38 +264,9 @@
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
|
||||
|
||||
<!-- Jquery Library File -->
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<!-- Bootstrap js file -->
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<!-- Validator js file -->
|
||||
<script src="js/validator.min.js"></script>
|
||||
<!-- SlickNav js file -->
|
||||
<script src="js/jquery.slicknav.js"></script>
|
||||
<!-- Swiper js file -->
|
||||
<script src="js/swiper-bundle.min.js"></script>
|
||||
<!-- Counter js file -->
|
||||
<script src="js/jquery.waypoints.min.js"></script>
|
||||
<script src="js/jquery.counterup.min.js"></script>
|
||||
<!-- Magnific js file -->
|
||||
<script src="js/jquery.magnific-popup.min.js"></script>
|
||||
<!-- SmoothScroll -->
|
||||
<script src="js/SmoothScroll.js"></script>
|
||||
<!-- Parallax js -->
|
||||
<script src="js/parallaxie.js"></script>
|
||||
<!-- MagicCursor js file -->
|
||||
<script src="js/gsap.min.js"></script>
|
||||
<script src="js/magiccursor.js"></script>
|
||||
<!-- Text Effect js file -->
|
||||
<script src="js/SplitText.js"></script>
|
||||
<script src="js/ScrollTrigger.min.js"></script>
|
||||
<!-- YTPlayer js File -->
|
||||
<script src="js/jquery.mb.YTPlayer.min.js"></script>
|
||||
<!-- Audio js File -->
|
||||
<script src="js/plyr.js"></script>
|
||||
<!-- Wow js file -->
|
||||
<script src="js/wow.js"></script>
|
||||
<!-- Main Custom js file -->
|
||||
<script src="js/function.js"></script>
|
||||
<script src="js/bundle-core.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
1236
about.html
BIN
attached_assets/image_1773780434476.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
attached_assets/image_1773780450841.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
attached_assets/image_1773780452708.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
attached_assets/image_1773784079107.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
BIN
attached_assets/image_1773784449474.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
516
austin.html
Normal file
@@ -0,0 +1,516 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
|
||||
<head>
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<meta name="author" content="Keshav Anand">
|
||||
<!-- Page Title -->
|
||||
<title>Austin League</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/logo.png">
|
||||
<!-- Google Fonts Css-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
||||
rel="stylesheet">
|
||||
<!-- Preload critical image -->
|
||||
<link rel="preload" href="images/page-header-bg.jpg" as="image">
|
||||
<!-- Bundled CSS -->
|
||||
<link href="css/bundle.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- Preloader Start -->
|
||||
<div class="preloader">
|
||||
<div class="loading-container">
|
||||
<div class="loading"></div>
|
||||
<div id="loading-icon"><img src="images/loader.svg" alt=""></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Preloader End -->
|
||||
|
||||
<!-- Header Start -->
|
||||
<header class="main-header">
|
||||
<div class="header-sticky">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
<div class="container">
|
||||
<!-- Logo Start -->
|
||||
<a class="navbar-brand" href="./">
|
||||
<img src="images/logo.png" alt="Logo" style="width: 60px; height: auto;">
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
<!-- Main Menu Start -->
|
||||
<div class="collapse navbar-collapse main-menu">
|
||||
<div class="nav-menu-wrapper">
|
||||
<ul class="navbar-nav mr-auto" id="menu">
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="about.html">About Us</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="dallas.html">Dallas Regionals</a></li>
|
||||
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="austin.html">Austin Regionals</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="contact.html">Contact Us</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="sponsors.html">Our
|
||||
Partners</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Let’s Start Button Start -->
|
||||
<div class="header-btn d-inline-flex">
|
||||
<a href="sponsors.html" class="btn-default">Our Partners</a>
|
||||
</div>
|
||||
<!-- Let’s Start Button End -->
|
||||
</div>
|
||||
<!-- Main Menu End -->
|
||||
<div class="navbar-toggle"></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="responsive-menu"></div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Header End -->
|
||||
|
||||
|
||||
<!-- Page Header Start -->
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-12">
|
||||
<!-- Page Header Box Start -->
|
||||
<div class="page-header-box">
|
||||
<h1 class="text-anime-style-2" data-cursor="-opaque"><span>Austin Regionals</span></h1>
|
||||
<nav class="wow fadeInUp">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="./">home</a></li>
|
||||
<li class="breadcrumb-item active"><a href="/austin.html">austin regionals</a></li>
|
||||
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- Page Header Box End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Header End -->
|
||||
|
||||
<!-- League Overview Section Start -->
|
||||
<div class="about-us page-about-us">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
|
||||
<!-- Text Column -->
|
||||
<div class="col-lg-7 wow fadeInLeft">
|
||||
<div class="section-title">
|
||||
<h3>about the regional competition</h3>
|
||||
<h2 class="text-anime-style-2" data-cursor="-opaque">Tech and Cricket in <span>ATX</span></h2>
|
||||
</div>
|
||||
<div class="about-content">
|
||||
<p>The Austin Regionals brings connects high school students from across the Austin region to compete at the highest level. Breaking the financial barrier to cricket, Austin regionals is the first intra-city high school league to be free of cost to players while being competitive at the highest level. Season One features nine schools divided across three geographic divisions — South, East, and North Austin — competing in a round-robin format to claim a spot in the State Championship.</p>
|
||||
<p>All matches are organized through CricClubs, where you can track live scores, standings, and full match statistics.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buttons Column -->
|
||||
<div class="col-lg-4 offset-lg-1 wow fadeInRight" data-wow-delay="0.2s">
|
||||
<div class="league-links d-flex flex-column gap-3 mt-4 mt-lg-0">
|
||||
<a href="https://cricclubs.com/USHSC/points-table?leagueId=g41t2-aF2KbqJyD7sSBu9w&year=2026&series=QKoRw7aJTppHXMxmRSTXmg&seriesName=USAHSC+2026"
|
||||
class="btn-default w-100 text-center" target="_blank">
|
||||
<i class="fa-solid fa-table-list me-2"></i> Points Table
|
||||
</a>
|
||||
<a href="https://cricclubs.com/USHSC/results?leagueId=g41t2-aF2KbqJyD7sSBu9w&year=2026&series=QKoRw7aJTppHXMxmRSTXmg&seriesName=USAHSC+2026"
|
||||
class="btn-default w-100 text-center" target="_blank">
|
||||
<i class="fa-solid fa-cricket-bat-ball me-2"></i> Our Latest Results
|
||||
</a>
|
||||
<a href="https://cricclubs.com/USHSC"
|
||||
class="btn-default w-100 text-center" target="_blank">
|
||||
<i class="fa-solid fa-arrow-up-right-from-square me-2"></i> League Home Page
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- League Overview Section End -->
|
||||
|
||||
|
||||
<!-- Our Teams Section Start -->
|
||||
<div class="our-teams">
|
||||
<div class="container">
|
||||
<div class="row align-items-center section-row">
|
||||
<div class="col-lg-12">
|
||||
<!-- Section Title Start -->
|
||||
<div class="section-title">
|
||||
<h3 class="wow fadeInUp">our teams</h3>
|
||||
<h2 class="text-anime-style-2" data-cursor="-opaque">Meet Our Dedicated <span>Teams</span></h2>
|
||||
</div>
|
||||
<!-- Section Title End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Team Grid Start -->
|
||||
<div class="row">
|
||||
<!-- Team 1: Plano East Panthers -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/mcneil.jpg" alt="McNeil High School">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>McNeil High School</h3>
|
||||
<p>South Austin</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 2: Frisco Lone Star -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="0.2s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/vandegrift.webp" alt="Vandegrift High School">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Vandegrift High School</h3>
|
||||
<p>South Austin</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 3: Prosper Predators -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="0.4s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/westwodd.jpeg" alt="Westwood High School">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Westwood High School</h3>
|
||||
<p>South Austin</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 4: Irving High Chargers -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="0.6s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/cedarridge.jpg" alt="Cedar Ridge High School">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Cedar Ridge High School</h3>
|
||||
<p>East Austin</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 5: Plano West Warriors -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="0.8s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/roundrock.jpeg" alt="Round Rock High School">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Round Rock High School</h3>
|
||||
<p>East Austin</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 6: Frisco Titans -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="1s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/westlake.jpg" alt="Westlake High School">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Westlake High School</h3>
|
||||
<p>East Austin</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 7: Prosper Patriots -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="1.2s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/leander.jpeg" alt="Leander High School">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Leander High School</h3>
|
||||
<p>North Austin</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 8: Irving Lions -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="1.4s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/legacyranch.jpg" alt="Legacy Ranch High School">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Legacy Ranch High School</h3>
|
||||
<p>North Austin</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 9: Plano Hawks -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="1.6s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/rouse.jpg" alt="Rouse High School">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Rouse High School</h3>
|
||||
<p>North Austin</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- Team Grid End -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- Our Teams Section End -->
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer class="main-footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<!-- About Footer Start -->
|
||||
<div class="about-footer">
|
||||
<!-- Footer Logo Start -->
|
||||
<div class="footer-logo">
|
||||
<img src="images/logo.png" alt="Footer Logo" style="width: 100px; height: auto;">
|
||||
</div>
|
||||
<!-- Footer Logo End -->
|
||||
|
||||
<!-- About Footer Content Start -->
|
||||
<div class="about-footer-content">
|
||||
<p id="age-text">Loading...</p>
|
||||
|
||||
<script>
|
||||
const foundingDate = new Date("2025-12-29");
|
||||
const now = new Date();
|
||||
|
||||
const months = (now.getFullYear() - foundingDate.getFullYear()) * 12
|
||||
+ (now.getMonth() - foundingDate.getMonth());
|
||||
|
||||
const years = Math.floor(months / 12);
|
||||
const remainingMonths = months % 12;
|
||||
|
||||
let duration = "";
|
||||
if (years > 0) duration += `${years} year${years > 1 ? "s" : ""}`;
|
||||
if (years > 0 && remainingMonths > 0) duration += " and ";
|
||||
if (remainingMonths > 0) duration += `${remainingMonths} month${remainingMonths > 1 ? "s" : ""}`;
|
||||
if (months === 0) duration = "less than a month";
|
||||
|
||||
document.getElementById("age-text").textContent =
|
||||
`TSCB has been proudly serving its community for ${duration}`;
|
||||
</script>
|
||||
</div>
|
||||
<!-- Footer Social Links Start -->
|
||||
<div class="footer-social-links">
|
||||
<ul>
|
||||
<li><a href="https://www.instagram.com/texasscholasticcricketboard/"><i
|
||||
class="fa-brands fa-instagram"></i></a></li>
|
||||
<li><a href="https://www.youtube.com/channel/UCdFfqkVWDJyFlFEEKfq27wg"><i class="fa-brands fa-youtube"></i></a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Links End -->
|
||||
|
||||
</div>
|
||||
<!-- About Footer End -->
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-6 col-md-3 col-lg-2">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>quick links</h3>
|
||||
<ul>
|
||||
<li><a href="/">home</a></li>
|
||||
<li><a href="/about.html">about</a></li>
|
||||
<li><a href="/sponsors.html">sponsors</a></li>
|
||||
<li><a href="/contact.html">contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-6 col-md-4 col-lg-3">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>our cricket</h3>
|
||||
<ul>
|
||||
<li><a href="/dallas.html">dallas regionals</a></li>
|
||||
<li><a href="/austin.html">austin regionals</a></li>
|
||||
<li><a href="https://cricclubs.com/TexasScholasticCricketBoard">dallas cricclubs league</a></li>
|
||||
<li><a href="https://cricclubs.com/USHSC/series-list/QKoRw7aJTppHXMxmRSTXmg?seriesName=USAHSC%25202026">austin cricclubs league</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-6 col-md-5 col-lg-3">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-contact">
|
||||
<h3>contact</h3>
|
||||
<!-- Footer Contact Details Start -->
|
||||
<div class="footer-contact-details">
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img loading="lazy" src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>(+1) (945) 900-1148</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img loading="lazy" src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>texasscholasticcricketboard@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
|
||||
</div>
|
||||
<!-- Footer Contact Details End -->
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Copyright Section Start -->
|
||||
<div class="footer-copyright">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Copyright Start -->
|
||||
<div class="footer-copyright-text">
|
||||
<p>Copyright 2026 Texas Scholastic Cricket Board. All Rights Reserved.</p>
|
||||
</div>
|
||||
<!-- Footer Copyright End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Social Link Start -->
|
||||
<div class="footer-privacy-policy">
|
||||
<ul>
|
||||
<li><a href="https://docs.google.com/document/d/10jrcqdHfUYqF6YBHKVqBewxep7vsUbvrIDLX7ednoCc/edit?tab=t.0#heading=h.xzi71qd5vfcz">policies</a></li>
|
||||
<li><a href="/liability.html">liability</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Link End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Copyright Section End -->
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
|
||||
<!-- Jquery Library File -->
|
||||
<script src="js/bundle-core.js"></script>
|
||||
<!-- Enhanced Animations js -->
|
||||
<script src="js/enhance.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
382
blog-single.html
@@ -1,382 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
<head>
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<meta name="author" content="Awaiken">
|
||||
<!-- Page Title -->
|
||||
<title>Avenix - Church HTML Template</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.png">
|
||||
<!-- Google Fonts Css-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
|
||||
<!-- Bootstrap Css -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<!-- SlickNav Css -->
|
||||
<link href="css/slicknav.min.css" rel="stylesheet">
|
||||
<!-- Swiper Css -->
|
||||
<link rel="stylesheet" href="css/swiper-bundle.min.css">
|
||||
<!-- Font Awesome Icon Css-->
|
||||
<link href="css/all.css" rel="stylesheet" media="screen">
|
||||
<!-- Animated Css -->
|
||||
<link href="css/animate.css" rel="stylesheet">
|
||||
<!-- Magnific Popup Core Css File -->
|
||||
<link rel="stylesheet" href="css/magnific-popup.css">
|
||||
<!-- Mouse Cursor Css File -->
|
||||
<link rel="stylesheet" href="css/mousecursor.css">
|
||||
<!-- Audio Css File -->
|
||||
<link rel="stylesheet" href="css/plyr.css">
|
||||
<!-- Main Custom Css -->
|
||||
<link href="css/custom.css" rel="stylesheet" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Preloader Start -->
|
||||
<div class="preloader">
|
||||
<div class="loading-container">
|
||||
<div class="loading"></div>
|
||||
<div id="loading-icon"><img src="images/loader.svg" alt=""></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Preloader End -->
|
||||
|
||||
<!-- Header Start -->
|
||||
<header class="main-header">
|
||||
<div class="header-sticky">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
<div class="container">
|
||||
<!-- Logo Start -->
|
||||
<a class="navbar-brand" href="./">
|
||||
<img src="images/logo.svg" alt="Logo">
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
<!-- Main Menu Start -->
|
||||
<div class="collapse navbar-collapse main-menu">
|
||||
<div class="nav-menu-wrapper">
|
||||
<ul class="navbar-nav mr-auto" id="menu">
|
||||
<li class="nav-item submenu"><a class="nav-link" href="./">Home</a>
|
||||
<ul class="sub-menu">
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home - Image</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-video.html">Home - Video</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-slider.html">Home - Slider</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="about.html">About Us</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="service.html">Services</a></li>
|
||||
<li class="nav-item submenu"><a class="nav-link" href="#">Pages</a>
|
||||
<ul>
|
||||
<li class="nav-item"><a class="nav-link" href="service-single.html">Service Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog.html">Blog</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog-single.html">Blog Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons.html">Sermons</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons-single.html">Sermons Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign.html">Campaigns</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign-single.html">Campaign Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministries.html">Ministries</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministry-single.html">Ministries Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="pastor.html">pastor</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="gallery.html">Gallery</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="404.html">404</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="contact.html">Contact Us</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="#">donate now</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Let’s Start Button Start -->
|
||||
<div class="header-btn d-inline-flex">
|
||||
<a href="#" class="btn-default">donate now</a>
|
||||
</div>
|
||||
<!-- Let’s Start Button End -->
|
||||
</div>
|
||||
<!-- Main Menu End -->
|
||||
<div class="navbar-toggle"></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="responsive-menu"></div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Header End -->
|
||||
|
||||
<!-- Page Header Start -->
|
||||
<div class="page-header parallaxie">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<!-- Page Header Box Start -->
|
||||
<div class="page-header-box">
|
||||
<h1 class="text-anime-style-2" data-cursor="-opaque">This Week's Sermon Embracing Forgiveness</h1>
|
||||
<div class="post-single-meta wow fadeInUp">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><i class="fa-regular fa-user"></i> admin</li>
|
||||
<li class="breadcrumb-item"><i class="fa-regular fa-clock"></i> 26 july 2024</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Header Box End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Header End -->
|
||||
|
||||
<!-- Page Single Post Start -->
|
||||
<div class="page-single-post">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<!-- Post Featured Image Start -->
|
||||
<div class="post-image">
|
||||
<figure class="image-anime reveal">
|
||||
<img src="images/post-1.jpg" alt="">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Post Featured Image Start -->
|
||||
|
||||
<!-- Post Single Content Start -->
|
||||
<div class="post-content">
|
||||
<!-- Post Entry Start -->
|
||||
<div class="post-entry">
|
||||
<p class="wow fadeInUp">Join us for the Christmas Eve Candlelight Service, a Avenix evening of carols, scripture readings, and heartfelt worship. Illuminate the night with candlelight as we celebrate the birth of Jesus Christ. Bring your family and friends to share in the warmth, joy, and peace of this special tradition.</p>
|
||||
|
||||
<p class="wow fadeInUp" data-wow-delay="0.2s">Magical evening that brings our community together to celebrate the birth of Jesus Christ. The service features beautiful carols, inspiring scripture readings, and heartfelt worship, all illuminated by the gentle glow of candlelight. This avenix and reflective experience offers a moment of peace and joy in the midst of the holiday season. Bring your family and friends to share in this cherished tradition, creating lasting memories and a deeper connection to the true meaning of Christmas. We look forward to welcoming you to this special night of worship and fellowship.</p>
|
||||
|
||||
<blockquote class="wow fadeInUp" data-wow-delay="0.4s">
|
||||
<p>Join us for the Christmas Eve Candlelight Service, a avenix evening of carols, scripture readings, and worship. Celebrate the birth of Jesus Christ in the warm glow of candlelight. This special service offers a peaceful and reflective atmosphere, perfect for bringing family and friends together to honor the true meaning of Christmas.</p>
|
||||
</blockquote>
|
||||
|
||||
<p class="wow fadeInUp" data-wow-delay="0.6s">Magical evening that brings our community together to celebrate the birth of Jesus Christ. The service features beautiful carols, inspiring scripture readings, and heartfelt worship, all illuminated by the gentle glow of candlelight. This avenix and reflective experience offers a moment of peace and joy in the midst of the holiday season. Bring your family and friends to share in this cherished tradition, creating lasting memories and a deeper connection to the true meaning of Christmas. We look forward to welcoming you to this special night of worship and fellowship.</p>
|
||||
|
||||
<h2 class="text-anime-style-3" data-cursor="-opaque">Christmas Eve Candlelight Service Celebrate with Us</h2>
|
||||
|
||||
<p class="wow fadeInUp" data-wow-delay="0.8s">Celebrate with us at the Christmas Eve Candlelight Service. Experience a night of uplifting carols, meaningful scripture readings, and heartfelt worship, all in a avenix, candlelit atmosphere. Gather with family and friends to honor the birth of Jesus Christ and embrace the true spirit of Christmas in a warm, reflective setting.</p>
|
||||
|
||||
<ul class="wow fadeInUp" data-wow-delay="1s">
|
||||
<li>Uplifting carols and scripture readings</li>
|
||||
<li>Atmosphere avenix, candlelit setting</li>
|
||||
<li>Fellowship Gather with family and friends</li>
|
||||
<li>Reflect Embrace the true spirit of Christmas</li>
|
||||
</ul>
|
||||
|
||||
<p class="wow fadeInUp" data-wow-delay="1.2s">Join us for the Christmas Eve Candlelight Service as we celebrate the birth of Jesus Christ. Enjoy a avenix evening of beautiful carols, meaningful scripture readings, and heartfelt worship in a warm, candlelit setting. This special service is a perfect opportunity to gather with family and friends, reflecting on the true spirit of Christmas together.</p>
|
||||
</div>
|
||||
<!-- Post Entry End -->
|
||||
|
||||
<!-- Post Tag Links Start -->
|
||||
<div class="post-tag-links">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-8">
|
||||
<!-- Post Tags Start -->
|
||||
<div class="post-tags wow fadeInUp" data-wow-delay="0.5s">
|
||||
<span class="tag-links">
|
||||
Tags:
|
||||
<a href="#">worship</a>
|
||||
<a href="#">prayer</a>
|
||||
<a href="#">jesus</a>
|
||||
<a href="#">sermon</a>
|
||||
</span>
|
||||
</div>
|
||||
<!-- Post Tags End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<!-- Post Social Links Start -->
|
||||
<div class="post-social-sharing wow fadeInUp" data-wow-delay="0.5s">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-linkedin-in"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-x-twitter"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Post Social Links End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Post Tag Links End -->
|
||||
</div>
|
||||
<!-- Post Single Content End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Single Post End -->
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer class="main-footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<!-- About Footer Start -->
|
||||
<div class="about-footer">
|
||||
<!-- Footer Logo Start -->
|
||||
<div class="footer-logo">
|
||||
<img src="images/footer-logo.svg" alt="">
|
||||
</div>
|
||||
<!-- Footer Logo End -->
|
||||
|
||||
<!-- About Footer Content Start -->
|
||||
<div class="about-footer-content">
|
||||
<p>Lorem Ipsum is simply dummy text of printing and typesetting industry. Lorem Ipsum has been the industry's.</p>
|
||||
</div>
|
||||
<!-- Footer Social Links Start -->
|
||||
<div class="footer-social-links">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-x-twitter"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-linkedin-in"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Links End -->
|
||||
|
||||
</div>
|
||||
<!-- About Footer End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-2 col-md-3 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>quick links</h3>
|
||||
<ul>
|
||||
<li><a href="#">home</a></li>
|
||||
<li><a href="#">our chruch</a></li>
|
||||
<li><a href="#">services</a></li>
|
||||
<li><a href="#">event</a></li>
|
||||
<li><a href="#">news</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-4 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>our services</h3>
|
||||
<ul>
|
||||
<li><a href="#">support groups</a></li>
|
||||
<li><a href="#">special events</a></li>
|
||||
<li><a href="#">online services</a></li>
|
||||
<li><a href="#">pastoral care</a></li>
|
||||
<li><a href="#">sunday worship</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-5">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-contact">
|
||||
<h3>contact</h3>
|
||||
<!-- Footer Contact Details Start -->
|
||||
<div class="footer-contact-details">
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>(+0) 789 345 012</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>domain@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-location.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>24/11 Robert Road,New York,USA</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
</div>
|
||||
<!-- Footer Contact Details End -->
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Copyright Section Start -->
|
||||
<div class="footer-copyright">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Copyright Start -->
|
||||
<div class="footer-copyright-text">
|
||||
<p>Copyright 2024 Avenix. All Rights Reserved.</p>
|
||||
</div>
|
||||
<!-- Footer Copyright End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Social Link Start -->
|
||||
<div class="footer-privacy-policy">
|
||||
<ul>
|
||||
<li><a href="#">term & condition</a></li>
|
||||
<li><a href="#">support</a></li>
|
||||
<li><a href="#">privacy policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Link End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Copyright Section End -->
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
|
||||
<!-- Jquery Library File -->
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<!-- Bootstrap js file -->
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<!-- Validator js file -->
|
||||
<script src="js/validator.min.js"></script>
|
||||
<!-- SlickNav js file -->
|
||||
<script src="js/jquery.slicknav.js"></script>
|
||||
<!-- Swiper js file -->
|
||||
<script src="js/swiper-bundle.min.js"></script>
|
||||
<!-- Counter js file -->
|
||||
<script src="js/jquery.waypoints.min.js"></script>
|
||||
<script src="js/jquery.counterup.min.js"></script>
|
||||
<!-- Magnific js file -->
|
||||
<script src="js/jquery.magnific-popup.min.js"></script>
|
||||
<!-- SmoothScroll -->
|
||||
<script src="js/SmoothScroll.js"></script>
|
||||
<!-- Parallax js -->
|
||||
<script src="js/parallaxie.js"></script>
|
||||
<!-- MagicCursor js file -->
|
||||
<script src="js/gsap.min.js"></script>
|
||||
<script src="js/magiccursor.js"></script>
|
||||
<!-- Text Effect js file -->
|
||||
<script src="js/SplitText.js"></script>
|
||||
<script src="js/ScrollTrigger.min.js"></script>
|
||||
<!-- YTPlayer js File -->
|
||||
<script src="js/jquery.mb.YTPlayer.min.js"></script>
|
||||
<!-- Audio js File -->
|
||||
<script src="js/plyr.js"></script>
|
||||
<!-- Wow js file -->
|
||||
<script src="js/wow.js"></script>
|
||||
<!-- Main Custom js file -->
|
||||
<script src="js/function.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
490
blog.html
@@ -1,490 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
<head>
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<meta name="author" content="Awaiken">
|
||||
<!-- Page Title -->
|
||||
<title>Avenix - Church HTML Template</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.png">
|
||||
<!-- Google Fonts Css-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
|
||||
<!-- Bootstrap Css -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<!-- SlickNav Css -->
|
||||
<link href="css/slicknav.min.css" rel="stylesheet">
|
||||
<!-- Swiper Css -->
|
||||
<link rel="stylesheet" href="css/swiper-bundle.min.css">
|
||||
<!-- Font Awesome Icon Css-->
|
||||
<link href="css/all.css" rel="stylesheet" media="screen">
|
||||
<!-- Animated Css -->
|
||||
<link href="css/animate.css" rel="stylesheet">
|
||||
<!-- Magnific Popup Core Css File -->
|
||||
<link rel="stylesheet" href="css/magnific-popup.css">
|
||||
<!-- Mouse Cursor Css File -->
|
||||
<link rel="stylesheet" href="css/mousecursor.css">
|
||||
<!-- Audio Css File -->
|
||||
<link rel="stylesheet" href="css/plyr.css">
|
||||
<!-- Main Custom Css -->
|
||||
<link href="css/custom.css" rel="stylesheet" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Preloader Start -->
|
||||
<div class="preloader">
|
||||
<div class="loading-container">
|
||||
<div class="loading"></div>
|
||||
<div id="loading-icon"><img src="images/loader.svg" alt=""></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Preloader End -->
|
||||
|
||||
<!-- Header Start -->
|
||||
<header class="main-header">
|
||||
<div class="header-sticky">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
<div class="container">
|
||||
<!-- Logo Start -->
|
||||
<a class="navbar-brand" href="./">
|
||||
<img src="images/logo.svg" alt="Logo">
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
<!-- Main Menu Start -->
|
||||
<div class="collapse navbar-collapse main-menu">
|
||||
<div class="nav-menu-wrapper">
|
||||
<ul class="navbar-nav mr-auto" id="menu">
|
||||
<li class="nav-item submenu"><a class="nav-link" href="./">Home</a>
|
||||
<ul class="sub-menu">
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home - Image</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-video.html">Home - Video</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-slider.html">Home - Slider</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="about.html">About Us</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="service.html">Services</a></li>
|
||||
<li class="nav-item submenu"><a class="nav-link" href="#">Pages</a>
|
||||
<ul>
|
||||
<li class="nav-item"><a class="nav-link" href="service-single.html">Service Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog.html">Blog</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog-single.html">Blog Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons.html">Sermons</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons-single.html">Sermons Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign.html">Campaigns</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign-single.html">Campaign Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministries.html">Ministries</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministry-single.html">Ministries Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="pastor.html">pastor</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="gallery.html">Gallery</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="404.html">404</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="contact.html">Contact Us</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="#">donate now</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Let’s Start Button Start -->
|
||||
<div class="header-btn d-inline-flex">
|
||||
<a href="#" class="btn-default">donate now</a>
|
||||
</div>
|
||||
<!-- Let’s Start Button End -->
|
||||
</div>
|
||||
<!-- Main Menu End -->
|
||||
<div class="navbar-toggle"></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="responsive-menu"></div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Header End -->
|
||||
|
||||
<!-- Page Header Start -->
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-12">
|
||||
<!-- Page Header Box Start -->
|
||||
<div class="page-header-box">
|
||||
<h1 class="text-anime-style-2" data-cursor="-opaque">Latest Articles</h1>
|
||||
<nav class="wow fadeInUp">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="./">home</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">blog</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- Page Header Box End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Header End -->
|
||||
|
||||
<!-- Page Blog Start -->
|
||||
<div class="page-blog">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Blog Item Start -->
|
||||
<div class="blog-item wow fadeInUp">
|
||||
<!-- Post Featured Image Start-->
|
||||
<div class="post-featured-image" data-cursor-text="View">
|
||||
<figure>
|
||||
<a href="#" class="image-anime">
|
||||
<img src="images/post-1.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Post Featured Image End -->
|
||||
|
||||
<!-- post Item Body Start -->
|
||||
<div class="post-item-body">
|
||||
<h2><a href="#">This Week's Sermon Embracing Forgiveness</a></h2>
|
||||
</div>
|
||||
<!-- Post Item Body End-->
|
||||
|
||||
<!-- Post Item Footer Start-->
|
||||
<div class="post-item-footer">
|
||||
<a href="#" class="read-more-btn">read more</a>
|
||||
</div>
|
||||
<!-- Post Item Footer End-->
|
||||
</div>
|
||||
<!-- Blog Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Blog Item Start -->
|
||||
<div class="blog-item wow fadeInUp" data-wow-delay="0.25s">
|
||||
<!-- Post Featured Image Start-->
|
||||
<div class="post-featured-image" data-cursor-text="View">
|
||||
<figure>
|
||||
<a href="#" class="image-anime">
|
||||
<img src="images/post-2.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Post Featured Image End -->
|
||||
|
||||
<!-- post Item Body Start -->
|
||||
<div class="post-item-body">
|
||||
<h2><a href="#">Join Us for the Christmas Eve Candlelight Service</a></h2>
|
||||
</div>
|
||||
<!-- Post Item Body End-->
|
||||
|
||||
<!-- Post Item Footer Start-->
|
||||
<div class="post-item-footer">
|
||||
<a href="#" class="read-more-btn">read more</a>
|
||||
</div>
|
||||
<!-- Post Item Footer End-->
|
||||
</div>
|
||||
<!-- Blog Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Blog Item Start -->
|
||||
<div class="blog-item wow fadeInUp" data-wow-delay="0.5s">
|
||||
<!-- Post Featured Image Start-->
|
||||
<div class="post-featured-image" data-cursor-text="View">
|
||||
<figure>
|
||||
<a href="#" class="image-anime">
|
||||
<img src="images/post-3.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Post Featured Image End -->
|
||||
|
||||
<!-- post Item Body Start -->
|
||||
<div class="post-item-body">
|
||||
<h2><a href="#">New Bible Study Series Starts This Sunday</a></h2>
|
||||
</div>
|
||||
<!-- Post Item Body End-->
|
||||
|
||||
<!-- Post Item Footer Start-->
|
||||
<div class="post-item-footer">
|
||||
<a href="#" class="read-more-btn">read more</a>
|
||||
</div>
|
||||
<!-- Post Item Footer End-->
|
||||
</div>
|
||||
<!-- Blog Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Blog Item Start -->
|
||||
<div class="blog-item wow fadeInUp" data-wow-delay="0.75s">
|
||||
<!-- Post Featured Image Start-->
|
||||
<div class="post-featured-image" data-cursor-text="View">
|
||||
<figure>
|
||||
<a href="#" class="image-anime">
|
||||
<img src="images/post-4.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Post Featured Image End -->
|
||||
|
||||
<!-- post Item Body Start -->
|
||||
<div class="post-item-body">
|
||||
<h2><a href="#">Role of Worship in Our Spiritual Lives</a></h2>
|
||||
</div>
|
||||
<!-- Post Item Body End-->
|
||||
|
||||
<!-- Post Item Footer Start-->
|
||||
<div class="post-item-footer">
|
||||
<a href="#" class="read-more-btn">read more</a>
|
||||
</div>
|
||||
<!-- Post Item Footer End-->
|
||||
</div>
|
||||
<!-- Blog Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Blog Item Start -->
|
||||
<div class="blog-item wow fadeInUp" data-wow-delay="1s">
|
||||
<!-- Post Featured Image Start-->
|
||||
<div class="post-featured-image" data-cursor-text="View">
|
||||
<figure>
|
||||
<a href="#" class="image-anime">
|
||||
<img src="images/post-5.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Post Featured Image End -->
|
||||
|
||||
<!-- post Item Body Start -->
|
||||
<div class="post-item-body">
|
||||
<h2><a href="#">How to Get Involved Joining Church Ministries and Programs</a></h2>
|
||||
</div>
|
||||
<!-- Post Item Body End-->
|
||||
|
||||
<!-- Post Item Footer Start-->
|
||||
<div class="post-item-footer">
|
||||
<a href="#" class="read-more-btn">read more</a>
|
||||
</div>
|
||||
<!-- Post Item Footer End-->
|
||||
</div>
|
||||
<!-- Blog Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Blog Item Start -->
|
||||
<div class="blog-item wow fadeInUp" data-wow-delay="1.25s">
|
||||
<!-- Post Featured Image Start-->
|
||||
<div class="post-featured-image" data-cursor-text="View">
|
||||
<figure>
|
||||
<a href="#" class="image-anime">
|
||||
<img src="images/post-6.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Post Featured Image End -->
|
||||
|
||||
<!-- post Item Body Start -->
|
||||
<div class="post-item-body">
|
||||
<h2><a href="#">Inspiring Testimonies from Our Congregation</a></h2>
|
||||
</div>
|
||||
<!-- Post Item Body End-->
|
||||
|
||||
<!-- Post Item Footer Start-->
|
||||
<div class="post-item-footer">
|
||||
<a href="#" class="read-more-btn">read more</a>
|
||||
</div>
|
||||
<!-- Post Item Footer End-->
|
||||
</div>
|
||||
<!-- Blog Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
<!-- Page Pagination Start -->
|
||||
<div class="page-pagination wow fadeInUp" data-wow-delay="0.5s">
|
||||
<ul class="pagination">
|
||||
<li><a href="#"><i class="fa-solid fa-arrow-left-long"></i></a></li>
|
||||
<li class="active"><a href="#">1</a></li>
|
||||
<li><a href="#">2</a></li>
|
||||
<li><a href="#">3</a></li>
|
||||
<li><a href="#"><i class="fa-solid fa-arrow-right-long"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Page Pagination End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Blog End -->
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer class="main-footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<!-- About Footer Start -->
|
||||
<div class="about-footer">
|
||||
<!-- Footer Logo Start -->
|
||||
<div class="footer-logo">
|
||||
<img src="images/footer-logo.svg" alt="">
|
||||
</div>
|
||||
<!-- Footer Logo End -->
|
||||
|
||||
<!-- About Footer Content Start -->
|
||||
<div class="about-footer-content">
|
||||
<p>Lorem Ipsum is simply dummy text of printing and typesetting industry. Lorem Ipsum has been the industry's.</p>
|
||||
</div>
|
||||
<!-- Footer Social Links Start -->
|
||||
<div class="footer-social-links">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-x-twitter"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-linkedin-in"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Links End -->
|
||||
|
||||
</div>
|
||||
<!-- About Footer End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-2 col-md-3 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>quick links</h3>
|
||||
<ul>
|
||||
<li><a href="#">home</a></li>
|
||||
<li><a href="#">our chruch</a></li>
|
||||
<li><a href="#">services</a></li>
|
||||
<li><a href="#">event</a></li>
|
||||
<li><a href="#">news</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-4 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>our services</h3>
|
||||
<ul>
|
||||
<li><a href="#">support groups</a></li>
|
||||
<li><a href="#">special events</a></li>
|
||||
<li><a href="#">online services</a></li>
|
||||
<li><a href="#">pastoral care</a></li>
|
||||
<li><a href="#">sunday worship</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-5">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-contact">
|
||||
<h3>contact</h3>
|
||||
<!-- Footer Contact Details Start -->
|
||||
<div class="footer-contact-details">
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>(+0) 789 345 012</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>domain@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-location.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>24/11 Robert Road,New York,USA</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
</div>
|
||||
<!-- Footer Contact Details End -->
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Copyright Section Start -->
|
||||
<div class="footer-copyright">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Copyright Start -->
|
||||
<div class="footer-copyright-text">
|
||||
<p>Copyright 2024 Avenix. All Rights Reserved.</p>
|
||||
</div>
|
||||
<!-- Footer Copyright End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Social Link Start -->
|
||||
<div class="footer-privacy-policy">
|
||||
<ul>
|
||||
<li><a href="#">term & condition</a></li>
|
||||
<li><a href="#">support</a></li>
|
||||
<li><a href="#">privacy policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Link End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Copyright Section End -->
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
|
||||
<!-- Jquery Library File -->
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<!-- Bootstrap js file -->
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<!-- Validator js file -->
|
||||
<script src="js/validator.min.js"></script>
|
||||
<!-- SlickNav js file -->
|
||||
<script src="js/jquery.slicknav.js"></script>
|
||||
<!-- Swiper js file -->
|
||||
<script src="js/swiper-bundle.min.js"></script>
|
||||
<!-- Counter js file -->
|
||||
<script src="js/jquery.waypoints.min.js"></script>
|
||||
<script src="js/jquery.counterup.min.js"></script>
|
||||
<!-- Magnific js file -->
|
||||
<script src="js/jquery.magnific-popup.min.js"></script>
|
||||
<!-- SmoothScroll -->
|
||||
<script src="js/SmoothScroll.js"></script>
|
||||
<!-- Parallax js -->
|
||||
<script src="js/parallaxie.js"></script>
|
||||
<!-- MagicCursor js file -->
|
||||
<script src="js/gsap.min.js"></script>
|
||||
<script src="js/magiccursor.js"></script>
|
||||
<!-- Text Effect js file -->
|
||||
<script src="js/SplitText.js"></script>
|
||||
<script src="js/ScrollTrigger.min.js"></script>
|
||||
<!-- YTPlayer js File -->
|
||||
<script src="js/jquery.mb.YTPlayer.min.js"></script>
|
||||
<!-- Audio js File -->
|
||||
<script src="js/plyr.js"></script>
|
||||
<!-- Wow js file -->
|
||||
<script src="js/wow.js"></script>
|
||||
<!-- Main Custom js file -->
|
||||
<script src="js/function.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,637 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
<head>
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<meta name="author" content="Awaiken">
|
||||
<!-- Page Title -->
|
||||
<title>Avenix - Church HTML Template</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.png">
|
||||
<!-- Google Fonts Css-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
|
||||
<!-- Bootstrap Css -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<!-- SlickNav Css -->
|
||||
<link href="css/slicknav.min.css" rel="stylesheet">
|
||||
<!-- Swiper Css -->
|
||||
<link rel="stylesheet" href="css/swiper-bundle.min.css">
|
||||
<!-- Font Awesome Icon Css-->
|
||||
<link href="css/all.css" rel="stylesheet" media="screen">
|
||||
<!-- Animated Css -->
|
||||
<link href="css/animate.css" rel="stylesheet">
|
||||
<!-- Magnific Popup Core Css File -->
|
||||
<link rel="stylesheet" href="css/magnific-popup.css">
|
||||
<!-- Mouse Cursor Css File -->
|
||||
<link rel="stylesheet" href="css/mousecursor.css">
|
||||
<!-- Audio Css File -->
|
||||
<link rel="stylesheet" href="css/plyr.css">
|
||||
<!-- Main Custom Css -->
|
||||
<link href="css/custom.css" rel="stylesheet" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Preloader Start -->
|
||||
<div class="preloader">
|
||||
<div class="loading-container">
|
||||
<div class="loading"></div>
|
||||
<div id="loading-icon"><img src="images/loader.svg" alt=""></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Preloader End -->
|
||||
|
||||
<!-- Header Start -->
|
||||
<header class="main-header">
|
||||
<div class="header-sticky">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
<div class="container">
|
||||
<!-- Logo Start -->
|
||||
<a class="navbar-brand" href="./">
|
||||
<img src="images/logo.svg" alt="Logo">
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
<!-- Main Menu Start -->
|
||||
<div class="collapse navbar-collapse main-menu">
|
||||
<div class="nav-menu-wrapper">
|
||||
<ul class="navbar-nav mr-auto" id="menu">
|
||||
<li class="nav-item submenu"><a class="nav-link" href="./">Home</a>
|
||||
<ul class="sub-menu">
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home - Image</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-video.html">Home - Video</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-slider.html">Home - Slider</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="about.html">About Us</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="service.html">Services</a></li>
|
||||
<li class="nav-item submenu"><a class="nav-link" href="#">Pages</a>
|
||||
<ul>
|
||||
<li class="nav-item"><a class="nav-link" href="service-single.html">Service Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog.html">Blog</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog-single.html">Blog Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons.html">Sermons</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons-single.html">Sermons Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign.html">Campaigns</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign-single.html">Campaign Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministries.html">Ministries</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministry-single.html">Ministries Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="pastor.html">pastor</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="gallery.html">Gallery</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="404.html">404</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="contact.html">Contact Us</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="#">donate now</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Let’s Start Button Start -->
|
||||
<div class="header-btn d-inline-flex">
|
||||
<a href="#" class="btn-default">donate now</a>
|
||||
</div>
|
||||
<!-- Let’s Start Button End -->
|
||||
</div>
|
||||
<!-- Main Menu End -->
|
||||
<div class="navbar-toggle"></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="responsive-menu"></div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Header End -->
|
||||
|
||||
<!-- Page Header Start -->
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-12">
|
||||
<!-- Page Header Box Start -->
|
||||
<div class="page-header-box">
|
||||
<h1 class="text-anime-style-2" data-cursor="-opaque">Kids Sports Activity</h1>
|
||||
<nav class="wow fadeInUp">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="./">home</a></li>
|
||||
<li class="breadcrumb-item"><a href="./">campaign</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">kids sports activity</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- Page Header Box End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Header End -->
|
||||
|
||||
<!-- Page Campaign Single Start -->
|
||||
<div class="page-campaign-single">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="campaign-single-content">
|
||||
<!-- Campaign Featured Image Start -->
|
||||
<div class="campaign-featured-image">
|
||||
<figure class="image-anime reveal">
|
||||
<img src="images/campaign-img-1.jpg" alt="">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Campaign Featured Image End -->
|
||||
|
||||
<!-- Campaign Donate Box Start -->
|
||||
<div class="campaign-donate-box">
|
||||
<!-- Skills Progress Bar Start -->
|
||||
<div class="skills-progress-bar">
|
||||
<!-- Skill Item Start -->
|
||||
<div class="skillbar" data-percent="68%">
|
||||
<div class="skill-progress">
|
||||
<div class="count-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Skill Item End -->
|
||||
</div>
|
||||
<!-- Skills Progress Bar End -->
|
||||
|
||||
<!-- Campaign Donate Content Start -->
|
||||
<div class="campaign-donate-content">
|
||||
<div class="campaign-donate-item campaign-raised">
|
||||
<h3>$<span class="counter">9,870</span></h3>
|
||||
<p>raised</p>
|
||||
</div>
|
||||
<div class="campaign-donate-item campaign-donations">
|
||||
<h3>$<span class="counter">00</span></h3>
|
||||
<p>donations</p>
|
||||
</div>
|
||||
<div class="campaign-donate-item campaign-goal">
|
||||
<h3>$<span class="counter">3000</span></h3>
|
||||
<p>goal</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Campaign Donate Content End -->
|
||||
</div>
|
||||
<!-- Campaign Donate Box End -->
|
||||
|
||||
<!-- Campaign Entry Content Start -->
|
||||
<div class="campaign-entry">
|
||||
<h2 class="text-anime-style-2" data-cursor="-opaque">Donate for Kid's Sports Activities Today!</h2>
|
||||
<p class="wow fadeInUp" data-wow-delay="0.2s">Support our kids by donating to our church's sports activities program. Your contributions provide equipment, uniforms, and opportunities for children to participate in healthy, fun, and team-building activities. Help us promote fitness, teamwork, and community spirit among our youth. Every donation makes a difference. Thank you for your generosity!</p>
|
||||
<p class="wow fadeInUp" data-wow-delay="0.4s">we can ensure every child has the chance to participate and grow. Every donation, big or small, makes a significant impact. Thank you for helping us nurture the physical and spiritual well-being of our children!</p>
|
||||
<ul class="wow fadeInUp" data-wow-delay="0.6s">
|
||||
<li>Help kids participate in fun, healthy activities.</li>
|
||||
<li>Teach kids valuable skills in cooperation.</li>
|
||||
<li>Your donations fund essential sports gear.</li>
|
||||
<li>Strengthen the bonds within our church.</li>
|
||||
<li>Encourage physical activity and a healthy lifestyle.</li>
|
||||
<li>Ensure all children have the opportunity to join.</li>
|
||||
</ul>
|
||||
|
||||
<!-- Campaign Entry Gallery Start -->
|
||||
<div class="campaign-entry-gallery">
|
||||
<div class="row gallery-items">
|
||||
<div class="col-lg-3 col-6">
|
||||
<!-- Image gallery start -->
|
||||
<div class="campaign-gallery wow fadeInUp" data-wow-delay="0.2s" data-cursor-text="View">
|
||||
<a href="images/campaign-gallery-1.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/campaign-gallery-1.jpg" alt="img">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Image gallery end -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-6">
|
||||
<!-- Image gallery start -->
|
||||
<div class="campaign-gallery wow fadeInUp" data-wow-delay="0.4s" data-cursor-text="View">
|
||||
<a href="images/campaign-gallery-2.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/campaign-gallery-2.jpg" alt="img">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Image gallery end -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-6">
|
||||
<!-- Image gallery start -->
|
||||
<div class="campaign-gallery wow fadeInUp" data-wow-delay="0.6s" data-cursor-text="View">
|
||||
<a href="images/campaign-gallery-3.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/campaign-gallery-3.jpg" alt="img">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Image gallery end -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-6">
|
||||
<!-- Image gallery start -->
|
||||
<div class="campaign-gallery wow fadeInUp" data-wow-delay="0.8s" data-cursor-text="View">
|
||||
<a href="images/campaign-gallery-4.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/campaign-gallery-4.jpg" alt="img">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Image gallery end -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Campaign Entry Gallery End -->
|
||||
</div>
|
||||
<!-- Campaign Entry Content End -->
|
||||
|
||||
<!-- Campaign Single Faqs Start -->
|
||||
<div class="campaign-single-faqs">
|
||||
<!-- Section Title Start -->
|
||||
<div class="section-title">
|
||||
<h2 class="text-anime-style-2" data-cursor="-opaque">Our Core Value</h2>
|
||||
</div>
|
||||
<!-- Section Title End -->
|
||||
|
||||
<!-- Core Value FAQ Accordion Start -->
|
||||
<div class="core-value-faqs-accordion" id="accordion">
|
||||
<!-- FAQ Item Start -->
|
||||
<div class="accordion-item wow fadeInUp">
|
||||
<h2 class="accordion-header" id="headingOne">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
Why is faith a core value?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne"
|
||||
data-bs-parent="#accordion">
|
||||
<div class="accordion-body">
|
||||
<p>We demonstrate love through compassionate service, supportive relationships, and inclusive community practices.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- FAQ Item End -->
|
||||
|
||||
<!-- FAQ Item Start -->
|
||||
<div class="accordion-item wow fadeInUp" data-wow-delay="0.25s">
|
||||
<h2 class="accordion-header" id="headingTwo">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
How does the church demonstrate love?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo"
|
||||
data-bs-parent="#accordion">
|
||||
<div class="accordion-body">
|
||||
<p>We demonstrate love through compassionate service, supportive relationships, and inclusive community practices.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- FAQ Item End -->
|
||||
|
||||
<!-- FAQ Item Start -->
|
||||
<div class="accordion-item wow fadeInUp" data-wow-delay="0.5s">
|
||||
<h2 class="accordion-header" id="headingThree">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
||||
How is community fostered within the church?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree"
|
||||
data-bs-parent="#accordion">
|
||||
<div class="accordion-body">
|
||||
<p>We demonstrate love through compassionate service, supportive relationships, and inclusive community practices.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- FAQ Item End -->
|
||||
|
||||
<!-- FAQ Item Start -->
|
||||
<div class="accordion-item wow fadeInUp" data-wow-delay="0.75s">
|
||||
<h2 class="accordion-header" id="headingfour">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapsefour" aria-expanded="false" aria-controls="collapsefour">
|
||||
What is the importance of spiritual growth?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapsefour" class="accordion-collapse collapse" aria-labelledby="headingfour"
|
||||
data-bs-parent="#accordion">
|
||||
<div class="accordion-body">
|
||||
<p>We demonstrate love through compassionate service, supportive relationships, and inclusive community practices.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- FAQ Item End -->
|
||||
|
||||
<!-- FAQ Item Start -->
|
||||
<div class="accordion-item wow fadeInUp" data-wow-delay="1s">
|
||||
<h2 class="accordion-header" id="headingfive">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapsefive" aria-expanded="false" aria-controls="collapsefive">
|
||||
How do these values shape church activities?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapsefive" class="accordion-collapse collapse" aria-labelledby="headingfive"
|
||||
data-bs-parent="#accordion">
|
||||
<div class="accordion-body">
|
||||
<p>We demonstrate love through compassionate service, supportive relationships, and inclusive community practices.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- FAQ Item End -->
|
||||
</div>
|
||||
<!-- Core Value FAQ Accordion End -->
|
||||
</div>
|
||||
<!-- Service Single Faqs End -->
|
||||
|
||||
<!-- Sermons Social Sharing Start -->
|
||||
<div class="sermons-social-sharing wow fadeInUp" data-wow-delay="0.5s">
|
||||
<div class="sermons-social-sharing-title">
|
||||
<h3>Share This Sermon :</h3>
|
||||
</div>
|
||||
<div class="sermons-social-sharing-list">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-linkedin-in"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-x-twitter"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Sermons Social Sharing End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="campaign-single-sidebar">
|
||||
<div class="campaign-sidebar-title">
|
||||
<h3 class="wow fadeInUp"><span>give</span> today</h3>
|
||||
<p class="wow fadeInUp" data-wow-delay="0.25s">Every time you give to find Faith Church, you're helping fulfill the mission.</p>
|
||||
</div>
|
||||
<div class="campaign-donate-form">
|
||||
<form id="donateForm" action="#" method="POST">
|
||||
<div class="campaign-donate-value">
|
||||
<div class="form-group mb-4">
|
||||
<input type="text" name="text" class="form-control" id="text" placeholder="donate now ..." required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
|
||||
<fieldset class="donate-value-box">
|
||||
<div class="donate-value">
|
||||
<input type="radio" id="value1" name="value" value="value1" checked>
|
||||
<label for="value1">$ 100.00</label>
|
||||
</div>
|
||||
|
||||
<div class="donate-value">
|
||||
<input type="radio" id="value2" name="value" value="value2">
|
||||
<label for="value2">$ 200.00</label>
|
||||
</div>
|
||||
|
||||
<div class="donate-value">
|
||||
<input type="radio" id="value3" name="value" value="value3">
|
||||
<label for="value3">$ 300.00</label>
|
||||
</div>
|
||||
|
||||
<div class="donate-value">
|
||||
<input type="radio" id="value4" name="value" value="value4" checked>
|
||||
<label for="value4">$ 400.00</label>
|
||||
</div>
|
||||
|
||||
<div class="donate-value">
|
||||
<input type="radio" id="value5" name="value" value="value5">
|
||||
<label for="value5">$ 500.00</label>
|
||||
</div>
|
||||
|
||||
<div class="donate-value">
|
||||
<input type="radio" id="value6" name="value" value="value6">
|
||||
<label for="value6">$ 600.00</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="donate-payment-method">
|
||||
<div class="payment-method-title">
|
||||
<h3>select payment method</h3>
|
||||
</div>
|
||||
<div class="donate-payment-type">
|
||||
<div class="payment-method">
|
||||
<input type="radio" id="test" name="payment" value="Test" checked>
|
||||
<label for="test">test donation</label>
|
||||
</div>
|
||||
<div class="payment-method">
|
||||
<input type="radio" id="Offline" name="payment" value="Offline">
|
||||
<label for="Offline">offline donation</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="donar-personal-info">
|
||||
<div class="row">
|
||||
<div class="form-group col-6 mb-3">
|
||||
<input type="text" name="name" class="form-control" id="fname" placeholder="First Name" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-6 mb-3">
|
||||
<input type="text" name="name" class="form-control" id="lname" placeholder="Last Name" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<input type="email" name ="email" class="form-control" id="email" placeholder="Email Address" required>
|
||||
</div>
|
||||
|
||||
<div class="donar-personal-form-account">
|
||||
<div class="donar-personal-create-account">
|
||||
<input type="checkbox" id="vehicle1" name="vehicle1" value="Bike">
|
||||
<label for="vehicle1">create account</label>
|
||||
</div>
|
||||
<div class="donar-personal-login-account">
|
||||
<P>Already Have Account? <a href="#">login</a></P>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group-btn">
|
||||
<button type="submit" class="btn-default">donate now</button>
|
||||
<div id="msgSubmit" class="h3 hidden"></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Campaign Single End -->
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer class="main-footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<!-- About Footer Start -->
|
||||
<div class="about-footer">
|
||||
<!-- Footer Logo Start -->
|
||||
<div class="footer-logo">
|
||||
<img src="images/footer-logo.svg" alt="">
|
||||
</div>
|
||||
<!-- Footer Logo End -->
|
||||
|
||||
<!-- About Footer Content Start -->
|
||||
<div class="about-footer-content">
|
||||
<p>Lorem Ipsum is simply dummy text of printing and typesetting industry. Lorem Ipsum has been the industry's.</p>
|
||||
</div>
|
||||
<!-- Footer Social Links Start -->
|
||||
<div class="footer-social-links">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-x-twitter"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-linkedin-in"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Links End -->
|
||||
|
||||
</div>
|
||||
<!-- About Footer End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-2 col-md-3 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>quick links</h3>
|
||||
<ul>
|
||||
<li><a href="#">home</a></li>
|
||||
<li><a href="#">our chruch</a></li>
|
||||
<li><a href="#">services</a></li>
|
||||
<li><a href="#">event</a></li>
|
||||
<li><a href="#">news</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-4 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>our services</h3>
|
||||
<ul>
|
||||
<li><a href="#">support groups</a></li>
|
||||
<li><a href="#">special events</a></li>
|
||||
<li><a href="#">online services</a></li>
|
||||
<li><a href="#">pastoral care</a></li>
|
||||
<li><a href="#">sunday worship</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-5">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-contact">
|
||||
<h3>contact</h3>
|
||||
<!-- Footer Contact Details Start -->
|
||||
<div class="footer-contact-details">
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>(+0) 789 345 012</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>domain@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-location.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>24/11 Robert Road,New York,USA</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
</div>
|
||||
<!-- Footer Contact Details End -->
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Copyright Section Start -->
|
||||
<div class="footer-copyright">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Copyright Start -->
|
||||
<div class="footer-copyright-text">
|
||||
<p>Copyright 2024 Avenix. All Rights Reserved.</p>
|
||||
</div>
|
||||
<!-- Footer Copyright End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Social Link Start -->
|
||||
<div class="footer-privacy-policy">
|
||||
<ul>
|
||||
<li><a href="#">term & condition</a></li>
|
||||
<li><a href="#">support</a></li>
|
||||
<li><a href="#">privacy policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Link End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Copyright Section End -->
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
|
||||
<!-- Jquery Library File -->
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<!-- Bootstrap js file -->
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<!-- Validator js file -->
|
||||
<script src="js/validator.min.js"></script>
|
||||
<!-- SlickNav js file -->
|
||||
<script src="js/jquery.slicknav.js"></script>
|
||||
<!-- Swiper js file -->
|
||||
<script src="js/swiper-bundle.min.js"></script>
|
||||
<!-- Counter js file -->
|
||||
<script src="js/jquery.waypoints.min.js"></script>
|
||||
<script src="js/jquery.counterup.min.js"></script>
|
||||
<!-- Magnific js file -->
|
||||
<script src="js/jquery.magnific-popup.min.js"></script>
|
||||
<!-- SmoothScroll -->
|
||||
<script src="js/SmoothScroll.js"></script>
|
||||
<!-- Parallax js -->
|
||||
<script src="js/parallaxie.js"></script>
|
||||
<!-- MagicCursor js file -->
|
||||
<script src="js/gsap.min.js"></script>
|
||||
<script src="js/magiccursor.js"></script>
|
||||
<!-- Text Effect js file -->
|
||||
<script src="js/SplitText.js"></script>
|
||||
<script src="js/ScrollTrigger.min.js"></script>
|
||||
<!-- YTPlayer js File -->
|
||||
<script src="js/jquery.mb.YTPlayer.min.js"></script>
|
||||
<!-- Audio js File -->
|
||||
<script src="js/plyr.js"></script>
|
||||
<!-- Wow js file -->
|
||||
<script src="js/wow.js"></script>
|
||||
<!-- Main Custom js file -->
|
||||
<script src="js/function.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
616
campaign.html
@@ -1,616 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
<head>
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<meta name="author" content="Awaiken">
|
||||
<!-- Page Title -->
|
||||
<title>Avenix - Church HTML Template</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.png">
|
||||
<!-- Google Fonts Css-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
|
||||
<!-- Bootstrap Css -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<!-- SlickNav Css -->
|
||||
<link href="css/slicknav.min.css" rel="stylesheet">
|
||||
<!-- Swiper Css -->
|
||||
<link rel="stylesheet" href="css/swiper-bundle.min.css">
|
||||
<!-- Font Awesome Icon Css-->
|
||||
<link href="css/all.css" rel="stylesheet" media="screen">
|
||||
<!-- Animated Css -->
|
||||
<link href="css/animate.css" rel="stylesheet">
|
||||
<!-- Magnific Popup Core Css File -->
|
||||
<link rel="stylesheet" href="css/magnific-popup.css">
|
||||
<!-- Mouse Cursor Css File -->
|
||||
<link rel="stylesheet" href="css/mousecursor.css">
|
||||
<!-- Audio Css File -->
|
||||
<link rel="stylesheet" href="css/plyr.css">
|
||||
<!-- Main Custom Css -->
|
||||
<link href="css/custom.css" rel="stylesheet" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Preloader Start -->
|
||||
<div class="preloader">
|
||||
<div class="loading-container">
|
||||
<div class="loading"></div>
|
||||
<div id="loading-icon"><img src="images/loader.svg" alt=""></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Preloader End -->
|
||||
|
||||
<!-- Header Start -->
|
||||
<header class="main-header">
|
||||
<div class="header-sticky">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
<div class="container">
|
||||
<!-- Logo Start -->
|
||||
<a class="navbar-brand" href="./">
|
||||
<img src="images/logo.svg" alt="Logo">
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
<!-- Main Menu Start -->
|
||||
<div class="collapse navbar-collapse main-menu">
|
||||
<div class="nav-menu-wrapper">
|
||||
<ul class="navbar-nav mr-auto" id="menu">
|
||||
<li class="nav-item submenu"><a class="nav-link" href="./">Home</a>
|
||||
<ul class="sub-menu">
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home - Image</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-video.html">Home - Video</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-slider.html">Home - Slider</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="about.html">About Us</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="service.html">Services</a></li>
|
||||
<li class="nav-item submenu"><a class="nav-link" href="#">Pages</a>
|
||||
<ul>
|
||||
<li class="nav-item"><a class="nav-link" href="service-single.html">Service Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog.html">Blog</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog-single.html">Blog Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons.html">Sermons</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons-single.html">Sermons Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign.html">Campaigns</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign-single.html">Campaign Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministries.html">Ministries</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministry-single.html">Ministries Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="pastor.html">pastor</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="gallery.html">Gallery</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="404.html">404</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="contact.html">Contact Us</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="#">donate now</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Let’s Start Button Start -->
|
||||
<div class="header-btn d-inline-flex">
|
||||
<a href="#" class="btn-default">donate now</a>
|
||||
</div>
|
||||
<!-- Let’s Start Button End -->
|
||||
</div>
|
||||
<!-- Main Menu End -->
|
||||
<div class="navbar-toggle"></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="responsive-menu"></div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Header End -->
|
||||
|
||||
<!-- Page Header Start -->
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-12">
|
||||
<!-- Page Header Box Start -->
|
||||
<div class="page-header-box">
|
||||
<h1 class="text-anime-style-2" data-cursor="-opaque">Our Campaigns</h1>
|
||||
<nav class="wow fadeInUp">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="./">home</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">campaigns</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- Page Header Box End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Header End -->
|
||||
|
||||
<!-- Page Campaign Start -->
|
||||
<div class="page-campaign">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Campaign Item Start -->
|
||||
<div class="campaign-item wow fadeInUp">
|
||||
<!-- Campaign Image Start -->
|
||||
<div class="campaign-image">
|
||||
<figure>
|
||||
<a href="#" class="image-anime" data-cursor-text="View">
|
||||
<img src="images/campaign-img-1.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Campaign Image End -->
|
||||
|
||||
<!-- Campaign Body Start -->
|
||||
<div class="campaign-body">
|
||||
<!-- Campaign Title Start -->
|
||||
<div class="campaign-content">
|
||||
<h2>Kids Sports Activity</h2>
|
||||
<p>Find out which items we need for our chur5h's programs and services.</p>
|
||||
</div>
|
||||
<!-- Campaign Title End -->
|
||||
|
||||
<!-- Campaign List Start -->
|
||||
<div class="campaign-btn">
|
||||
<a href="#" class="read-more-btn">donate</a>
|
||||
</div>
|
||||
<!-- Campaign List End -->
|
||||
|
||||
<!-- Skills Progress Bar Start -->
|
||||
<div class="skills-progress-bar">
|
||||
<!-- Skill Item Start -->
|
||||
<div class="skillbar" data-percent="40%">
|
||||
<div class="skill-data">
|
||||
<div class="skill-title"><span>$0</span> of $9,870</div>
|
||||
<div class="skill-no"><span>40%</span> Donations</div>
|
||||
</div>
|
||||
<div class="skill-progress">
|
||||
<div class="count-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Skill Item End -->
|
||||
</div>
|
||||
<!-- Skills Progress Bar End -->
|
||||
</div>
|
||||
<!-- Campaign Body End -->
|
||||
</div>
|
||||
<!-- Campaign Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Campaign Item Start -->
|
||||
<div class="campaign-item wow fadeInUp" data-wow-delay="0.25s">
|
||||
<!-- Campaign Image Start -->
|
||||
<div class="campaign-image">
|
||||
<figure>
|
||||
<a href="#" class="image-anime" data-cursor-text="View">
|
||||
<img src="images/campaign-img-2.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Campaign Image End -->
|
||||
|
||||
<!-- Campaign Body Start -->
|
||||
<div class="campaign-body">
|
||||
<!-- Campaign Title Start -->
|
||||
<div class="campaign-content">
|
||||
<h2>Current Fundraising Campaigns</h2>
|
||||
<p>Find out how you can contribute to our ongoing fundraising efforts.</p>
|
||||
</div>
|
||||
<!-- Campaign Title End -->
|
||||
|
||||
<!-- Campaign List Start -->
|
||||
<div class="campaign-btn">
|
||||
<a href="#" class="read-more-btn">donate</a>
|
||||
</div>
|
||||
<!-- Campaign List End -->
|
||||
|
||||
<!-- Skills Progress Bar Start -->
|
||||
<div class="skills-progress-bar">
|
||||
<!-- Skill Item Start -->
|
||||
<div class="skillbar" data-percent="98%">
|
||||
<div class="skill-data">
|
||||
<div class="skill-title"><span>$0</span> of $9,870</div>
|
||||
<div class="skill-no"><span>98%</span> Donations</div>
|
||||
</div>
|
||||
<div class="skill-progress">
|
||||
<div class="count-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Skill Item End -->
|
||||
</div>
|
||||
<!-- Skills Progress Bar End -->
|
||||
</div>
|
||||
<!-- Campaign Body End -->
|
||||
</div>
|
||||
<!-- Campaign Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Campaign Item Start -->
|
||||
<div class="campaign-item wow fadeInUp" data-wow-delay="0.5s">
|
||||
<!-- Campaign Image Start -->
|
||||
<div class="campaign-image">
|
||||
<figure>
|
||||
<a href="#" class="image-anime" data-cursor-text="View">
|
||||
<img src="images/campaign-img-3.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Campaign Image End -->
|
||||
|
||||
<!-- Campaign Body Start -->
|
||||
<div class="campaign-body">
|
||||
<!-- Campaign Title Start -->
|
||||
<div class="campaign-content">
|
||||
<h2>endowment gifts</h2>
|
||||
<p>Learn about making endowment gifts to secure the future of our church.</p>
|
||||
</div>
|
||||
<!-- Campaign Title End -->
|
||||
|
||||
<!-- Campaign List Start -->
|
||||
<div class="campaign-btn">
|
||||
<a href="#" class="read-more-btn">donate</a>
|
||||
</div>
|
||||
<!-- Campaign List End -->
|
||||
|
||||
<!-- Skills Progress Bar Start -->
|
||||
<div class="skills-progress-bar">
|
||||
<!-- Skill Item Start -->
|
||||
<div class="skillbar" data-percent="77%">
|
||||
<div class="skill-data">
|
||||
<div class="skill-title"><span>$0</span> of $9,870</div>
|
||||
<div class="skill-no"><span>77%</span> Donations</div>
|
||||
</div>
|
||||
<div class="skill-progress">
|
||||
<div class="count-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Skill Item End -->
|
||||
</div>
|
||||
<!-- Skills Progress Bar End -->
|
||||
</div>
|
||||
<!-- Campaign Body End -->
|
||||
</div>
|
||||
<!-- Campaign Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Campaign Item Start -->
|
||||
<div class="campaign-item wow fadeInUp" data-wow-delay="0.75s">
|
||||
<!-- Campaign Image Start -->
|
||||
<div class="campaign-image">
|
||||
<figure>
|
||||
<a href="#" class="image-anime" data-cursor-text="View">
|
||||
<img src="images/campaign-img-4.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Campaign Image End -->
|
||||
|
||||
<!-- Campaign Body Start -->
|
||||
<div class="campaign-body">
|
||||
<!-- Campaign Title Start -->
|
||||
<div class="campaign-content">
|
||||
<h2>tithes and offerings</h2>
|
||||
<p>Understand the significance of regular tithes and offerings in sustaining.</p>
|
||||
</div>
|
||||
<!-- Campaign Title End -->
|
||||
|
||||
<!-- Campaign List Start -->
|
||||
<div class="campaign-btn">
|
||||
<a href="#" class="read-more-btn">donate</a>
|
||||
</div>
|
||||
<!-- Campaign List End -->
|
||||
|
||||
<!-- Skills Progress Bar Start -->
|
||||
<div class="skills-progress-bar">
|
||||
<!-- Skill Item Start -->
|
||||
<div class="skillbar" data-percent="93%">
|
||||
<div class="skill-data">
|
||||
<div class="skill-title"><span>$0</span> of $9,870</div>
|
||||
<div class="skill-no"><span>93%</span> Donations</div>
|
||||
</div>
|
||||
<div class="skill-progress">
|
||||
<div class="count-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Skill Item End -->
|
||||
</div>
|
||||
<!-- Skills Progress Bar End -->
|
||||
</div>
|
||||
<!-- Campaign Body End -->
|
||||
</div>
|
||||
<!-- Campaign Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Campaign Item Start -->
|
||||
<div class="campaign-item wow fadeInUp" data-wow-delay="1s">
|
||||
<!-- Campaign Image Start -->
|
||||
<div class="campaign-image">
|
||||
<figure>
|
||||
<a href="#" class="image-anime" data-cursor-text="View">
|
||||
<img src="images/campaign-img-5.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Campaign Image End -->
|
||||
|
||||
<!-- Campaign Body Start -->
|
||||
<div class="campaign-body">
|
||||
<!-- Campaign Title Start -->
|
||||
<div class="campaign-content">
|
||||
<h2>planned giving</h2>
|
||||
<p>Explore planned giving options to leave a lasting legacy for our church.</p>
|
||||
</div>
|
||||
<!-- Campaign Title End -->
|
||||
|
||||
<!-- Campaign List Start -->
|
||||
<div class="campaign-btn">
|
||||
<a href="#" class="read-more-btn">donate</a>
|
||||
</div>
|
||||
<!-- Campaign List End -->
|
||||
|
||||
<!-- Skills Progress Bar Start -->
|
||||
<div class="skills-progress-bar">
|
||||
<!-- Skill Item Start -->
|
||||
<div class="skillbar" data-percent="60%">
|
||||
<div class="skill-data">
|
||||
<div class="skill-title"><span>$0</span> of $9,870</div>
|
||||
<div class="skill-no"><span>60%</span> Donations</div>
|
||||
</div>
|
||||
<div class="skill-progress">
|
||||
<div class="count-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Skill Item End -->
|
||||
</div>
|
||||
<!-- Skills Progress Bar End -->
|
||||
</div>
|
||||
<!-- Campaign Body End -->
|
||||
</div>
|
||||
<!-- Campaign Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<!-- Campaign Item Start -->
|
||||
<div class="campaign-item wow fadeInUp" data-wow-delay="1.25s">
|
||||
<!-- Campaign Image Start -->
|
||||
<div class="campaign-image">
|
||||
<figure>
|
||||
<a href="#" class="image-anime" data-cursor-text="View">
|
||||
<img src="images/campaign-img-6.jpg" alt="">
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Campaign Image End -->
|
||||
|
||||
<!-- Campaign Body Start -->
|
||||
<div class="campaign-body">
|
||||
<!-- Campaign Title Start -->
|
||||
<div class="campaign-content">
|
||||
<h2>community fundraisers</h2>
|
||||
<p>Join us in community fundraisers to support various church initiatives.</p>
|
||||
</div>
|
||||
<!-- Campaign Title End -->
|
||||
|
||||
<!-- Campaign List Start -->
|
||||
<div class="campaign-btn">
|
||||
<a href="#" class="read-more-btn">donate</a>
|
||||
</div>
|
||||
<!-- Campaign List End -->
|
||||
|
||||
<!-- Skills Progress Bar Start -->
|
||||
<div class="skills-progress-bar">
|
||||
<!-- Skill Item Start -->
|
||||
<div class="skillbar" data-percent="80%">
|
||||
<div class="skill-data">
|
||||
<div class="skill-title"><span>$0</span> of $9,870</div>
|
||||
<div class="skill-no"><span>80%</span> Donations</div>
|
||||
</div>
|
||||
<div class="skill-progress">
|
||||
<div class="count-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Skill Item End -->
|
||||
</div>
|
||||
<!-- Skills Progress Bar End -->
|
||||
</div>
|
||||
<!-- Campaign Body End -->
|
||||
</div>
|
||||
<!-- Campaign Item End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
<!-- Page Pagination Start -->
|
||||
<div class="page-pagination wow fadeInUp" data-wow-delay="0.5s">
|
||||
<ul class="pagination">
|
||||
<li><a href="#"><i class="fa-solid fa-arrow-left-long"></i></a></li>
|
||||
<li class="active"><a href="#">1</a></li>
|
||||
<li><a href="#">2</a></li>
|
||||
<li><a href="#">3</a></li>
|
||||
<li><a href="#"><i class="fa-solid fa-arrow-right-long"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Page Pagination End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Campaign End -->
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer class="main-footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<!-- About Footer Start -->
|
||||
<div class="about-footer">
|
||||
<!-- Footer Logo Start -->
|
||||
<div class="footer-logo">
|
||||
<img src="images/footer-logo.svg" alt="">
|
||||
</div>
|
||||
<!-- Footer Logo End -->
|
||||
|
||||
<!-- About Footer Content Start -->
|
||||
<div class="about-footer-content">
|
||||
<p>Lorem Ipsum is simply dummy text of printing and typesetting industry. Lorem Ipsum has been the industry's.</p>
|
||||
</div>
|
||||
<!-- Footer Social Links Start -->
|
||||
<div class="footer-social-links">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-x-twitter"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-linkedin-in"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Links End -->
|
||||
|
||||
</div>
|
||||
<!-- About Footer End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-2 col-md-3 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>quick links</h3>
|
||||
<ul>
|
||||
<li><a href="#">home</a></li>
|
||||
<li><a href="#">our chruch</a></li>
|
||||
<li><a href="#">services</a></li>
|
||||
<li><a href="#">event</a></li>
|
||||
<li><a href="#">news</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-4 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>our services</h3>
|
||||
<ul>
|
||||
<li><a href="#">support groups</a></li>
|
||||
<li><a href="#">special events</a></li>
|
||||
<li><a href="#">online services</a></li>
|
||||
<li><a href="#">pastoral care</a></li>
|
||||
<li><a href="#">sunday worship</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-5">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-contact">
|
||||
<h3>contact</h3>
|
||||
<!-- Footer Contact Details Start -->
|
||||
<div class="footer-contact-details">
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>(+0) 789 345 012</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>domain@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-location.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>24/11 Robert Road,New York,USA</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
</div>
|
||||
<!-- Footer Contact Details End -->
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Copyright Section Start -->
|
||||
<div class="footer-copyright">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Copyright Start -->
|
||||
<div class="footer-copyright-text">
|
||||
<p>Copyright 2024 Avenix. All Rights Reserved.</p>
|
||||
</div>
|
||||
<!-- Footer Copyright End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Social Link Start -->
|
||||
<div class="footer-privacy-policy">
|
||||
<ul>
|
||||
<li><a href="#">term & condition</a></li>
|
||||
<li><a href="#">support</a></li>
|
||||
<li><a href="#">privacy policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Link End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Copyright Section End -->
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
|
||||
<!-- Jquery Library File -->
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<!-- Bootstrap js file -->
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<!-- Validator js file -->
|
||||
<script src="js/validator.min.js"></script>
|
||||
<!-- SlickNav js file -->
|
||||
<script src="js/jquery.slicknav.js"></script>
|
||||
<!-- Swiper js file -->
|
||||
<script src="js/swiper-bundle.min.js"></script>
|
||||
<!-- Counter js file -->
|
||||
<script src="js/jquery.waypoints.min.js"></script>
|
||||
<script src="js/jquery.counterup.min.js"></script>
|
||||
<!-- Magnific js file -->
|
||||
<script src="js/jquery.magnific-popup.min.js"></script>
|
||||
<!-- SmoothScroll -->
|
||||
<script src="js/SmoothScroll.js"></script>
|
||||
<!-- Parallax js -->
|
||||
<script src="js/parallaxie.js"></script>
|
||||
<!-- MagicCursor js file -->
|
||||
<script src="js/gsap.min.js"></script>
|
||||
<script src="js/magiccursor.js"></script>
|
||||
<!-- Text Effect js file -->
|
||||
<script src="js/SplitText.js"></script>
|
||||
<script src="js/ScrollTrigger.min.js"></script>
|
||||
<!-- YTPlayer js File -->
|
||||
<script src="js/jquery.mb.YTPlayer.min.js"></script>
|
||||
<!-- Audio js File -->
|
||||
<script src="js/plyr.js"></script>
|
||||
<!-- Wow js file -->
|
||||
<script src="js/wow.js"></script>
|
||||
<!-- Main Custom js file -->
|
||||
<script src="js/function.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
15
client/index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1" />
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Architects+Daughter&family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=Fira+Code:wght@300..700&family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&family=Lora:ital,wght@0,400..700;1,400..700&family=Merriweather:ital,opsz,wght@0,18..144,300..900;1,18..144,300..900&family=Montserrat:ital,wght@0,100..900;1,100..900&family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Outfit:wght@100..900&family=Oxanium:wght@200..800&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100..900;1,100..900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&family=Space+Grotesk:wght@300..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
client/public/favicon.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
30
client/src/App.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Switch, Route } from "wouter";
|
||||
import { queryClient } from "./lib/queryClient";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { Toaster } from "@/components/ui/toaster";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import NotFound from "@/pages/not-found";
|
||||
|
||||
function Router() {
|
||||
return (
|
||||
<Switch>
|
||||
{/* Add pages below */}
|
||||
{/* <Route path="/" component={Home}/> */}
|
||||
{/* Fallback to 404 */}
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TooltipProvider>
|
||||
<Toaster />
|
||||
<Router />
|
||||
</TooltipProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
56
client/src/components/ui/accordion.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import * as React from "react"
|
||||
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
||||
import { ChevronDown } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Accordion = AccordionPrimitive.Root
|
||||
|
||||
const AccordionItem = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AccordionPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn("border-b", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AccordionItem.displayName = "AccordionItem"
|
||||
|
||||
const AccordionTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AccordionPrimitive.Header className="flex">
|
||||
<AccordionPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200" />
|
||||
</AccordionPrimitive.Trigger>
|
||||
</AccordionPrimitive.Header>
|
||||
))
|
||||
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
|
||||
|
||||
const AccordionContent = React.forwardRef<
|
||||
React.ElementRef<typeof AccordionPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<AccordionPrimitive.Content
|
||||
ref={ref}
|
||||
className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
||||
{...props}
|
||||
>
|
||||
<div className={cn("pb-4 pt-0", className)}>{children}</div>
|
||||
</AccordionPrimitive.Content>
|
||||
))
|
||||
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
||||
139
client/src/components/ui/alert-dialog.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
import * as React from "react"
|
||||
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "@/components/ui/button"
|
||||
|
||||
const AlertDialog = AlertDialogPrimitive.Root
|
||||
|
||||
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
|
||||
|
||||
const AlertDialogPortal = AlertDialogPrimitive.Portal
|
||||
|
||||
const AlertDialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
))
|
||||
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
||||
|
||||
const AlertDialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay />
|
||||
<AlertDialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</AlertDialogPortal>
|
||||
))
|
||||
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
||||
|
||||
const AlertDialogHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
AlertDialogHeader.displayName = "AlertDialogHeader"
|
||||
|
||||
const AlertDialogFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
AlertDialogFooter.displayName = "AlertDialogFooter"
|
||||
|
||||
const AlertDialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
||||
|
||||
const AlertDialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDialogDescription.displayName =
|
||||
AlertDialogPrimitive.Description.displayName
|
||||
|
||||
const AlertDialogAction = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Action
|
||||
ref={ref}
|
||||
className={cn(buttonVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
||||
|
||||
const AlertDialogCancel = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Cancel
|
||||
ref={ref}
|
||||
className={cn(
|
||||
buttonVariants({ variant: "outline" }),
|
||||
"mt-2 sm:mt-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
||||
|
||||
export {
|
||||
AlertDialog,
|
||||
AlertDialogPortal,
|
||||
AlertDialogOverlay,
|
||||
AlertDialogTrigger,
|
||||
AlertDialogContent,
|
||||
AlertDialogHeader,
|
||||
AlertDialogFooter,
|
||||
AlertDialogTitle,
|
||||
AlertDialogDescription,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
}
|
||||
59
client/src/components/ui/alert.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import * as React from "react"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const alertVariants = cva(
|
||||
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-background text-foreground",
|
||||
destructive:
|
||||
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const Alert = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
|
||||
>(({ className, variant, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
role="alert"
|
||||
className={cn(alertVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Alert.displayName = "Alert"
|
||||
|
||||
const AlertTitle = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLHeadingElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<h5
|
||||
ref={ref}
|
||||
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertTitle.displayName = "AlertTitle"
|
||||
|
||||
const AlertDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("text-sm [&_p]:leading-relaxed", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AlertDescription.displayName = "AlertDescription"
|
||||
|
||||
export { Alert, AlertTitle, AlertDescription }
|
||||
5
client/src/components/ui/aspect-ratio.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
|
||||
|
||||
const AspectRatio = AspectRatioPrimitive.Root
|
||||
|
||||
export { AspectRatio }
|
||||
51
client/src/components/ui/avatar.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Avatar = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(`
|
||||
after:content-[''] after:block after:absolute after:inset-0 after:rounded-full after:pointer-events-none after:border after:border-black/10 dark:after:border-white/10
|
||||
relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full`,
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Avatar.displayName = AvatarPrimitive.Root.displayName
|
||||
|
||||
const AvatarImage = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Image>,
|
||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Image
|
||||
ref={ref}
|
||||
className={cn("aspect-square h-full w-full", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarImage.displayName = AvatarPrimitive.Image.displayName
|
||||
|
||||
const AvatarFallback = React.forwardRef<
|
||||
React.ElementRef<typeof AvatarPrimitive.Fallback>,
|
||||
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AvatarPrimitive.Fallback
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback }
|
||||
38
client/src/components/ui/badge.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import * as React from "react"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const badgeVariants = cva(
|
||||
// Whitespace-nowrap: Badges should never wrap.
|
||||
"whitespace-nowrap inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2" +
|
||||
" hover-elevate " ,
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"border-transparent bg-primary text-primary-foreground shadow-xs",
|
||||
secondary: "border-transparent bg-secondary text-secondary-foreground",
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground shadow-xs",
|
||||
|
||||
outline: " border [border-color:var(--badge-outline)] shadow-xs",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
export interface BadgeProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof badgeVariants> {}
|
||||
|
||||
function Badge({ className, variant, ...props }: BadgeProps) {
|
||||
return (
|
||||
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
export { Badge, badgeVariants }
|
||||
115
client/src/components/ui/breadcrumb.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Breadcrumb = React.forwardRef<
|
||||
HTMLElement,
|
||||
React.ComponentPropsWithoutRef<"nav"> & {
|
||||
separator?: React.ReactNode
|
||||
}
|
||||
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />)
|
||||
Breadcrumb.displayName = "Breadcrumb"
|
||||
|
||||
const BreadcrumbList = React.forwardRef<
|
||||
HTMLOListElement,
|
||||
React.ComponentPropsWithoutRef<"ol">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ol
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
BreadcrumbList.displayName = "BreadcrumbList"
|
||||
|
||||
const BreadcrumbItem = React.forwardRef<
|
||||
HTMLLIElement,
|
||||
React.ComponentPropsWithoutRef<"li">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<li
|
||||
ref={ref}
|
||||
className={cn("inline-flex items-center gap-1.5", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
BreadcrumbItem.displayName = "BreadcrumbItem"
|
||||
|
||||
const BreadcrumbLink = React.forwardRef<
|
||||
HTMLAnchorElement,
|
||||
React.ComponentPropsWithoutRef<"a"> & {
|
||||
asChild?: boolean
|
||||
}
|
||||
>(({ asChild, className, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "a"
|
||||
|
||||
return (
|
||||
<Comp
|
||||
ref={ref}
|
||||
className={cn("transition-colors hover:text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
BreadcrumbLink.displayName = "BreadcrumbLink"
|
||||
|
||||
const BreadcrumbPage = React.forwardRef<
|
||||
HTMLSpanElement,
|
||||
React.ComponentPropsWithoutRef<"span">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<span
|
||||
ref={ref}
|
||||
role="link"
|
||||
aria-disabled="true"
|
||||
aria-current="page"
|
||||
className={cn("font-normal text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
BreadcrumbPage.displayName = "BreadcrumbPage"
|
||||
|
||||
const BreadcrumbSeparator = ({
|
||||
children,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"li">) => (
|
||||
<li
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
className={cn("[&>svg]:w-3.5 [&>svg]:h-3.5", className)}
|
||||
{...props}
|
||||
>
|
||||
{children ?? <ChevronRight />}
|
||||
</li>
|
||||
)
|
||||
BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
|
||||
|
||||
const BreadcrumbEllipsis = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"span">) => (
|
||||
<span
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
||||
{...props}
|
||||
>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
<span className="sr-only">More</span>
|
||||
</span>
|
||||
)
|
||||
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
|
||||
|
||||
export {
|
||||
Breadcrumb,
|
||||
BreadcrumbList,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
BreadcrumbEllipsis,
|
||||
}
|
||||
62
client/src/components/ui/button.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0" +
|
||||
" hover-elevate active-elevate-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground border border-primary-border",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground border border-destructive-border",
|
||||
outline:
|
||||
// Shows the background color of whatever card / sidebar / accent background it is inside of.
|
||||
// Inherits the current text color.
|
||||
" border [border-color:var(--button-outline)] shadow-xs active:shadow-none ",
|
||||
secondary: "border bg-secondary text-secondary-foreground border border-secondary-border ",
|
||||
// Add a transparent border so that when someone toggles a border on later, it doesn't shift layout/size.
|
||||
ghost: "border border-transparent",
|
||||
},
|
||||
// Heights are set as "min" heights, because sometimes Ai will place large amount of content
|
||||
// inside buttons. With a min-height they will look appropriate with small amounts of content,
|
||||
// but will expand to fit large amounts of content.
|
||||
size: {
|
||||
default: "min-h-9 px-4 py-2",
|
||||
sm: "min-h-8 rounded-md px-3 text-xs",
|
||||
lg: "min-h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
},
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
|
||||
export { Button, buttonVariants }
|
||||
68
client/src/components/ui/calendar.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import * as React from "react"
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react"
|
||||
import { DayPicker } from "react-day-picker"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "@/components/ui/button"
|
||||
|
||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>
|
||||
|
||||
function Calendar({
|
||||
className,
|
||||
classNames,
|
||||
showOutsideDays = true,
|
||||
...props
|
||||
}: CalendarProps) {
|
||||
return (
|
||||
<DayPicker
|
||||
showOutsideDays={showOutsideDays}
|
||||
className={cn("p-3", className)}
|
||||
classNames={{
|
||||
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
|
||||
month: "space-y-4",
|
||||
caption: "flex justify-center pt-1 relative items-center",
|
||||
caption_label: "text-sm font-medium",
|
||||
nav: "space-x-1 flex items-center",
|
||||
nav_button: cn(
|
||||
buttonVariants({ variant: "outline" }),
|
||||
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
||||
),
|
||||
nav_button_previous: "absolute left-1",
|
||||
nav_button_next: "absolute right-1",
|
||||
table: "w-full border-collapse space-y-1",
|
||||
head_row: "flex",
|
||||
head_cell:
|
||||
"text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
|
||||
row: "flex w-full mt-2",
|
||||
cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
|
||||
day: cn(
|
||||
buttonVariants({ variant: "ghost" }),
|
||||
"h-9 w-9 p-0 font-normal aria-selected:opacity-100"
|
||||
),
|
||||
day_range_end: "day-range-end",
|
||||
day_selected:
|
||||
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
||||
day_today: "bg-accent text-accent-foreground",
|
||||
day_outside:
|
||||
"day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
|
||||
day_disabled: "text-muted-foreground opacity-50",
|
||||
day_range_middle:
|
||||
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
||||
day_hidden: "invisible",
|
||||
...classNames,
|
||||
}}
|
||||
components={{
|
||||
IconLeft: ({ className, ...props }) => (
|
||||
<ChevronLeft className={cn("h-4 w-4", className)} {...props} />
|
||||
),
|
||||
IconRight: ({ className, ...props }) => (
|
||||
<ChevronRight className={cn("h-4 w-4", className)} {...props} />
|
||||
),
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Calendar.displayName = "Calendar"
|
||||
|
||||
export { Calendar }
|
||||
85
client/src/components/ui/card.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Card = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"shadcn-card rounded-xl border bg-card border-card-border text-card-foreground shadow-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
Card.displayName = "Card"
|
||||
|
||||
const CardHeader = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardHeader.displayName = "CardHeader"
|
||||
|
||||
const CardTitle = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-2xl font-semibold leading-none tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardTitle.displayName = "CardTitle"
|
||||
|
||||
const CardDescription = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CardDescription.displayName = "CardDescription"
|
||||
|
||||
const CardContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||
))
|
||||
CardContent.displayName = "CardContent"
|
||||
|
||||
const CardFooter = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex items-center p-6 pt-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CardFooter.displayName = "CardFooter"
|
||||
export {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
}
|
||||
260
client/src/components/ui/carousel.tsx
Normal file
@@ -0,0 +1,260 @@
|
||||
import * as React from "react"
|
||||
import useEmblaCarousel, {
|
||||
type UseEmblaCarouselType,
|
||||
} from "embla-carousel-react"
|
||||
import { ArrowLeft, ArrowRight } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
type CarouselApi = UseEmblaCarouselType[1]
|
||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
||||
type CarouselOptions = UseCarouselParameters[0]
|
||||
type CarouselPlugin = UseCarouselParameters[1]
|
||||
|
||||
type CarouselProps = {
|
||||
opts?: CarouselOptions
|
||||
plugins?: CarouselPlugin
|
||||
orientation?: "horizontal" | "vertical"
|
||||
setApi?: (api: CarouselApi) => void
|
||||
}
|
||||
|
||||
type CarouselContextProps = {
|
||||
carouselRef: ReturnType<typeof useEmblaCarousel>[0]
|
||||
api: ReturnType<typeof useEmblaCarousel>[1]
|
||||
scrollPrev: () => void
|
||||
scrollNext: () => void
|
||||
canScrollPrev: boolean
|
||||
canScrollNext: boolean
|
||||
} & CarouselProps
|
||||
|
||||
const CarouselContext = React.createContext<CarouselContextProps | null>(null)
|
||||
|
||||
function useCarousel() {
|
||||
const context = React.useContext(CarouselContext)
|
||||
|
||||
if (!context) {
|
||||
throw new Error("useCarousel must be used within a <Carousel />")
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
const Carousel = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement> & CarouselProps
|
||||
>(
|
||||
(
|
||||
{
|
||||
orientation = "horizontal",
|
||||
opts,
|
||||
setApi,
|
||||
plugins,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [carouselRef, api] = useEmblaCarousel(
|
||||
{
|
||||
...opts,
|
||||
axis: orientation === "horizontal" ? "x" : "y",
|
||||
},
|
||||
plugins
|
||||
)
|
||||
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
||||
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
||||
|
||||
const onSelect = React.useCallback((api: CarouselApi) => {
|
||||
if (!api) {
|
||||
return
|
||||
}
|
||||
|
||||
setCanScrollPrev(api.canScrollPrev())
|
||||
setCanScrollNext(api.canScrollNext())
|
||||
}, [])
|
||||
|
||||
const scrollPrev = React.useCallback(() => {
|
||||
api?.scrollPrev()
|
||||
}, [api])
|
||||
|
||||
const scrollNext = React.useCallback(() => {
|
||||
api?.scrollNext()
|
||||
}, [api])
|
||||
|
||||
const handleKeyDown = React.useCallback(
|
||||
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||
if (event.key === "ArrowLeft") {
|
||||
event.preventDefault()
|
||||
scrollPrev()
|
||||
} else if (event.key === "ArrowRight") {
|
||||
event.preventDefault()
|
||||
scrollNext()
|
||||
}
|
||||
},
|
||||
[scrollPrev, scrollNext]
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api || !setApi) {
|
||||
return
|
||||
}
|
||||
|
||||
setApi(api)
|
||||
}, [api, setApi])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api) {
|
||||
return
|
||||
}
|
||||
|
||||
onSelect(api)
|
||||
api.on("reInit", onSelect)
|
||||
api.on("select", onSelect)
|
||||
|
||||
return () => {
|
||||
api?.off("select", onSelect)
|
||||
}
|
||||
}, [api, onSelect])
|
||||
|
||||
return (
|
||||
<CarouselContext.Provider
|
||||
value={{
|
||||
carouselRef,
|
||||
api: api,
|
||||
opts,
|
||||
orientation:
|
||||
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
|
||||
scrollPrev,
|
||||
scrollNext,
|
||||
canScrollPrev,
|
||||
canScrollNext,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
ref={ref}
|
||||
onKeyDownCapture={handleKeyDown}
|
||||
className={cn("relative", className)}
|
||||
role="region"
|
||||
aria-roledescription="carousel"
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</CarouselContext.Provider>
|
||||
)
|
||||
}
|
||||
)
|
||||
Carousel.displayName = "Carousel"
|
||||
|
||||
const CarouselContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { carouselRef, orientation } = useCarousel()
|
||||
|
||||
return (
|
||||
<div ref={carouselRef} className="overflow-hidden">
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex",
|
||||
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
CarouselContent.displayName = "CarouselContent"
|
||||
|
||||
const CarouselItem = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { orientation } = useCarousel()
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
role="group"
|
||||
aria-roledescription="slide"
|
||||
className={cn(
|
||||
"min-w-0 shrink-0 grow-0 basis-full",
|
||||
orientation === "horizontal" ? "pl-4" : "pt-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
CarouselItem.displayName = "CarouselItem"
|
||||
|
||||
const CarouselPrevious = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
React.ComponentProps<typeof Button>
|
||||
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
|
||||
|
||||
return (
|
||||
<Button
|
||||
ref={ref}
|
||||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"absolute h-8 w-8 rounded-full",
|
||||
orientation === "horizontal"
|
||||
? "-left-12 top-1/2 -translate-y-1/2"
|
||||
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className
|
||||
)}
|
||||
disabled={!canScrollPrev}
|
||||
onClick={scrollPrev}
|
||||
{...props}
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
<span className="sr-only">Previous slide</span>
|
||||
</Button>
|
||||
)
|
||||
})
|
||||
CarouselPrevious.displayName = "CarouselPrevious"
|
||||
|
||||
const CarouselNext = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
React.ComponentProps<typeof Button>
|
||||
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||
const { orientation, scrollNext, canScrollNext } = useCarousel()
|
||||
|
||||
return (
|
||||
<Button
|
||||
ref={ref}
|
||||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"absolute h-8 w-8 rounded-full",
|
||||
orientation === "horizontal"
|
||||
? "-right-12 top-1/2 -translate-y-1/2"
|
||||
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className
|
||||
)}
|
||||
disabled={!canScrollNext}
|
||||
onClick={scrollNext}
|
||||
{...props}
|
||||
>
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
<span className="sr-only">Next slide</span>
|
||||
</Button>
|
||||
)
|
||||
})
|
||||
CarouselNext.displayName = "CarouselNext"
|
||||
|
||||
export {
|
||||
type CarouselApi,
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselPrevious,
|
||||
CarouselNext,
|
||||
}
|
||||
365
client/src/components/ui/chart.tsx
Normal file
@@ -0,0 +1,365 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as RechartsPrimitive from "recharts"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
// Format: { THEME_NAME: CSS_SELECTOR }
|
||||
const THEMES = { light: "", dark: ".dark" } as const
|
||||
|
||||
export type ChartConfig = {
|
||||
[k in string]: {
|
||||
label?: React.ReactNode
|
||||
icon?: React.ComponentType
|
||||
} & (
|
||||
| { color?: string; theme?: never }
|
||||
| { color?: never; theme: Record<keyof typeof THEMES, string> }
|
||||
)
|
||||
}
|
||||
|
||||
type ChartContextProps = {
|
||||
config: ChartConfig
|
||||
}
|
||||
|
||||
const ChartContext = React.createContext<ChartContextProps | null>(null)
|
||||
|
||||
function useChart() {
|
||||
const context = React.useContext(ChartContext)
|
||||
|
||||
if (!context) {
|
||||
throw new Error("useChart must be used within a <ChartContainer />")
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
const ChartContainer = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<"div"> & {
|
||||
config: ChartConfig
|
||||
children: React.ComponentProps<
|
||||
typeof RechartsPrimitive.ResponsiveContainer
|
||||
>["children"]
|
||||
}
|
||||
>(({ id, className, children, config, ...props }, ref) => {
|
||||
const uniqueId = React.useId()
|
||||
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
|
||||
|
||||
return (
|
||||
<ChartContext.Provider value={{ config }}>
|
||||
<div
|
||||
data-chart={chartId}
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChartStyle id={chartId} config={config} />
|
||||
<RechartsPrimitive.ResponsiveContainer>
|
||||
{children}
|
||||
</RechartsPrimitive.ResponsiveContainer>
|
||||
</div>
|
||||
</ChartContext.Provider>
|
||||
)
|
||||
})
|
||||
ChartContainer.displayName = "Chart"
|
||||
|
||||
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
|
||||
const colorConfig = Object.entries(config).filter(
|
||||
([, config]) => config.theme || config.color
|
||||
)
|
||||
|
||||
if (!colorConfig.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: Object.entries(THEMES)
|
||||
.map(
|
||||
([theme, prefix]) => `
|
||||
${prefix} [data-chart=${id}] {
|
||||
${colorConfig
|
||||
.map(([key, itemConfig]) => {
|
||||
const color =
|
||||
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
|
||||
itemConfig.color
|
||||
return color ? ` --color-${key}: ${color};` : null
|
||||
})
|
||||
.join("\n")}
|
||||
}
|
||||
`
|
||||
)
|
||||
.join("\n"),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const ChartTooltip = RechartsPrimitive.Tooltip
|
||||
|
||||
const ChartTooltipContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
||||
React.ComponentProps<"div"> & {
|
||||
hideLabel?: boolean
|
||||
hideIndicator?: boolean
|
||||
indicator?: "line" | "dot" | "dashed"
|
||||
nameKey?: string
|
||||
labelKey?: string
|
||||
}
|
||||
>(
|
||||
(
|
||||
{
|
||||
active,
|
||||
payload,
|
||||
className,
|
||||
indicator = "dot",
|
||||
hideLabel = false,
|
||||
hideIndicator = false,
|
||||
label,
|
||||
labelFormatter,
|
||||
labelClassName,
|
||||
formatter,
|
||||
color,
|
||||
nameKey,
|
||||
labelKey,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const { config } = useChart()
|
||||
|
||||
const tooltipLabel = React.useMemo(() => {
|
||||
if (hideLabel || !payload?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const [item] = payload
|
||||
const key = `${labelKey || item?.dataKey || item?.name || "value"}`
|
||||
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||
const value =
|
||||
!labelKey && typeof label === "string"
|
||||
? config[label as keyof typeof config]?.label || label
|
||||
: itemConfig?.label
|
||||
|
||||
if (labelFormatter) {
|
||||
return (
|
||||
<div className={cn("font-medium", labelClassName)}>
|
||||
{labelFormatter(value, payload)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <div className={cn("font-medium", labelClassName)}>{value}</div>
|
||||
}, [
|
||||
label,
|
||||
labelFormatter,
|
||||
payload,
|
||||
hideLabel,
|
||||
labelClassName,
|
||||
config,
|
||||
labelKey,
|
||||
])
|
||||
|
||||
if (!active || !payload?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const nestLabel = payload.length === 1 && indicator !== "dot"
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!nestLabel ? tooltipLabel : null}
|
||||
<div className="grid gap-1.5">
|
||||
{payload.map((item, index) => {
|
||||
const key = `${nameKey || item.name || item.dataKey || "value"}`
|
||||
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||
const indicatorColor = color || item.payload.fill || item.color
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.dataKey}
|
||||
className={cn(
|
||||
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
|
||||
indicator === "dot" && "items-center"
|
||||
)}
|
||||
>
|
||||
{formatter && item?.value !== undefined && item.name ? (
|
||||
formatter(item.value, item.name, item, index, item.payload)
|
||||
) : (
|
||||
<>
|
||||
{itemConfig?.icon ? (
|
||||
<itemConfig.icon />
|
||||
) : (
|
||||
!hideIndicator && (
|
||||
<div
|
||||
className={cn(
|
||||
"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
|
||||
{
|
||||
"h-2.5 w-2.5": indicator === "dot",
|
||||
"w-1": indicator === "line",
|
||||
"w-0 border-[1.5px] border-dashed bg-transparent":
|
||||
indicator === "dashed",
|
||||
"my-0.5": nestLabel && indicator === "dashed",
|
||||
}
|
||||
)}
|
||||
style={
|
||||
{
|
||||
"--color-bg": indicatorColor,
|
||||
"--color-border": indicatorColor,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-1 justify-between leading-none",
|
||||
nestLabel ? "items-end" : "items-center"
|
||||
)}
|
||||
>
|
||||
<div className="grid gap-1.5">
|
||||
{nestLabel ? tooltipLabel : null}
|
||||
<span className="text-muted-foreground">
|
||||
{itemConfig?.label || item.name}
|
||||
</span>
|
||||
</div>
|
||||
{item.value && (
|
||||
<span className="font-mono font-medium tabular-nums text-foreground">
|
||||
{item.value.toLocaleString()}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
ChartTooltipContent.displayName = "ChartTooltip"
|
||||
|
||||
const ChartLegend = RechartsPrimitive.Legend
|
||||
|
||||
const ChartLegendContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<"div"> &
|
||||
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
|
||||
hideIcon?: boolean
|
||||
nameKey?: string
|
||||
}
|
||||
>(
|
||||
(
|
||||
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
|
||||
ref
|
||||
) => {
|
||||
const { config } = useChart()
|
||||
|
||||
if (!payload?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex items-center justify-center gap-4",
|
||||
verticalAlign === "top" ? "pb-3" : "pt-3",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{payload.map((item) => {
|
||||
const key = `${nameKey || item.dataKey || "value"}`
|
||||
const itemConfig = getPayloadConfigFromPayload(config, item, key)
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.value}
|
||||
className={cn(
|
||||
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{itemConfig?.icon && !hideIcon ? (
|
||||
<itemConfig.icon />
|
||||
) : (
|
||||
<div
|
||||
className="h-2 w-2 shrink-0 rounded-[2px]"
|
||||
style={{
|
||||
backgroundColor: item.color,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{itemConfig?.label}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
ChartLegendContent.displayName = "ChartLegend"
|
||||
|
||||
// Helper to extract item config from a payload.
|
||||
function getPayloadConfigFromPayload(
|
||||
config: ChartConfig,
|
||||
payload: unknown,
|
||||
key: string
|
||||
) {
|
||||
if (typeof payload !== "object" || payload === null) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const payloadPayload =
|
||||
"payload" in payload &&
|
||||
typeof payload.payload === "object" &&
|
||||
payload.payload !== null
|
||||
? payload.payload
|
||||
: undefined
|
||||
|
||||
let configLabelKey: string = key
|
||||
|
||||
if (
|
||||
key in payload &&
|
||||
typeof payload[key as keyof typeof payload] === "string"
|
||||
) {
|
||||
configLabelKey = payload[key as keyof typeof payload] as string
|
||||
} else if (
|
||||
payloadPayload &&
|
||||
key in payloadPayload &&
|
||||
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
|
||||
) {
|
||||
configLabelKey = payloadPayload[
|
||||
key as keyof typeof payloadPayload
|
||||
] as string
|
||||
}
|
||||
|
||||
return configLabelKey in config
|
||||
? config[configLabelKey]
|
||||
: config[key as keyof typeof config]
|
||||
}
|
||||
|
||||
export {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
ChartLegend,
|
||||
ChartLegendContent,
|
||||
ChartStyle,
|
||||
}
|
||||
28
client/src/components/ui/checkbox.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import * as React from "react"
|
||||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
||||
import { Check } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Checkbox = React.forwardRef<
|
||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<CheckboxPrimitive.Indicator
|
||||
className={cn("flex items-center justify-center text-current")}
|
||||
>
|
||||
<Check className="h-4 w-4" />
|
||||
</CheckboxPrimitive.Indicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
))
|
||||
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
||||
|
||||
export { Checkbox }
|
||||
11
client/src/components/ui/collapsible.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
"use client"
|
||||
|
||||
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
|
||||
|
||||
const Collapsible = CollapsiblePrimitive.Root
|
||||
|
||||
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
|
||||
|
||||
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
|
||||
|
||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
|
||||
151
client/src/components/ui/command.tsx
Normal file
@@ -0,0 +1,151 @@
|
||||
import * as React from "react"
|
||||
import { type DialogProps } from "@radix-ui/react-dialog"
|
||||
import { Command as CommandPrimitive } from "cmdk"
|
||||
import { Search } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog"
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Command.displayName = CommandPrimitive.displayName
|
||||
|
||||
const CommandDialog = ({ children, ...props }: DialogProps) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0 shadow-lg">
|
||||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||
>((props, ref) => (
|
||||
<CommandPrimitive.Empty
|
||||
ref={ref}
|
||||
className="py-6 text-center text-sm"
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 h-px bg-border", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName
|
||||
|
||||
const CommandShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
CommandShortcut.displayName = "CommandShortcut"
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
}
|
||||
198
client/src/components/ui/context-menu.tsx
Normal file
@@ -0,0 +1,198 @@
|
||||
import * as React from "react"
|
||||
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
|
||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const ContextMenu = ContextMenuPrimitive.Root
|
||||
|
||||
const ContextMenuTrigger = ContextMenuPrimitive.Trigger
|
||||
|
||||
const ContextMenuGroup = ContextMenuPrimitive.Group
|
||||
|
||||
const ContextMenuPortal = ContextMenuPrimitive.Portal
|
||||
|
||||
const ContextMenuSub = ContextMenuPrimitive.Sub
|
||||
|
||||
const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup
|
||||
|
||||
const ContextMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<ContextMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto h-4 w-4" />
|
||||
</ContextMenuPrimitive.SubTrigger>
|
||||
))
|
||||
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName
|
||||
|
||||
const ContextMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ContextMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-context-menu-content-transform-origin]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName
|
||||
|
||||
const ContextMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof ContextMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ContextMenuPrimitive.Portal>
|
||||
<ContextMenuPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 max-h-[--radix-context-menu-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-context-menu-content-transform-origin]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</ContextMenuPrimitive.Portal>
|
||||
))
|
||||
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName
|
||||
|
||||
const ContextMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof ContextMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<ContextMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName
|
||||
|
||||
const ContextMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
|
||||
>(({ className, children, checked, ...props }, ref) => (
|
||||
<ContextMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<ContextMenuPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</ContextMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</ContextMenuPrimitive.CheckboxItem>
|
||||
))
|
||||
ContextMenuCheckboxItem.displayName =
|
||||
ContextMenuPrimitive.CheckboxItem.displayName
|
||||
|
||||
const ContextMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<ContextMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<ContextMenuPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
</ContextMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</ContextMenuPrimitive.RadioItem>
|
||||
))
|
||||
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName
|
||||
|
||||
const ContextMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof ContextMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<ContextMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold text-foreground",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName
|
||||
|
||||
const ContextMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof ContextMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ContextMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName
|
||||
|
||||
const ContextMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
ContextMenuShortcut.displayName = "ContextMenuShortcut"
|
||||
|
||||
export {
|
||||
ContextMenu,
|
||||
ContextMenuTrigger,
|
||||
ContextMenuContent,
|
||||
ContextMenuItem,
|
||||
ContextMenuCheckboxItem,
|
||||
ContextMenuRadioItem,
|
||||
ContextMenuLabel,
|
||||
ContextMenuSeparator,
|
||||
ContextMenuShortcut,
|
||||
ContextMenuGroup,
|
||||
ContextMenuPortal,
|
||||
ContextMenuSub,
|
||||
ContextMenuSubContent,
|
||||
ContextMenuSubTrigger,
|
||||
ContextMenuRadioGroup,
|
||||
}
|
||||
122
client/src/components/ui/dialog.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Dialog = DialogPrimitive.Root
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger
|
||||
|
||||
const DialogPortal = DialogPrimitive.Portal
|
||||
|
||||
const DialogClose = DialogPrimitive.Close
|
||||
|
||||
const DialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
))
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||
|
||||
const DialogHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogHeader.displayName = "DialogHeader"
|
||||
|
||||
const DialogFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogFooter.displayName = "DialogFooter"
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogClose,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
}
|
||||
118
client/src/components/ui/drawer.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { Drawer as DrawerPrimitive } from "vaul"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Drawer = ({
|
||||
shouldScaleBackground = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
|
||||
<DrawerPrimitive.Root
|
||||
shouldScaleBackground={shouldScaleBackground}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
Drawer.displayName = "Drawer"
|
||||
|
||||
const DrawerTrigger = DrawerPrimitive.Trigger
|
||||
|
||||
const DrawerPortal = DrawerPrimitive.Portal
|
||||
|
||||
const DrawerClose = DrawerPrimitive.Close
|
||||
|
||||
const DrawerOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DrawerPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DrawerPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn("fixed inset-0 z-50 bg-black/80", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
|
||||
|
||||
const DrawerContent = React.forwardRef<
|
||||
React.ElementRef<typeof DrawerPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DrawerPortal>
|
||||
<DrawerOverlay />
|
||||
<DrawerPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
|
||||
{children}
|
||||
</DrawerPrimitive.Content>
|
||||
</DrawerPortal>
|
||||
))
|
||||
DrawerContent.displayName = "DrawerContent"
|
||||
|
||||
const DrawerHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DrawerHeader.displayName = "DrawerHeader"
|
||||
|
||||
const DrawerFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DrawerFooter.displayName = "DrawerFooter"
|
||||
|
||||
const DrawerTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DrawerPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DrawerPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DrawerTitle.displayName = DrawerPrimitive.Title.displayName
|
||||
|
||||
const DrawerDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DrawerPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DrawerPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DrawerDescription.displayName = DrawerPrimitive.Description.displayName
|
||||
|
||||
export {
|
||||
Drawer,
|
||||
DrawerPortal,
|
||||
DrawerOverlay,
|
||||
DrawerTrigger,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerHeader,
|
||||
DrawerFooter,
|
||||
DrawerTitle,
|
||||
DrawerDescription,
|
||||
}
|
||||
198
client/src/components/ui/dropdown-menu.tsx
Normal file
@@ -0,0 +1,198 @@
|
||||
import * as React from "react"
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root
|
||||
|
||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
|
||||
|
||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group
|
||||
|
||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
|
||||
|
||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
||||
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
))
|
||||
DropdownMenuSubTrigger.displayName =
|
||||
DropdownMenuPrimitive.SubTrigger.displayName
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSubContent.displayName =
|
||||
DropdownMenuPrimitive.SubContent.displayName
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
))
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
||||
|
||||
const DropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
||||
|
||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||
>(({ className, children, checked, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
))
|
||||
DropdownMenuCheckboxItem.displayName =
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
))
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
||||
|
||||
const DropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
||||
|
||||
const DropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
||||
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
}
|
||||
178
client/src/components/ui/form.tsx
Normal file
@@ -0,0 +1,178 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import {
|
||||
Controller,
|
||||
FormProvider,
|
||||
useFormContext,
|
||||
type ControllerProps,
|
||||
type FieldPath,
|
||||
type FieldValues,
|
||||
} from "react-hook-form"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Label } from "@/components/ui/label"
|
||||
|
||||
const Form = FormProvider
|
||||
|
||||
type FormFieldContextValue<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
> = {
|
||||
name: TName
|
||||
}
|
||||
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||
{} as FormFieldContextValue
|
||||
)
|
||||
|
||||
const FormField = <
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
>({
|
||||
...props
|
||||
}: ControllerProps<TFieldValues, TName>) => {
|
||||
return (
|
||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||
<Controller {...props} />
|
||||
</FormFieldContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const useFormField = () => {
|
||||
const fieldContext = React.useContext(FormFieldContext)
|
||||
const itemContext = React.useContext(FormItemContext)
|
||||
const { getFieldState, formState } = useFormContext()
|
||||
|
||||
const fieldState = getFieldState(fieldContext.name, formState)
|
||||
|
||||
if (!fieldContext) {
|
||||
throw new Error("useFormField should be used within <FormField>")
|
||||
}
|
||||
|
||||
const { id } = itemContext
|
||||
|
||||
return {
|
||||
id,
|
||||
name: fieldContext.name,
|
||||
formItemId: `${id}-form-item`,
|
||||
formDescriptionId: `${id}-form-item-description`,
|
||||
formMessageId: `${id}-form-item-message`,
|
||||
...fieldState,
|
||||
}
|
||||
}
|
||||
|
||||
type FormItemContextValue = {
|
||||
id: string
|
||||
}
|
||||
|
||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||
{} as FormItemContextValue
|
||||
)
|
||||
|
||||
const FormItem = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const id = React.useId()
|
||||
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
||||
</FormItemContext.Provider>
|
||||
)
|
||||
})
|
||||
FormItem.displayName = "FormItem"
|
||||
|
||||
const FormLabel = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { error, formItemId } = useFormField()
|
||||
|
||||
return (
|
||||
<Label
|
||||
ref={ref}
|
||||
className={cn(error && "text-destructive", className)}
|
||||
htmlFor={formItemId}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormLabel.displayName = "FormLabel"
|
||||
|
||||
const FormControl = React.forwardRef<
|
||||
React.ElementRef<typeof Slot>,
|
||||
React.ComponentPropsWithoutRef<typeof Slot>
|
||||
>(({ ...props }, ref) => {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
||||
|
||||
return (
|
||||
<Slot
|
||||
ref={ref}
|
||||
id={formItemId}
|
||||
aria-describedby={
|
||||
!error
|
||||
? `${formDescriptionId}`
|
||||
: `${formDescriptionId} ${formMessageId}`
|
||||
}
|
||||
aria-invalid={!!error}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormControl.displayName = "FormControl"
|
||||
|
||||
const FormDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { formDescriptionId } = useFormField()
|
||||
|
||||
return (
|
||||
<p
|
||||
ref={ref}
|
||||
id={formDescriptionId}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormDescription.displayName = "FormDescription"
|
||||
|
||||
const FormMessage = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { error, formMessageId } = useFormField()
|
||||
const body = error ? String(error?.message ?? "") : children
|
||||
|
||||
if (!body) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<p
|
||||
ref={ref}
|
||||
id={formMessageId}
|
||||
className={cn("text-sm font-medium text-destructive", className)}
|
||||
{...props}
|
||||
>
|
||||
{body}
|
||||
</p>
|
||||
)
|
||||
})
|
||||
FormMessage.displayName = "FormMessage"
|
||||
|
||||
export {
|
||||
useFormField,
|
||||
Form,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormMessage,
|
||||
FormField,
|
||||
}
|
||||
29
client/src/components/ui/hover-card.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const HoverCard = HoverCardPrimitive.Root
|
||||
|
||||
const HoverCardTrigger = HoverCardPrimitive.Trigger
|
||||
|
||||
const HoverCardContent = React.forwardRef<
|
||||
React.ElementRef<typeof HoverCardPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<HoverCardPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-hover-card-content-transform-origin]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
|
||||
|
||||
export { HoverCard, HoverCardTrigger, HoverCardContent }
|
||||
69
client/src/components/ui/input-otp.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import * as React from "react"
|
||||
import { OTPInput, OTPInputContext } from "input-otp"
|
||||
import { Dot } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const InputOTP = React.forwardRef<
|
||||
React.ElementRef<typeof OTPInput>,
|
||||
React.ComponentPropsWithoutRef<typeof OTPInput>
|
||||
>(({ className, containerClassName, ...props }, ref) => (
|
||||
<OTPInput
|
||||
ref={ref}
|
||||
containerClassName={cn(
|
||||
"flex items-center gap-2 has-[:disabled]:opacity-50",
|
||||
containerClassName
|
||||
)}
|
||||
className={cn("disabled:cursor-not-allowed", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
InputOTP.displayName = "InputOTP"
|
||||
|
||||
const InputOTPGroup = React.forwardRef<
|
||||
React.ElementRef<"div">,
|
||||
React.ComponentPropsWithoutRef<"div">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("flex items-center", className)} {...props} />
|
||||
))
|
||||
InputOTPGroup.displayName = "InputOTPGroup"
|
||||
|
||||
const InputOTPSlot = React.forwardRef<
|
||||
React.ElementRef<"div">,
|
||||
React.ComponentPropsWithoutRef<"div"> & { index: number }
|
||||
>(({ index, className, ...props }, ref) => {
|
||||
const inputOTPContext = React.useContext(OTPInputContext)
|
||||
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
|
||||
isActive && "z-10 ring-2 ring-ring ring-offset-background",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{char}
|
||||
{hasFakeCaret && (
|
||||
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
||||
<div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
InputOTPSlot.displayName = "InputOTPSlot"
|
||||
|
||||
const InputOTPSeparator = React.forwardRef<
|
||||
React.ElementRef<"div">,
|
||||
React.ComponentPropsWithoutRef<"div">
|
||||
>(({ ...props }, ref) => (
|
||||
<div ref={ref} role="separator" {...props}>
|
||||
<Dot />
|
||||
</div>
|
||||
))
|
||||
InputOTPSeparator.displayName = "InputOTPSeparator"
|
||||
|
||||
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }
|
||||
23
client/src/components/ui/input.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
// h-9 to match icon buttons and default buttons.
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Input.displayName = "Input"
|
||||
|
||||
export { Input }
|
||||
24
client/src/components/ui/label.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import * as React from "react"
|
||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
)
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||
VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(labelVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Label.displayName = LabelPrimitive.Root.displayName
|
||||
|
||||
export { Label }
|
||||
256
client/src/components/ui/menubar.tsx
Normal file
@@ -0,0 +1,256 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as MenubarPrimitive from "@radix-ui/react-menubar"
|
||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function MenubarMenu({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
|
||||
return <MenubarPrimitive.Menu {...props} />
|
||||
}
|
||||
|
||||
function MenubarGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Group>) {
|
||||
return <MenubarPrimitive.Group {...props} />
|
||||
}
|
||||
|
||||
function MenubarPortal({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
|
||||
return <MenubarPrimitive.Portal {...props} />
|
||||
}
|
||||
|
||||
function MenubarRadioGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
|
||||
return <MenubarPrimitive.RadioGroup {...props} />
|
||||
}
|
||||
|
||||
function MenubarSub({
|
||||
...props
|
||||
}: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
|
||||
return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />
|
||||
}
|
||||
|
||||
const Menubar = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenubarPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 items-center space-x-1 rounded-md border bg-background p-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Menubar.displayName = MenubarPrimitive.Root.displayName
|
||||
|
||||
const MenubarTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenubarPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName
|
||||
|
||||
const MenubarSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<MenubarPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto h-4 w-4" />
|
||||
</MenubarPrimitive.SubTrigger>
|
||||
))
|
||||
MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName
|
||||
|
||||
const MenubarSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenubarPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-menubar-content-transform-origin]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName
|
||||
|
||||
const MenubarContent = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>
|
||||
>(
|
||||
(
|
||||
{ className, align = "start", alignOffset = -4, sideOffset = 8, ...props },
|
||||
ref
|
||||
) => (
|
||||
<MenubarPrimitive.Portal>
|
||||
<MenubarPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
alignOffset={alignOffset}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-menubar-content-transform-origin]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</MenubarPrimitive.Portal>
|
||||
)
|
||||
)
|
||||
MenubarContent.displayName = MenubarPrimitive.Content.displayName
|
||||
|
||||
const MenubarItem = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<MenubarPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarItem.displayName = MenubarPrimitive.Item.displayName
|
||||
|
||||
const MenubarCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem>
|
||||
>(({ className, children, checked, ...props }, ref) => (
|
||||
<MenubarPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<MenubarPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</MenubarPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</MenubarPrimitive.CheckboxItem>
|
||||
))
|
||||
MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName
|
||||
|
||||
const MenubarRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<MenubarPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<MenubarPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
</MenubarPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</MenubarPrimitive.RadioItem>
|
||||
))
|
||||
MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName
|
||||
|
||||
const MenubarLabel = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<MenubarPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarLabel.displayName = MenubarPrimitive.Label.displayName
|
||||
|
||||
const MenubarSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof MenubarPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<MenubarPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName
|
||||
|
||||
const MenubarShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
MenubarShortcut.displayname = "MenubarShortcut"
|
||||
|
||||
export {
|
||||
Menubar,
|
||||
MenubarMenu,
|
||||
MenubarTrigger,
|
||||
MenubarContent,
|
||||
MenubarItem,
|
||||
MenubarSeparator,
|
||||
MenubarLabel,
|
||||
MenubarCheckboxItem,
|
||||
MenubarRadioGroup,
|
||||
MenubarRadioItem,
|
||||
MenubarPortal,
|
||||
MenubarSubContent,
|
||||
MenubarSubTrigger,
|
||||
MenubarGroup,
|
||||
MenubarSub,
|
||||
MenubarShortcut,
|
||||
}
|
||||
128
client/src/components/ui/navigation-menu.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import * as React from "react"
|
||||
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
|
||||
import { cva } from "class-variance-authority"
|
||||
import { ChevronDown } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const NavigationMenu = React.forwardRef<
|
||||
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<NavigationMenuPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-10 flex max-w-max flex-1 items-center justify-center",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<NavigationMenuViewport />
|
||||
</NavigationMenuPrimitive.Root>
|
||||
))
|
||||
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
|
||||
|
||||
const NavigationMenuList = React.forwardRef<
|
||||
React.ElementRef<typeof NavigationMenuPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<NavigationMenuPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"group flex flex-1 list-none items-center justify-center space-x-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
|
||||
|
||||
const NavigationMenuItem = NavigationMenuPrimitive.Item
|
||||
|
||||
const navigationMenuTriggerStyle = cva(
|
||||
"group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:bg-accent/50 data-[state=open]:hover:bg-accent data-[state=open]:focus:bg-accent"
|
||||
)
|
||||
|
||||
const NavigationMenuTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<NavigationMenuPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(navigationMenuTriggerStyle(), "group", className)}
|
||||
{...props}
|
||||
>
|
||||
{children}{" "}
|
||||
<ChevronDown
|
||||
className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</NavigationMenuPrimitive.Trigger>
|
||||
))
|
||||
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
|
||||
|
||||
const NavigationMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<NavigationMenuPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
|
||||
|
||||
const NavigationMenuLink = NavigationMenuPrimitive.Link
|
||||
|
||||
const NavigationMenuViewport = React.forwardRef<
|
||||
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
|
||||
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className={cn("absolute left-0 top-full flex justify-center")}>
|
||||
<NavigationMenuPrimitive.Viewport
|
||||
className={cn(
|
||||
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
NavigationMenuViewport.displayName =
|
||||
NavigationMenuPrimitive.Viewport.displayName
|
||||
|
||||
const NavigationMenuIndicator = React.forwardRef<
|
||||
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
|
||||
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<NavigationMenuPrimitive.Indicator
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
|
||||
</NavigationMenuPrimitive.Indicator>
|
||||
))
|
||||
NavigationMenuIndicator.displayName =
|
||||
NavigationMenuPrimitive.Indicator.displayName
|
||||
|
||||
export {
|
||||
navigationMenuTriggerStyle,
|
||||
NavigationMenu,
|
||||
NavigationMenuList,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuContent,
|
||||
NavigationMenuTrigger,
|
||||
NavigationMenuLink,
|
||||
NavigationMenuIndicator,
|
||||
NavigationMenuViewport,
|
||||
}
|
||||
117
client/src/components/ui/pagination.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
import * as React from "react"
|
||||
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { ButtonProps, buttonVariants } from "@/components/ui/button"
|
||||
|
||||
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
|
||||
<nav
|
||||
role="navigation"
|
||||
aria-label="pagination"
|
||||
className={cn("mx-auto flex w-full justify-center", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
Pagination.displayName = "Pagination"
|
||||
|
||||
const PaginationContent = React.forwardRef<
|
||||
HTMLUListElement,
|
||||
React.ComponentProps<"ul">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ul
|
||||
ref={ref}
|
||||
className={cn("flex flex-row items-center gap-1", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
PaginationContent.displayName = "PaginationContent"
|
||||
|
||||
const PaginationItem = React.forwardRef<
|
||||
HTMLLIElement,
|
||||
React.ComponentProps<"li">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<li ref={ref} className={cn("", className)} {...props} />
|
||||
))
|
||||
PaginationItem.displayName = "PaginationItem"
|
||||
|
||||
type PaginationLinkProps = {
|
||||
isActive?: boolean
|
||||
} & Pick<ButtonProps, "size"> &
|
||||
React.ComponentProps<"a">
|
||||
|
||||
const PaginationLink = ({
|
||||
className,
|
||||
isActive,
|
||||
size = "icon",
|
||||
...props
|
||||
}: PaginationLinkProps) => (
|
||||
<a
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
variant: isActive ? "outline" : "ghost",
|
||||
size,
|
||||
}),
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
PaginationLink.displayName = "PaginationLink"
|
||||
|
||||
const PaginationPrevious = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PaginationLink>) => (
|
||||
<PaginationLink
|
||||
aria-label="Go to previous page"
|
||||
size="default"
|
||||
className={cn("gap-1 pl-2.5", className)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
<span>Previous</span>
|
||||
</PaginationLink>
|
||||
)
|
||||
PaginationPrevious.displayName = "PaginationPrevious"
|
||||
|
||||
const PaginationNext = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PaginationLink>) => (
|
||||
<PaginationLink
|
||||
aria-label="Go to next page"
|
||||
size="default"
|
||||
className={cn("gap-1 pr-2.5", className)}
|
||||
{...props}
|
||||
>
|
||||
<span>Next</span>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</PaginationLink>
|
||||
)
|
||||
PaginationNext.displayName = "PaginationNext"
|
||||
|
||||
const PaginationEllipsis = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"span">) => (
|
||||
<span
|
||||
aria-hidden
|
||||
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
||||
{...props}
|
||||
>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
<span className="sr-only">More pages</span>
|
||||
</span>
|
||||
)
|
||||
PaginationEllipsis.displayName = "PaginationEllipsis"
|
||||
|
||||
export {
|
||||
Pagination,
|
||||
PaginationContent,
|
||||
PaginationEllipsis,
|
||||
PaginationItem,
|
||||
PaginationLink,
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
}
|
||||
29
client/src/components/ui/popover.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Popover = PopoverPrimitive.Root
|
||||
|
||||
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||
|
||||
const PopoverContent = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
))
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent }
|
||||
28
client/src/components/ui/progress.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as ProgressPrimitive from "@radix-ui/react-progress"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Progress = React.forwardRef<
|
||||
React.ElementRef<typeof ProgressPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
|
||||
>(({ className, value, ...props }, ref) => (
|
||||
<ProgressPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative h-4 w-full overflow-hidden rounded-full bg-secondary",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ProgressPrimitive.Indicator
|
||||
className="h-full w-full flex-1 bg-primary transition-all"
|
||||
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||
/>
|
||||
</ProgressPrimitive.Root>
|
||||
))
|
||||
Progress.displayName = ProgressPrimitive.Root.displayName
|
||||
|
||||
export { Progress }
|
||||
42
client/src/components/ui/radio-group.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import * as React from "react"
|
||||
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
||||
import { Circle } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const RadioGroup = React.forwardRef<
|
||||
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<RadioGroupPrimitive.Root
|
||||
className={cn("grid gap-2", className)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
|
||||
|
||||
const RadioGroupItem = React.forwardRef<
|
||||
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<RadioGroupPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
|
||||
<Circle className="h-2.5 w-2.5 fill-current text-current" />
|
||||
</RadioGroupPrimitive.Indicator>
|
||||
</RadioGroupPrimitive.Item>
|
||||
)
|
||||
})
|
||||
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
||||
|
||||
export { RadioGroup, RadioGroupItem }
|
||||
45
client/src/components/ui/resizable.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
"use client"
|
||||
|
||||
import { GripVertical } from "lucide-react"
|
||||
import * as ResizablePrimitive from "react-resizable-panels"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const ResizablePanelGroup = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
|
||||
<ResizablePrimitive.PanelGroup
|
||||
className={cn(
|
||||
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
const ResizablePanel = ResizablePrimitive.Panel
|
||||
|
||||
const ResizableHandle = ({
|
||||
withHandle,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
|
||||
withHandle?: boolean
|
||||
}) => (
|
||||
<ResizablePrimitive.PanelResizeHandle
|
||||
className={cn(
|
||||
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{withHandle && (
|
||||
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
|
||||
<GripVertical className="h-2.5 w-2.5" />
|
||||
</div>
|
||||
)}
|
||||
</ResizablePrimitive.PanelResizeHandle>
|
||||
)
|
||||
|
||||
export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
|
||||
46
client/src/components/ui/scroll-area.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as React from "react"
|
||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
))
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
||||
|
||||
const ScrollBar = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
))
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
||||
|
||||
export { ScrollArea, ScrollBar }
|
||||
160
client/src/components/ui/select.tsx
Normal file
@@ -0,0 +1,160 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Select = SelectPrimitive.Root
|
||||
|
||||
const SelectGroup = SelectPrimitive.Group
|
||||
|
||||
const SelectValue = SelectPrimitive.Value
|
||||
|
||||
const SelectTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-9 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
))
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
||||
|
||||
const SelectScrollUpButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
))
|
||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
||||
|
||||
const SelectScrollDownButton = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
))
|
||||
SelectScrollDownButton.displayName =
|
||||
SelectPrimitive.ScrollDownButton.displayName
|
||||
|
||||
const SelectContent = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
))
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
||||
|
||||
const SelectLabel = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
||||
|
||||
const SelectItem = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
))
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
||||
|
||||
const SelectSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectScrollUpButton,
|
||||
SelectScrollDownButton,
|
||||
}
|
||||
29
client/src/components/ui/separator.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import * as React from "react"
|
||||
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Separator = React.forwardRef<
|
||||
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
|
||||
>(
|
||||
(
|
||||
{ className, orientation = "horizontal", decorative = true, ...props },
|
||||
ref
|
||||
) => (
|
||||
<SeparatorPrimitive.Root
|
||||
ref={ref}
|
||||
decorative={decorative}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"shrink-0 bg-border",
|
||||
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)
|
||||
Separator.displayName = SeparatorPrimitive.Root.displayName
|
||||
|
||||
export { Separator }
|
||||
140
client/src/components/ui/sheet.tsx
Normal file
@@ -0,0 +1,140 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as SheetPrimitive from "@radix-ui/react-dialog"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Sheet = SheetPrimitive.Root
|
||||
|
||||
const SheetTrigger = SheetPrimitive.Trigger
|
||||
|
||||
const SheetClose = SheetPrimitive.Close
|
||||
|
||||
const SheetPortal = SheetPrimitive.Portal
|
||||
|
||||
const SheetOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
))
|
||||
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
|
||||
|
||||
const sheetVariants = cva(
|
||||
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
||||
{
|
||||
variants: {
|
||||
side: {
|
||||
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
||||
bottom:
|
||||
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
||||
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
||||
right:
|
||||
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
side: "right",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
interface SheetContentProps
|
||||
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
||||
VariantProps<typeof sheetVariants> {}
|
||||
|
||||
const SheetContent = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Content>,
|
||||
SheetContentProps
|
||||
>(({ side = "right", className, children, ...props }, ref) => (
|
||||
<SheetPortal>
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(sheetVariants({ side }), className)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
</SheetPrimitive.Content>
|
||||
</SheetPortal>
|
||||
))
|
||||
SheetContent.displayName = SheetPrimitive.Content.displayName
|
||||
|
||||
const SheetHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
SheetHeader.displayName = "SheetHeader"
|
||||
|
||||
const SheetFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
SheetFooter.displayName = "SheetFooter"
|
||||
|
||||
const SheetTitle = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SheetTitle.displayName = SheetPrimitive.Title.displayName
|
||||
|
||||
const SheetDescription = React.forwardRef<
|
||||
React.ElementRef<typeof SheetPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SheetPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SheetDescription.displayName = SheetPrimitive.Description.displayName
|
||||
|
||||
export {
|
||||
Sheet,
|
||||
SheetPortal,
|
||||
SheetOverlay,
|
||||
SheetTrigger,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetFooter,
|
||||
SheetTitle,
|
||||
SheetDescription,
|
||||
}
|
||||
727
client/src/components/ui/sidebar.tsx
Normal file
@@ -0,0 +1,727 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, VariantProps } from "class-variance-authority"
|
||||
import { PanelLeftIcon } from "lucide-react"
|
||||
|
||||
import { useIsMobile } from "@/hooks/use-mobile"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from "@/components/ui/sheet"
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip"
|
||||
|
||||
const SIDEBAR_COOKIE_NAME = "sidebar_state"
|
||||
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
|
||||
const SIDEBAR_WIDTH = "16rem"
|
||||
const SIDEBAR_WIDTH_MOBILE = "18rem"
|
||||
const SIDEBAR_WIDTH_ICON = "3rem"
|
||||
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
|
||||
|
||||
type SidebarContextProps = {
|
||||
state: "expanded" | "collapsed"
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
openMobile: boolean
|
||||
setOpenMobile: (open: boolean) => void
|
||||
isMobile: boolean
|
||||
toggleSidebar: () => void
|
||||
}
|
||||
|
||||
const SidebarContext = React.createContext<SidebarContextProps | null>(null)
|
||||
|
||||
function useSidebar() {
|
||||
const context = React.useContext(SidebarContext)
|
||||
if (!context) {
|
||||
throw new Error("useSidebar must be used within a SidebarProvider.")
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
function SidebarProvider({
|
||||
defaultOpen = true,
|
||||
open: openProp,
|
||||
onOpenChange: setOpenProp,
|
||||
className,
|
||||
style,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & {
|
||||
defaultOpen?: boolean
|
||||
open?: boolean
|
||||
onOpenChange?: (open: boolean) => void
|
||||
}) {
|
||||
const isMobile = useIsMobile()
|
||||
const [openMobile, setOpenMobile] = React.useState(false)
|
||||
|
||||
// This is the internal state of the sidebar.
|
||||
// We use openProp and setOpenProp for control from outside the component.
|
||||
const [_open, _setOpen] = React.useState(defaultOpen)
|
||||
const open = openProp ?? _open
|
||||
const setOpen = React.useCallback(
|
||||
(value: boolean | ((value: boolean) => boolean)) => {
|
||||
const openState = typeof value === "function" ? value(open) : value
|
||||
if (setOpenProp) {
|
||||
setOpenProp(openState)
|
||||
} else {
|
||||
_setOpen(openState)
|
||||
}
|
||||
|
||||
// This sets the cookie to keep the sidebar state.
|
||||
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
||||
},
|
||||
[setOpenProp, open]
|
||||
)
|
||||
|
||||
// Helper to toggle the sidebar.
|
||||
const toggleSidebar = React.useCallback(() => {
|
||||
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
|
||||
}, [isMobile, setOpen, setOpenMobile])
|
||||
|
||||
// Adds a keyboard shortcut to toggle the sidebar.
|
||||
React.useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (
|
||||
event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
|
||||
(event.metaKey || event.ctrlKey)
|
||||
) {
|
||||
event.preventDefault()
|
||||
toggleSidebar()
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown)
|
||||
return () => window.removeEventListener("keydown", handleKeyDown)
|
||||
}, [toggleSidebar])
|
||||
|
||||
// We add a state so that we can do data-state="expanded" or "collapsed".
|
||||
// This makes it easier to style the sidebar with Tailwind classes.
|
||||
const state = open ? "expanded" : "collapsed"
|
||||
|
||||
const contextValue = React.useMemo<SidebarContextProps>(
|
||||
() => ({
|
||||
state,
|
||||
open,
|
||||
setOpen,
|
||||
isMobile,
|
||||
openMobile,
|
||||
setOpenMobile,
|
||||
toggleSidebar,
|
||||
}),
|
||||
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
|
||||
)
|
||||
|
||||
return (
|
||||
<SidebarContext.Provider value={contextValue}>
|
||||
<TooltipProvider delayDuration={0}>
|
||||
<div
|
||||
data-slot="sidebar-wrapper"
|
||||
style={
|
||||
{
|
||||
"--sidebar-width": SIDEBAR_WIDTH,
|
||||
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
|
||||
...style,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
className={cn(
|
||||
"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</SidebarContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
function Sidebar({
|
||||
side = "left",
|
||||
variant = "sidebar",
|
||||
collapsible = "offcanvas",
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & {
|
||||
side?: "left" | "right"
|
||||
variant?: "sidebar" | "floating" | "inset"
|
||||
collapsible?: "offcanvas" | "icon" | "none"
|
||||
}) {
|
||||
const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
|
||||
|
||||
if (collapsible === "none") {
|
||||
return (
|
||||
<div
|
||||
data-slot="sidebar"
|
||||
className={cn(
|
||||
"bg-sidebar text-sidebar-foreground flex h-full w-[var(--sidebar-width)] flex-col",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (isMobile) {
|
||||
return (
|
||||
<Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
|
||||
<SheetContent
|
||||
data-sidebar="sidebar"
|
||||
data-slot="sidebar"
|
||||
data-mobile="true"
|
||||
className="bg-sidebar text-sidebar-foreground w-[var(--sidebar-width)] p-0 [&>button]:hidden"
|
||||
style={
|
||||
{
|
||||
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
side={side}
|
||||
>
|
||||
<SheetHeader className="sr-only">
|
||||
<SheetTitle>Sidebar</SheetTitle>
|
||||
<SheetDescription>Displays the mobile sidebar.</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div className="flex h-full w-full flex-col">{children}</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="group peer text-sidebar-foreground hidden md:block"
|
||||
data-state={state}
|
||||
data-collapsible={state === "collapsed" ? collapsible : ""}
|
||||
data-variant={variant}
|
||||
data-side={side}
|
||||
data-slot="sidebar"
|
||||
>
|
||||
{/* This is what handles the sidebar gap on desktop */}
|
||||
<div
|
||||
data-slot="sidebar-gap"
|
||||
className={cn(
|
||||
"relative w-[var(--sidebar-width)] bg-transparent transition-[width] duration-200 ease-linear",
|
||||
"group-data-[collapsible=offcanvas]:w-0",
|
||||
"group-data-[side=right]:rotate-180",
|
||||
variant === "floating" || variant === "inset"
|
||||
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+var(--spacing-4))]"
|
||||
: "group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)]"
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
data-slot="sidebar-container"
|
||||
className={cn(
|
||||
"fixed inset-y-0 z-10 hidden h-svh w-[var(--sidebar-width)] transition-[left,right,width] duration-200 ease-linear md:flex",
|
||||
side === "left"
|
||||
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
|
||||
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
||||
// Adjust the padding for floating and inset variants.
|
||||
variant === "floating" || variant === "inset"
|
||||
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+var(--spacing-4)+2px)]"
|
||||
: "group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)] group-data-[side=left]:border-r group-data-[side=right]:border-l",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<div
|
||||
data-sidebar="sidebar"
|
||||
data-slot="sidebar-inner"
|
||||
className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarTrigger({
|
||||
className,
|
||||
onClick,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Button>) {
|
||||
const { toggleSidebar } = useSidebar()
|
||||
|
||||
return (
|
||||
<Button
|
||||
data-sidebar="trigger"
|
||||
data-slot="sidebar-trigger"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className={cn("h-7 w-7", className)}
|
||||
onClick={(event) => {
|
||||
onClick?.(event)
|
||||
toggleSidebar()
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<PanelLeftIcon />
|
||||
<span className="sr-only">Toggle Sidebar</span>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
|
||||
const { toggleSidebar } = useSidebar()
|
||||
|
||||
// Note: Tailwind v3.4 doesn't support "in-" selectors. So the rail won't work perfectly.
|
||||
return (
|
||||
<button
|
||||
data-sidebar="rail"
|
||||
data-slot="sidebar-rail"
|
||||
aria-label="Toggle Sidebar"
|
||||
tabIndex={-1}
|
||||
onClick={toggleSidebar}
|
||||
title="Toggle Sidebar"
|
||||
className={cn(
|
||||
"hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
|
||||
"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
|
||||
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
|
||||
"hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
|
||||
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
|
||||
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
|
||||
return (
|
||||
<main
|
||||
data-slot="sidebar-inset"
|
||||
className={cn(
|
||||
"bg-background relative flex w-full flex-1 flex-col",
|
||||
"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarInput({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Input>) {
|
||||
return (
|
||||
<Input
|
||||
data-slot="sidebar-input"
|
||||
data-sidebar="input"
|
||||
className={cn("bg-background h-8 w-full shadow-none", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="sidebar-header"
|
||||
data-sidebar="header"
|
||||
className={cn("flex flex-col gap-2 p-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="sidebar-footer"
|
||||
data-sidebar="footer"
|
||||
className={cn("flex flex-col gap-2 p-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Separator>) {
|
||||
return (
|
||||
<Separator
|
||||
data-slot="sidebar-separator"
|
||||
data-sidebar="separator"
|
||||
className={cn("bg-sidebar-border mx-2 w-auto", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="sidebar-content"
|
||||
data-sidebar="content"
|
||||
className={cn(
|
||||
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="sidebar-group"
|
||||
data-sidebar="group"
|
||||
className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarGroupLabel({
|
||||
className,
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & { asChild?: boolean }) {
|
||||
const Comp = asChild ? Slot : "div"
|
||||
|
||||
return (
|
||||
<Comp
|
||||
data-slot="sidebar-group-label"
|
||||
data-sidebar="group-label"
|
||||
className={cn(
|
||||
"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0",
|
||||
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarGroupAction({
|
||||
className,
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<"button"> & { asChild?: boolean }) {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
|
||||
return (
|
||||
<Comp
|
||||
data-slot="sidebar-group-action"
|
||||
data-sidebar="group-action"
|
||||
className={cn(
|
||||
"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
// Increases the hit area of the button on mobile.
|
||||
"after:absolute after:-inset-2 md:after:hidden",
|
||||
"group-data-[collapsible=icon]:hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarGroupContent({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="sidebar-group-content"
|
||||
data-sidebar="group-content"
|
||||
className={cn("w-full text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
|
||||
return (
|
||||
<ul
|
||||
data-slot="sidebar-menu"
|
||||
data-sidebar="menu"
|
||||
className={cn("flex w-full min-w-0 flex-col gap-1", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
|
||||
return (
|
||||
<li
|
||||
data-slot="sidebar-menu-item"
|
||||
data-sidebar="menu-item"
|
||||
className={cn("group/menu-item relative", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const sidebarMenuButtonVariants = cva(
|
||||
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:w-8! group-data-[collapsible=icon]:h-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
||||
outline:
|
||||
"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
|
||||
},
|
||||
size: {
|
||||
default: "h-8 text-sm",
|
||||
sm: "h-7 text-xs",
|
||||
lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
function SidebarMenuButton({
|
||||
asChild = false,
|
||||
isActive = false,
|
||||
variant = "default",
|
||||
size = "default",
|
||||
tooltip,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"button"> & {
|
||||
asChild?: boolean
|
||||
isActive?: boolean
|
||||
tooltip?: string | React.ComponentProps<typeof TooltipContent>
|
||||
} & VariantProps<typeof sidebarMenuButtonVariants>) {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
const { isMobile, state } = useSidebar()
|
||||
|
||||
const button = (
|
||||
<Comp
|
||||
data-slot="sidebar-menu-button"
|
||||
data-sidebar="menu-button"
|
||||
data-size={size}
|
||||
data-active={isActive}
|
||||
className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
if (!tooltip) {
|
||||
return button
|
||||
}
|
||||
|
||||
if (typeof tooltip === "string") {
|
||||
tooltip = {
|
||||
children: tooltip,
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
||||
<TooltipContent
|
||||
side="right"
|
||||
align="center"
|
||||
hidden={state !== "collapsed" || isMobile}
|
||||
{...tooltip}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarMenuAction({
|
||||
className,
|
||||
asChild = false,
|
||||
showOnHover = false,
|
||||
...props
|
||||
}: React.ComponentProps<"button"> & {
|
||||
asChild?: boolean
|
||||
showOnHover?: boolean
|
||||
}) {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
|
||||
return (
|
||||
<Comp
|
||||
data-slot="sidebar-menu-action"
|
||||
data-sidebar="menu-action"
|
||||
className={cn(
|
||||
"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
// Increases the hit area of the button on mobile.
|
||||
"after:absolute after:-inset-2 md:after:hidden",
|
||||
"peer-data-[size=sm]/menu-button:top-1",
|
||||
"peer-data-[size=default]/menu-button:top-1.5",
|
||||
"peer-data-[size=lg]/menu-button:top-2.5",
|
||||
"group-data-[collapsible=icon]:hidden",
|
||||
showOnHover &&
|
||||
"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarMenuBadge({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="sidebar-menu-badge"
|
||||
data-sidebar="menu-badge"
|
||||
className={cn(
|
||||
"text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none",
|
||||
"peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
|
||||
"peer-data-[size=sm]/menu-button:top-1",
|
||||
"peer-data-[size=default]/menu-button:top-1.5",
|
||||
"peer-data-[size=lg]/menu-button:top-2.5",
|
||||
"group-data-[collapsible=icon]:hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarMenuSkeleton({
|
||||
className,
|
||||
showIcon = false,
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & {
|
||||
showIcon?: boolean
|
||||
}) {
|
||||
// Random width between 50 to 90%.
|
||||
const width = React.useMemo(() => {
|
||||
return `${Math.floor(Math.random() * 40) + 50}%`
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
data-slot="sidebar-menu-skeleton"
|
||||
data-sidebar="menu-skeleton"
|
||||
className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
|
||||
{...props}
|
||||
>
|
||||
{showIcon && (
|
||||
<Skeleton
|
||||
className="size-4 rounded-md"
|
||||
data-sidebar="menu-skeleton-icon"
|
||||
/>
|
||||
)}
|
||||
<Skeleton
|
||||
className="h-4 max-w-[var(--skeleton-width)] flex-1"
|
||||
data-sidebar="menu-skeleton-text"
|
||||
style={
|
||||
{
|
||||
"--skeleton-width": width,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
|
||||
return (
|
||||
<ul
|
||||
data-slot="sidebar-menu-sub"
|
||||
data-sidebar="menu-sub"
|
||||
className={cn(
|
||||
"border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5",
|
||||
"group-data-[collapsible=icon]:hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarMenuSubItem({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"li">) {
|
||||
return (
|
||||
<li
|
||||
data-slot="sidebar-menu-sub-item"
|
||||
data-sidebar="menu-sub-item"
|
||||
className={cn("group/menu-sub-item relative", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SidebarMenuSubButton({
|
||||
asChild = false,
|
||||
size = "md",
|
||||
isActive = false,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"a"> & {
|
||||
asChild?: boolean
|
||||
size?: "sm" | "md"
|
||||
isActive?: boolean
|
||||
}) {
|
||||
const Comp = asChild ? Slot : "a"
|
||||
|
||||
return (
|
||||
<Comp
|
||||
data-slot="sidebar-menu-sub-button"
|
||||
data-sidebar="menu-sub-button"
|
||||
data-size={size}
|
||||
data-active={isActive}
|
||||
className={cn(
|
||||
"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline outline-2 outline-transparent outline-offset-2 focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
|
||||
size === "sm" && "text-xs",
|
||||
size === "md" && "text-sm",
|
||||
"group-data-[collapsible=icon]:hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupAction,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarHeader,
|
||||
SidebarInput,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuAction,
|
||||
SidebarMenuBadge,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSkeleton,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
SidebarProvider,
|
||||
SidebarRail,
|
||||
SidebarSeparator,
|
||||
SidebarTrigger,
|
||||
useSidebar,
|
||||
}
|
||||
15
client/src/components/ui/skeleton.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Skeleton({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div
|
||||
className={cn("animate-pulse rounded-md bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Skeleton }
|
||||
26
client/src/components/ui/slider.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import * as React from "react"
|
||||
import * as SliderPrimitive from "@radix-ui/react-slider"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Slider = React.forwardRef<
|
||||
React.ElementRef<typeof SliderPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SliderPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full touch-none select-none items-center",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
|
||||
<SliderPrimitive.Range className="absolute h-full bg-primary" />
|
||||
</SliderPrimitive.Track>
|
||||
<SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
|
||||
</SliderPrimitive.Root>
|
||||
))
|
||||
Slider.displayName = SliderPrimitive.Root.displayName
|
||||
|
||||
export { Slider }
|
||||
27
client/src/components/ui/switch.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as React from "react"
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
|
||||
export { Switch }
|
||||
117
client/src/components/ui/table.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Table = React.forwardRef<
|
||||
HTMLTableElement,
|
||||
React.HTMLAttributes<HTMLTableElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="relative w-full overflow-auto">
|
||||
<table
|
||||
ref={ref}
|
||||
className={cn("w-full caption-bottom text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
Table.displayName = "Table"
|
||||
|
||||
const TableHeader = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
||||
))
|
||||
TableHeader.displayName = "TableHeader"
|
||||
|
||||
const TableBody = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tbody
|
||||
ref={ref}
|
||||
className={cn("[&_tr:last-child]:border-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableBody.displayName = "TableBody"
|
||||
|
||||
const TableFooter = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tfoot
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableFooter.displayName = "TableFooter"
|
||||
|
||||
const TableRow = React.forwardRef<
|
||||
HTMLTableRowElement,
|
||||
React.HTMLAttributes<HTMLTableRowElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tr
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableRow.displayName = "TableRow"
|
||||
|
||||
const TableHead = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.ThHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableHead.displayName = "TableHead"
|
||||
|
||||
const TableCell = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<td
|
||||
ref={ref}
|
||||
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableCell.displayName = "TableCell"
|
||||
|
||||
const TableCaption = React.forwardRef<
|
||||
HTMLTableCaptionElement,
|
||||
React.HTMLAttributes<HTMLTableCaptionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<caption
|
||||
ref={ref}
|
||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableCaption.displayName = "TableCaption"
|
||||
|
||||
export {
|
||||
Table,
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableCaption,
|
||||
}
|
||||
53
client/src/components/ui/tabs.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import * as React from "react"
|
||||
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Tabs = TabsPrimitive.Root
|
||||
|
||||
const TabsList = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TabsList.displayName = TabsPrimitive.List.displayName
|
||||
|
||||
const TabsTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
||||
|
||||
const TabsContent = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<TabsPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TabsContent.displayName = TabsPrimitive.Content.displayName
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
||||
22
client/src/components/ui/textarea.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Textarea = React.forwardRef<
|
||||
HTMLTextAreaElement,
|
||||
React.ComponentProps<"textarea">
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
Textarea.displayName = "Textarea"
|
||||
|
||||
export { Textarea }
|
||||
127
client/src/components/ui/toast.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import * as React from "react"
|
||||
import * as ToastPrimitives from "@radix-ui/react-toast"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const ToastProvider = ToastPrimitives.Provider
|
||||
|
||||
const ToastViewport = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Viewport>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Viewport
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
|
||||
|
||||
const toastVariants = cva(
|
||||
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "border bg-background text-foreground",
|
||||
destructive:
|
||||
"destructive group border-destructive bg-destructive text-destructive-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const Toast = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
|
||||
VariantProps<typeof toastVariants>
|
||||
>(({ className, variant, ...props }, ref) => {
|
||||
return (
|
||||
<ToastPrimitives.Root
|
||||
ref={ref}
|
||||
className={cn(toastVariants({ variant }), className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
Toast.displayName = ToastPrimitives.Root.displayName
|
||||
|
||||
const ToastAction = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Action>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Action
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastAction.displayName = ToastPrimitives.Action.displayName
|
||||
|
||||
const ToastClose = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Close>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Close
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
|
||||
className
|
||||
)}
|
||||
toast-close=""
|
||||
{...props}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</ToastPrimitives.Close>
|
||||
))
|
||||
ToastClose.displayName = ToastPrimitives.Close.displayName
|
||||
|
||||
const ToastTitle = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Title
|
||||
ref={ref}
|
||||
className={cn("text-sm font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastTitle.displayName = ToastPrimitives.Title.displayName
|
||||
|
||||
const ToastDescription = React.forwardRef<
|
||||
React.ElementRef<typeof ToastPrimitives.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ToastPrimitives.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm opacity-90", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
ToastDescription.displayName = ToastPrimitives.Description.displayName
|
||||
|
||||
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
|
||||
|
||||
type ToastActionElement = React.ReactElement<typeof ToastAction>
|
||||
|
||||
export {
|
||||
type ToastProps,
|
||||
type ToastActionElement,
|
||||
ToastProvider,
|
||||
ToastViewport,
|
||||
Toast,
|
||||
ToastTitle,
|
||||
ToastDescription,
|
||||
ToastClose,
|
||||
ToastAction,
|
||||
}
|
||||
33
client/src/components/ui/toaster.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { useToast } from "@/hooks/use-toast"
|
||||
import {
|
||||
Toast,
|
||||
ToastClose,
|
||||
ToastDescription,
|
||||
ToastProvider,
|
||||
ToastTitle,
|
||||
ToastViewport,
|
||||
} from "@/components/ui/toast"
|
||||
|
||||
export function Toaster() {
|
||||
const { toasts } = useToast()
|
||||
|
||||
return (
|
||||
<ToastProvider>
|
||||
{toasts.map(function ({ id, title, description, action, ...props }) {
|
||||
return (
|
||||
<Toast key={id} {...props}>
|
||||
<div className="grid gap-1">
|
||||
{title && <ToastTitle>{title}</ToastTitle>}
|
||||
{description && (
|
||||
<ToastDescription>{description}</ToastDescription>
|
||||
)}
|
||||
</div>
|
||||
{action}
|
||||
<ToastClose />
|
||||
</Toast>
|
||||
)
|
||||
})}
|
||||
<ToastViewport />
|
||||
</ToastProvider>
|
||||
)
|
||||
}
|
||||
61
client/src/components/ui/toggle-group.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
|
||||
import { type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { toggleVariants } from "@/components/ui/toggle"
|
||||
|
||||
const ToggleGroupContext = React.createContext<
|
||||
VariantProps<typeof toggleVariants>
|
||||
>({
|
||||
size: "default",
|
||||
variant: "default",
|
||||
})
|
||||
|
||||
const ToggleGroup = React.forwardRef<
|
||||
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
|
||||
VariantProps<typeof toggleVariants>
|
||||
>(({ className, variant, size, children, ...props }, ref) => (
|
||||
<ToggleGroupPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("flex items-center justify-center gap-1", className)}
|
||||
{...props}
|
||||
>
|
||||
<ToggleGroupContext.Provider value={{ variant, size }}>
|
||||
{children}
|
||||
</ToggleGroupContext.Provider>
|
||||
</ToggleGroupPrimitive.Root>
|
||||
))
|
||||
|
||||
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName
|
||||
|
||||
const ToggleGroupItem = React.forwardRef<
|
||||
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
|
||||
VariantProps<typeof toggleVariants>
|
||||
>(({ className, children, variant, size, ...props }, ref) => {
|
||||
const context = React.useContext(ToggleGroupContext)
|
||||
|
||||
return (
|
||||
<ToggleGroupPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
toggleVariants({
|
||||
variant: context.variant || variant,
|
||||
size: context.size || size,
|
||||
}),
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</ToggleGroupPrimitive.Item>
|
||||
)
|
||||
})
|
||||
|
||||
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName
|
||||
|
||||
export { ToggleGroup, ToggleGroupItem }
|
||||
43
client/src/components/ui/toggle.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import * as React from "react"
|
||||
import * as TogglePrimitive from "@radix-ui/react-toggle"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const toggleVariants = cva(
|
||||
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 gap-2",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-transparent",
|
||||
outline:
|
||||
"border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-3 min-w-10",
|
||||
sm: "h-9 px-2.5 min-w-9",
|
||||
lg: "h-11 px-5 min-w-11",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const Toggle = React.forwardRef<
|
||||
React.ElementRef<typeof TogglePrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
|
||||
VariantProps<typeof toggleVariants>
|
||||
>(({ className, variant, size, ...props }, ref) => (
|
||||
<TogglePrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(toggleVariants({ variant, size, className }))}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
|
||||
Toggle.displayName = TogglePrimitive.Root.displayName
|
||||
|
||||
export { Toggle, toggleVariants }
|
||||
30
client/src/components/ui/tooltip.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const TooltipProvider = TooltipPrimitive.Provider
|
||||
|
||||
const Tooltip = TooltipPrimitive.Root
|
||||
|
||||
const TooltipTrigger = TooltipPrimitive.Trigger
|
||||
|
||||
const TooltipContent = React.forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<TooltipPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
||||
19
client/src/hooks/use-mobile.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import * as React from "react"
|
||||
|
||||
const MOBILE_BREAKPOINT = 768
|
||||
|
||||
export function useIsMobile() {
|
||||
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
|
||||
|
||||
React.useEffect(() => {
|
||||
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
|
||||
const onChange = () => {
|
||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
||||
}
|
||||
mql.addEventListener("change", onChange)
|
||||
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
||||
return () => mql.removeEventListener("change", onChange)
|
||||
}, [])
|
||||
|
||||
return !!isMobile
|
||||
}
|
||||
191
client/src/hooks/use-toast.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
import * as React from "react"
|
||||
|
||||
import type {
|
||||
ToastActionElement,
|
||||
ToastProps,
|
||||
} from "@/components/ui/toast"
|
||||
|
||||
const TOAST_LIMIT = 1
|
||||
const TOAST_REMOVE_DELAY = 1000000
|
||||
|
||||
type ToasterToast = ToastProps & {
|
||||
id: string
|
||||
title?: React.ReactNode
|
||||
description?: React.ReactNode
|
||||
action?: ToastActionElement
|
||||
}
|
||||
|
||||
const actionTypes = {
|
||||
ADD_TOAST: "ADD_TOAST",
|
||||
UPDATE_TOAST: "UPDATE_TOAST",
|
||||
DISMISS_TOAST: "DISMISS_TOAST",
|
||||
REMOVE_TOAST: "REMOVE_TOAST",
|
||||
} as const
|
||||
|
||||
let count = 0
|
||||
|
||||
function genId() {
|
||||
count = (count + 1) % Number.MAX_SAFE_INTEGER
|
||||
return count.toString()
|
||||
}
|
||||
|
||||
type ActionType = typeof actionTypes
|
||||
|
||||
type Action =
|
||||
| {
|
||||
type: ActionType["ADD_TOAST"]
|
||||
toast: ToasterToast
|
||||
}
|
||||
| {
|
||||
type: ActionType["UPDATE_TOAST"]
|
||||
toast: Partial<ToasterToast>
|
||||
}
|
||||
| {
|
||||
type: ActionType["DISMISS_TOAST"]
|
||||
toastId?: ToasterToast["id"]
|
||||
}
|
||||
| {
|
||||
type: ActionType["REMOVE_TOAST"]
|
||||
toastId?: ToasterToast["id"]
|
||||
}
|
||||
|
||||
interface State {
|
||||
toasts: ToasterToast[]
|
||||
}
|
||||
|
||||
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
|
||||
|
||||
const addToRemoveQueue = (toastId: string) => {
|
||||
if (toastTimeouts.has(toastId)) {
|
||||
return
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
toastTimeouts.delete(toastId)
|
||||
dispatch({
|
||||
type: "REMOVE_TOAST",
|
||||
toastId: toastId,
|
||||
})
|
||||
}, TOAST_REMOVE_DELAY)
|
||||
|
||||
toastTimeouts.set(toastId, timeout)
|
||||
}
|
||||
|
||||
export const reducer = (state: State, action: Action): State => {
|
||||
switch (action.type) {
|
||||
case "ADD_TOAST":
|
||||
return {
|
||||
...state,
|
||||
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
||||
}
|
||||
|
||||
case "UPDATE_TOAST":
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === action.toast.id ? { ...t, ...action.toast } : t
|
||||
),
|
||||
}
|
||||
|
||||
case "DISMISS_TOAST": {
|
||||
const { toastId } = action
|
||||
|
||||
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
||||
// but I'll keep it here for simplicity
|
||||
if (toastId) {
|
||||
addToRemoveQueue(toastId)
|
||||
} else {
|
||||
state.toasts.forEach((toast) => {
|
||||
addToRemoveQueue(toast.id)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === toastId || toastId === undefined
|
||||
? {
|
||||
...t,
|
||||
open: false,
|
||||
}
|
||||
: t
|
||||
),
|
||||
}
|
||||
}
|
||||
case "REMOVE_TOAST":
|
||||
if (action.toastId === undefined) {
|
||||
return {
|
||||
...state,
|
||||
toasts: [],
|
||||
}
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const listeners: Array<(state: State) => void> = []
|
||||
|
||||
let memoryState: State = { toasts: [] }
|
||||
|
||||
function dispatch(action: Action) {
|
||||
memoryState = reducer(memoryState, action)
|
||||
listeners.forEach((listener) => {
|
||||
listener(memoryState)
|
||||
})
|
||||
}
|
||||
|
||||
type Toast = Omit<ToasterToast, "id">
|
||||
|
||||
function toast({ ...props }: Toast) {
|
||||
const id = genId()
|
||||
|
||||
const update = (props: ToasterToast) =>
|
||||
dispatch({
|
||||
type: "UPDATE_TOAST",
|
||||
toast: { ...props, id },
|
||||
})
|
||||
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
|
||||
|
||||
dispatch({
|
||||
type: "ADD_TOAST",
|
||||
toast: {
|
||||
...props,
|
||||
id,
|
||||
open: true,
|
||||
onOpenChange: (open) => {
|
||||
if (!open) dismiss()
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
id: id,
|
||||
dismiss,
|
||||
update,
|
||||
}
|
||||
}
|
||||
|
||||
function useToast() {
|
||||
const [state, setState] = React.useState<State>(memoryState)
|
||||
|
||||
React.useEffect(() => {
|
||||
listeners.push(setState)
|
||||
return () => {
|
||||
const index = listeners.indexOf(setState)
|
||||
if (index > -1) {
|
||||
listeners.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}, [state])
|
||||
|
||||
return {
|
||||
...state,
|
||||
toast,
|
||||
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
|
||||
}
|
||||
}
|
||||
|
||||
export { useToast, toast }
|
||||
329
client/src/index.css
Normal file
@@ -0,0 +1,329 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* LIGHT MODE */
|
||||
:root {
|
||||
--button-outline: rgba(0,0,0, .10);
|
||||
--badge-outline: rgba(0,0,0, .05);
|
||||
|
||||
/* Automatic computation of border around primary / danger buttons */
|
||||
--opaque-button-border-intensity: -8; /* In terms of percentages */
|
||||
|
||||
/* Backgrounds applied on top of other backgrounds when hovered/active */
|
||||
--elevate-1: rgba(0,0,0, .03);
|
||||
--elevate-2: rgba(0,0,0, .08);
|
||||
|
||||
--background: red; /*replace with H S L */
|
||||
|
||||
--foreground: red; /*replace with H S L */
|
||||
|
||||
--border: red; /*replace with H S L */
|
||||
|
||||
--card: red; /*replace with H S L */
|
||||
|
||||
--card-foreground: red; /*replace with H S L */
|
||||
|
||||
--card-border: red; /*replace with H S L */
|
||||
|
||||
--sidebar: red; /*replace with H S L */
|
||||
|
||||
--sidebar-foreground: red; /*replace with H S L */
|
||||
|
||||
--sidebar-border: red; /*replace with H S L */
|
||||
|
||||
--sidebar-primary: red; /*replace with H S L */
|
||||
|
||||
--sidebar-primary-foreground: red; /*replace with H S L */
|
||||
|
||||
--sidebar-accent: red; /*replace with H S L */
|
||||
|
||||
--sidebar-accent-foreground: red; /*replace with H S L */
|
||||
|
||||
--sidebar-ring: red; /*replace with H S L */
|
||||
|
||||
--popover: red; /*replace with H S L */
|
||||
|
||||
--popover-foreground: red; /*replace with H S L */
|
||||
|
||||
--popover-border: red; /*replace with H S L */
|
||||
|
||||
--primary: red; /*replace with H S L */
|
||||
|
||||
--primary-foreground: red; /*replace with H S L */
|
||||
|
||||
--secondary: red; /*replace with H S L */
|
||||
|
||||
--secondary-foreground: red; /*replace with H S L */
|
||||
|
||||
--muted: red; /*replace with H S L */
|
||||
|
||||
--muted-foreground: red; /*replace with H S L */
|
||||
|
||||
--accent: red; /*replace with H S L */
|
||||
|
||||
--accent-foreground: red; /*replace with H S L */
|
||||
|
||||
--destructive: red; /*replace with H S L */
|
||||
|
||||
--destructive-foreground: red; /*replace with H S L */
|
||||
|
||||
--input: red; /*replace with H S L */
|
||||
--ring: red; /*replace with H S L */
|
||||
--chart-1: red; /*replace with H S L */
|
||||
--chart-2: red; /*replace with H S L */
|
||||
--chart-3: red; /*replace with H S L */
|
||||
--chart-4: red; /*replace with H S L */
|
||||
--chart-5: red; /*replace with H S L */
|
||||
|
||||
--font-sans: 'Inter', sans-serif;
|
||||
--font-serif: Georgia, serif;
|
||||
--font-mono: Menlo, monospace;
|
||||
--radius: .5rem; /* 8px */
|
||||
--shadow-2xs: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00); /*replace with H S L */
|
||||
--shadow-xs: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00); /*replace with H S L */
|
||||
--shadow-sm: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 1px 2px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 1px 2px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-md: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 2px 4px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-lg: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 4px 6px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-xl: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 8px 10px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-2xl: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--tracking-normal: 0em;
|
||||
--spacing: 0.25rem;
|
||||
|
||||
/* Automatically computed borders - intensity can be controlled by the user by the --opaque-button-border-intensity setting */
|
||||
|
||||
/* Fallback for older browsers */
|
||||
--sidebar-primary-border: hsl(var(--sidebar-primary));
|
||||
--sidebar-primary-border: hsl(from hsl(var(--sidebar-primary)) h s calc(l + var(--opaque-button-border-intensity)) / alpha);
|
||||
|
||||
/* Fallback for older browsers */
|
||||
--sidebar-accent-border: hsl(var(--sidebar-accent));
|
||||
--sidebar-accent-border: hsl(from hsl(var(--sidebar-accent)) h s calc(l + var(--opaque-button-border-intensity)) / alpha);
|
||||
|
||||
/* Fallback for older browsers */
|
||||
--primary-border: hsl(var(--primary));
|
||||
--primary-border: hsl(from hsl(var(--primary)) h s calc(l + var(--opaque-button-border-intensity)) / alpha);
|
||||
|
||||
/* Fallback for older browsers */
|
||||
--secondary-border: hsl(var(--secondary));
|
||||
--secondary-border: hsl(from hsl(var(--secondary)) h s calc(l + var(--opaque-button-border-intensity)) / alpha);
|
||||
|
||||
/* Fallback for older browsers */
|
||||
--muted-border: hsl(var(--muted));
|
||||
--muted-border: hsl(from hsl(var(--muted)) h s calc(l + var(--opaque-button-border-intensity)) / alpha);
|
||||
|
||||
/* Fallback for older browsers */
|
||||
--accent-border: hsl(var(--accent));
|
||||
--accent-border: hsl(from hsl(var(--accent)) h s calc(l + var(--opaque-button-border-intensity)) / alpha);
|
||||
|
||||
/* Fallback for older browsers */
|
||||
--destructive-border: hsl(var(--destructive));
|
||||
--destructive-border: hsl(from hsl(var(--destructive)) h s calc(l + var(--opaque-button-border-intensity)) / alpha);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--button-outline: rgba(255,255,255, .10);
|
||||
--badge-outline: rgba(255,255,255, .05);
|
||||
|
||||
--opaque-button-border-intensity: 9; /* In terms of percentages */
|
||||
|
||||
/* Backgrounds applied on top of other backgrounds when hovered/active */
|
||||
--elevate-1: rgba(255,255,255, .04);
|
||||
--elevate-2: rgba(255,255,255, .09);
|
||||
|
||||
--background: red; /*replace with H S L */
|
||||
|
||||
--foreground: red; /*replace with H S L */
|
||||
|
||||
--border: red; /*replace with H S L */
|
||||
|
||||
--card: red; /*replace with H S L */
|
||||
|
||||
--card-foreground: red; /*replace with H S L */
|
||||
|
||||
--card-border: red; /*replace with H S L */
|
||||
|
||||
--sidebar: red; /*replace with H S L */
|
||||
|
||||
--sidebar-foreground: red; /*replace with H S L */
|
||||
|
||||
--sidebar-border: red; /*replace with H S L */
|
||||
|
||||
--sidebar-primary: red; /*replace with H S L */
|
||||
|
||||
--sidebar-primary-foreground: red; /*replace with H S L */
|
||||
|
||||
--sidebar-accent: red; /*replace with H S L */
|
||||
|
||||
--sidebar-accent-foreground: red; /*replace with H S L */
|
||||
|
||||
--sidebar-ring: red; /*replace with H S L */
|
||||
|
||||
--popover: red; /*replace with H S L */
|
||||
|
||||
--popover-foreground: red; /*replace with H S L */
|
||||
|
||||
--popover-border: red; /*replace with H S L */
|
||||
|
||||
--primary: red; /*replace with H S L */
|
||||
|
||||
--primary-foreground: red; /*replace with H S L */
|
||||
|
||||
--secondary: red; /*replace with H S L */
|
||||
|
||||
--secondary-foreground: red; /*replace with H S L */
|
||||
|
||||
--muted: red; /*replace with H S L */
|
||||
|
||||
--muted-foreground: red; /*replace with H S L */
|
||||
|
||||
--accent: red; /*replace with H S L */
|
||||
|
||||
--accent-foreground: red; /*replace with H S L */
|
||||
|
||||
--destructive: red; /*replace with H S L */
|
||||
|
||||
--destructive-foreground: red; /*replace with H S L */
|
||||
|
||||
/* Used as the border around inputs. Dark mode: Should be a border that is light enough to have high contrast when rendered on a --card background. More contrast than standard --border */
|
||||
--input: red; /*replace with H S L */
|
||||
--ring: red; /*replace with H S L */
|
||||
--chart-1: red; /*replace with H S L */
|
||||
--chart-2: red; /*replace with H S L */
|
||||
--chart-3: red; /*replace with H S L */
|
||||
--chart-4: red; /*replace with H S L */
|
||||
--chart-5: red; /*replace with H S L */
|
||||
|
||||
--shadow-2xs: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-xs: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-sm: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 1px 2px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 1px 2px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-md: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 2px 4px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-lg: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 4px 6px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-xl: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00), 0px 8px 10px -1px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
--shadow-2xl: 0px 2px 0px 0px hsl(202.8169 89.1213% 53.1373% / 0.00);
|
||||
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply font-sans antialiased bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the elevate system.
|
||||
* Automatic contrast adjustment.
|
||||
*
|
||||
* <element className="hover-elevate" />
|
||||
* <element className="active-elevate-2" />
|
||||
*
|
||||
* // Using the tailwind utility when a data attribute is "on"
|
||||
* <element className="toggle-elevate data-[state=on]:toggle-elevated" />
|
||||
* // Or manually controlling the toggle state
|
||||
* <element className="toggle-elevate toggle-elevated" />
|
||||
*
|
||||
* Elevation systems have to handle many states.
|
||||
* - not-hovered, vs. hovered vs. active (three mutually exclusive states)
|
||||
* - toggled or not
|
||||
* - focused or not (this is not handled with these utilities)
|
||||
*
|
||||
* Even without handling focused or not, this is six possible combinations that
|
||||
* need to be distinguished from eachother visually.
|
||||
*/
|
||||
@layer utilities {
|
||||
|
||||
/* Hide ugly search cancel button in Chrome until we can style it properly */
|
||||
input[type="search"]::-webkit-search-cancel-button {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
/* Placeholder styling for contentEditable div */
|
||||
[contenteditable][data-placeholder]:empty::before {
|
||||
content: attr(data-placeholder);
|
||||
color: hsl(var(--muted-foreground));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* .no-default-hover-elevate/no-default-active-elevate is an escape hatch so consumers of
|
||||
* buttons/badges can remove the automatic brightness adjustment on interactions
|
||||
* and program their own. */
|
||||
.no-default-hover-elevate {}
|
||||
|
||||
.no-default-active-elevate {}
|
||||
|
||||
|
||||
/**
|
||||
* Toggleable backgrounds go behind the content. Hoverable/active goes on top.
|
||||
* This way they can stack/compound. Both will overlap the parent's borders!
|
||||
* So borders will be automatically adjusted both on toggle, and hover/active,
|
||||
* and they will be compounded.
|
||||
*/
|
||||
.toggle-elevate::before,
|
||||
.toggle-elevate-2::before {
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
inset: 0px;
|
||||
/*border-radius: inherit; match rounded corners */
|
||||
border-radius: inherit;
|
||||
z-index: -1;
|
||||
/* sits behind content but above backdrop */
|
||||
}
|
||||
|
||||
.toggle-elevate.toggle-elevated::before {
|
||||
background-color: var(--elevate-2);
|
||||
}
|
||||
|
||||
/* If there's a 1px border, adjust the inset so that it covers that parent's border */
|
||||
.border.toggle-elevate::before {
|
||||
inset: -1px;
|
||||
}
|
||||
|
||||
/* Does not work on elements with overflow:hidden! */
|
||||
.hover-elevate:not(.no-default-hover-elevate),
|
||||
.active-elevate:not(.no-default-active-elevate),
|
||||
.hover-elevate-2:not(.no-default-hover-elevate),
|
||||
.active-elevate-2:not(.no-default-active-elevate) {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.hover-elevate:not(.no-default-hover-elevate)::after,
|
||||
.active-elevate:not(.no-default-active-elevate)::after,
|
||||
.hover-elevate-2:not(.no-default-hover-elevate)::after,
|
||||
.active-elevate-2:not(.no-default-active-elevate)::after {
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
inset: 0px;
|
||||
/*border-radius: inherit; match rounded corners */
|
||||
border-radius: inherit;
|
||||
z-index: 999;
|
||||
/* sits in front of content */
|
||||
}
|
||||
|
||||
.hover-elevate:hover:not(.no-default-hover-elevate)::after,
|
||||
.active-elevate:active:not(.no-default-active-elevate)::after {
|
||||
background-color: var(--elevate-1);
|
||||
}
|
||||
|
||||
.hover-elevate-2:hover:not(.no-default-hover-elevate)::after,
|
||||
.active-elevate-2:active:not(.no-default-active-elevate)::after {
|
||||
background-color: var(--elevate-2);
|
||||
}
|
||||
|
||||
/* If there's a 1px border, adjust the inset so that it covers that parent's border */
|
||||
.border.hover-elevate:not(.no-hover-interaction-elevate)::after,
|
||||
.border.active-elevate:not(.no-active-interaction-elevate)::after,
|
||||
.border.hover-elevate-2:not(.no-hover-interaction-elevate)::after,
|
||||
.border.active-elevate-2:not(.no-active-interaction-elevate)::after,
|
||||
.border.hover-elevate:not(.no-hover-interaction-elevate)::after {
|
||||
inset: -1px;
|
||||
}
|
||||
}
|
||||
57
client/src/lib/queryClient.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { QueryClient, QueryFunction } from "@tanstack/react-query";
|
||||
|
||||
async function throwIfResNotOk(res: Response) {
|
||||
if (!res.ok) {
|
||||
const text = (await res.text()) || res.statusText;
|
||||
throw new Error(`${res.status}: ${text}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiRequest(
|
||||
method: string,
|
||||
url: string,
|
||||
data?: unknown | undefined,
|
||||
): Promise<Response> {
|
||||
const res = await fetch(url, {
|
||||
method,
|
||||
headers: data ? { "Content-Type": "application/json" } : {},
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
await throwIfResNotOk(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
type UnauthorizedBehavior = "returnNull" | "throw";
|
||||
export const getQueryFn: <T>(options: {
|
||||
on401: UnauthorizedBehavior;
|
||||
}) => QueryFunction<T> =
|
||||
({ on401: unauthorizedBehavior }) =>
|
||||
async ({ queryKey }) => {
|
||||
const res = await fetch(queryKey.join("/") as string, {
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
if (unauthorizedBehavior === "returnNull" && res.status === 401) {
|
||||
return null;
|
||||
}
|
||||
|
||||
await throwIfResNotOk(res);
|
||||
return await res.json();
|
||||
};
|
||||
|
||||
export const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
queryFn: getQueryFn({ on401: "throw" }),
|
||||
refetchInterval: false,
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: Infinity,
|
||||
retry: false,
|
||||
},
|
||||
mutations: {
|
||||
retry: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
6
client/src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
5
client/src/main.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App";
|
||||
import "./index.css";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(<App />);
|
||||
21
client/src/pages/not-found.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { AlertCircle } from "lucide-react";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="min-h-screen w-full flex items-center justify-center bg-gray-50">
|
||||
<Card className="w-full max-w-md mx-4">
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex mb-4 gap-2">
|
||||
<AlertCircle className="h-8 w-8 text-red-500" />
|
||||
<h1 className="text-2xl font-bold text-gray-900">404 Page Not Found</h1>
|
||||
</div>
|
||||
|
||||
<p className="mt-4 text-sm text-gray-600">
|
||||
Did you forget to add the page to the router?
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
20
components.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.ts",
|
||||
"css": "client/src/index.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
}
|
||||
}
|
||||
323
contact.html
@@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
|
||||
<head>
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
@@ -7,34 +8,23 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<meta name="author" content="Awaiken">
|
||||
<meta name="author" content="Keshav Anand">
|
||||
<!-- Page Title -->
|
||||
<title>Avenix - Church HTML Template</title>
|
||||
<title>TSCB - Contact Us</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.png">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/logo.png">
|
||||
<!-- Google Fonts Css-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
|
||||
<!-- Bootstrap Css -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<!-- SlickNav Css -->
|
||||
<link href="css/slicknav.min.css" rel="stylesheet">
|
||||
<!-- Swiper Css -->
|
||||
<link rel="stylesheet" href="css/swiper-bundle.min.css">
|
||||
<!-- Font Awesome Icon Css-->
|
||||
<link href="css/all.css" rel="stylesheet" media="screen">
|
||||
<!-- Animated Css -->
|
||||
<link href="css/animate.css" rel="stylesheet">
|
||||
<!-- Magnific Popup Core Css File -->
|
||||
<link rel="stylesheet" href="css/magnific-popup.css">
|
||||
<!-- Mouse Cursor Css File -->
|
||||
<link rel="stylesheet" href="css/mousecursor.css">
|
||||
<!-- Audio Css File -->
|
||||
<link rel="stylesheet" href="css/plyr.css">
|
||||
<!-- Main Custom Css -->
|
||||
<link href="css/custom.css" rel="stylesheet" media="screen">
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
||||
rel="stylesheet">
|
||||
<!-- Preload critical image -->
|
||||
<link rel="preload" href="images/page-header-bg.jpg" as="image">
|
||||
<!-- Bundled CSS -->
|
||||
<link href="css/bundle.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- Preloader Start -->
|
||||
@@ -45,7 +35,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- Preloader End -->
|
||||
|
||||
<!-- Header Start -->
|
||||
<header class="main-header">
|
||||
<div class="header-sticky">
|
||||
@@ -53,7 +42,7 @@
|
||||
<div class="container">
|
||||
<!-- Logo Start -->
|
||||
<a class="navbar-brand" href="./">
|
||||
<img src="images/logo.svg" alt="Logo">
|
||||
<img src="images/logo.png" alt="Logo" style="width: 60px; height: auto;">
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
@@ -61,38 +50,22 @@
|
||||
<div class="collapse navbar-collapse main-menu">
|
||||
<div class="nav-menu-wrapper">
|
||||
<ul class="navbar-nav mr-auto" id="menu">
|
||||
<li class="nav-item submenu"><a class="nav-link" href="./">Home</a>
|
||||
<ul class="sub-menu">
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home - Image</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-video.html">Home - Video</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-slider.html">Home - Slider</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="about.html">About Us</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="service.html">Services</a></li>
|
||||
<li class="nav-item submenu"><a class="nav-link" href="#">Pages</a>
|
||||
<ul>
|
||||
<li class="nav-item"><a class="nav-link" href="service-single.html">Service Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog.html">Blog</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog-single.html">Blog Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons.html">Sermons</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons-single.html">Sermons Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign.html">Campaigns</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign-single.html">Campaign Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministries.html">Ministries</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministry-single.html">Ministries Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="pastor.html">pastor</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="gallery.html">Gallery</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="404.html">404</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="dallas.html">Dallas Regionals</a></li>
|
||||
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="austin.html">Austin Regionals</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="contact.html">Contact Us</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="#">donate now</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="sponsors.html">Our
|
||||
Partners</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Let’s Start Button Start -->
|
||||
<div class="header-btn d-inline-flex">
|
||||
<a href="#" class="btn-default">donate now</a>
|
||||
<a href="sponsors.html" class="btn-default">Our Partners</a>
|
||||
</div>
|
||||
<!-- Let’s Start Button End -->
|
||||
</div>
|
||||
@@ -105,6 +78,7 @@
|
||||
</header>
|
||||
<!-- Header End -->
|
||||
|
||||
|
||||
<!-- Page Header Start -->
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
@@ -115,7 +89,7 @@
|
||||
<h1 class="text-anime-style-2" data-cursor="-opaque">Contact Us</h1>
|
||||
<nav class="wow fadeInUp">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="./">home</a></li>
|
||||
<li class="breadcrumb-item"><a href="index.html">home</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">contact us</li>
|
||||
</ol>
|
||||
</nav>
|
||||
@@ -131,14 +105,17 @@
|
||||
<div class="page-contact-us">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6">
|
||||
<div class="col-lg-12">
|
||||
<!-- Contact Information Start -->
|
||||
<div class="contact-information">
|
||||
<!-- Contact Information Title Start -->
|
||||
<div class="section-title">
|
||||
<h3 class="wow fadeInUp">contact us</h3>
|
||||
<h2 class="text-anime-style-2" data-cursor="-opaque">Reach Out to Our <span>Church Support</span></h2>
|
||||
<p class="wow fadeInUp" data-wow-delay="0.25s">Contact us for support, information, or to get involved. We're here to help and welcome you to our community.</p>
|
||||
<h3 class="wow fadeInUp">Reach Out</h3>
|
||||
<h2 class="text-anime-style-2" data-cursor="-opaque">Reach Out to Our <span>Student-Led
|
||||
Board</span></h2>
|
||||
<p class="wow fadeInUp" data-wow-delay="0.25s">Whether you're a student, parent, or school
|
||||
administrator, we're here to help. Reach out to our student-led board with any questions
|
||||
about joining a team, starting a new program, or getting involved with TSCB.</p>
|
||||
</div>
|
||||
<!-- Contact Information Title End -->
|
||||
|
||||
@@ -148,14 +125,14 @@
|
||||
<div class="contact-info-item wow fadeInUp" data-wow-delay="0.25s">
|
||||
<!-- Icon Box Start -->
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-phone.svg" alt="">
|
||||
<img loading="lazy" src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<!-- Icon Box End -->
|
||||
|
||||
<!-- Contact Info Content Start -->
|
||||
<div class="contact-info-content">
|
||||
<p>give us a call</p>
|
||||
<h3>(+01) 789 859 654</h3>
|
||||
<h3>(+1) (945) 900-1148</h3>
|
||||
</div>
|
||||
<!-- Contact Info Content End -->
|
||||
</div>
|
||||
@@ -165,80 +142,80 @@
|
||||
<div class="contact-info-item wow fadeInUp" data-wow-delay="0.5s">
|
||||
<!-- Icon Box Start -->
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-mail.svg" alt="">
|
||||
<img loading="lazy" src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<!-- Icon Box End -->
|
||||
|
||||
<!-- Contact Info Content Start -->
|
||||
<div class="contact-info-content">
|
||||
<p>Send us a message</p>
|
||||
<h3>info@domain.com</h3>
|
||||
<h3>texasscholasticcricketboard@gmail.com</h3>
|
||||
</div>
|
||||
<!-- Contact Info Content End -->
|
||||
</div>
|
||||
<!-- Contact Info Item End -->
|
||||
|
||||
<!-- Contact Info Item Start -->
|
||||
<div class="contact-info-item wow fadeInUp" data-wow-delay="0.75s">
|
||||
<!-- Icon Box Start -->
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-location.svg" alt="">
|
||||
</div>
|
||||
<!-- Icon Box End -->
|
||||
|
||||
<!-- Contact Info Content Start -->
|
||||
<div class="contact-info-content">
|
||||
<p>Visit our location</p>
|
||||
<h3>786 Maple Avenue Smalltown, USA 67890</h3>
|
||||
</div>
|
||||
<!-- Contact Info Content End -->
|
||||
</div>
|
||||
<!-- Contact Info Item End -->
|
||||
</div>
|
||||
<!-- Contact Information List End -->
|
||||
</div>
|
||||
<!-- Contact Information End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<!-- Contact Form Start -->
|
||||
<div class="contact-us-form wow fadeInUp" data-wow-delay="0.25s">
|
||||
<form id="contactForm" action="#" method="POST" data-toggle="validator" class="wow fadeInUp" data-wow-delay="0.5s">
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6 mb-4">
|
||||
<input type="text" name="name" class="form-control" id="fname" placeholder="First Name" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
<script>
|
||||
async function submitForm() {
|
||||
const fname = document.getElementById('fname').value.trim();
|
||||
const lname = document.getElementById('lname').value.trim();
|
||||
const email = document.getElementById('email').value.trim();
|
||||
const phone = document.getElementById('phone').value.trim();
|
||||
const message = document.getElementById('msg').value.trim();
|
||||
const btn = document.getElementById('submitBtn');
|
||||
const errorEl = document.getElementById('errorMsg');
|
||||
|
||||
<div class="form-group col-md-6 mb-4">
|
||||
<input type="text" name="name" class="form-control" id="lname" placeholder="Last Name" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
// Basic validation
|
||||
if (!fname || !lname || !email || !phone || !message) {
|
||||
errorEl.textContent = 'Please fill in all fields.';
|
||||
errorEl.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
<div class="form-group col-md-6 mb-4">
|
||||
<input type="email" name ="email" class="form-control" id="email" placeholder="Email Address" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
// Button loading state
|
||||
btn.textContent = 'Sending...';
|
||||
btn.disabled = true;
|
||||
errorEl.style.display = 'none';
|
||||
|
||||
<div class="form-group col-md-6 mb-4">
|
||||
<input type="text" name="phone" class="form-control" id="phone" placeholder="Phone No" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
try {
|
||||
const response = await fetch('https://api.web3forms.com/submit', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
access_key: '6c4376f3-1658-48cc-bec1-5bbf3df39b1a',
|
||||
subject: 'New Contact Inquiry - TSCB Website',
|
||||
name: `${fname} ${lname}`,
|
||||
email: email,
|
||||
phone: phone,
|
||||
message: message,
|
||||
})
|
||||
});
|
||||
|
||||
<div class="form-group col-md-12 mb-4">
|
||||
<textarea name="msg" class="form-control" id="msg" rows="5" placeholder="Message" required></textarea>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
const data = await response.json();
|
||||
|
||||
<div class="col-lg-12">
|
||||
<div class="contact-form-btn">
|
||||
<button type="submit" class="btn-default">submit message</button>
|
||||
<div id="msgSubmit" class="h3 hidden"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
if (data.success) {
|
||||
// Hide form, show success
|
||||
document.getElementById('contactFormFields').style.display = 'none';
|
||||
document.getElementById('successMsg').style.display = 'block';
|
||||
} else {
|
||||
throw new Error(data.message || 'Submission failed');
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
btn.textContent = 'submit message';
|
||||
btn.disabled = false;
|
||||
errorEl.textContent = 'Something went wrong. Please try again or email us directly.';
|
||||
errorEl.style.display = 'block';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Contact Form End -->
|
||||
</div>
|
||||
</div>
|
||||
@@ -246,21 +223,6 @@
|
||||
</div>
|
||||
<!-- Page Contact Us End -->
|
||||
|
||||
<!-- Google Map Start -->
|
||||
<div class="google-map">
|
||||
<div class="container-fluid">
|
||||
<div class="row no-gutter">
|
||||
<div class="col-lg-12">
|
||||
<!-- Google Map Iframe Start -->
|
||||
<div class="google-map-iframe">
|
||||
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d96737.10562045308!2d-74.08535042841811!3d40.739265258395164!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x89c24fa5d33f083b%3A0xc80b8f06e177fe62!2sNew%20York%2C%20NY%2C%20USA!5e0!3m2!1sen!2sin!4v1703158537552!5m2!1sen!2sin" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
|
||||
</div>
|
||||
<!-- Google Map Iframe End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Google Map End -->
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer class="main-footer">
|
||||
@@ -271,21 +233,41 @@
|
||||
<div class="about-footer">
|
||||
<!-- Footer Logo Start -->
|
||||
<div class="footer-logo">
|
||||
<img src="images/footer-logo.svg" alt="">
|
||||
<img src="images/logo.png" alt="Footer Logo" style="width: 100px; height: auto;">
|
||||
</div>
|
||||
<!-- Footer Logo End -->
|
||||
|
||||
<!-- About Footer Content Start -->
|
||||
<div class="about-footer-content">
|
||||
<p>Lorem Ipsum is simply dummy text of printing and typesetting industry. Lorem Ipsum has been the industry's.</p>
|
||||
<p id="age-text">Loading...</p>
|
||||
|
||||
<script>
|
||||
const foundingDate = new Date("2025-12-29");
|
||||
const now = new Date();
|
||||
|
||||
const months = (now.getFullYear() - foundingDate.getFullYear()) * 12
|
||||
+ (now.getMonth() - foundingDate.getMonth());
|
||||
|
||||
const years = Math.floor(months / 12);
|
||||
const remainingMonths = months % 12;
|
||||
|
||||
let duration = "";
|
||||
if (years > 0) duration += `${years} year${years > 1 ? "s" : ""}`;
|
||||
if (years > 0 && remainingMonths > 0) duration += " and ";
|
||||
if (remainingMonths > 0) duration += `${remainingMonths} month${remainingMonths > 1 ? "s" : ""}`;
|
||||
if (months === 0) duration = "less than a month";
|
||||
|
||||
document.getElementById("age-text").textContent =
|
||||
`TSCB has been proudly serving its community for ${duration}`;
|
||||
</script>
|
||||
</div>
|
||||
<!-- Footer Social Links Start -->
|
||||
<div class="footer-social-links">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-x-twitter"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-linkedin-in"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
<li><a href="https://www.instagram.com/texasscholasticcricketboard/"><i
|
||||
class="fa-brands fa-instagram"></i></a></li>
|
||||
<li><a href="https://www.youtube.com/channel/UCdFfqkVWDJyFlFEEKfq27wg"><i class="fa-brands fa-youtube"></i></a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Links End -->
|
||||
@@ -299,11 +281,10 @@
|
||||
<div class="footer-links">
|
||||
<h3>quick links</h3>
|
||||
<ul>
|
||||
<li><a href="#">home</a></li>
|
||||
<li><a href="#">our chruch</a></li>
|
||||
<li><a href="#">services</a></li>
|
||||
<li><a href="#">event</a></li>
|
||||
<li><a href="#">news</a></li>
|
||||
<li><a href="/">home</a></li>
|
||||
<li><a href="/about.html">about</a></li>
|
||||
<li><a href="/sponsors.html">sponsors</a></li>
|
||||
<li><a href="/contact.html">contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
@@ -312,13 +293,12 @@
|
||||
<div class="col-lg-3 col-md-4 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>our services</h3>
|
||||
<h3>our cricket</h3>
|
||||
<ul>
|
||||
<li><a href="#">support groups</a></li>
|
||||
<li><a href="#">special events</a></li>
|
||||
<li><a href="#">online services</a></li>
|
||||
<li><a href="#">pastoral care</a></li>
|
||||
<li><a href="#">sunday worship</a></li>
|
||||
<li><a href="/dallas.html">dallas regionals</a></li>
|
||||
<li><a href="/austin.html">austin regionals</a></li>
|
||||
<li><a href="https://cricclubs.com/TexasScholasticCricketBoard">dallas cricclubs league</a></li>
|
||||
<li><a href="https://cricclubs.com/USHSC/series-list/QKoRw7aJTppHXMxmRSTXmg?seriesName=USAHSC%25202026">austin cricclubs league</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
@@ -333,10 +313,10 @@
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-phone.svg" alt="">
|
||||
<img loading="lazy" src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>(+0) 789 345 012</p>
|
||||
<p>(+1) (945) 900-1148</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
@@ -344,24 +324,15 @@
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-mail.svg" alt="">
|
||||
<img loading="lazy" src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>domain@gmail.com</p>
|
||||
<p>texasscholasticcricketboard@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-location.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>24/11 Robert Road,New York,USA</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
</div>
|
||||
<!-- Footer Contact Details End -->
|
||||
</div>
|
||||
@@ -375,7 +346,7 @@
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Copyright Start -->
|
||||
<div class="footer-copyright-text">
|
||||
<p>Copyright 2024 Avenix. All Rights Reserved.</p>
|
||||
<p>Copyright 2026 Texas Scholastic Cricket Board. All Rights Reserved.</p>
|
||||
</div>
|
||||
<!-- Footer Copyright End -->
|
||||
</div>
|
||||
@@ -384,9 +355,8 @@
|
||||
<!-- Footer Social Link Start -->
|
||||
<div class="footer-privacy-policy">
|
||||
<ul>
|
||||
<li><a href="#">term & condition</a></li>
|
||||
<li><a href="#">support</a></li>
|
||||
<li><a href="#">privacy policy</a></li>
|
||||
<li><a href="https://docs.google.com/document/d/10jrcqdHfUYqF6YBHKVqBewxep7vsUbvrIDLX7ednoCc/edit?tab=t.0#heading=h.xzi71qd5vfcz">policies</a></li>
|
||||
<li><a href="/liability.html">liability</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Link End -->
|
||||
@@ -398,38 +368,11 @@
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
|
||||
|
||||
<!-- Jquery Library File -->
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<!-- Bootstrap js file -->
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<!-- Validator js file -->
|
||||
<script src="js/validator.min.js"></script>
|
||||
<!-- SlickNav js file -->
|
||||
<script src="js/jquery.slicknav.js"></script>
|
||||
<!-- Swiper js file -->
|
||||
<script src="js/swiper-bundle.min.js"></script>
|
||||
<!-- Counter js file -->
|
||||
<script src="js/jquery.waypoints.min.js"></script>
|
||||
<script src="js/jquery.counterup.min.js"></script>
|
||||
<!-- Magnific js file -->
|
||||
<script src="js/jquery.magnific-popup.min.js"></script>
|
||||
<!-- SmoothScroll -->
|
||||
<script src="js/SmoothScroll.js"></script>
|
||||
<!-- Parallax js -->
|
||||
<script src="js/parallaxie.js"></script>
|
||||
<!-- MagicCursor js file -->
|
||||
<script src="js/gsap.min.js"></script>
|
||||
<script src="js/magiccursor.js"></script>
|
||||
<!-- Text Effect js file -->
|
||||
<script src="js/SplitText.js"></script>
|
||||
<script src="js/ScrollTrigger.min.js"></script>
|
||||
<!-- YTPlayer js File -->
|
||||
<script src="js/jquery.mb.YTPlayer.min.js"></script>
|
||||
<!-- Audio js File -->
|
||||
<script src="js/plyr.js"></script>
|
||||
<!-- Wow js file -->
|
||||
<script src="js/wow.js"></script>
|
||||
<!-- Main Custom js file -->
|
||||
<script src="js/function.js"></script>
|
||||
<script src="js/bundle-core.js"></script>
|
||||
<!-- Enhanced Animations js -->
|
||||
<script src="js/enhance.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
10971
css/bundle.css
Normal file
120
css/custom.css
@@ -50,12 +50,12 @@
|
||||
|
||||
:root{
|
||||
--primary-color : #000000;
|
||||
--secondary-color : #FFF4F1;
|
||||
--secondary-color : #ce9c5b;
|
||||
--text-color : #525252;
|
||||
--accent-color : #fe5d35;
|
||||
--white-color : #FFFFFF;
|
||||
--accent-color : #d92800;
|
||||
--white-color : #f3dbbb;
|
||||
--divider-color : #FFFFFF26;
|
||||
--dark-divider-color : #E9E9E9;
|
||||
--dark-divider-color : #e9e9e9;
|
||||
--error-color : rgb(230, 87, 87);
|
||||
--default-font : "Fira Sans Condensed", sans-serif;
|
||||
}
|
||||
@@ -2661,10 +2661,25 @@ header.main-header .header-sticky.active{
|
||||
.team-member-item{
|
||||
position: relative;
|
||||
height: calc(100% - 30px);
|
||||
margin-bottom: 30px;
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Tablet breakpoint: increase padding for larger screens */
|
||||
@media (min-width: 768px) {
|
||||
.team-member-item {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Desktop breakpoint (1200px+): maximum padding for optimal spacing */
|
||||
@media (min-width: 1200px) {
|
||||
.team-member-item {
|
||||
padding: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.team-image{
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
@@ -2675,12 +2690,19 @@ header.main-header .header-sticky.active{
|
||||
|
||||
.team-image img{
|
||||
width: 100%;
|
||||
aspect-ratio: 1/1.22;
|
||||
aspect-ratio: 1/1.22; /* default desktop */
|
||||
object-fit: cover;
|
||||
border-radius: 0 0 80px 0;
|
||||
transition: all 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
/* Mobile breakpoint (575px and below): square aspect ratio for better fit */
|
||||
@media (max-width: 575px) {
|
||||
.team-image img {
|
||||
aspect-ratio: 1/1; /* square on mobile for better fit */
|
||||
}
|
||||
}
|
||||
|
||||
.team-member-item:hover .team-image img{
|
||||
transform: scale(1.1);
|
||||
}
|
||||
@@ -4512,6 +4534,74 @@ header.main-header .header-sticky.active{
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
/************************************/
|
||||
/*** 35b. Sponsors Section ***/
|
||||
/************************************/
|
||||
|
||||
.our-sponsors-section{
|
||||
padding: 70px 0 60px;
|
||||
background-color: var(--white-color);
|
||||
}
|
||||
|
||||
.sponsors-logo-grid{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 40px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.sponsor-logo-item{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #fff;
|
||||
border: 1px solid var(--dark-divider-color);
|
||||
border-radius: 12px;
|
||||
padding: 20px 30px;
|
||||
transition: box-shadow 0.3s ease-in-out, transform 0.3s ease-in-out;
|
||||
min-width: 200px;
|
||||
max-width: 260px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sponsor-logo-item:hover{
|
||||
box-shadow: 0 8px 30px rgba(0,0,0,0.10);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.sponsor-logo-item img{
|
||||
max-width: 100%;
|
||||
max-height: 100px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sponsors-footer{
|
||||
text-align: center;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.sponsors-footer p{
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.sponsors-footer p a{
|
||||
font-weight: 700;
|
||||
color: var(--accent-color);
|
||||
text-decoration: underline;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.sponsors-footer p a:hover{
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
/************************************/
|
||||
/*** 36. responsive css ***/
|
||||
/************************************/
|
||||
@@ -5520,6 +5610,24 @@ header.main-header .header-sticky.active{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.our-sponsors-section{
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
.sponsors-logo-grid{
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.sponsor-logo-item{
|
||||
min-width: 140px;
|
||||
max-width: 180px;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.sponsor-logo-item img{
|
||||
max-height: 70px;
|
||||
}
|
||||
|
||||
.mission-img{
|
||||
padding: 0 0 60px 60px;
|
||||
}
|
||||
|
||||
939
css/enhance.css
Normal file
@@ -0,0 +1,939 @@
|
||||
/* =====================================================
|
||||
TSCB — Enhanced Animations & Visual Excellence
|
||||
===================================================== */
|
||||
|
||||
/* ---- Scroll Progress Bar ---- */
|
||||
#tscb-progress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 3px;
|
||||
width: 0%;
|
||||
background: linear-gradient(90deg, #d92800 0%, #ce9c5b 50%, #d92800 100%);
|
||||
background-size: 200% 100%;
|
||||
animation: progressShift 3s ease infinite;
|
||||
z-index: 999999;
|
||||
transition: width 0.08s linear;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes progressShift {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
/* ---- Hero Section Decorative Orbs ---- */
|
||||
.hero {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hero-orb-1,
|
||||
.hero-orb-2,
|
||||
.hero-orb-3 {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.hero-orb-1 {
|
||||
width: 700px;
|
||||
height: 700px;
|
||||
background: radial-gradient(circle, rgba(217, 40, 0, 0.16) 0%, transparent 65%);
|
||||
top: -300px;
|
||||
right: -200px;
|
||||
animation: orbDrift 12s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.hero-orb-2 {
|
||||
width: 450px;
|
||||
height: 450px;
|
||||
background: radial-gradient(circle, rgba(206, 156, 91, 0.11) 0%, transparent 65%);
|
||||
bottom: -100px;
|
||||
left: -150px;
|
||||
animation: orbDrift 16s ease-in-out infinite reverse;
|
||||
}
|
||||
|
||||
.hero-orb-3 {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
background: radial-gradient(circle, rgba(217, 40, 0, 0.07) 0%, transparent 65%);
|
||||
top: 40%;
|
||||
left: 30%;
|
||||
animation: orbDrift 9s ease-in-out infinite 2s;
|
||||
}
|
||||
|
||||
@keyframes orbDrift {
|
||||
0%, 100% { transform: translate(0px, 0px) scale(1); }
|
||||
33% { transform: translate(30px, -30px) scale(1.06); }
|
||||
66% { transform: translate(-20px, 20px) scale(0.96); }
|
||||
}
|
||||
|
||||
/* ---- Hero subtle grid overlay ---- */
|
||||
.hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image:
|
||||
linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
|
||||
background-size: 60px 60px;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hero .down-arrow {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ---- Down arrow bounce ---- */
|
||||
.hero .down-arrow a {
|
||||
animation: arrowBounce 2.2s ease-in-out infinite;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@keyframes arrowBounce {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(12px); }
|
||||
}
|
||||
|
||||
/* ---- Nav hover underline animation ---- */
|
||||
.main-menu .navbar-nav > .nav-item > a {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-menu .navbar-nav > .nav-item > a::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
height: 2px;
|
||||
background: var(--accent-color);
|
||||
transform: scaleX(0);
|
||||
transform-origin: right;
|
||||
transition: transform 0.35s cubic-bezier(0.76, 0, 0.24, 1);
|
||||
}
|
||||
|
||||
.main-menu .navbar-nav > .nav-item > a:hover::after,
|
||||
.main-menu .navbar-nav > .nav-item.active > a::after {
|
||||
transform: scaleX(1);
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
/* ---- Enhanced sticky header glass effect ---- */
|
||||
header.main-header .header-sticky.active {
|
||||
background: rgba(0, 0, 0, 0.90) !important;
|
||||
backdrop-filter: blur(24px) saturate(180%) !important;
|
||||
-webkit-backdrop-filter: blur(24px) saturate(180%) !important;
|
||||
border-bottom: 1px solid rgba(206, 156, 91, 0.25) !important;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.5) !important;
|
||||
}
|
||||
|
||||
/* ---- Enhanced Button Animations ---- */
|
||||
.btn-default {
|
||||
letter-spacing: 0.03em;
|
||||
transition: all 0.45s cubic-bezier(0.25, 0.46, 0.45, 0.94) !important;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.btn-default:active {
|
||||
transform: scale(0.95) !important;
|
||||
}
|
||||
|
||||
.btn-default::before {
|
||||
transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
|
||||
}
|
||||
|
||||
/* ---- About image list item hover ---- */
|
||||
.about-list-item {
|
||||
transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.about-list-item:hover {
|
||||
transform: translateX(8px);
|
||||
}
|
||||
|
||||
.about-list-item .icon-box {
|
||||
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.4s ease;
|
||||
}
|
||||
|
||||
.about-list-item:hover .icon-box {
|
||||
transform: scale(1.15) rotate(-5deg);
|
||||
box-shadow: 0 10px 30px rgba(217, 40, 0, 0.35);
|
||||
}
|
||||
|
||||
/* About image layout overrides are handled below in the FOUNDERS SECTION block. */
|
||||
|
||||
/* ---- Counter section enhanced ---- */
|
||||
.our-counter {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.counter-box {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.counter-box::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
background: conic-gradient(
|
||||
from 0deg at 50% 50%,
|
||||
transparent 0deg,
|
||||
rgba(255,255,255,0.03) 60deg,
|
||||
transparent 120deg,
|
||||
rgba(255,255,255,0.03) 180deg,
|
||||
transparent 240deg,
|
||||
rgba(255,255,255,0.03) 300deg,
|
||||
transparent 360deg
|
||||
);
|
||||
animation: counterRotate 25s linear infinite;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes counterRotate {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.counter-item {
|
||||
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.counter-item:hover {
|
||||
transform: translateY(-6px);
|
||||
}
|
||||
|
||||
.counter-title h2 {
|
||||
font-size: 62px !important;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
/* ---- Service Item enhanced hover ---- */
|
||||
.service-item {
|
||||
transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.5s ease !important;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.06);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.service-item:hover {
|
||||
transform: translateY(-10px) !important;
|
||||
box-shadow: 0 30px 60px rgba(0,0,0,0.18) !important;
|
||||
}
|
||||
|
||||
.service-item .icon-box img {
|
||||
transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
|
||||
}
|
||||
|
||||
.service-item:hover .icon-box img {
|
||||
transform: scale(1.1) rotate(-8deg) !important;
|
||||
}
|
||||
|
||||
/* ---- Service icon shine sweep ---- */
|
||||
.service-item .icon-box {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.service-item .icon-box::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -120%;
|
||||
width: 60%;
|
||||
height: 100%;
|
||||
background: linear-gradient(105deg, transparent 30%, rgba(255,255,255,0.4) 50%, transparent 70%);
|
||||
transform: skewX(-15deg);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.service-item:hover .icon-box::after {
|
||||
left: 150%;
|
||||
transition: left 0.5s ease;
|
||||
}
|
||||
|
||||
/* ---- Services dot background ---- */
|
||||
.our-services {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.our-services::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: radial-gradient(circle, rgba(0,0,0,0.06) 1px, transparent 1px);
|
||||
background-size: 28px 28px;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.our-services .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ---- Service footer slide on hover ---- */
|
||||
.service-footer {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.service-item:hover .service-footer {
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
/* ---- Ticker gradient fade edges ---- */
|
||||
.service-ticker {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.service-ticker::before,
|
||||
.service-ticker::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 120px;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.service-ticker::before {
|
||||
left: 0;
|
||||
background: linear-gradient(90deg, var(--primary-color) 20%, transparent 100%);
|
||||
}
|
||||
|
||||
.service-ticker::after {
|
||||
right: 0;
|
||||
background: linear-gradient(-90deg, var(--primary-color) 20%, transparent 100%);
|
||||
}
|
||||
|
||||
/* ---- Sponsor logos — NO default opacity:0, GSAP handles initial state ---- */
|
||||
.sponsor-logo-item {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1),
|
||||
box-shadow 0.45s ease,
|
||||
border-color 0.3s ease !important;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
/* Shimmer sweep on hover */
|
||||
.sponsor-logo-item::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -120%;
|
||||
width: 60%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
105deg,
|
||||
transparent 30%,
|
||||
rgba(255, 255, 255, 0.55) 50%,
|
||||
transparent 70%
|
||||
);
|
||||
transform: skewX(-15deg);
|
||||
transition: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sponsor-logo-item:hover::after {
|
||||
left: 160%;
|
||||
transition: left 0.65s ease;
|
||||
}
|
||||
|
||||
.sponsor-logo-item:hover {
|
||||
border-color: var(--accent-color) !important;
|
||||
transform: translateY(-8px) scale(1.03) !important;
|
||||
box-shadow: 0 20px 50px rgba(217, 40, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
.sponsor-logo-item img {
|
||||
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
|
||||
}
|
||||
|
||||
.sponsor-logo-item:hover img {
|
||||
transform: scale(1.06) !important;
|
||||
}
|
||||
|
||||
/* ---- Sponsors section subtle dot background ---- */
|
||||
.our-sponsors-section {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.our-sponsors-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: radial-gradient(circle, rgba(206, 156, 91, 0.07) 1px, transparent 1px);
|
||||
background-size: 32px 32px;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.our-sponsors-section .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ---- Mission section ---- */
|
||||
.our-mission {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.our-mission::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(206, 156, 91, 0.07) 0%, transparent 65%);
|
||||
top: -100px;
|
||||
right: -150px;
|
||||
pointer-events: none;
|
||||
animation: orbDrift 18s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.mission-content-body p {
|
||||
border-left: 3px solid var(--accent-color) !important;
|
||||
padding-left: 18px !important;
|
||||
transition: border-color 0.3s ease, padding-left 0.3s ease;
|
||||
}
|
||||
|
||||
.mission-content-body p:hover {
|
||||
border-left-color: var(--secondary-color) !important;
|
||||
padding-left: 24px !important;
|
||||
}
|
||||
|
||||
/* ---- CTA Box orb ---- */
|
||||
.cta-box {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cta-box::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(217, 40, 0, 0.10) 0%, transparent 65%);
|
||||
top: -200px;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
animation: orbDrift 14s ease-in-out infinite 1s;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.cta-box .container {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ---- Footer glow border ---- */
|
||||
.main-footer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-footer::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 10%;
|
||||
right: 10%;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, var(--secondary-color), transparent);
|
||||
}
|
||||
|
||||
/* ---- Footer social links spring ---- */
|
||||
.footer-social-links ul li a {
|
||||
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
|
||||
box-shadow 0.3s ease !important;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.footer-social-links ul li a:hover {
|
||||
transform: translateY(-6px) scale(1.15) !important;
|
||||
box-shadow: 0 10px 25px rgba(217, 40, 0, 0.4) !important;
|
||||
}
|
||||
|
||||
/* ---- Footer links underline ---- */
|
||||
.footer-links ul li a {
|
||||
position: relative;
|
||||
transition: color 0.3s ease !important;
|
||||
}
|
||||
|
||||
.footer-links ul li a::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -2px;
|
||||
width: 0;
|
||||
height: 1px;
|
||||
background: var(--accent-color);
|
||||
transition: width 0.35s cubic-bezier(0.76, 0, 0.24, 1);
|
||||
}
|
||||
|
||||
.footer-links ul li a:hover::before {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ---- Page header orb ---- */
|
||||
.page-header {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page-header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(217, 40, 0, 0.10) 0%, transparent 60%);
|
||||
bottom: -250px;
|
||||
right: -100px;
|
||||
pointer-events: none;
|
||||
animation: orbDrift 15s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* ---- Animated gradient on accent spans ---- */
|
||||
.section-title h2 span,
|
||||
.section-title h1 span {
|
||||
background: linear-gradient(90deg, #d92800 0%, #ff5c38 40%, #d92800 100%);
|
||||
background-size: 200% auto;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
animation: textGradientShift 4s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes textGradientShift {
|
||||
0% { background-position: 0% center; }
|
||||
50% { background-position: 100% center; }
|
||||
100% { background-position: 0% center; }
|
||||
}
|
||||
|
||||
/* ---- Preloader gradient ---- */
|
||||
.preloader {
|
||||
background: linear-gradient(135deg, #d92800 0%, #b01d00 100%) !important;
|
||||
}
|
||||
|
||||
/* ---- Team member hover ---- */
|
||||
.team-member-item {
|
||||
transition: transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.45s ease;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.team-member-item:hover {
|
||||
transform: translateY(-8px);
|
||||
box-shadow: 0 25px 55px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
/* ---- Readmore btn spring ---- */
|
||||
.readmore-btn {
|
||||
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
|
||||
background-color 0.3s ease,
|
||||
box-shadow 0.3s ease !important;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.readmore-btn:hover {
|
||||
transform: scale(1.15) rotate(45deg) !important;
|
||||
box-shadow: 0 10px 30px rgba(217, 40, 0, 0.45) !important;
|
||||
}
|
||||
|
||||
/* ---- Logo footer hover ---- */
|
||||
.footer-logo img {
|
||||
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
.footer-logo img:hover {
|
||||
transform: scale(1.08) rotate(-3deg);
|
||||
}
|
||||
|
||||
/* ---- Body smooth scroll ---- */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* ---- Smooth body fade in ---- */
|
||||
body {
|
||||
animation: bodyReveal 0.4s ease both;
|
||||
}
|
||||
|
||||
@keyframes bodyReveal {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
ABOUT.HTML — Single-image first section fix
|
||||
.page-about-us now only has .about-img-1 (no overlay).
|
||||
Remove the padding-top that was there for the second image
|
||||
and make the image fill the column properly.
|
||||
============================================================ */
|
||||
|
||||
.page-about-us .about-image {
|
||||
padding-top: 0 !important;
|
||||
max-width: 100% !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.page-about-us .about-img-1 {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* Pastors section: remove inline dimension override, let CSS size it */
|
||||
.pastors-message .about-img-2 img {
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
TABLET (≤ 1024px)
|
||||
============================================================ */
|
||||
@media (max-width: 1024px) {
|
||||
/* Shrink orbs so they don't cause scrollbar */
|
||||
.hero-orb-1 { width: 500px; height: 500px; }
|
||||
.hero-orb-2 { width: 350px; height: 350px; }
|
||||
|
||||
/* Mission life circle is decorative — hide on tablet to simplify */
|
||||
.mission-life-circle {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
TABLET PORTRAIT (≤ 991px)
|
||||
============================================================ */
|
||||
@media (max-width: 991px) {
|
||||
/* About single-image: center and constrain */
|
||||
.page-about-us .about-image {
|
||||
max-width: 580px !important;
|
||||
margin: 0 auto 35px !important;
|
||||
}
|
||||
|
||||
/* Counter items: remove divider borders at tablet */
|
||||
.counter-item {
|
||||
border-right: none !important;
|
||||
padding-right: 15px !important;
|
||||
}
|
||||
|
||||
/* CTA button: center on smaller screens */
|
||||
.cta-box-btn {
|
||||
text-align: center !important;
|
||||
margin-top: 20px !important;
|
||||
}
|
||||
|
||||
.cta-box-btn::before {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Service items: consistent margin when they wrap */
|
||||
.service-item {
|
||||
margin-bottom: 24px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
MOBILE (≤ 767px)
|
||||
============================================================ */
|
||||
@media (max-width: 767px) {
|
||||
/* Orbs: shrink and simplify */
|
||||
.hero-orb-1 { width: 300px; height: 300px; top: -150px; right: -100px; }
|
||||
.hero-orb-2 { width: 220px; height: 220px; bottom: -80px; left: -80px; }
|
||||
.hero-orb-3 { display: none; }
|
||||
|
||||
/* Hero: prevent overflow */
|
||||
.hero { overflow: hidden; }
|
||||
.hero .container { overflow: visible; }
|
||||
|
||||
/* Counter h2 */
|
||||
.counter-title h2 { font-size: 42px !important; }
|
||||
|
||||
/* Ticker fade edges narrower */
|
||||
.service-ticker::before,
|
||||
.service-ticker::after { width: 50px; }
|
||||
|
||||
/* Sponsors grid: 2 col on mobile */
|
||||
.sponsors-logo-grid {
|
||||
gap: 16px !important;
|
||||
}
|
||||
.sponsor-logo-item {
|
||||
min-width: 130px !important;
|
||||
max-width: 48% !important;
|
||||
padding: 14px 16px !important;
|
||||
}
|
||||
|
||||
/* About single-image mobile */
|
||||
.page-about-us .about-image {
|
||||
max-width: 100% !important;
|
||||
margin-bottom: 30px !important;
|
||||
}
|
||||
.page-about-us .about-img-1 img {
|
||||
aspect-ratio: 16 / 10 !important;
|
||||
}
|
||||
|
||||
/* Mission content first on mobile */
|
||||
.our-mission .col-lg-6:last-child {
|
||||
margin-top: 30px !important;
|
||||
}
|
||||
|
||||
/* CTA text smaller */
|
||||
.cta-box-content .section-title h2 {
|
||||
font-size: 22px !important;
|
||||
}
|
||||
|
||||
/* Footer: better spacing */
|
||||
.footer-widget {
|
||||
margin-bottom: 30px !important;
|
||||
}
|
||||
|
||||
/* Nav "Our Partners" button in header: hide on very small */
|
||||
.header-btn .btn-default {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
SMALL MOBILE (≤ 575px)
|
||||
============================================================ */
|
||||
@media (max-width: 575px) {
|
||||
/* Hero title size */
|
||||
.section-title h1,
|
||||
.hero-content h1 {
|
||||
font-size: 30px !important;
|
||||
line-height: 1.18 !important;
|
||||
}
|
||||
|
||||
/* Counter: stack to 1 column, show divider lines */
|
||||
.counter-title h2 { font-size: 34px !important; }
|
||||
|
||||
.counter-item {
|
||||
border-right: none !important;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.12) !important;
|
||||
padding-bottom: 24px !important;
|
||||
margin-bottom: 24px !important;
|
||||
}
|
||||
|
||||
.counter-box .col-lg-3:last-child .counter-item {
|
||||
border-bottom: none !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/* Sponsors: single column */
|
||||
.sponsor-logo-item {
|
||||
min-width: calc(50% - 12px) !important;
|
||||
max-width: calc(50% - 12px) !important;
|
||||
}
|
||||
|
||||
/* Hero buttons: stack */
|
||||
.hero-content-body {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
gap: 12px !important;
|
||||
align-items: flex-start !important;
|
||||
}
|
||||
|
||||
.hero-content-body .btn-default {
|
||||
margin-left: 0 !important;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
/* About list items: single column */
|
||||
.about-content-body {
|
||||
grid-template-columns: 1fr !important;
|
||||
}
|
||||
|
||||
/* Section title padding */
|
||||
.section-title {
|
||||
margin-bottom: 24px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
CRICKET IMAGE — blurred-backdrop frame
|
||||
The .cricket-blur-bg div fills the full column with a blurred
|
||||
version of the same image; the real img sits centered on top
|
||||
at its natural aspect ratio so no void remains.
|
||||
============================================================ */
|
||||
.page-about-us .about-img-1 figure {
|
||||
position: relative !important;
|
||||
overflow: hidden !important;
|
||||
border-radius: 18px !important;
|
||||
height: 490px !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
box-shadow:
|
||||
0 0 0 2px rgba(217, 40, 0, 0.35),
|
||||
0 0 0 5px rgba(206, 156, 91, 0.15),
|
||||
0 16px 56px rgba(0, 0, 0, 0.45) !important;
|
||||
}
|
||||
|
||||
.page-about-us .about-img-1 .cricket-blur-bg {
|
||||
position: absolute !important;
|
||||
inset: -40px !important;
|
||||
background: url('../images/cricket.webp') center / cover no-repeat !important;
|
||||
filter: blur(28px) brightness(0.55) saturate(1.4) !important;
|
||||
z-index: 0 !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.page-about-us .about-img-1 img {
|
||||
position: relative !important;
|
||||
z-index: 1 !important;
|
||||
width: auto !important;
|
||||
max-width: 100% !important;
|
||||
height: 100% !important;
|
||||
object-fit: contain !important;
|
||||
display: block !important;
|
||||
aspect-ratio: unset !important;
|
||||
filter: drop-shadow(0 6px 28px rgba(0, 0, 0, 0.5)) !important;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.page-about-us .about-img-1 figure {
|
||||
height: 320px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
FOUNDERS SECTION — Equal-sized side-by-side layout
|
||||
Both founders shown at identical size with matching borders.
|
||||
Stacks vertically on mobile.
|
||||
============================================================ */
|
||||
|
||||
.pastors-message .about-image {
|
||||
padding-top: 0 !important;
|
||||
display: flex !important;
|
||||
flex-direction: row !important;
|
||||
align-items: stretch !important;
|
||||
gap: 12px !important;
|
||||
}
|
||||
|
||||
/* Both images exactly equal width */
|
||||
.pastors-message .about-img-1,
|
||||
.pastors-message .about-img-2 {
|
||||
position: static !important;
|
||||
top: auto !important;
|
||||
right: auto !important;
|
||||
width: 50% !important;
|
||||
flex: 0 0 50% !important;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.pastors-message .about-img-1 figure,
|
||||
.pastors-message .about-img-2 figure {
|
||||
display: block !important;
|
||||
height: 100% !important;
|
||||
border-radius: 16px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
/* Identical treatment on both images */
|
||||
.pastors-message .about-img-1 img,
|
||||
.pastors-message .about-img-2 img {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
aspect-ratio: 3 / 4 !important;
|
||||
object-fit: cover !important;
|
||||
object-position: top center !important;
|
||||
border-radius: 16px !important;
|
||||
border: 4px solid rgba(255, 255, 255, 0.85) !important;
|
||||
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.16) !important;
|
||||
}
|
||||
|
||||
/* ---- Founders: tablet (≤ 991px) ---- */
|
||||
@media (max-width: 991px) {
|
||||
.pastors-message .about-image {
|
||||
max-width: 520px !important;
|
||||
margin: 0 auto 35px !important;
|
||||
gap: 10px !important;
|
||||
}
|
||||
|
||||
.pastors-message .about-img-1,
|
||||
.pastors-message .about-img-2 {
|
||||
width: 50% !important;
|
||||
flex: 0 0 50% !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Founders: mobile (≤ 767px) ---- */
|
||||
@media (max-width: 767px) {
|
||||
.pastors-message .about-image {
|
||||
max-width: 420px !important;
|
||||
gap: 8px !important;
|
||||
}
|
||||
|
||||
.pastors-message .about-img-1 img,
|
||||
.pastors-message .about-img-2 img {
|
||||
border-width: 3px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Founders: small mobile (≤ 575px) — stack vertically ---- */
|
||||
@media (max-width: 575px) {
|
||||
.pastors-message .about-image {
|
||||
flex-direction: column !important;
|
||||
max-width: 100% !important;
|
||||
gap: 10px !important;
|
||||
margin: 0 0 30px !important;
|
||||
}
|
||||
|
||||
.pastors-message .about-img-1,
|
||||
.pastors-message .about-img-2 {
|
||||
width: 100% !important;
|
||||
flex: 0 0 100% !important;
|
||||
}
|
||||
|
||||
.pastors-message .about-img-1 img,
|
||||
.pastors-message .about-img-2 img {
|
||||
aspect-ratio: 4 / 3 !important;
|
||||
border-width: 3px !important;
|
||||
border-radius: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
COUNTER HOVER — Distinct color change (not orange/cream)
|
||||
The default cream (#f3dbbb) blends into the accent color.
|
||||
On hover: crisp white with a blue-tinted glow to contrast.
|
||||
============================================================ */
|
||||
.counter-item:hover .counter-title h2 {
|
||||
color: #ffffff !important;
|
||||
text-shadow: 0 0 24px rgba(130, 200, 255, 0.55),
|
||||
0 0 8px rgba(130, 200, 255, 0.35) !important;
|
||||
transition: color 0.35s ease, text-shadow 0.35s ease !important;
|
||||
}
|
||||
|
||||
.counter-item:hover .counter-content h3 {
|
||||
color: #ffffff !important;
|
||||
transition: color 0.35s ease !important;
|
||||
}
|
||||
|
||||
.counter-title h2,
|
||||
.counter-content h3 {
|
||||
transition: color 0.35s ease, text-shadow 0.35s ease;
|
||||
}
|
||||
516
dallas.html
Normal file
@@ -0,0 +1,516 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
|
||||
<head>
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<meta name="author" content="Keshav Anand">
|
||||
<!-- Page Title -->
|
||||
<title>Dallas League</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/logo.png">
|
||||
<!-- Google Fonts Css-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
|
||||
rel="stylesheet">
|
||||
<!-- Preload critical image -->
|
||||
<link rel="preload" href="images/page-header-bg.jpg" as="image">
|
||||
<!-- Bundled CSS -->
|
||||
<link href="css/bundle.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- Preloader Start -->
|
||||
<div class="preloader">
|
||||
<div class="loading-container">
|
||||
<div class="loading"></div>
|
||||
<div id="loading-icon"><img src="images/loader.svg" alt=""></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Preloader End -->
|
||||
|
||||
<!-- Header Start -->
|
||||
<header class="main-header">
|
||||
<div class="header-sticky">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
<div class="container">
|
||||
<!-- Logo Start -->
|
||||
<a class="navbar-brand" href="./">
|
||||
<img src="images/logo.png" alt="Logo" style="width: 60px; height: auto;">
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
<!-- Main Menu Start -->
|
||||
<div class="collapse navbar-collapse main-menu">
|
||||
<div class="nav-menu-wrapper">
|
||||
<ul class="navbar-nav mr-auto" id="menu">
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="about.html">About Us</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="dallas.html">Dallas Regionals</a></li>
|
||||
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="austin.html">Austin Regionals</a></li>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="contact.html">Contact Us</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="sponsors.html">Our
|
||||
Partners</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Let’s Start Button Start -->
|
||||
<div class="header-btn d-inline-flex">
|
||||
<a href="sponsors.html" class="btn-default">Our Partners</a>
|
||||
</div>
|
||||
<!-- Let’s Start Button End -->
|
||||
</div>
|
||||
<!-- Main Menu End -->
|
||||
<div class="navbar-toggle"></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="responsive-menu"></div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Header End -->
|
||||
|
||||
|
||||
<!-- Page Header Start -->
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-12">
|
||||
<!-- Page Header Box Start -->
|
||||
<div class="page-header-box">
|
||||
<h1 class="text-anime-style-2" data-cursor="-opaque"><span>Dallas Regionals</span></h1>
|
||||
<nav class="wow fadeInUp">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="./">home</a></li>
|
||||
<li class="breadcrumb-item active"><a href="/dallas.html">dallas regionals</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- Page Header Box End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Header End -->
|
||||
|
||||
<!-- League Overview Section Start -->
|
||||
<div class="about-us page-about-us">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
|
||||
<!-- Text Column -->
|
||||
<div class="col-lg-7 wow fadeInLeft">
|
||||
<div class="section-title">
|
||||
<h3>about the regional competition</h3>
|
||||
<h2 class="text-anime-style-2" data-cursor="-opaque">More than cowboys in <span>D-Town</span></h2>
|
||||
</div>
|
||||
<div class="about-content">
|
||||
<p>The Dallas Regionals is the first-ever fully integrated high school tapeball cricket league Dallas-Fort Worth area, bringing together high school students from across the region to compete at the highest level. Season One features nine schools divided across three geographic divisions — South, Central, and North Dallas — competing in a round-robin format to claim a spot in the State Championship.</p>
|
||||
<p>All matches are organized through CricClubs, where you can track live scores, standings, and full match statistics.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buttons Column -->
|
||||
<div class="col-lg-4 offset-lg-1 wow fadeInRight" data-wow-delay="0.2s">
|
||||
<div class="league-links d-flex flex-column gap-3 mt-4 mt-lg-0">
|
||||
<a href="https://cricclubs.com/TexasScholasticCricketBoard/points-table?leagueId=hKGWBeaND6UfZE7_FQSDeQ"
|
||||
class="btn-default w-100 text-center" target="_blank">
|
||||
<i class="fa-solid fa-table-list me-2"></i> Points Table
|
||||
</a>
|
||||
<a href="https://cricclubs.com/TexasScholasticCricketBoard/results?leagueId=hKGWBeaND6UfZE7_FQSDeQ&year=2026&series=YL5qVXl5UzTJ9e6vFfDgmg&seriesName=DALLAS+REGIONALS+-+SEASON+ONE"
|
||||
class="btn-default w-100 text-center" target="_blank">
|
||||
<i class="fa-solid fa-cricket-bat-ball me-2"></i> Our Latest Results
|
||||
</a>
|
||||
<a href="https://cricclubs.com/TexasScholasticCricketBoard"
|
||||
class="btn-default w-100 text-center" target="_blank">
|
||||
<i class="fa-solid fa-arrow-up-right-from-square me-2"></i> League Home Page
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- League Overview Section End -->
|
||||
|
||||
|
||||
<!-- Our Teams Section Start -->
|
||||
<div class="our-teams">
|
||||
<div class="container">
|
||||
<div class="row align-items-center section-row">
|
||||
<div class="col-lg-12">
|
||||
<!-- Section Title Start -->
|
||||
<div class="section-title">
|
||||
<h3 class="wow fadeInUp">our teams</h3>
|
||||
<h2 class="text-anime-style-2" data-cursor="-opaque">Meet Our Dedicated <span>Teams</span></h2>
|
||||
</div>
|
||||
<!-- Section Title End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Team Grid Start -->
|
||||
<div class="row">
|
||||
<!-- Team 1: Plano East Panthers -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/pesh.jpeg" alt="Plano East Panthers">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Plano East Panthers</h3>
|
||||
<p>South Dallas</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 2: Frisco Lone Star -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="0.2s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/ranchview.jpg" alt="Ranchview Wolves">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Ranchview Wolves</h3>
|
||||
<p>South Dallas</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 3: Prosper Predators -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="0.4s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/friscofury.webp" alt="Frisco Fury">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Frisco Fury</h3>
|
||||
<p>South Dallas</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 4: Irving High Chargers -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="0.6s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/heritage.webp" alt="Heritage Coyotes">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Heritage Coyotes</h3>
|
||||
<p>Central Dallas</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 5: Plano West Warriors -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="0.8s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/lebanon.jpeg" alt="Lebanon Trail Challengers">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Lebanon Trail Challengers</h3>
|
||||
<p>Central Dallas</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 6: Frisco Titans -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="1s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/liberty.jpeg" alt="Frisco Titans">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Liberty Redhawks</h3>
|
||||
<p>Central Dallas</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 7: Prosper Patriots -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="1.2s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/prosper.webp" alt="Prosper Eagles">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Prosper Eagles</h3>
|
||||
<p>North Dallas</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 8: Irving Lions -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="1.4s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/rockhill.jpeg" alt="Rock Hill Bluehawks">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Rock Hill Bluehawks</h3>
|
||||
<p>North Dallas</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
|
||||
<!-- Team 9: Plano Hawks -->
|
||||
<div class="col-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<!-- Team Member Item Start -->
|
||||
<div class="team-member-item wow fadeInUp" data-wow-delay="1.6s">
|
||||
<!-- Team Image Start -->
|
||||
<div class="team-image">
|
||||
<figure class="image-anime">
|
||||
<img loading="lazy" src="images/walnut.webp" alt="Walnut Grove Wildcats">
|
||||
</figure>
|
||||
</div>
|
||||
<!-- Team Image End -->
|
||||
|
||||
<!-- Team Content Start -->
|
||||
<div class="team-content">
|
||||
<h3>Walnut Grove Wildcats</h3>
|
||||
<p>North Dallas</p>
|
||||
</div>
|
||||
<!-- Team Content End -->
|
||||
</div>
|
||||
<!-- Team Member Item End -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- Team Grid End -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- Our Teams Section End -->
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer class="main-footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<!-- About Footer Start -->
|
||||
<div class="about-footer">
|
||||
<!-- Footer Logo Start -->
|
||||
<div class="footer-logo">
|
||||
<img src="images/logo.png" alt="Footer Logo" style="width: 100px; height: auto;">
|
||||
</div>
|
||||
<!-- Footer Logo End -->
|
||||
|
||||
<!-- About Footer Content Start -->
|
||||
<div class="about-footer-content">
|
||||
<p id="age-text">Loading...</p>
|
||||
|
||||
<script>
|
||||
const foundingDate = new Date("2025-12-29");
|
||||
const now = new Date();
|
||||
|
||||
const months = (now.getFullYear() - foundingDate.getFullYear()) * 12
|
||||
+ (now.getMonth() - foundingDate.getMonth());
|
||||
|
||||
const years = Math.floor(months / 12);
|
||||
const remainingMonths = months % 12;
|
||||
|
||||
let duration = "";
|
||||
if (years > 0) duration += `${years} year${years > 1 ? "s" : ""}`;
|
||||
if (years > 0 && remainingMonths > 0) duration += " and ";
|
||||
if (remainingMonths > 0) duration += `${remainingMonths} month${remainingMonths > 1 ? "s" : ""}`;
|
||||
if (months === 0) duration = "less than a month";
|
||||
|
||||
document.getElementById("age-text").textContent =
|
||||
`TSCB has been proudly serving its community for ${duration}`;
|
||||
</script>
|
||||
</div>
|
||||
<!-- Footer Social Links Start -->
|
||||
<div class="footer-social-links">
|
||||
<ul>
|
||||
<li><a href="https://www.instagram.com/texasscholasticcricketboard/"><i
|
||||
class="fa-brands fa-instagram"></i></a></li>
|
||||
<li><a href="https://www.youtube.com/channel/UCdFfqkVWDJyFlFEEKfq27wg"><i class="fa-brands fa-youtube"></i></a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Links End -->
|
||||
|
||||
</div>
|
||||
<!-- About Footer End -->
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-6 col-md-3 col-lg-2">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>quick links</h3>
|
||||
<ul>
|
||||
<li><a href="/">home</a></li>
|
||||
<li><a href="/about.html">about</a></li>
|
||||
<li><a href="/sponsors.html">sponsors</a></li>
|
||||
<li><a href="/contact.html">contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-6 col-md-4 col-lg-3">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>our cricket</h3>
|
||||
<ul>
|
||||
<li><a href="/dallas.html">dallas regionals</a></li>
|
||||
<li><a href="/austin.html">austin regionals</a></li>
|
||||
<li><a href="https://cricclubs.com/TexasScholasticCricketBoard">dallas cricclubs league</a></li>
|
||||
<li><a href="https://cricclubs.com/USHSC/series-list/QKoRw7aJTppHXMxmRSTXmg?seriesName=USAHSC%25202026">austin cricclubs league</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-6 col-md-5 col-lg-3">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-contact">
|
||||
<h3>contact</h3>
|
||||
<!-- Footer Contact Details Start -->
|
||||
<div class="footer-contact-details">
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img loading="lazy" src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>(+1) (945) 900-1148</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img loading="lazy" src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>texasscholasticcricketboard@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
|
||||
</div>
|
||||
<!-- Footer Contact Details End -->
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Copyright Section Start -->
|
||||
<div class="footer-copyright">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Copyright Start -->
|
||||
<div class="footer-copyright-text">
|
||||
<p>Copyright 2026 Texas Scholastic Cricket Board. All Rights Reserved.</p>
|
||||
</div>
|
||||
<!-- Footer Copyright End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Social Link Start -->
|
||||
<div class="footer-privacy-policy">
|
||||
<ul>
|
||||
<li><a href="https://docs.google.com/document/d/10jrcqdHfUYqF6YBHKVqBewxep7vsUbvrIDLX7ednoCc/edit?tab=t.0#heading=h.xzi71qd5vfcz">policies</a></li>
|
||||
<li><a href="/liability.html">liability</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Link End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Copyright Section End -->
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
|
||||
|
||||
<!-- Jquery Library File -->
|
||||
<script src="js/bundle-core.js"></script>
|
||||
<!-- Enhanced Animations js -->
|
||||
<script src="js/enhance.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
14
drizzle.config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
|
||||
if (!process.env.DATABASE_URL) {
|
||||
throw new Error("DATABASE_URL, ensure the database is provisioned");
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
out: "./migrations",
|
||||
schema: "./shared/schema.ts",
|
||||
dialect: "postgresql",
|
||||
dbCredentials: {
|
||||
url: process.env.DATABASE_URL,
|
||||
},
|
||||
});
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
$errorMSG = "";
|
||||
|
||||
// FIRSTNAME
|
||||
if (empty($_POST["fname"])) {
|
||||
$errorMSG = "Full Name is required. ";
|
||||
} else {
|
||||
$fname = $_POST["fname"];
|
||||
}
|
||||
|
||||
// LASTNAME
|
||||
if (empty($_POST["lname"])) {
|
||||
$errorMSG = "Full Name is required. ";
|
||||
} else {
|
||||
$lname = $_POST["lname"];
|
||||
}
|
||||
|
||||
// EMAIL
|
||||
if (empty($_POST["email"])) {
|
||||
$errorMSG .= "Email is required. ";
|
||||
} else {
|
||||
$email = $_POST["email"];
|
||||
}
|
||||
|
||||
// PHONE
|
||||
if (empty($_POST["phone"])) {
|
||||
$errorMSG .= "Phone is required. ";
|
||||
} else {
|
||||
$phone = $_POST["phone"];
|
||||
}
|
||||
|
||||
// MESSAGE
|
||||
if (empty($_POST["message"])) {
|
||||
$errorMSG .= "Message is required. ";
|
||||
} else {
|
||||
$message = $_POST["message"];
|
||||
}
|
||||
|
||||
$subject = 'Contact Inquiry from Physiocare Website';
|
||||
|
||||
//$EmailTo = "info@yourdomain.com"; // Replace with your email.
|
||||
$EmailTo = "awaikentechnology@gmail.com";
|
||||
|
||||
// prepare email body text
|
||||
$Body = "";
|
||||
$Body .= "Name: ";
|
||||
$Body .= $fname." ".$lname;
|
||||
$Body .= "\n";
|
||||
$Body .= "Email: ";
|
||||
$Body .= $email;
|
||||
$Body .= "\n";
|
||||
$Body .= "Phone: ";
|
||||
$Body .= $phone;
|
||||
$Body .= "\n";
|
||||
$Body .= "Message: ";
|
||||
$Body .= $message;
|
||||
$Body .= "\n";
|
||||
|
||||
// send email
|
||||
$success = @mail($EmailTo, $subject, $Body, "From:".$email);
|
||||
|
||||
// redirect to success page
|
||||
if ($success && $errorMSG == ""){
|
||||
echo "success";
|
||||
}else{
|
||||
if($errorMSG == ""){
|
||||
echo "Something went wrong :(";
|
||||
} else {
|
||||
echo $errorMSG;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
382
gallery.html
@@ -1,382 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zxx">
|
||||
<head>
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="keywords" content="">
|
||||
<meta name="author" content="Awaiken">
|
||||
<!-- Page Title -->
|
||||
<title>Avenix - Church HTML Template</title>
|
||||
<!-- Favicon Icon -->
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.png">
|
||||
<!-- Google Fonts Css-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
|
||||
<!-- Bootstrap Css -->
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
|
||||
<!-- SlickNav Css -->
|
||||
<link href="css/slicknav.min.css" rel="stylesheet">
|
||||
<!-- Swiper Css -->
|
||||
<link rel="stylesheet" href="css/swiper-bundle.min.css">
|
||||
<!-- Font Awesome Icon Css-->
|
||||
<link href="css/all.css" rel="stylesheet" media="screen">
|
||||
<!-- Animated Css -->
|
||||
<link href="css/animate.css" rel="stylesheet">
|
||||
<!-- Magnific Popup Core Css File -->
|
||||
<link rel="stylesheet" href="css/magnific-popup.css">
|
||||
<!-- Mouse Cursor Css File -->
|
||||
<link rel="stylesheet" href="css/mousecursor.css">
|
||||
<!-- Audio Css File -->
|
||||
<link rel="stylesheet" href="css/plyr.css">
|
||||
<!-- Main Custom Css -->
|
||||
<link href="css/custom.css" rel="stylesheet" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Preloader Start -->
|
||||
<div class="preloader">
|
||||
<div class="loading-container">
|
||||
<div class="loading"></div>
|
||||
<div id="loading-icon"><img src="images/loader.svg" alt=""></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Preloader End -->
|
||||
|
||||
<!-- Header Start -->
|
||||
<header class="main-header">
|
||||
<div class="header-sticky">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
<div class="container">
|
||||
<!-- Logo Start -->
|
||||
<a class="navbar-brand" href="./">
|
||||
<img src="images/logo.svg" alt="Logo">
|
||||
</a>
|
||||
<!-- Logo End -->
|
||||
|
||||
<!-- Main Menu Start -->
|
||||
<div class="collapse navbar-collapse main-menu">
|
||||
<div class="nav-menu-wrapper">
|
||||
<ul class="navbar-nav mr-auto" id="menu">
|
||||
<li class="nav-item submenu"><a class="nav-link" href="./">Home</a>
|
||||
<ul class="sub-menu">
|
||||
<li class="nav-item"><a class="nav-link" href="index.html">Home - Image</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-video.html">Home - Video</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="index-slider.html">Home - Slider</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="about.html">About Us</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="service.html">Services</a></li>
|
||||
<li class="nav-item submenu"><a class="nav-link" href="#">Pages</a>
|
||||
<ul>
|
||||
<li class="nav-item"><a class="nav-link" href="service-single.html">Service Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog.html">Blog</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="blog-single.html">Blog Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons.html">Sermons</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sermons-single.html">Sermons Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign.html">Campaigns</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="campaign-single.html">Campaign Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministries.html">Ministries</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="ministry-single.html">Ministries Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="pastor.html">pastor</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="gallery.html">Gallery</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="404.html">404</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item"><a class="nav-link" href="contact.html">Contact Us</a></li>
|
||||
<li class="nav-item highlighted-menu"><a class="nav-link" href="#">donate now</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Let’s Start Button Start -->
|
||||
<div class="header-btn d-inline-flex">
|
||||
<a href="#" class="btn-default">donate now</a>
|
||||
</div>
|
||||
<!-- Let’s Start Button End -->
|
||||
</div>
|
||||
<!-- Main Menu End -->
|
||||
<div class="navbar-toggle"></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="responsive-menu"></div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Header End -->
|
||||
|
||||
<!-- Page Header Start -->
|
||||
<div class="page-header">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-12">
|
||||
<!-- Page Header Box Start -->
|
||||
<div class="page-header-box">
|
||||
<h1 class="text-anime-style-2" data-cursor="-opaque">Gallery</h1>
|
||||
<nav class="wow fadeInUp">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="./">home</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">gallery</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<!-- Page Header Box End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page Header End -->
|
||||
|
||||
<!-- Photo Gallery Section Start -->
|
||||
<div class="page-gallery">
|
||||
<div class="container">
|
||||
<!-- gallery section start -->
|
||||
<div class="row gallery-items page-gallery-box">
|
||||
<div class="col-lg-4 col-6">
|
||||
<!-- image gallery start -->
|
||||
<div class="photo-gallery wow fadeInUp" data-cursor-text="View">
|
||||
<a href="images/gallery-1.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/gallery-1.jpg" alt="">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- image gallery end -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-6">
|
||||
<!-- image gallery start -->
|
||||
<div class="photo-gallery wow fadeInUp" data-wow-delay="0.2s" data-cursor-text="View">
|
||||
<a href="images/gallery-2.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/gallery-2.jpg" alt="">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- image gallery end -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-6">
|
||||
<!-- image gallery start -->
|
||||
<div class="photo-gallery wow fadeInUp" data-wow-delay="0.4s" data-cursor-text="View">
|
||||
<a href="images/gallery-3.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/gallery-3.jpg" alt="">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- image gallery end -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-6">
|
||||
<!-- image gallery start -->
|
||||
<div class="photo-gallery wow fadeInUp" data-wow-delay="0.6s" data-cursor-text="View">
|
||||
<a href="images/gallery-4.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/gallery-4.jpg" alt="">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- image gallery end -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-6">
|
||||
<!-- image gallery start -->
|
||||
<div class="photo-gallery wow fadeInUp" data-wow-delay="0.8s" data-cursor-text="View">
|
||||
<a href="images/gallery-5.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/gallery-5.jpg" alt="">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- image gallery end -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-6">
|
||||
<!-- image gallery start -->
|
||||
<div class="photo-gallery wow fadeInUp" data-wow-delay="1s" data-cursor-text="View">
|
||||
<a href="images/gallery-6.jpg">
|
||||
<figure class="image-anime">
|
||||
<img src="images/gallery-6.jpg" alt="">
|
||||
</figure>
|
||||
</a>
|
||||
</div>
|
||||
<!-- image gallery end -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- gallery section end -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- Photo Gallery Section End -->
|
||||
|
||||
<!-- Footer Start -->
|
||||
<footer class="main-footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<!-- About Footer Start -->
|
||||
<div class="about-footer">
|
||||
<!-- Footer Logo Start -->
|
||||
<div class="footer-logo">
|
||||
<img src="images/footer-logo.svg" alt="">
|
||||
</div>
|
||||
<!-- Footer Logo End -->
|
||||
|
||||
<!-- About Footer Content Start -->
|
||||
<div class="about-footer-content">
|
||||
<p>Lorem Ipsum is simply dummy text of printing and typesetting industry. Lorem Ipsum has been the industry's.</p>
|
||||
</div>
|
||||
<!-- Footer Social Links Start -->
|
||||
<div class="footer-social-links">
|
||||
<ul>
|
||||
<li><a href="#"><i class="fa-brands fa-facebook-f"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-x-twitter"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-linkedin-in"></i></a></li>
|
||||
<li><a href="#"><i class="fa-brands fa-instagram"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Links End -->
|
||||
|
||||
</div>
|
||||
<!-- About Footer End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-2 col-md-3 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>quick links</h3>
|
||||
<ul>
|
||||
<li><a href="#">home</a></li>
|
||||
<li><a href="#">our chruch</a></li>
|
||||
<li><a href="#">services</a></li>
|
||||
<li><a href="#">event</a></li>
|
||||
<li><a href="#">news</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-4 col-6">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-links">
|
||||
<h3>our services</h3>
|
||||
<ul>
|
||||
<li><a href="#">support groups</a></li>
|
||||
<li><a href="#">special events</a></li>
|
||||
<li><a href="#">online services</a></li>
|
||||
<li><a href="#">pastoral care</a></li>
|
||||
<li><a href="#">sunday worship</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 col-md-5">
|
||||
<!-- About Links Start -->
|
||||
<div class="footer-contact">
|
||||
<h3>contact</h3>
|
||||
<!-- Footer Contact Details Start -->
|
||||
<div class="footer-contact-details">
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-phone.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>(+0) 789 345 012</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-mail.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>domain@gmail.com</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
|
||||
<!-- Footer Info Box Start -->
|
||||
<div class="footer-info-box">
|
||||
<div class="icon-box">
|
||||
<img src="images/icon-location.svg" alt="">
|
||||
</div>
|
||||
<div class="footer-info-box-content">
|
||||
<p>24/11 Robert Road,New York,USA</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Info Box End -->
|
||||
</div>
|
||||
<!-- Footer Contact Details End -->
|
||||
</div>
|
||||
<!-- About Links End -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Copyright Section Start -->
|
||||
<div class="footer-copyright">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Copyright Start -->
|
||||
<div class="footer-copyright-text">
|
||||
<p>Copyright 2024 Avenix. All Rights Reserved.</p>
|
||||
</div>
|
||||
<!-- Footer Copyright End -->
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 col-md-6">
|
||||
<!-- Footer Social Link Start -->
|
||||
<div class="footer-privacy-policy">
|
||||
<ul>
|
||||
<li><a href="#">term & condition</a></li>
|
||||
<li><a href="#">support</a></li>
|
||||
<li><a href="#">privacy policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Footer Social Link End -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer Copyright Section End -->
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Footer End -->
|
||||
|
||||
<!-- Jquery Library File -->
|
||||
<script src="js/jquery-3.7.1.min.js"></script>
|
||||
<!-- Bootstrap js file -->
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<!-- Validator js file -->
|
||||
<script src="js/validator.min.js"></script>
|
||||
<!-- SlickNav js file -->
|
||||
<script src="js/jquery.slicknav.js"></script>
|
||||
<!-- Swiper js file -->
|
||||
<script src="js/swiper-bundle.min.js"></script>
|
||||
<!-- Counter js file -->
|
||||
<script src="js/jquery.waypoints.min.js"></script>
|
||||
<script src="js/jquery.counterup.min.js"></script>
|
||||
<!-- Magnific js file -->
|
||||
<script src="js/jquery.magnific-popup.min.js"></script>
|
||||
<!-- SmoothScroll -->
|
||||
<script src="js/SmoothScroll.js"></script>
|
||||
<!-- Parallax js -->
|
||||
<script src="js/parallaxie.js"></script>
|
||||
<!-- MagicCursor js file -->
|
||||
<script src="js/gsap.min.js"></script>
|
||||
<script src="js/magiccursor.js"></script>
|
||||
<!-- Text Effect js file -->
|
||||
<script src="js/SplitText.js"></script>
|
||||
<script src="js/ScrollTrigger.min.js"></script>
|
||||
<!-- YTPlayer js File -->
|
||||
<script src="js/jquery.mb.YTPlayer.min.js"></script>
|
||||
<!-- Audio js File -->
|
||||
<script src="js/plyr.js"></script>
|
||||
<!-- Wow js file -->
|
||||
<script src="js/wow.js"></script>
|
||||
<!-- Main Custom js file -->
|
||||
<script src="js/function.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 57 KiB |
BIN
images/abhiram.jpg
Normal file
|
After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
BIN
images/austin.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
BIN
images/cedarridge.jpg
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
BIN
images/cricket.png
Normal file
|
After Width: | Height: | Size: 702 KiB |
BIN
images/cricket.webp
Normal file
|
After Width: | Height: | Size: 50 KiB |