From fcc2f4704e39b0e69b377cc138f75027721dac22 Mon Sep 17 00:00:00 2001 From: Dawid Rycerz Date: Tue, 22 Jul 2025 15:08:37 +0300 Subject: Initial template --- src/assets/favicons/apple-touch-icon.png | Bin 0 -> 26374 bytes src/assets/favicons/favicon.ico | Bin 0 -> 15086 bytes src/assets/favicons/favicon.png | Bin 0 -> 1403 bytes src/assets/favicons/favicon.svg | 20 ++ src/assets/images/app-store.png | Bin 0 -> 11251 bytes src/assets/images/ceramic-coating.svg | 18 ++ src/assets/images/color-change.svg | 44 +++ src/assets/images/content-image-new.webp | Bin 0 -> 226484 bytes src/assets/images/content-image.webp | Bin 0 -> 86184 bytes src/assets/images/content-image2-new.webp | Bin 0 -> 297522 bytes src/assets/images/content-image2.webp | Bin 0 -> 11238 bytes src/assets/images/customworks-hero.webp | Bin 0 -> 119260 bytes src/assets/images/customworks-logo.png | Bin 0 -> 18151 bytes src/assets/images/engine-cleaning.svg | 2 + src/assets/images/google-play.png | Bin 0 -> 13307 bytes src/assets/images/hero-image.jpg | Bin 0 -> 190587 bytes src/assets/images/interior-detailing.svg | 16 + src/assets/images/invisible-wipers.svg | 20 ++ src/assets/images/paint-restoration.svg | 2 + src/assets/images/ppf-protection.svg | 30 ++ src/assets/images/rzetelna-firma-logo.png | Bin 0 -> 3679 bytes src/assets/images/visual-tuning.svg | 2 + src/assets/styles/tailwind.css | 95 ++++++ src/components/CustomStyles.astro | 69 +++++ src/components/Favicons.astro | 10 + src/components/Logo.astro | 9 + src/components/blog/Grid.astro | 14 + src/components/blog/GridItem.astro | 71 +++++ src/components/blog/Headline.astro | 12 + src/components/blog/List.astro | 20 ++ src/components/blog/ListItem.astro | 120 ++++++++ src/components/blog/Pagination.astro | 36 +++ src/components/blog/RelatedPosts.astro | 31 ++ src/components/blog/SinglePost.astro | 103 +++++++ src/components/blog/Tags.astro | 43 +++ src/components/blog/ToBlogLink.astro | 20 ++ src/components/common/Analytics.astro | 13 + src/components/common/ApplyColorMode.astro | 33 ++ src/components/common/BasicScripts.astro | 255 ++++++++++++++++ src/components/common/CommonMeta.astro | 8 + src/components/common/Image.astro | 61 ++++ src/components/common/Metadata.astro | 68 +++++ src/components/common/SiteVerification.astro | 5 + src/components/common/SocialShare.astro | 65 ++++ src/components/common/SplitbeeAnalytics.astro | 6 + src/components/common/ToggleMenu.astro | 29 ++ src/components/common/ToggleTheme.astro | 28 ++ src/components/ui/Background.astro | 11 + src/components/ui/Button.astro | 40 +++ src/components/ui/DListItem.astro | 22 ++ src/components/ui/Form.astro | 87 ++++++ src/components/ui/Headline.astro | 35 +++ src/components/ui/ItemGrid.astro | 65 ++++ src/components/ui/ItemGrid2.astro | 59 ++++ src/components/ui/Timeline.astro | 60 ++++ src/components/ui/WidgetWrapper.astro | 34 +++ src/components/widgets/Announcement.astro | 16 + src/components/widgets/BlogHighlightedPosts.astro | 64 ++++ src/components/widgets/BlogLatestPosts.astro | 63 ++++ src/components/widgets/Brands.astro | 38 +++ src/components/widgets/CallToAction.astro | 58 ++++ src/components/widgets/CallToActionImage.astro | 73 +++++ src/components/widgets/Contact.astro | 40 +++ src/components/widgets/Content.astro | 94 ++++++ src/components/widgets/FAQs.astro | 33 ++ src/components/widgets/Features.astro | 36 +++ src/components/widgets/Features2.astro | 38 +++ src/components/widgets/Features3.astro | 70 +++++ src/components/widgets/Footer.astro | 61 ++++ src/components/widgets/Header.astro | 14 + src/components/widgets/Hero.astro | 99 ++++++ src/components/widgets/Hero2.astro | 99 ++++++ src/components/widgets/HeroText.astro | 86 ++++++ src/components/widgets/Note.astro | 23 ++ src/components/widgets/Pricing.astro | 83 +++++ src/components/widgets/Stats.astro | 46 +++ src/components/widgets/Steps.astro | 59 ++++ src/components/widgets/Steps2.astro | 79 +++++ src/components/widgets/Testimonials.astro | 75 +++++ src/config.yaml | 68 +++++ src/content/config.ts | 70 +++++ src/env.d.ts | 5 + src/layouts/LandingLayout.astro | 30 ++ src/layouts/Layout.astro | 48 +++ src/layouts/MarkdownLayout.astro | 28 ++ src/layouts/PageLayout.astro | 27 ++ src/navigation.ts | 130 ++++++++ src/pages/404.astro | 24 ++ src/pages/index.astro | 195 ++++++++++++ src/pages/polityka-prywatnosci.md | 37 +++ src/types.d.ts | 281 +++++++++++++++++ src/utils/blog.ts | 281 +++++++++++++++++ src/utils/directories.ts | 18 ++ src/utils/frontmatter.ts | 50 +++ src/utils/images-optimization.ts | 351 ++++++++++++++++++++++ src/utils/images.ts | 111 +++++++ src/utils/permalinks.ts | 134 +++++++++ src/utils/utils.ts | 52 ++++ 98 files changed, 5078 insertions(+) create mode 100644 src/assets/favicons/apple-touch-icon.png create mode 100644 src/assets/favicons/favicon.ico create mode 100644 src/assets/favicons/favicon.png create mode 100644 src/assets/favicons/favicon.svg create mode 100644 src/assets/images/app-store.png create mode 100644 src/assets/images/ceramic-coating.svg create mode 100644 src/assets/images/color-change.svg create mode 100644 src/assets/images/content-image-new.webp create mode 100644 src/assets/images/content-image.webp create mode 100644 src/assets/images/content-image2-new.webp create mode 100644 src/assets/images/content-image2.webp create mode 100644 src/assets/images/customworks-hero.webp create mode 100644 src/assets/images/customworks-logo.png create mode 100644 src/assets/images/engine-cleaning.svg create mode 100644 src/assets/images/google-play.png create mode 100644 src/assets/images/hero-image.jpg create mode 100644 src/assets/images/interior-detailing.svg create mode 100644 src/assets/images/invisible-wipers.svg create mode 100644 src/assets/images/paint-restoration.svg create mode 100644 src/assets/images/ppf-protection.svg create mode 100644 src/assets/images/rzetelna-firma-logo.png create mode 100644 src/assets/images/visual-tuning.svg create mode 100644 src/assets/styles/tailwind.css create mode 100644 src/components/CustomStyles.astro create mode 100644 src/components/Favicons.astro create mode 100644 src/components/Logo.astro create mode 100644 src/components/blog/Grid.astro create mode 100644 src/components/blog/GridItem.astro create mode 100644 src/components/blog/Headline.astro create mode 100644 src/components/blog/List.astro create mode 100644 src/components/blog/ListItem.astro create mode 100644 src/components/blog/Pagination.astro create mode 100644 src/components/blog/RelatedPosts.astro create mode 100644 src/components/blog/SinglePost.astro create mode 100644 src/components/blog/Tags.astro create mode 100644 src/components/blog/ToBlogLink.astro create mode 100644 src/components/common/Analytics.astro create mode 100644 src/components/common/ApplyColorMode.astro create mode 100644 src/components/common/BasicScripts.astro create mode 100644 src/components/common/CommonMeta.astro create mode 100644 src/components/common/Image.astro create mode 100644 src/components/common/Metadata.astro create mode 100644 src/components/common/SiteVerification.astro create mode 100644 src/components/common/SocialShare.astro create mode 100644 src/components/common/SplitbeeAnalytics.astro create mode 100644 src/components/common/ToggleMenu.astro create mode 100644 src/components/common/ToggleTheme.astro create mode 100644 src/components/ui/Background.astro create mode 100644 src/components/ui/Button.astro create mode 100644 src/components/ui/DListItem.astro create mode 100644 src/components/ui/Form.astro create mode 100644 src/components/ui/Headline.astro create mode 100644 src/components/ui/ItemGrid.astro create mode 100644 src/components/ui/ItemGrid2.astro create mode 100644 src/components/ui/Timeline.astro create mode 100644 src/components/ui/WidgetWrapper.astro create mode 100644 src/components/widgets/Announcement.astro create mode 100644 src/components/widgets/BlogHighlightedPosts.astro create mode 100644 src/components/widgets/BlogLatestPosts.astro create mode 100644 src/components/widgets/Brands.astro create mode 100644 src/components/widgets/CallToAction.astro create mode 100644 src/components/widgets/CallToActionImage.astro create mode 100644 src/components/widgets/Contact.astro create mode 100644 src/components/widgets/Content.astro create mode 100644 src/components/widgets/FAQs.astro create mode 100644 src/components/widgets/Features.astro create mode 100644 src/components/widgets/Features2.astro create mode 100644 src/components/widgets/Features3.astro create mode 100644 src/components/widgets/Footer.astro create mode 100644 src/components/widgets/Header.astro create mode 100644 src/components/widgets/Hero.astro create mode 100644 src/components/widgets/Hero2.astro create mode 100644 src/components/widgets/HeroText.astro create mode 100644 src/components/widgets/Note.astro create mode 100644 src/components/widgets/Pricing.astro create mode 100644 src/components/widgets/Stats.astro create mode 100644 src/components/widgets/Steps.astro create mode 100644 src/components/widgets/Steps2.astro create mode 100644 src/components/widgets/Testimonials.astro create mode 100644 src/config.yaml create mode 100644 src/content/config.ts create mode 100644 src/env.d.ts create mode 100644 src/layouts/LandingLayout.astro create mode 100644 src/layouts/Layout.astro create mode 100644 src/layouts/MarkdownLayout.astro create mode 100644 src/layouts/PageLayout.astro create mode 100644 src/navigation.ts create mode 100644 src/pages/404.astro create mode 100644 src/pages/index.astro create mode 100644 src/pages/polityka-prywatnosci.md create mode 100644 src/types.d.ts create mode 100644 src/utils/blog.ts create mode 100644 src/utils/directories.ts create mode 100644 src/utils/frontmatter.ts create mode 100644 src/utils/images-optimization.ts create mode 100644 src/utils/images.ts create mode 100644 src/utils/permalinks.ts create mode 100644 src/utils/utils.ts (limited to 'src') diff --git a/src/assets/favicons/apple-touch-icon.png b/src/assets/favicons/apple-touch-icon.png new file mode 100644 index 0000000..b5cdb19 Binary files /dev/null and b/src/assets/favicons/apple-touch-icon.png differ diff --git a/src/assets/favicons/favicon.ico b/src/assets/favicons/favicon.ico new file mode 100644 index 0000000..cc0080d Binary files /dev/null and b/src/assets/favicons/favicon.ico differ diff --git a/src/assets/favicons/favicon.png b/src/assets/favicons/favicon.png new file mode 100644 index 0000000..f7cf5c7 Binary files /dev/null and b/src/assets/favicons/favicon.png differ diff --git a/src/assets/favicons/favicon.svg b/src/assets/favicons/favicon.svg new file mode 100644 index 0000000..8fcd56b --- /dev/null +++ b/src/assets/favicons/favicon.svg @@ -0,0 +1,20 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + + + + diff --git a/src/assets/images/app-store.png b/src/assets/images/app-store.png new file mode 100644 index 0000000..8d634c0 Binary files /dev/null and b/src/assets/images/app-store.png differ diff --git a/src/assets/images/ceramic-coating.svg b/src/assets/images/ceramic-coating.svg new file mode 100644 index 0000000..ecf7c18 --- /dev/null +++ b/src/assets/images/ceramic-coating.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/color-change.svg b/src/assets/images/color-change.svg new file mode 100644 index 0000000..9f9d7ad --- /dev/null +++ b/src/assets/images/color-change.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/content-image-new.webp b/src/assets/images/content-image-new.webp new file mode 100644 index 0000000..899afc1 Binary files /dev/null and b/src/assets/images/content-image-new.webp differ diff --git a/src/assets/images/content-image.webp b/src/assets/images/content-image.webp new file mode 100644 index 0000000..3c2c1f5 Binary files /dev/null and b/src/assets/images/content-image.webp differ diff --git a/src/assets/images/content-image2-new.webp b/src/assets/images/content-image2-new.webp new file mode 100644 index 0000000..f0ff71e Binary files /dev/null and b/src/assets/images/content-image2-new.webp differ diff --git a/src/assets/images/content-image2.webp b/src/assets/images/content-image2.webp new file mode 100644 index 0000000..498d480 Binary files /dev/null and b/src/assets/images/content-image2.webp differ diff --git a/src/assets/images/customworks-hero.webp b/src/assets/images/customworks-hero.webp new file mode 100644 index 0000000..f2c54f1 Binary files /dev/null and b/src/assets/images/customworks-hero.webp differ diff --git a/src/assets/images/customworks-logo.png b/src/assets/images/customworks-logo.png new file mode 100644 index 0000000..5305ce7 Binary files /dev/null and b/src/assets/images/customworks-logo.png differ diff --git a/src/assets/images/engine-cleaning.svg b/src/assets/images/engine-cleaning.svg new file mode 100644 index 0000000..64691ca --- /dev/null +++ b/src/assets/images/engine-cleaning.svg @@ -0,0 +1,2 @@ + + diff --git a/src/assets/images/google-play.png b/src/assets/images/google-play.png new file mode 100644 index 0000000..179f1ff Binary files /dev/null and b/src/assets/images/google-play.png differ diff --git a/src/assets/images/hero-image.jpg b/src/assets/images/hero-image.jpg new file mode 100644 index 0000000..9aee81c Binary files /dev/null and b/src/assets/images/hero-image.jpg differ diff --git a/src/assets/images/interior-detailing.svg b/src/assets/images/interior-detailing.svg new file mode 100644 index 0000000..fcf50a2 --- /dev/null +++ b/src/assets/images/interior-detailing.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/images/invisible-wipers.svg b/src/assets/images/invisible-wipers.svg new file mode 100644 index 0000000..b5ac70b --- /dev/null +++ b/src/assets/images/invisible-wipers.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/paint-restoration.svg b/src/assets/images/paint-restoration.svg new file mode 100644 index 0000000..499f8f0 --- /dev/null +++ b/src/assets/images/paint-restoration.svg @@ -0,0 +1,2 @@ + + diff --git a/src/assets/images/ppf-protection.svg b/src/assets/images/ppf-protection.svg new file mode 100644 index 0000000..ceeafd0 --- /dev/null +++ b/src/assets/images/ppf-protection.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/rzetelna-firma-logo.png b/src/assets/images/rzetelna-firma-logo.png new file mode 100644 index 0000000..cc9332a Binary files /dev/null and b/src/assets/images/rzetelna-firma-logo.png differ diff --git a/src/assets/images/visual-tuning.svg b/src/assets/images/visual-tuning.svg new file mode 100644 index 0000000..76afbd5 --- /dev/null +++ b/src/assets/images/visual-tuning.svg @@ -0,0 +1,2 @@ + + diff --git a/src/assets/styles/tailwind.css b/src/assets/styles/tailwind.css new file mode 100644 index 0000000..a086ee1 --- /dev/null +++ b/src/assets/styles/tailwind.css @@ -0,0 +1,95 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer utilities { + .bg-page { + background-color: var(--aw-color-bg-page); + } + .bg-dark { + background-color: var(--aw-color-bg-page-dark); + } + .bg-light { + background-color: var(--aw-color-bg-page); + } + .bg-section { + background-color: var(--aw-color-bg-section); + } + .text-page { + color: var(--aw-color-text-page); + } + .text-muted { + color: var(--aw-color-text-muted); + } +} + +@layer components { + .btn { + @apply inline-flex items-center justify-center rounded-full border-gray-400 border bg-transparent font-medium text-center text-base text-page leading-snug transition py-3.5 px-6 md:px-8 ease-in duration-200 focus:ring-primary focus:ring-offset-2 focus:ring-2 focus:ring-offset-2 hover:bg-gray-100 hover:border-primary dark:text-slate-300 dark:border-slate-500 dark:hover:bg-slate-800 dark:hover:border-slate-800 cursor-pointer; + } + + .btn-primary { + @apply btn font-semibold bg-primary text-white border-primary hover:bg-secondary hover:border-secondary hover:text-white dark:text-white dark:bg-primary dark:border-primary dark:hover:border-secondary dark:hover:bg-secondary; + } + + .btn-secondary { + @apply btn; + } + + .btn-tertiary { + @apply btn border-none shadow-none text-muted hover:text-default dark:text-gray-400 dark:hover:text-white; + } +} + +#header.scroll > div:first-child { + @apply bg-page md:bg-white/90 md:backdrop-blur-md; + box-shadow: 0 0.375rem 1.5rem 0 rgb(140 152 164 / 13%); +} +.dark #header.scroll > div:first-child, +#header.scroll.dark > div:first-child { + @apply bg-page md:bg-[#030621e6] border-b border-gray-500/20; + box-shadow: none; +} +/* #header.scroll > div:last-child { + @apply py-3; +} */ + +#header.expanded nav { + position: fixed; + top: 70px; + left: 0; + right: 0; + bottom: 70px !important; + padding: 0 5px; +} + +.dropdown:focus .dropdown-menu, +.dropdown:focus-within .dropdown-menu, +.dropdown:hover .dropdown-menu { + display: block; +} + +[astro-icon].icon-light > * { + stroke-width: 1.2; +} + +[astro-icon].icon-bold > * { + stroke-width: 2.4; +} + +[data-aw-toggle-menu] path { + @apply transition; +} +[data-aw-toggle-menu].expanded g > path:first-child { + @apply -rotate-45 translate-y-[15px] translate-x-[-3px]; +} + +[data-aw-toggle-menu].expanded g > path:last-child { + @apply rotate-45 translate-y-[-8px] translate-x-[14px]; +} + +/* To deprecated */ + +.dd *:first-child { + margin-top: 0; +} diff --git a/src/components/CustomStyles.astro b/src/components/CustomStyles.astro new file mode 100644 index 0000000..9798cb6 --- /dev/null +++ b/src/components/CustomStyles.astro @@ -0,0 +1,69 @@ +--- +import '@fontsource/kanit'; +import '@fontsource/poppins'; + +// 'DM Sans' +// Nunito +// Dosis +// Outfit +// Roboto +// Literata +// 'IBM Plex Sans' +// Karla +// Poppins +// 'Fira Sans' +// 'Libre Franklin' +// Inconsolata +// Raleway +// Oswald +// 'Space Grotesk' +// Urbanist +--- + + diff --git a/src/components/Favicons.astro b/src/components/Favicons.astro new file mode 100644 index 0000000..fed6696 --- /dev/null +++ b/src/components/Favicons.astro @@ -0,0 +1,10 @@ +--- +import favIcon from '~/assets/favicons/favicon.ico'; +import favIconSvg from '~/assets/favicons/favicon.svg'; +import appleTouchIcon from '~/assets/favicons/apple-touch-icon.png'; +--- + + + + + diff --git a/src/components/Logo.astro b/src/components/Logo.astro new file mode 100644 index 0000000..8469792 --- /dev/null +++ b/src/components/Logo.astro @@ -0,0 +1,9 @@ +--- +import { SITE } from 'astrowind:config'; +--- + + + 🚀 {SITE?.name} + diff --git a/src/components/blog/Grid.astro b/src/components/blog/Grid.astro new file mode 100644 index 0000000..1b62be4 --- /dev/null +++ b/src/components/blog/Grid.astro @@ -0,0 +1,14 @@ +--- +import Item from '~/components/blog/GridItem.astro'; +import type { Post } from '~/types'; + +export interface Props { + posts: Array; +} + +const { posts } = Astro.props; +--- + +
+ {posts.map((post) => )} +
diff --git a/src/components/blog/GridItem.astro b/src/components/blog/GridItem.astro new file mode 100644 index 0000000..73353ca --- /dev/null +++ b/src/components/blog/GridItem.astro @@ -0,0 +1,71 @@ +--- +import { APP_BLOG } from 'astrowind:config'; +import type { Post } from '~/types'; + +import Image from '~/components/common/Image.astro'; + +import { findImage } from '~/utils/images'; +import { getPermalink } from '~/utils/permalinks'; + +export interface Props { + post: Post; +} + +const { post } = Astro.props; +const image = await findImage(post.image); + +const link = APP_BLOG?.post?.isEnabled ? getPermalink(post.permalink, 'post') : ''; +--- + +
+
+ { + image && + (link ? ( + + {post.title} + + ) : ( + {post.title} + )) + } +
+ +

+ { + link ? ( + + {post.title} + + ) : ( + post.title + ) + } +

+ +

{post.excerpt}

+
diff --git a/src/components/blog/Headline.astro b/src/components/blog/Headline.astro new file mode 100644 index 0000000..5d3ccc6 --- /dev/null +++ b/src/components/blog/Headline.astro @@ -0,0 +1,12 @@ +--- +const { title = await Astro.slots.render('default'), subtitle = await Astro.slots.render('subtitle') } = Astro.props; +--- + +
+

+ { + subtitle && ( +
+ ) + } +

diff --git a/src/components/blog/List.astro b/src/components/blog/List.astro new file mode 100644 index 0000000..6a80ae3 --- /dev/null +++ b/src/components/blog/List.astro @@ -0,0 +1,20 @@ +--- +import Item from '~/components/blog/ListItem.astro'; +import type { Post } from '~/types'; + +export interface Props { + posts: Array; +} + +const { posts } = Astro.props; +--- + +
    + { + posts.map((post) => ( +
  • + +
  • + )) + } +
diff --git a/src/components/blog/ListItem.astro b/src/components/blog/ListItem.astro new file mode 100644 index 0000000..36602f2 --- /dev/null +++ b/src/components/blog/ListItem.astro @@ -0,0 +1,120 @@ +--- +import type { ImageMetadata } from 'astro'; +import { Icon } from 'astro-icon/components'; +import Image from '~/components/common/Image.astro'; +import PostTags from '~/components/blog/Tags.astro'; + +import { APP_BLOG } from 'astrowind:config'; +import type { Post } from '~/types'; + +import { getPermalink } from '~/utils/permalinks'; +import { findImage } from '~/utils/images'; +import { getFormattedDate } from '~/utils/utils'; + +export interface Props { + post: Post; +} + +const { post } = Astro.props; +const image = (await findImage(post.image)) as ImageMetadata | undefined; + +const link = APP_BLOG?.post?.isEnabled ? getPermalink(post.permalink, 'post') : ''; +--- + +
+ { + image && + (link ? ( + + + + ) : ( + + )) + } +
+
+
+ + + + { + post.author && ( + <> + {' '} + · + {post.author.replaceAll('-', ' ')} + + ) + } + { + post.category && ( + <> + {' '} + ·{' '} + + {post.category.title} + + + ) + } + +
+

+ { + link ? ( + + {post.title} + + ) : ( + post.title + ) + } +

+
+ + {post.excerpt &&

{post.excerpt}

} + { + post.tags && Array.isArray(post.tags) ? ( +
+ +
+ ) : ( + + ) + } +
+
diff --git a/src/components/blog/Pagination.astro b/src/components/blog/Pagination.astro new file mode 100644 index 0000000..051587c --- /dev/null +++ b/src/components/blog/Pagination.astro @@ -0,0 +1,36 @@ +--- +import { Icon } from 'astro-icon/components'; +import { getPermalink } from '~/utils/permalinks'; +import Button from '~/components/ui/Button.astro'; + +export interface Props { + prevUrl?: string; + nextUrl?: string; + prevText?: string; + nextText?: string; +} + +const { prevUrl, nextUrl, prevText = 'Newer posts', nextText = 'Older posts' } = Astro.props; +--- + +{ + (prevUrl || nextUrl) && ( +
+
+ + + +
+
+ ) +} diff --git a/src/components/blog/RelatedPosts.astro b/src/components/blog/RelatedPosts.astro new file mode 100644 index 0000000..f4036e9 --- /dev/null +++ b/src/components/blog/RelatedPosts.astro @@ -0,0 +1,31 @@ +--- +import { APP_BLOG } from 'astrowind:config'; + +import { getRelatedPosts } from '~/utils/blog'; +import BlogHighlightedPosts from '../widgets/BlogHighlightedPosts.astro'; +import type { Post } from '~/types'; +import { getBlogPermalink } from '~/utils/permalinks'; + +export interface Props { + post: Post; +} + +const { post } = Astro.props; + +const relatedPosts = post.tags ? await getRelatedPosts(post, 4) : []; +--- + +{ + APP_BLOG.isRelatedPostsEnabled ? ( + post.id)} + /> + ) : null +} diff --git a/src/components/blog/SinglePost.astro b/src/components/blog/SinglePost.astro new file mode 100644 index 0000000..ac92cd3 --- /dev/null +++ b/src/components/blog/SinglePost.astro @@ -0,0 +1,103 @@ +--- +import { Icon } from 'astro-icon/components'; + +import Image from '~/components/common/Image.astro'; +import PostTags from '~/components/blog/Tags.astro'; +import SocialShare from '~/components/common/SocialShare.astro'; + +import { getPermalink } from '~/utils/permalinks'; +import { getFormattedDate } from '~/utils/utils'; + +import type { Post } from '~/types'; + +export interface Props { + post: Post; + url: string | URL; +} + +const { post, url } = Astro.props; +--- + +
+
+
+
+

+ + + { + post.author && ( + <> + {' '} + · + {post.author} + + ) + } + { + post.category && ( + <> + {' '} + ·{' '} + + {post.category.title} + + + ) + } + { + post.readingTime && ( + <> +  · {post.readingTime} min read + + ) + } +

+
+ +

+ {post.title} +

+

+ {post.excerpt} +

+ + { + post.image ? ( + {post?.excerpt + ) : ( +
+
+
+ ) + } +
+
+ +
+
+ + +
+
+
diff --git a/src/components/blog/Tags.astro b/src/components/blog/Tags.astro new file mode 100644 index 0000000..ae46a24 --- /dev/null +++ b/src/components/blog/Tags.astro @@ -0,0 +1,43 @@ +--- +import { getPermalink } from '~/utils/permalinks'; + +import { APP_BLOG } from 'astrowind:config'; +import type { Post } from '~/types'; + +export interface Props { + tags: Post['tags']; + class?: string; + title?: string | undefined; + isCategory?: boolean; +} + +const { tags, class: className = 'text-sm', title = undefined, isCategory = false } = Astro.props; +--- + +{ + tags && Array.isArray(tags) && ( + <> + {title !== undefined && ( + + {title} + + )} +
    + {tags.map((tag) => ( +
  • + {!APP_BLOG?.tag?.isEnabled ? ( + tag.title + ) : ( + + {tag.title} + + )} +
  • + ))} +
+ + ) +} diff --git a/src/components/blog/ToBlogLink.astro b/src/components/blog/ToBlogLink.astro new file mode 100644 index 0000000..7fb7a49 --- /dev/null +++ b/src/components/blog/ToBlogLink.astro @@ -0,0 +1,20 @@ +--- +import { Icon } from 'astro-icon/components'; +import { getBlogPermalink } from '~/utils/permalinks'; +import { I18N } from 'astrowind:config'; +import Button from '~/components/ui/Button.astro'; + +const { textDirection } = I18N; +--- + +
+ +
diff --git a/src/components/common/Analytics.astro b/src/components/common/Analytics.astro new file mode 100644 index 0000000..a1a553d --- /dev/null +++ b/src/components/common/Analytics.astro @@ -0,0 +1,13 @@ +--- +import { GoogleAnalytics } from '@astrolib/analytics'; +import { ANALYTICS } from 'astrowind:config'; +--- + +{ + ANALYTICS?.vendors?.googleAnalytics?.id ? ( + + ) : null +} diff --git a/src/components/common/ApplyColorMode.astro b/src/components/common/ApplyColorMode.astro new file mode 100644 index 0000000..d0d97fe --- /dev/null +++ b/src/components/common/ApplyColorMode.astro @@ -0,0 +1,33 @@ +--- +import { UI } from 'astrowind:config'; + +// TODO: This code is temporary +--- + + diff --git a/src/components/common/BasicScripts.astro b/src/components/common/BasicScripts.astro new file mode 100644 index 0000000..c7290b2 --- /dev/null +++ b/src/components/common/BasicScripts.astro @@ -0,0 +1,255 @@ +--- +import { UI } from 'astrowind:config'; +--- + + + + diff --git a/src/components/common/CommonMeta.astro b/src/components/common/CommonMeta.astro new file mode 100644 index 0000000..aab6dd4 --- /dev/null +++ b/src/components/common/CommonMeta.astro @@ -0,0 +1,8 @@ +--- +import { getAsset } from '~/utils/permalinks'; +--- + + + + + diff --git a/src/components/common/Image.astro b/src/components/common/Image.astro new file mode 100644 index 0000000..d113b68 --- /dev/null +++ b/src/components/common/Image.astro @@ -0,0 +1,61 @@ +--- +import type { HTMLAttributes } from 'astro/types'; +import { findImage } from '~/utils/images'; +import { + getImagesOptimized, + astroAssetsOptimizer, + unpicOptimizer, + isUnpicCompatible, + type ImageProps, +} from '~/utils/images-optimization'; + +type Props = ImageProps; +type ImageType = { + src: string; + attributes: HTMLAttributes<'img'>; +}; + +const props = Astro.props; + +if (props.alt === undefined || props.alt === null) { + throw new Error(); +} + +if (typeof props.width === 'string') { + props.width = parseInt(props.width); +} + +if (typeof props.height === 'string') { + props.height = parseInt(props.height); +} + +if (!props.loading) { + props.loading = 'lazy'; +} + +if (!props.decoding) { + props.decoding = 'async'; +} + +const _image = await findImage(props.src); + +let image: ImageType | undefined = undefined; + +if ( + typeof _image === 'string' && + (_image.startsWith('http://') || _image.startsWith('https://')) && + isUnpicCompatible(_image) +) { + image = await getImagesOptimized(_image, props, unpicOptimizer); +} else if (_image) { + image = await getImagesOptimized(_image, props, astroAssetsOptimizer); +} +--- + +{ + !image ? ( + + ) : ( + + ) +} diff --git a/src/components/common/Metadata.astro b/src/components/common/Metadata.astro new file mode 100644 index 0000000..a4c573e --- /dev/null +++ b/src/components/common/Metadata.astro @@ -0,0 +1,68 @@ +--- +import merge from 'lodash.merge'; +import { AstroSeo } from '@astrolib/seo'; + +import type { Props as AstroSeoProps } from '@astrolib/seo'; + +import { SITE, METADATA, I18N } from 'astrowind:config'; +import type { MetaData } from '~/types'; +import { getCanonical } from '~/utils/permalinks'; + +import { adaptOpenGraphImages } from '~/utils/images'; + +export interface Props extends MetaData { + dontUseTitleTemplate?: boolean; +} + +const { + title, + ignoreTitleTemplate = false, + canonical = String(getCanonical(String(Astro.url.pathname))), + robots = {}, + description, + openGraph = {}, + twitter = {}, +} = Astro.props; + +const seoProps: AstroSeoProps = merge( + { + title: '', + titleTemplate: '%s', + canonical: canonical, + noindex: true, + nofollow: true, + description: undefined, + openGraph: { + url: canonical, + site_name: SITE?.name, + images: [], + locale: I18N?.language || 'en', + type: 'website', + }, + twitter: { + cardType: openGraph?.images?.length ? 'summary_large_image' : 'summary', + }, + }, + { + title: METADATA?.title?.default, + titleTemplate: METADATA?.title?.template, + noindex: typeof METADATA?.robots?.index !== 'undefined' ? !METADATA.robots.index : undefined, + nofollow: typeof METADATA?.robots?.follow !== 'undefined' ? !METADATA.robots.follow : undefined, + description: METADATA?.description, + openGraph: METADATA?.openGraph, + twitter: METADATA?.twitter, + }, + { + title: title, + titleTemplate: ignoreTitleTemplate ? '%s' : undefined, + canonical: canonical, + noindex: typeof robots?.index !== 'undefined' ? !robots.index : undefined, + nofollow: typeof robots?.follow !== 'undefined' ? !robots.follow : undefined, + description: description, + openGraph: { url: canonical, ...openGraph }, + twitter: twitter, + } +); +--- + + diff --git a/src/components/common/SiteVerification.astro b/src/components/common/SiteVerification.astro new file mode 100644 index 0000000..000baad --- /dev/null +++ b/src/components/common/SiteVerification.astro @@ -0,0 +1,5 @@ +--- +import { SITE } from 'astrowind:config'; +--- + +{SITE.googleSiteVerificationId && } diff --git a/src/components/common/SocialShare.astro b/src/components/common/SocialShare.astro new file mode 100644 index 0000000..d035e8f --- /dev/null +++ b/src/components/common/SocialShare.astro @@ -0,0 +1,65 @@ +--- +import { Icon } from 'astro-icon/components'; + +export interface Props { + text: string; + url: string | URL; + class?: string; +} + +const { text, url, class: className = 'inline-block' } = Astro.props; +--- + +
+ Share: + + + + + +
diff --git a/src/components/common/SplitbeeAnalytics.astro b/src/components/common/SplitbeeAnalytics.astro new file mode 100644 index 0000000..66651db --- /dev/null +++ b/src/components/common/SplitbeeAnalytics.astro @@ -0,0 +1,6 @@ +--- +const { doNotTrack = true, noCookieMode = false, url = 'https://cdn.splitbee.io/sb.js' } = Astro.props; +--- + + + diff --git a/src/components/common/ToggleMenu.astro b/src/components/common/ToggleMenu.astro new file mode 100644 index 0000000..2d19b16 --- /dev/null +++ b/src/components/common/ToggleMenu.astro @@ -0,0 +1,29 @@ +--- +export interface Props { + label?: string; + class?: string; +} + +const { + label = 'Toggle Menu', + class: className = 'flex flex-col h-12 w-12 rounded justify-center items-center cursor-pointer group', +} = Astro.props; +--- + + diff --git a/src/components/common/ToggleTheme.astro b/src/components/common/ToggleTheme.astro new file mode 100644 index 0000000..8f3aafb --- /dev/null +++ b/src/components/common/ToggleTheme.astro @@ -0,0 +1,28 @@ +--- +import { Icon } from 'astro-icon/components'; + +import { UI } from 'astrowind:config'; + +export interface Props { + label?: string; + class?: string; + iconClass?: string; + iconName?: string; +} + +const { + label = 'Toggle between Dark and Light mode', + class: + className = 'text-muted dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5 inline-flex items-center', + iconClass = 'w-6 h-6', + iconName = 'tabler:sun', +} = Astro.props; +--- + +{ + !(UI.theme && UI.theme.endsWith(':only')) && ( + + ) +} diff --git a/src/components/ui/Background.astro b/src/components/ui/Background.astro new file mode 100644 index 0000000..f220487 --- /dev/null +++ b/src/components/ui/Background.astro @@ -0,0 +1,11 @@ +--- +export interface Props { + isDark?: boolean; +} + +const { isDark = false } = Astro.props; +--- + +
+ +
diff --git a/src/components/ui/Button.astro b/src/components/ui/Button.astro new file mode 100644 index 0000000..d3c2398 --- /dev/null +++ b/src/components/ui/Button.astro @@ -0,0 +1,40 @@ +--- +import { Icon } from 'astro-icon/components'; +import { twMerge } from 'tailwind-merge'; +import type { CallToAction as Props } from '~/types'; + +const { + variant = 'secondary', + target, + text = Astro.slots.render('default'), + icon = '', + class: className = '', + type, + ...rest +} = Astro.props; + +const variants = { + primary: 'btn-primary', + secondary: 'btn-secondary', + tertiary: 'btn btn-tertiary', + link: 'cursor-pointer hover:text-primary', +}; +--- + +{ + type === 'button' || type === 'submit' || type === 'reset' ? ( + + ) : ( + + + {icon && } + + ) +} diff --git a/src/components/ui/DListItem.astro b/src/components/ui/DListItem.astro new file mode 100644 index 0000000..36d4072 --- /dev/null +++ b/src/components/ui/DListItem.astro @@ -0,0 +1,22 @@ +--- +// component: DListItem +// +// Mimics the html 'dl' (description list) +// +// The 'dt' item is the item 'term' and is inserted into an 'h6' tag. +// Caller needs to style the 'h6' tag appropriately. +// +// You can put pretty much any content you want between the open and +// closing tags - it's simply contained in an enclosing div with a +// margin left. No need for 'dd' items. +// +const { dt } = Astro.props; +interface Props { + dt: string; +} + +const content: string = await Astro.slots.render('default'); +--- + +
+
diff --git a/src/components/ui/Form.astro b/src/components/ui/Form.astro new file mode 100644 index 0000000..276b39f --- /dev/null +++ b/src/components/ui/Form.astro @@ -0,0 +1,87 @@ +--- +import type { Form as Props } from '~/types'; +import Button from '~/components/ui/Button.astro'; + +const { inputs, textarea, disclaimer, button = 'Contact us', description = '' } = Astro.props; +--- + +
+ { + inputs && + inputs.map( + ({ type = 'text', name, label = '', autocomplete = 'on', placeholder = '' }) => + name && ( +
+ {label && ( + + )} + +
+ ) + ) + } + + { + textarea && ( +
+ +