diff --git a/.gitignore b/.gitignore index d574012f..8b5569b3 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,7 @@ yarn-error.log* package-lock.json # astro build files -.astro \ No newline at end of file +.astro + +# cursor rules +.cursor/rules \ No newline at end of file diff --git a/README.md b/README.md index bc2ff79f..5e2aab8a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![accessible-astro-starter](https://github.com/user-attachments/assets/f3538452-5d57-4118-b713-4631dd51bd84) -A ready-to-use, SEO and accessibility-focused Astro starter template. Built with modern web standards and WCAG guidelines in mind, it provides a solid foundation for creating inclusive websites. Features Tailwind CSS integration, comprehensive component library, and example pages including a dynamic blog, 404, and MDX support. +A ready-to-use, SEO and accessibility-focused Astro starter template. Built with modern web standards and WCAG guidelines in mind, it provides a solid foundation for creating inclusive websites. Features Tailwind CSS 4 integration, comprehensive component library, color contrast checker, and typography with Atkinson Hyperlegible font for improved readability. Includes dynamic blog/portfolio pages with social sharing, and full MDX support. [![LIVE DEMO](https://img.shields.io/badge/LIVE_DEMO-4ECCA3?style=for-the-badge&logo=astro&logoColor=black)](https://accessible-astro-starter.incluud.dev/)   [![DOCUMENTATION](https://img.shields.io/badge/DOCUMENTATION-A682FF?style=for-the-badge&logo=astro&logoColor=black)](https://accessible-astro.incluud.dev/)   @@ -16,30 +16,39 @@ A ready-to-use, SEO and accessibility-focused Astro starter template. Built with ## (Accessibility) Features -- Astro 5+ -- Tailwind CSS support +- Astro 5.7.5+ +- Tailwind CSS 4 support +- TypeScript integration with path aliases for easier imports - Prettier integration with `prettier-plugin-astro` and `prettier-plugin-tailwind` - ESLint integration with strict accessibility settings for `eslint-plugin-jsx-a11y` -- Markdown and MDX support with examples included in the theme -- Uses the awesome `astro-icon` package for the icons +- Markdown and MDX support with comprehensive examples and components +- Modern OKLCH color system with automatic palette generation from primary/secondary colors +- Atkinson Hyperlegible font for improved readability and accessibility +- Lucide icon set via `astro-icon` for consistent, friendly icons - Excellent Lighthouse/PageSpeed scores - Accessible landmarks such as `header`, `main`, `footer`, `section` and `nav` - Outline focus indicator which works on dark and light backgrounds - Several `aria` attributes which provide a better experience for screen reader users - `[...page].astro` and `[post].astro` demonstrate the use of dynamic routes and provide a basic blog with breadcrumbs and pagination - `404.astro` provides a custom 404 error page which you can adjust to your needs -- `Header.astro` component included in the `DefaultLayout.astro` layout -- `Footer.astro` component included in the `DefaultLayout.astro` layout +- `Header.astro` component with optimized accessibility and design +- `Footer.astro` component with informative content and links - `SkipLinks.astro` component to skip to either the main menu or the main content -- `Navigation.astro` component with keyboard accessible (dropdown) navigation (arrow keys, escape key) -- `ResponsiveToggle.astro` component with an accessible responsive toggle button for the mobile navigation +- `Navigation.astro` component with keyboard accessible (dropdown) navigation and highlighted menu item option +- `ResponsiveToggle.astro` component with accessible responsive toggle functionality - `DarkMode.astro` component toggle with accessible button and a user system preferred color scheme setting - `SiteMeta.astro` SEO component for setting custom meta data on different pages - `.sr-only` utility class for screen reader only text content (hides text visually) - `prefers-reduced-motion` disables animations for users that have this preference turned on -- Ships with many components such as Accordions, Breadcrumbs, Modals, Pagination [and many more](https://accessible-astro-starter.incluud.dev/accessible-components/) -- A collection of utility classes such as breakpoints, button classes, font settings, resets and outlines in `src/assets/scss/base` -- Astro's View Transitions +- Components including `ColorContrast.astro`, `BlockQuote.astro`, `BreakoutImage.astro`, `ExternalLink.astro`, `Logo.astro`, `SocialShares.astro`, and `PageHeader.astro` +- Blog and portfolio pages with featured images, author details, social sharing, and breakout images +- Accessibility Statement template page +- Color Contrast Checker interactive page +- Smooth micro-interactions and animations on hover, open and close states (respecting reduced motion preferences) +- Comprehensive SCSS utility classes +- CSS with logical properties and custom properties +- Accessible button and hyperlink styling with clear focus states +- Styled `` element for keyboard shortcut documentation ## Getting started @@ -59,7 +68,7 @@ Clone this theme locally and run any of the following commands in your terminal: - [Accessible Astro Dashboard](https://github.com/incluud/accessible-astro-dashboard/): User-friendly dashboard interface with a login screen and widgets. - [Accessible Astro Docs](https://github.com/incluud/accessible-astro-docs): Comprehensive documentation for all Accessible Astro projects. -Check out our [roadmap](https://github.com/orgs/incluud/projects/4/views/1) to see what's coming next! +Check out our [roadmap](https://github.com/orgs/incluud/projects/4/views/1) to see what's coming next! ## Contributing diff --git a/astro.config.mjs b/astro.config.mjs index 10522435..19752e9a 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,21 +1,16 @@ import { defineConfig } from 'astro/config' import mdx from '@astrojs/mdx' -import tailwind from '@astrojs/tailwind' import compress from 'astro-compress' import icon from 'astro-icon' +import tailwindcss from '@tailwindcss/vite' +import { fileURLToPath } from 'url' +import path from 'path' // https://astro.build/config export default defineConfig({ compressHTML: true, - site: 'https://accessible-astro.netlify.app', - integrations: [ - mdx(), - icon(), - tailwind({ - applyBaseStyles: false, - }), - compress(), - ], + site: 'https://accessible-astro-starter.incluud.dev', + integrations: [mdx(), icon(), compress()], vite: { css: { preprocessorOptions: { @@ -26,5 +21,18 @@ export default defineConfig({ }, }, }, + plugins: [tailwindcss()], + resolve: { + alias: { + '@components': fileURLToPath(new URL('./src/components', import.meta.url)), + '@layouts': fileURLToPath(new URL('./src/layouts', import.meta.url)), + '@assets': fileURLToPath(new URL('./src/assets', import.meta.url)), + '@content': fileURLToPath(new URL('./src/content', import.meta.url)), + '@pages': fileURLToPath(new URL('./src/pages', import.meta.url)), + '@public': fileURLToPath(new URL('./public', import.meta.url)), + '@post-images': fileURLToPath(new URL('./public/posts', import.meta.url)), + '@project-images': fileURLToPath(new URL('./public/projects', import.meta.url)), + }, + }, }, }) diff --git a/package.json b/package.json index ab679a33..3869948b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "accessible-astro-starter", "description": "An Accessible Starter Theme for Astro including several accessibility features and tools to help you build faster.", - "version": "3.4.1", + "version": "4.0.0", "author": "Incluud", "license": "MIT", "homepage": "https://accessible-astro.netlify.app/", @@ -22,7 +22,8 @@ "responsive", "ui-library", "ui-components", - "blog" + "blog", + "portfolio" ], "repository": { "type": "git", @@ -32,28 +33,28 @@ "url": "https://github.com/incluud/accessible-astro-starter/issues" }, "devDependencies": { - "@astrojs/mdx": "^4.0.8", - "@astrojs/partytown": "^2.1.3", - "@astrojs/tailwind": "^6.0.0", - "@iconify-json/ion": "^1.2.1", - "@iconify-json/mdi": "^1.2.1", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", - "astro": "^5.3.0", - "astro-compress": "^2.3.5", - "astro-icon": "^1.1.4", - "eslint": "^8.57.0", - "eslint-plugin-astro": "^0.31.4", + "@astrojs/mdx": "^4.2.5", + "@astrojs/partytown": "^2.1.4", + "@iconify-json/lucide": "^1.2.39", + "@typescript-eslint/eslint-plugin": "^8.31.0", + "@typescript-eslint/parser": "^8.31.0", + "astro": "^5.7.5", + "astro-compress": "^2.3.8", + "astro-icon": "^1.1.5", + "eslint": "^9.0.0", + "eslint-plugin-astro": "^1.3.1", "eslint-plugin-jsx-a11y": "^6.10.2", - "prettier": "^3.4.1", + "prettier": "^3.5.3", "prettier-plugin-astro": "^0.14.1", "prettier-plugin-css-order": "^2.1.2", - "prettier-plugin-tailwindcss": "^0.6.9", - "sass": "^1.81.0", + "prettier-plugin-tailwindcss": "^0.6.11", + "sanitize-html": "^2.16.0", + "sass": "^1.87.0", "svgo": "^3.3.2", - "tailwindcss": "^3.4.15" + "tailwindcss": "^4.1.4" }, "dependencies": { - "accessible-astro-components": "^4.1.0" + "@tailwindcss/vite": "^4.1.4", + "accessible-astro-components": "^4.1.1" } } diff --git a/public/fonts/AtkinsonHyperlegibleNext-Bold.woff2 b/public/fonts/AtkinsonHyperlegibleNext-Bold.woff2 new file mode 100644 index 00000000..3b735977 Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-Bold.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-BoldItalic.woff2 b/public/fonts/AtkinsonHyperlegibleNext-BoldItalic.woff2 new file mode 100644 index 00000000..25b28580 Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-BoldItalic.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-ExtraBold.woff2 b/public/fonts/AtkinsonHyperlegibleNext-ExtraBold.woff2 new file mode 100644 index 00000000..65039ac4 Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-ExtraBold.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-ExtraBoldItalic.woff2 b/public/fonts/AtkinsonHyperlegibleNext-ExtraBoldItalic.woff2 new file mode 100644 index 00000000..5abb72ec Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-ExtraBoldItalic.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-ExtraLight.woff2 b/public/fonts/AtkinsonHyperlegibleNext-ExtraLight.woff2 new file mode 100644 index 00000000..5a136036 Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-ExtraLight.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-ExtraLightItalic.woff2 b/public/fonts/AtkinsonHyperlegibleNext-ExtraLightItalic.woff2 new file mode 100644 index 00000000..ad1940c3 Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-ExtraLightItalic.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-Light.woff2 b/public/fonts/AtkinsonHyperlegibleNext-Light.woff2 new file mode 100644 index 00000000..b1eac3fd Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-Light.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-LightItalic.woff2 b/public/fonts/AtkinsonHyperlegibleNext-LightItalic.woff2 new file mode 100644 index 00000000..f0f492f2 Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-LightItalic.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-Medium.woff2 b/public/fonts/AtkinsonHyperlegibleNext-Medium.woff2 new file mode 100644 index 00000000..e82765dd Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-Medium.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-MediumItalic.woff2 b/public/fonts/AtkinsonHyperlegibleNext-MediumItalic.woff2 new file mode 100644 index 00000000..c9e218a1 Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-MediumItalic.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-Regular.woff2 b/public/fonts/AtkinsonHyperlegibleNext-Regular.woff2 new file mode 100644 index 00000000..d2babdfc Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-Regular.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-RegularItalic.woff2 b/public/fonts/AtkinsonHyperlegibleNext-RegularItalic.woff2 new file mode 100644 index 00000000..dc05d06d Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-RegularItalic.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-SemiBold.woff2 b/public/fonts/AtkinsonHyperlegibleNext-SemiBold.woff2 new file mode 100644 index 00000000..a7d9ece2 Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-SemiBold.woff2 differ diff --git a/public/fonts/AtkinsonHyperlegibleNext-SemiBoldItalic.woff2 b/public/fonts/AtkinsonHyperlegibleNext-SemiBoldItalic.woff2 new file mode 100644 index 00000000..f9111766 Binary files /dev/null and b/public/fonts/AtkinsonHyperlegibleNext-SemiBoldItalic.woff2 differ diff --git a/public/fonts/OFL.txt b/public/fonts/OFL.txt new file mode 100644 index 00000000..ed208c10 --- /dev/null +++ b/public/fonts/OFL.txt @@ -0,0 +1,89 @@ +Copyright (c) 2020, Braille Institute of America, Inc. (https://www.brailleinstitute.org/), +with Reserved Font Names: "ATKINSON" and "HYPERLEGIBLE". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Names" refers to any names specified as such after the +copyright statement. + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder. + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical writer or other +person who contributed to the Font Software. + +PERMISSION & CONDITIONS +VP/#68933639.2 +Permission is hereby granted, free of charge, to any person obtaining a copy of the Font +Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and +unmodified copies of the Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in Original or +Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, redistributed +and/or sold with any software, provided that each copy contains the above copyright +notice and this license. These can be included either as stand-alone text files, human- +readable headers or in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Names unless +explicit written permission is granted by the Copyright Holder. This restriction only +applies to the primary font name as presented to the users. + +4) The name of the Copyright Holder or the Author(s) of the Font Software shall not be +used to promote, endorse or advertise any Modified Version, except to acknowledge the +contributions of the Copyright Holder and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be distributed +entirely under this license, and must not be distributed under any other license. The +requirement for fonts to remain under this license does not apply to any document +created using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO +EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR +CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT +SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/public/fonts/OpenSans-Bold.woff b/public/fonts/OpenSans-Bold.woff deleted file mode 100644 index 7b4560a9..00000000 Binary files a/public/fonts/OpenSans-Bold.woff and /dev/null differ diff --git a/public/fonts/OpenSans-Bold.woff2 b/public/fonts/OpenSans-Bold.woff2 deleted file mode 100644 index 68926688..00000000 Binary files a/public/fonts/OpenSans-Bold.woff2 and /dev/null differ diff --git a/public/fonts/OpenSans-ExtraBold.woff b/public/fonts/OpenSans-ExtraBold.woff deleted file mode 100644 index a9335c15..00000000 Binary files a/public/fonts/OpenSans-ExtraBold.woff and /dev/null differ diff --git a/public/fonts/OpenSans-ExtraBold.woff2 b/public/fonts/OpenSans-ExtraBold.woff2 deleted file mode 100644 index 7f1d713d..00000000 Binary files a/public/fonts/OpenSans-ExtraBold.woff2 and /dev/null differ diff --git a/public/fonts/OpenSans-Italic.woff b/public/fonts/OpenSans-Italic.woff deleted file mode 100644 index 3035b2cd..00000000 Binary files a/public/fonts/OpenSans-Italic.woff and /dev/null differ diff --git a/public/fonts/OpenSans-Italic.woff2 b/public/fonts/OpenSans-Italic.woff2 deleted file mode 100644 index da25c280..00000000 Binary files a/public/fonts/OpenSans-Italic.woff2 and /dev/null differ diff --git a/public/fonts/OpenSans-Regular.woff b/public/fonts/OpenSans-Regular.woff deleted file mode 100644 index 3ccb7bdd..00000000 Binary files a/public/fonts/OpenSans-Regular.woff and /dev/null differ diff --git a/public/fonts/OpenSans-Regular.woff2 b/public/fonts/OpenSans-Regular.woff2 deleted file mode 100644 index 8171d775..00000000 Binary files a/public/fonts/OpenSans-Regular.woff2 and /dev/null differ diff --git a/public/posts/post-image-1.png b/public/posts/post-image-1.png new file mode 100644 index 00000000..6f6f5745 Binary files /dev/null and b/public/posts/post-image-1.png differ diff --git a/public/posts/post-image-2.png b/public/posts/post-image-2.png new file mode 100644 index 00000000..394c766f Binary files /dev/null and b/public/posts/post-image-2.png differ diff --git a/public/posts/post-image-3.png b/public/posts/post-image-3.png new file mode 100644 index 00000000..94059c0f Binary files /dev/null and b/public/posts/post-image-3.png differ diff --git a/public/posts/post-image-4.png b/public/posts/post-image-4.png new file mode 100644 index 00000000..c193798c Binary files /dev/null and b/public/posts/post-image-4.png differ diff --git a/public/posts/post-image-5.png b/public/posts/post-image-5.png new file mode 100644 index 00000000..7898fbf3 Binary files /dev/null and b/public/posts/post-image-5.png differ diff --git a/public/posts/post-image-6.png b/public/posts/post-image-6.png new file mode 100644 index 00000000..ec82ef74 Binary files /dev/null and b/public/posts/post-image-6.png differ diff --git a/public/projects/project-image-1.png b/public/projects/project-image-1.png new file mode 100644 index 00000000..6f6f5745 Binary files /dev/null and b/public/projects/project-image-1.png differ diff --git a/public/projects/project-image-2.png b/public/projects/project-image-2.png new file mode 100644 index 00000000..394c766f Binary files /dev/null and b/public/projects/project-image-2.png differ diff --git a/public/projects/project-image-3.png b/public/projects/project-image-3.png new file mode 100644 index 00000000..94059c0f Binary files /dev/null and b/public/projects/project-image-3.png differ diff --git a/public/projects/project-image-4.png b/public/projects/project-image-4.png new file mode 100644 index 00000000..c193798c Binary files /dev/null and b/public/projects/project-image-4.png differ diff --git a/public/projects/project-image-5.png b/public/projects/project-image-5.png new file mode 100644 index 00000000..7898fbf3 Binary files /dev/null and b/public/projects/project-image-5.png differ diff --git a/public/projects/project-image-6.png b/public/projects/project-image-6.png new file mode 100644 index 00000000..ec82ef74 Binary files /dev/null and b/public/projects/project-image-6.png differ diff --git a/public/social-preview-image.png b/public/social-preview-image.png index beaf305a..51fa2967 100644 Binary files a/public/social-preview-image.png and b/public/social-preview-image.png differ diff --git a/src/assets/images/posts/post-image-1.png b/src/assets/images/posts/post-image-1.png new file mode 100644 index 00000000..6f6f5745 Binary files /dev/null and b/src/assets/images/posts/post-image-1.png differ diff --git a/src/assets/images/posts/post-image-2.png b/src/assets/images/posts/post-image-2.png new file mode 100644 index 00000000..394c766f Binary files /dev/null and b/src/assets/images/posts/post-image-2.png differ diff --git a/src/assets/images/posts/post-image-3.png b/src/assets/images/posts/post-image-3.png new file mode 100644 index 00000000..94059c0f Binary files /dev/null and b/src/assets/images/posts/post-image-3.png differ diff --git a/src/assets/images/posts/post-image-4.png b/src/assets/images/posts/post-image-4.png new file mode 100644 index 00000000..c193798c Binary files /dev/null and b/src/assets/images/posts/post-image-4.png differ diff --git a/src/assets/images/posts/post-image-5.png b/src/assets/images/posts/post-image-5.png new file mode 100644 index 00000000..7898fbf3 Binary files /dev/null and b/src/assets/images/posts/post-image-5.png differ diff --git a/src/assets/images/posts/post-image-6.png b/src/assets/images/posts/post-image-6.png new file mode 100644 index 00000000..ec82ef74 Binary files /dev/null and b/src/assets/images/posts/post-image-6.png differ diff --git a/src/assets/images/projects/project-image-1.png b/src/assets/images/projects/project-image-1.png new file mode 100644 index 00000000..6f6f5745 Binary files /dev/null and b/src/assets/images/projects/project-image-1.png differ diff --git a/src/assets/images/projects/project-image-2.png b/src/assets/images/projects/project-image-2.png new file mode 100644 index 00000000..394c766f Binary files /dev/null and b/src/assets/images/projects/project-image-2.png differ diff --git a/src/assets/images/projects/project-image-3.png b/src/assets/images/projects/project-image-3.png new file mode 100644 index 00000000..94059c0f Binary files /dev/null and b/src/assets/images/projects/project-image-3.png differ diff --git a/src/assets/images/projects/project-image-4.png b/src/assets/images/projects/project-image-4.png new file mode 100644 index 00000000..c193798c Binary files /dev/null and b/src/assets/images/projects/project-image-4.png differ diff --git a/src/assets/images/projects/project-image-5.png b/src/assets/images/projects/project-image-5.png new file mode 100644 index 00000000..7898fbf3 Binary files /dev/null and b/src/assets/images/projects/project-image-5.png differ diff --git a/src/assets/images/projects/project-image-6.png b/src/assets/images/projects/project-image-6.png new file mode 100644 index 00000000..ec82ef74 Binary files /dev/null and b/src/assets/images/projects/project-image-6.png differ diff --git a/src/assets/scss/base/_breakpoint.scss b/src/assets/scss/base/_breakpoint.scss index 70f6920f..ddb1fa92 100644 --- a/src/assets/scss/base/_breakpoint.scss +++ b/src/assets/scss/base/_breakpoint.scss @@ -1,26 +1,23 @@ -@use 'sass:map'; - -// | ------------------------------------------------------------- -// | Breakpoint -// | ------------------------------------------------------------- - $breakpoints: ( 'default': 0, - 'small': 24em, - 'medium': 48em, - 'large': 75em, + 'xs': 320px, + 's': 480px, + 'm': 768px, + 'l': 1024px, + 'xl': 1280px, + '2xl': 1536px, ) !default; @mixin breakpoint($breakpoint) { - @if map.has-key($breakpoints, $breakpoint) { - @media (min-width: map.get($breakpoints, $breakpoint)) { + @if map-has-key($breakpoints, $breakpoint) { + @media (min-width: map-get($breakpoints, $breakpoint)) { @content; } } @else if (type_of($breakpoint) == number) { - @media (min-width: $breakpoint+'px') { + @media (min-width: #{$breakpoint}px) { @content; } } @else { - @error "Not a correct value, check _base-breakpoints for available values."; + @error "Not a correct value"; } } diff --git a/src/assets/scss/base/_button.scss b/src/assets/scss/base/_button.scss index b205d4ad..8adc665a 100644 --- a/src/assets/scss/base/_button.scss +++ b/src/assets/scss/base/_button.scss @@ -1,146 +1,52 @@ -// | ------------------------------------------------------------- -// | Button -// | ------------------------------------------------------------- +@use './mixins' as *; .button { - display: inline-block; - padding: 0.75rem 1rem; - font-weight: bold; - text-decoration: none; - text-align: center; - color: var(--neutral-900); - background-color: var(--primary-100); - border: 3px solid var(--primary-100); - border-radius: 3px; - transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; - - &:hover, - &:focus { - text-decoration: underline; - background-color: var(--primary-200); - border-color: var(--primary-200); - } - - &:visited { - color: var(--neutral-900); + display: inline-flex; + position: relative; + justify-content: center; + align-items: center; + transition: all var(--animation-speed-fast) var(--cubic-bezier); + cursor: pointer; + border: 3px solid light-dark(var(--color-primary-200), var(--color-primary-100)); + border-radius: var(--radius-s); + background-color: light-dark(var(--color-primary-200), var(--color-primary-100)); + padding: var(--space-xs) var(--space-s); + inline-size: fit-content; + color: var(--color-neutral-900); + font-weight: 700; + + @include text-decoration(transparent, currentColor); + + &:where(:hover, :focus-visible) { + border-color: light-dark(var(--color-primary-300), var(--color-primary-300)); + background-color: light-dark(var(--color-primary-300), var(--color-primary-300)); + text-decoration-thickness: 2px; } &.color-secondary { - background-color: var(--secondary-100); - border-color: (var(--secondary-100)); - - &:hover, - &:focus { - background-color: var(--secondary-400); - border-color: var(--secondary-400); - } - } - - &.color-neutral { - background-color: var(--neutral-500); - border-color: (var(--neutral-500)); - - &:hover, - &:focus { - background-color: var(--neutral-400); - border-color: var(--neutral-400); - } - } - - &.color-info { - background-color: var(--info-300); - border-color: (var(--info-300)); + border-color: light-dark(var(--color-secondary-100), var(--color-secondary-100)); + background-color: light-dark(var(--color-secondary-100), var(--color-secondary-100)); - &:hover, - &:focus { - background-color: var(--info-200); - border-color: var(--info-200); - } - } - - &.color-success { - background-color: var(--success-400); - border-color: (var(--success-400)); - - &:hover, - &:focus { - background-color: var(--success-300); - border-color: var(--success-300); - } - } - - &.color-warning { - background-color: var(--warning-400); - border-color: (var(--warning-400)); - - &:hover, - &:focus { - background-color: var(--warning-300); - border-color: var(--warning-300); - } - } - - &.color-error { - background-color: var(--error-300); - border-color: (var(--error-300)); - - &:hover, - &:focus { - background-color: var(--error-200); - border-color: var(--error-200); - } - } - - &.size-tiny { - padding: 0.125rem 0.25rem; - font-size: 0.75rem; - line-height: 1.125rem; - } - - &.size-small { - padding: 0.25rem 0.5rem; - font-size: 0.875rem; - line-height: 1.3125rem; - } - - &.size-large { - padding: 0.75rem 1rem; - font-size: 1.125rem; - line-height: 1.6875rem; - } - - &.size-huge { - padding: 1rem 2rem; - font-size: 1.25rem; - line-height: 1.875rem; - } - - &.behavior-full { - display: block; - width: 100%; - } - - &.type-secondary { - background-color: transparent; - - &:hover, - &:focus { - background-color: transparent; + &:where(:hover, :focus-visible) { + border-color: light-dark(var(--color-secondary-300), var(--color-secondary-300)); + background-color: light-dark(var(--color-secondary-300), var(--color-secondary-300)); } } &.has-icon { display: flex; align-items: center; - gap: 0.5rem; + gap: var(--space-2xs); [data-icon] { - height: auto; - width: 30px; + inline-size: 30px; + block-size: auto; } - } -} -.darkmode .button.type-secondary { - color: var(--neutral-100); + &:where(:hover, :focus-visible) { + [data-icon] { + animation: boop 0.5s cubic-bezier(0.165, 0.84, 0.44, 1) forwards; + } + } + } } diff --git a/src/assets/scss/base/_color.scss b/src/assets/scss/base/_color.scss deleted file mode 100644 index ef2e06e3..00000000 --- a/src/assets/scss/base/_color.scss +++ /dev/null @@ -1,34 +0,0 @@ -// | ------------------------------------------------------------- -// | Color -// | ------------------------------------------------------------- - -$colors: ( - primary: ( - 100: hsl(276, 100%, 79%), - 200: hsl(276, 79%, 69%), - 300: hsl(276, 53%, 49%), - 400: hsl(276, 64%, 48%), - 500: hsl(276, 96%, 20%), - ), - secondary: ( - 100: hsl(173, 81%, 68%), - 200: hsl(173, 80%, 63%), - 300: hsl(173, 72%, 57%), - 400: hsl(173, 75%, 47%), - 500: hsl(173, 90%, 30%), - ), - neutral: ( - 100: hsl(0 0% 100%), - 200: hsl(200 23% 97%), - 300: hsl(200 12% 95%), - 400: hsl(205 12% 88%), - 500: hsl(209 13% 83%), - 600: hsl(208 6% 55%), - 700: hsl(210 8% 31%), - 800: hsl(212 9% 22%), - 900: hsl(210 10% 14%), - ), - dark: ( - 100: hsl(240, 4%, 9%), - ), -); diff --git a/src/assets/scss/base/_container.scss b/src/assets/scss/base/_container.scss deleted file mode 100644 index e76f0df2..00000000 --- a/src/assets/scss/base/_container.scss +++ /dev/null @@ -1,24 +0,0 @@ -// | ------------------------------------------------------------- -// | Container -// | ------------------------------------------------------------- - -@use "breakpoint" as *; - -.container { - margin: 0 auto; - padding: 0 calc(2rem / 2); - max-width: 100%; - - @include breakpoint(medium) { - padding: 0 2rem; - } - - @include breakpoint(large) { - padding: 0 calc(2rem / 2); - max-width: 1200px; - } - - &.stretch { - max-width: 100%; - } -} \ No newline at end of file diff --git a/src/assets/scss/base/_font.scss b/src/assets/scss/base/_font.scss index 76d663bc..9af25d84 100644 --- a/src/assets/scss/base/_font.scss +++ b/src/assets/scss/base/_font.scss @@ -1,161 +1,160 @@ -// | ------------------------------------------------------------- -// | Font -// | ------------------------------------------------------------- - @use 'breakpoint' as *; +// Atkinson Hyperlegible font faces @font-face { - font-family: 'Open Sans'; - src: - local('Open Sans ExtraBold'), - local('OpenSans-ExtraBold'), - url('/fonts/OpenSans-ExtraBold.woff2') format('woff2'), - url('/fonts/OpenSans-ExtraBold.woff') format('woff'); - font-weight: bold; font-style: normal; + font-weight: 400; + src: + local('Atkinson Hyperlegible Regular'), + local('AtkinsonHyperlegible-Regular'), + url('/fonts/AtkinsonHyperlegibleNext-Regular.woff2') format('woff2'); + font-family: 'Atkinson Hyperlegible'; font-display: swap; } @font-face { - font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; src: - local('Open Sans Bold'), - local('OpenSans-Bold'), - url('/fonts/OpenSans-Bold.woff2') format('woff2'), - url('/fonts/OpenSans-Bold.woff') format('woff'); - font-weight: bold; - font-style: normal; + local('Atkinson Hyperlegible Italic'), + local('AtkinsonHyperlegible-Italic'), + url('/fonts/AtkinsonHyperlegibleNext-RegularItalic.woff2') format('woff2'); + font-family: 'Atkinson Hyperlegible'; font-display: swap; } @font-face { - font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; src: - local('Open Sans Italic'), - local('OpenSans-Italic'), - url('/fonts/OpenSans-Italic.woff2') format('woff2'), - url('/fonts/OpenSans-Italic.woff') format('woff'); - font-weight: normal; + local('Atkinson Hyperlegible Bold'), + local('AtkinsonHyperlegible-Bold'), + url('/fonts/AtkinsonHyperlegibleNext-Bold.woff2') format('woff2'); + font-family: 'Atkinson Hyperlegible'; + font-display: swap; +} + +@font-face { font-style: italic; + font-weight: 700; + src: + local('Atkinson Hyperlegible Bold Italic'), + local('AtkinsonHyperlegible-BoldItalic'), + url('/fonts/AtkinsonHyperlegibleNext-BoldItalic.woff2') format('woff2'); + font-family: 'Atkinson Hyperlegible'; + font-display: swap; +} + +// Additional weights +@font-face { + font-style: normal; + font-weight: 300; + src: + local('Atkinson Hyperlegible Light'), + local('AtkinsonHyperlegible-Light'), + url('/fonts/AtkinsonHyperlegibleNext-Light.woff2') format('woff2'); + font-family: 'Atkinson Hyperlegible'; font-display: swap; } @font-face { - font-family: 'Open Sans'; + font-style: italic; + font-weight: 300; src: - local('Open Sans Regular'), - local('OpenSans-Regular'), - url('/fonts/OpenSans-Regular.woff2') format('woff2'), - url('/fonts/OpenSans-Regular.woff') format('woff'); - font-weight: normal; + local('Atkinson Hyperlegible Light Italic'), + local('AtkinsonHyperlegible-LightItalic'), + url('/fonts/AtkinsonHyperlegibleNext-LightItalic.woff2') format('woff2'); + font-family: 'Atkinson Hyperlegible'; + font-display: swap; +} + +@font-face { font-style: normal; + font-weight: 500; + src: + local('Atkinson Hyperlegible Medium'), + local('AtkinsonHyperlegible-Medium'), + url('/fonts/AtkinsonHyperlegibleNext-Medium.woff2') format('woff2'); + font-family: 'Atkinson Hyperlegible'; font-display: swap; } -body { - font-family: var(--font-family-default); - text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px; - text-rendering: optimizeLegibility; - font-synthesis: none; - font-size: 1rem; - line-height: 1.5rem; - -webkit-text-size-adjust: 100%; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - - a:not(.button) { - color: var(--action-color); - text-decoration: underline; - - &:visited { - color: var(--action-color); - } - - &:hover, - &:focus { - color: var(--action-color-state); - text-decoration: none; - } - } +@font-face { + font-style: italic; + font-weight: 500; + src: + local('Atkinson Hyperlegible Medium Italic'), + local('AtkinsonHyperlegible-MediumItalic'), + url('/fonts/AtkinsonHyperlegibleNext-MediumItalic.woff2') format('woff2'); + font-family: 'Atkinson Hyperlegible'; + font-display: swap; +} + +@font-face { + font-style: normal; + font-weight: 600; + src: + local('Atkinson Hyperlegible SemiBold'), + local('AtkinsonHyperlegible-SemiBold'), + url('/fonts/AtkinsonHyperlegibleNext-SemiBold.woff2') format('woff2'); + font-family: 'Atkinson Hyperlegible'; + font-display: swap; +} - :where(main) a { - word-wrap: break-word; - word-break: break-word; +@layer base { + p { + text-wrap: pretty; } - :where(h1, h2) { - font-family: var(--font-family-special); + h1, + h2, + h3, + h4, + h5, + h6 { + font-family: var(--font-heading); + text-wrap: balance; } h1, h2 { - font-weight: 800; + font-weight: 600; } h3, h4, h5, h6 { - font-weight: 600; + font-weight: 500; } h1 { - font-size: 2.25rem; - line-height: 3.375rem; - - @include breakpoint(medium) { - font-size: 3rem; - line-height: 3.625rem; - } + font-size: var(--font-size-6); + line-height: var(--font-size-7); } h2 { - font-size: 1.875rem; - line-height: 2.8125rem; - - @include breakpoint(medium) { - font-size: 2.25rem; - line-height: 3.375rem; - } + font-size: var(--font-size-5); + line-height: var(--font-size-6); } h3 { - font-size: 1.5rem; - line-height: 2.25rem; - - @include breakpoint(medium) { - font-size: 1.875rem; - line-height: 2.8125rem; - } + font-size: var(--font-size-4); + line-height: var(--font-size-5); } h4 { - font-size: 1.25rem; - line-height: 1.875rem; - - @include breakpoint(medium) { - font-size: 1.5rem; - line-height: 2.25rem; - } + font-size: var(--font-size-3); + line-height: var(--font-size-4); } h5 { - font-size: 1.125rem; - line-height: 1.6875rem; - - @include breakpoint(medium) { - font-size: 1.25rem; - line-height: 1.875rem; - } + font-size: var(--font-size-2); + line-height: var(--font-size-3); } h6 { - font-size: 1rem; - line-height: 1.5rem; - - @include breakpoint(medium) { - font-size: 1.125rem; - line-height: 1.6875rem; - } + font-size: var(--font-size-1); + line-height: var(--font-size-2); } } diff --git a/src/assets/scss/base/_general.scss b/src/assets/scss/base/_general.scss new file mode 100644 index 00000000..dfc0df05 --- /dev/null +++ b/src/assets/scss/base/_general.scss @@ -0,0 +1,61 @@ +@use './mixins' as *; + +@view-transition { + navigation: auto; +} + +body { + font-weight: 400; + font-size: 1.15rem; + line-height: 1.5; + font-family: var(--font-body); + font-synthesis: none; + text-rendering: optimizeLegibility; + text-shadow: rgba(0, 0, 0, 0.01) 0 0 1px; + -webkit-text-size-adjust: 100%; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + background-color: var(--background-color); + color: var(--foreground-color); +} + +a { + transition: color var(--animation-speed-fast) var(--cubic-bezier); + color: var(--link-color); + + &:where(:hover, :focus-visible) { + color: var(--link-hover-color); + } +} + +main a, +footer a { + @include text-decoration(var(--link-color), var(--link-hover-color)); + + color: var(--link-color); + + &:where(:hover, :focus-visible) { + color: var(--link-hover-color); + } + + &.external-link { + display: inline-flex; + align-items: center; + gap: var(--space-3xs); + + // small visual correction + svg { + margin-block-start: 3px; + } + } +} + +*:focus, +*:focus-visible { + @include outline; +} + +*:focus:not(:focus-visible) { + outline: none; + box-shadow: none; +} diff --git a/src/assets/scss/base/_kbd.scss b/src/assets/scss/base/_kbd.scss new file mode 100644 index 00000000..0407dfdc --- /dev/null +++ b/src/assets/scss/base/_kbd.scss @@ -0,0 +1,18 @@ +kbd { + position: relative; + inset-block-start: -1px; + box-shadow: 0 2px 0 1px light-dark(var(--color-neutral-400), var(--color-neutral-700)); + border: 1px solid light-dark(var(--color-neutral-400), var(--color-neutral-600)); + border-radius: var(--radius-s); + background-color: light-dark(var(--color-neutral-200), var(--color-neutral-800)); + padding: var(--space-4xs) var(--space-3xs); + aspect-ratio: var(--ratio-square); + min-inline-size: 12px; + color: light-dark(var(--color-neutral-900), var(--color-neutral-100)); + font-size: var(--font-size--2); + font-family: var(--font-family-sans-serif); + + &.flat { + box-shadow: none; + } +} diff --git a/src/assets/scss/base/_list.scss b/src/assets/scss/base/_list.scss index a3ca0706..2cfeaace 100644 --- a/src/assets/scss/base/_list.scss +++ b/src/assets/scss/base/_list.scss @@ -1,67 +1,60 @@ -// | ------------------------------------------------------------- -// | Lists -// | ------------------------------------------------------------- - @use 'breakpoint' as *; ul:not([class]), ol:not([class]) { - margin-left: 1rem; + margin-inline-start: var(--space-s); ul, ol { - padding: 0.5rem 1rem 0; + padding-inline-start: var(--space-s); } li { - margin-bottom: 0.5rem; + margin-block-end: var(--space-xs); } } ul:not([class]) { - > li::marker { - display: block; - color: var(--primary-800); - } + list-style-type: disc; } ol.incremented { counter-reset: item; +} - ol { - counter-reset: item; - } +ol.incremented ol { + counter-reset: item; +} - ol, - ul { - margin: 0.75rem 0 0 1rem; - } +ol.incremented ol, +ol.incremented ul { + margin: var(--space-xs) 0 0 var(--space-s); +} - li { - display: block; - margin-bottom: 0.5rem; +ol.incremented li { + display: block; + margin-block-end: var(--space-xs); +} - @include breakpoint(medium) { - margin-bottom: 0.75rem; - } +@media screen and (max-width: 48rem) { + ol.incremented li { + margin-block-end: var(--space-xs); + } +} - &::before { - content: counters(item, '.') '. '; - counter-increment: item; - } +ol.incremented li::before { + counter-increment: item; + content: counters(item, '.') '. '; +} - &:last-child { - margin-bottom: 0; - } +ol.incremented li:last-child { + margin-block-end: 0; +} - p { - display: inline; - } - } +ol.incremented li p { + display: inline; +} - ul { - li::before { - content: ''; - } - } +ol.incremented ul li::before { + content: ''; } diff --git a/src/assets/scss/base/_mixins.scss b/src/assets/scss/base/_mixins.scss new file mode 100644 index 00000000..21ae63b5 --- /dev/null +++ b/src/assets/scss/base/_mixins.scss @@ -0,0 +1,56 @@ +@mixin text-decoration( + $color: var(--text-decoration-color), + $hoverColor: var(--text-decoration-hover-color), + $thickness: 2px, + $hoverThickness: 1px, + $underlineOffset: 4px, + $hoverUnderlineOffset: 2px +) { + transition: text-decoration, text-underline-offset, text-decoration-color, text-decoration-thickness; + transition-duration: var(--animation-speed-fast); + transition-timing-function: var(--cubic-bezier); + text-decoration: underline; + text-decoration-style: solid; + text-decoration-color: $color; + text-decoration-thickness: $thickness; + text-decoration-skip-ink: none; + text-underline-offset: $underlineOffset; + + &:where(:hover, :focus-visible) { + text-decoration-color: $hoverColor; + text-decoration-thickness: $hoverThickness; + text-underline-offset: $hoverUnderlineOffset; + } +} + +@mixin outline { + outline: 2px dashed black; + outline-color: black; + outline-offset: 0; + -webkit-box-shadow: 0 0 0 2px white; + box-shadow: 0 0 0 2px white; +} + +@mixin sr-only { + position: absolute; + margin: -1px; + padding: 0; + inline-size: 1px; + block-size: 1px; + overflow: clip; + clip: rect(0, 0, 0, 0); + border-width: 0; + white-space: nowrap; +} + +@mixin rotate-icon-on-hover { + .icon svg { + transition: rotate var(--animation-speed-fast) var(--cubic-bezier); + } + + &:where(:hover, :focus-visible) { + .icon svg { + rotate: -90deg; + } + } +} diff --git a/src/assets/scss/base/_outline.scss b/src/assets/scss/base/_outline.scss deleted file mode 100644 index 44b5e676..00000000 --- a/src/assets/scss/base/_outline.scss +++ /dev/null @@ -1,21 +0,0 @@ -// | ------------------------------------------------------------- -// | Outline -// | ------------------------------------------------------------- - -@mixin outline { - outline: 2px dotted black; - outline-color: black; - outline-offset: 0; - -webkit-box-shadow: 0 0 0 2px white; - box-shadow: 0 0 0 2px white; -} - -*:focus, -*:focus-visible { - @include outline; -} - -*:focus:not(:focus-visible) { - outline: none; - box-shadow: none; -} diff --git a/src/assets/scss/base/_reset.scss b/src/assets/scss/base/_reset.scss index fe59939c..295432dc 100644 --- a/src/assets/scss/base/_reset.scss +++ b/src/assets/scss/base/_reset.scss @@ -1,121 +1,130 @@ -// | ------------------------------------------------------------- -// | > Reset -// | ------------------------------------------------------------- +@layer base { + html { + box-sizing: border-box; + scroll-behavior: smooth; + } -html { - box-sizing: border-box; - scroll-behavior: smooth; + *, + *::after, + *::before { + box-sizing: inherit; + } - @media (prefers-reduced-motion: reduce) { - scroll-behavior: auto; + *:focus, + *:focus-visible { + outline: 2px dashed black; + outline-color: black; + outline-offset: 0; + -webkit-box-shadow: 0 0 0 2px white; + box-shadow: 0 0 0 2px white; + } - body * { - animation-duration: 0s !important; - animation-delay: 0s !important; - } + *:focus:not(:focus-visible) { + outline: none; + box-shadow: none; } -} -*, -*::after, -*::before { - box-sizing: inherit; -} + blockquote, + body, + figure, + h1, + h2, + h3, + h4, + h5, + h6, + hr, + li, + ol, + p, + pre, + ul { + margin: 0; + padding: 0; + } -blockquote, -body, -figure, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -li, -ol, -p, -pre, -ul { - margin: 0; - padding: 0; -} + ul:where([class]) { + list-style: none; + } -ul:where([class]) { - list-style: none; -} + button, + input, + select, + textarea { + color: inherit; + font: inherit; + letter-spacing: inherit; + } -button, -input, -select, -textarea { - color: inherit; - letter-spacing: inherit; - font: inherit; -} + input[type='text'], + textarea { + inline-size: 100%; + } -input[type="text"], -textarea { - width: 100%; -} + fieldset { + border: none; + padding: 0; + } -fieldset { - padding: 0; - border: none; -} + legend { + margin-block-end: 0.5rem; + max-inline-size: 100%; + } -legend { - margin-bottom: 0.5rem; - max-width: 100%; -} + input, + textarea { + border: 1px solid gray; + } -button, -input, -textarea { - border: 1px solid gray; -} + button { + border: none; + border-radius: 0; + background-color: transparent; + padding: 0; + } -button { - padding: 0.75em 1em; - border-radius: 0; - background-color: transparent; - line-height: 1; -} + button * { + pointer-events: none; + } -button * { - pointer-events: none; -} + button:hover { + cursor: pointer; + } -button:hover { - cursor: pointer; -} + embed, + iframe, + img, + object, + svg, + video { + display: block; + max-width: 100%; + } -embed, -iframe, -img, -object, -svg, -video { - display: block; - max-width: 100%; -} + table { + inline-size: 100%; + table-layout: fixed; + } -table { - width: 100%; - table-layout: fixed; -} + [hidden] { + display: none !important; + } -[hidden] { - display: none !important; -} + noscript { + display: block; + margin-block-start: 1em; + margin-block-end: 1em; + } -noscript { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} + [tabindex='-1'] { + outline: none !important; + box-shadow: none !important; + } -[tabindex="-1"] { - outline: none !important; - box-shadow: none !important; + [popover] { + position: absolute; + inset: auto; + border: none; + padding: 0; + } } diff --git a/src/assets/scss/base/_root.scss b/src/assets/scss/base/_root.scss index 52b7faba..59d97eb6 100644 --- a/src/assets/scss/base/_root.scss +++ b/src/assets/scss/base/_root.scss @@ -1,16 +1,150 @@ -// | ------------------------------------------------------------- -// | Root -// | ------------------------------------------------------------- - -@use 'color' as *; - :root { - color-scheme: light dark; + color-scheme: light; interpolate-size: allow-keywords; - @each $color, $shades in $colors { - @each $shade, $value in $shades { - --#{$color}-#{$shade}: #{$value}; - } - } + // brand colors (change these to your own brand colors) + --brand-primary: #d648ff; + --brand-secondary: #00d1b7; + --brand-neutral: #b9bec4; + + // pallet brand + --color-primary-100: oklch(from var(--brand-primary) 90% c h); + --color-primary-200: oklch(from var(--brand-primary) 80% c h); + --color-primary-300: oklch(from var(--brand-primary) 70% c h); + --color-primary-400: oklch(from var(--brand-primary) 60% c h); + --color-primary-500: oklch(from var(--brand-primary) 50% c h); + --color-secondary-100: oklch(from var(--brand-secondary) 90% c h); + --color-secondary-200: oklch(from var(--brand-secondary) 80% c h); + --color-secondary-300: oklch(from var(--brand-secondary) 70% c h); + --color-secondary-400: oklch(from var(--brand-secondary) 60% c h); + --color-secondary-500: oklch(from var(--brand-secondary) 50% c h); + + // pallet neutral + --color-neutral-100: oklch(from var(--brand-neutral) 100% 0 0); + --color-neutral-200: oklch(from var(--brand-neutral) 95% c h); + --color-neutral-300: oklch(from var(--brand-neutral) 90% c h); + --color-neutral-400: oklch(from var(--brand-neutral) 85% c h); + --color-neutral-500: oklch(from var(--brand-neutral) 80% c h); + --color-neutral-600: oklch(from var(--brand-neutral) 60% c h); + --color-neutral-700: oklch(from var(--brand-neutral) 40% c h); + --color-neutral-800: oklch(from var(--brand-neutral) 30% c h); + --color-neutral-900: oklch(from var(--brand-neutral) 15% c h); + + // color scheme + --foreground-color: light-dark(var(--color-neutral-800), var(--color-neutral-100)); + --background-color: light-dark(var(--color-neutral-100), var(--color-neutral-900)); + --icon-color: light-dark(var(--color-neutral-800), var(--color-neutral-100)); + --link-color: light-dark(var(--color-primary-400), var(--color-secondary-100)); + --link-hover-color: light-dark(var(--color-primary-300), var(--color-secondary-200)); + --border-color: light-dark(var(--color-neutral-900), var(--color-neutral-100)); + --border-color-subtle: light-dark(var(--color-neutral-300), var(--color-neutral-800)); + --text-decoration-color: light-dark(var(--color-neutral-700), var(--color-neutral-100)); + --text-decoration-color-hover: light-dark(var(--color-neutral-100), var(--color-neutral-200)); + + // theme settings + --radius-small: 3px; + --radius-large: 6px; + --gap-default: 2rem; + --font-measure: 70ch; + --font-family-default: 'Atkinson Hyperlegible', sans-serif; + --font-family-special: 'Atkinson Hyperlegible', sans-serif; + + // font families + --font-heading: var(--font-family-special); + --font-body: var(--font-family-default); + + // font sizes + // @link https://utopia.fyi/type/calculator?c=320,16,1.2,1240,18,1.25,6,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 + --font-size--2: clamp(0.6944rem, 0.6855rem + 0.0446vw, 0.72rem); + --font-size--1: clamp(0.8331rem, 0.8099rem + 0.1163vw, 0.9rem); + --font-size-0: clamp(1rem, 0.9565rem + 0.2174vw, 1.125rem); + --font-size-1: clamp(1.2rem, 1.1283rem + 0.3587vw, 1.4063rem); + --font-size-2: clamp(1.44rem, 1.3293rem + 0.5533vw, 1.7581rem); + --font-size-3: clamp(1.7281rem, 1.5649rem + 0.8163vw, 2.1975rem); + --font-size-4: clamp(2.0738rem, 1.8396rem + 1.1707vw, 2.7469rem); + --font-size-5: clamp(2.4881rem, 2.1594rem + 1.6435vw, 3.4331rem); + --font-size-6: clamp(2.9863rem, 2.5323rem + 2.2696vw, 4.2913rem); + --font-size-7: clamp(3.5836rem, 2.9667rem + 3.0674vw, 5.3544rem); + --font-size-8: clamp(4.2999rem, 3.5601rem + 3.6935vw, 6.6856rem); + + // space + // @link https://utopia.fyi/space/calculator?c=320,16,1.2,1240,18,1.25,6,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,&g=s,l,xl,12 + --space-5xs: clamp(0.1rem, 0.0931rem + 0.1087vw, 0.125rem); + --space-4xs: clamp(0.125rem, 0.1131rem + 0.1087vw, 0.1563rem); + --space-3xs: clamp(0.25rem, 0.2283rem + 0.1087vw, 0.3125rem); + --space-2xs: clamp(0.5rem, 0.4783rem + 0.1087vw, 0.5625rem); + --space-xs: clamp(0.75rem, 0.7065rem + 0.2174vw, 0.875rem); + --space-s: clamp(1rem, 0.9565rem + 0.2174vw, 1.125rem); + --space-m: clamp(1.5rem, 1.4348rem + 0.3261vw, 1.6875rem); + --space-l: clamp(2rem, 1.913rem + 0.4348vw, 2.25rem); + --space-xl: clamp(3rem, 2.8696rem + 0.6522vw, 3.375rem); + --space-2xl: clamp(4rem, 3.8261rem + 0.8696vw, 4.5rem); + --space-3xl: clamp(6rem, 5.7391rem + 1.3043vw, 6.75rem); + --space-4xl: clamp(8rem, 7.6522rem + 1.7403vw, 8.25rem); + --space-5xl: clamp(10rem, 9.5652rem + 2.1741vw, 10.5rem); + + // grid + // https://utopia.fyi/grid/calculator?c=320,18,1.2,1240,20,1.25,5,2,&s=0.75%7C0.5%7C0.25,1.5%7C2%7C3%7C4%7C6,s-l&g=s,l,xl,12 + --grid-max-width: 90rem; + --grid-gutter: var(--space-s-l, clamp(1.125rem, 0.6467rem + 2.3913vw, 2.5rem)); + --grid-columns: 12; + + // border radius + --radius-xs: 0.125rem; + --radius-s: 0.25rem; + --radius-m: 0.5rem; + --radius-l: 0.75rem; + --radius-h: 1rem; + + // elevations + --elevation-1: 0 1px 3px rgba(0 0 0 / 0.12); + --elevation-2: 0 3px 6px rgba(0 0 0 / 0.15); + --elevation-3: 0 10px 20px rgba(0 0 0 / 0.15); + --elevation-4: 0 15px 25px rgba(0 0 0 / 0.15); + --elevation-5: 0 20px 40px rgba(0 0 0 / 0.5); + + // z-index + --z-index--1: -1; + --z-index-0: 0; + --z-index-1: 10; + --z-index-2: 20; + --z-index-3: 30; + --z-index-4: 40; + --z-index-5: 50; + --z-index-6: 60; + --z-index-7: 70; + --z-index-8: 80; + --z-index-9: 90; + --z-index-10: 100; + + // aspects + --ratio-square: 1; + --ratio-landscape: 4/3; + --ratio-portrait: 3/4; + --ratio-widescreen: 16/9; + --ratio-ultrawide: 18/5; + + // animations + --cubic-bezier: cubic-bezier(0.1, 0.1, 0, 1); + --animation-speed-slow: 0.4s; + --animation-speed-medium: 0.3s; + --animation-speed-fast: 0.2s; + --animation-speed-instant: 0.1s; + + // misc + --line-clamp: 3; + --target-size-min: 24px; + --target-size-max: 44px; + --backdrop-color: hsl(0deg 100% 0% / 0.75); + --backdrop-blur: blur(3px); + + // kbd + --kbd-color-text: light-dark(var(--color-gray-200), var(--color-gray-800)); + --kbd-color-border: light-dark(var(--color-gray-700), var(--color-gray-300)); + --kbd-color-background: light-dark(var(--color-gray-1000), var(--color-gray-200)); +} + +// dark color scheme overrides +.darkmode { + color-scheme: dark; } diff --git a/src/assets/scss/base/_space-content.scss b/src/assets/scss/base/_space-content.scss deleted file mode 100644 index 888b3346..00000000 --- a/src/assets/scss/base/_space-content.scss +++ /dev/null @@ -1,57 +0,0 @@ -// | ------------------------------------------------------------- -// | Space Content -// | ------------------------------------------------------------- - -@use 'breakpoint' as *; - -.space-content { - > * + *, - > dl > * + * { - margin-top: 1.5rem; - margin-bottom: 0; - } - - > h2 { - margin-top: 3rem; - - @include breakpoint(large) { - margin-top: 4rem; - } - } - - > h3 { - margin-top: 2rem; - - @include breakpoint(large) { - margin-top: 3rem; - } - } - - > h4 { - margin-top: 1.5rem; - - @include breakpoint(large) { - margin-top: 2rem; - } - } - - > h5 { - margin-top: 1rem; - - @include breakpoint(large) { - margin-top: 1.5rem; - } - } - - > h6 { - margin-top: 1rem; - - @include breakpoint(large) { - margin-top: 1.5rem; - } - } - - > *:first-child { - margin-top: 0; - } -} diff --git a/src/assets/scss/base/_utility.scss b/src/assets/scss/base/_utility.scss new file mode 100644 index 00000000..29733cc8 --- /dev/null +++ b/src/assets/scss/base/_utility.scss @@ -0,0 +1,234 @@ +@use 'breakpoint' as *; + +.container { + margin-inline: auto; + padding-inline: var(--grid-gutter); + max-width: var(--grid-max-width); + + @include breakpoint(m) { + padding-inline: 2rem; + } + + @include breakpoint(xl) { + padding-inline: calc(2rem / 2); + max-width: 1200px; + } + + &.stretch { + max-width: 100%; + } + + &.narrow { + max-width: 800px; + } +} + +.center-content { + display: grid; + place-items: center; +} + +.flex-center { + display: flex; + justify-content: center; + align-items: center; +} + +.horizontal-center { + margin: 0 auto; +} + +.h-stack { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + gap: var(--space-s); +} + +.v-stack { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--space-s); +} + +.space-between { + justify-content: space-between; +} + +.align-start { + align-items: flex-start; +} + +.align-stretch { + align-items: stretch; +} + +.align-center { + align-items: center; +} + +.align-end { + align-items: flex-end; +} + +.wrap { + flex-wrap: wrap; +} + +.no-gap { + gap: 0; +} + +.truncate { + overflow: clip; + text-overflow: ellipsis; + white-space: nowrap; +} + +.text-ellipsis { + display: -webkit-box; + -webkit-line-clamp: var(--line-clamp); + -webkit-box-orient: vertical; + overflow: clip; +} + +.uppercase { + text-transform: uppercase; +} + +.sr-only { + position: absolute; + overflow: clip; + clip: rect(0 0 0 0); + margin: 0; + border: 0; + padding: 0; + inline-size: 1px; + block-size: auto; + white-space: nowrap; +} + +$space-map: ( + 3xs: var(--space-3xs), + 2xs: var(--space-2xs), + xs: var(--space-xs), + s: var(--space-s), + m: var(--space-m), + l: var(--space-l), + xl: var(--space-xl), +); + +@each $size, $value in $space-map { + .space-content-#{$size} > * + * { + margin-block-start: $value; + } +} + +$gap-map: ( + 3xs: var(--space-3xs), + 2xs: var(--space-2xs), + xs: var(--space-xs), + s: var(--space-s), + m: var(--space-m), + l: var(--space-l), + xl: var(--space-xl), +); + +@each $size, $value in $space-map { + .gap-#{$size} { + gap: $value; + } +} + +$font-map: ( + -2: ( + font-size: var(--font-size--2), + line-height: var(--font-size--2), + ), + -1: ( + font-size: var(--font-size--1), + line-height: var(--font-size--1), + ), + 0: ( + font-size: var(--font-size-0), + line-height: var(--font-size-0), + ), + 1: ( + font-size: var(--font-size-1), + line-height: var(--font-size-1), + ), + 2: ( + font-size: var(--font-size-2), + line-height: var(--font-size-2), + ), + 3: ( + font-size: var(--font-size-3), + line-height: var(--font-size-3), + ), + 4: ( + font-size: var(--font-size-4), + line-height: var(--font-size-4), + ), + 5: ( + font-size: var(--font-size-5), + line-height: var(--font-size-5), + ), + 6: ( + font-size: var(--font-size-6), + line-height: var(--font-size-6), + ) +); + +@each $size, $value in $font-map { + .font-#{$size} { + font-size: map-get($value, font-size); + line-height: map-get($value, line-height); + } +} + +.space-content { + > * + *, + > dl > * + * { + margin-block-start: var(--space-s); + margin-block-end: 0; + } + + > h2 { + margin-block-start: var(--space-l); + + @include breakpoint(xl) { + margin-block-start: var(--space-xl); + } + } + + > h3 { + margin-block-start: var(--space-m); + + @include breakpoint(xl) { + margin-block-start: var(--space-l); + } + } + + > h4 { + margin-block-start: var(--space-s); + + @include breakpoint(xl) { + margin-block-start: var(--space-m); + } + } + + > h5, + > h6 { + margin-block-start: var(--space-xs); + + @include breakpoint(xl) { + margin-block-start: var(--space-s); + } + } + + > *:first-child { + margin-block-start: 0; + } +} diff --git a/src/assets/scss/globals.scss b/src/assets/scss/globals.scss deleted file mode 100644 index b15c2088..00000000 --- a/src/assets/scss/globals.scss +++ /dev/null @@ -1,14 +0,0 @@ -// | ------------------------------------------------------------- -// | Globals -// | ------------------------------------------------------------- - -@use 'base/reset'; -@use 'base/root'; -@use 'base/font'; -@use 'base/list'; -@use 'base/container'; -@use 'base/breakpoint'; -@use 'base/button'; -@use 'base/color'; -@use 'base/outline'; -@use 'base/space-content'; diff --git a/src/assets/scss/index.scss b/src/assets/scss/index.scss new file mode 100644 index 00000000..ae777c75 --- /dev/null +++ b/src/assets/scss/index.scss @@ -0,0 +1,10 @@ +@use 'base/reset'; +@use 'base/root'; +@use 'base/font'; +@use 'base/list'; +@use 'base/breakpoint'; +@use 'base/button'; +@use 'base/general'; +@use 'base/kbd'; +@use 'base/mixins'; +@use 'base/utility'; diff --git a/src/components/BlockQuote.astro b/src/components/BlockQuote.astro new file mode 100644 index 00000000..ec1a7c3b --- /dev/null +++ b/src/components/BlockQuote.astro @@ -0,0 +1,49 @@ +--- +import { Icon } from 'astro-icon/components' + +interface Props { + /** + * The quote content that will be displayed + */ + children: any + /** + * The name of the person who said the quote + */ + author?: string +} + +const { author } = Astro.props +--- + +
+
+ + + +
+ {author && {author}} +
+ + diff --git a/src/components/BreakoutImage.astro b/src/components/BreakoutImage.astro new file mode 100644 index 00000000..328273a9 --- /dev/null +++ b/src/components/BreakoutImage.astro @@ -0,0 +1,26 @@ +--- +import { Image } from 'astro:assets' + +/** + * BreakoutImage Component + * + * @description A component for displaying a landscape image that breaks out of the container + */ +interface Props { + /** + * The image source + */ + src: string + /** + * The image alt text + */ + alt: string +} + +const { src, alt = '' } = Astro.props +--- + +
+ {alt} +
+
diff --git a/src/components/CallToAction.astro b/src/components/CallToAction.astro index 5bcdd49b..5b96da26 100644 --- a/src/components/CallToAction.astro +++ b/src/components/CallToAction.astro @@ -1,30 +1,86 @@ +--- +import { Icon } from 'astro-icon/components' + +/** + * CallToAction Component + * + * @description A prominent call-to-action section with a title and link + */ +interface Props { + /** + * The title text to display + * @default "Get this theme on GitHub" + */ + title?: string + /** + * The URL the button should link to + * @default "https://github.com/incluud/accessible-astro-starter" + */ + link?: string + /** + * The text to display on the button + * @default "Get Started" + */ + linkText?: string +} + +const { + title = 'Get this theme on GitHub', + link = 'https://github.com/incluud/accessible-astro-starter', + linkText = 'Use this theme', +} = Astro.props +--- +
-
-

Get this theme on GitHub

- Use this theme +
+

{title}

+ + {linkText} + +
diff --git a/src/components/ColorContrast.astro b/src/components/ColorContrast.astro new file mode 100644 index 00000000..68ea9323 --- /dev/null +++ b/src/components/ColorContrast.astro @@ -0,0 +1,345 @@ +--- +interface Props { + class?: string +} + +const { class: className } = Astro.props + +import { Tabs, TabsList, TabsTab, TabsPanel } from 'accessible-astro-components' + +interface ColorGroup { + name: string + prefix: string + values: number[] +} + +interface Theme { + name: string + id: string + description: string + textColor: string + bgVar: string +} + +// Define color variants to test +const colorGroups: ColorGroup[] = [ + { name: 'Primary', prefix: 'primary', values: [100, 200, 300, 400, 500] }, + { name: 'Secondary', prefix: 'secondary', values: [100, 200, 300, 400, 500] }, + { name: 'Neutral', prefix: 'neutral', values: [100, 200, 300, 400, 500, 600, 700, 800, 900] }, +] + +// Define themes to test +const themes: Theme[] = [ + { + name: 'Light Mode', + id: 'light-mode', + description: 'Dark text on colored backgrounds', + textColor: '#1A1A1A', + bgVar: 'var(--color-neutral-100)', + }, + { + name: 'Dark Mode', + id: 'dark-mode', + description: 'Light text on colored backgrounds', + textColor: '#FFFFFF', + bgVar: 'var(--color-neutral-900)', + }, +] +--- + +
+
+ + + { + themes.map((theme, index) => ( + + {theme.name} + + )) + } + + + { + themes.map((theme, index) => ( + +
+
+

{theme.name}

+

{theme.description}

+
+
+ {/* Three column layout for color categories */} +
+

Primary Colors

+
+ {colorGroups[0].values.map((value) => ( +
+ + {colorGroups[0].prefix} {value} + + +
+ ))} +
+
+ +
+

Secondary Colors

+
+ {colorGroups[1].values.map((value) => ( +
+ + {colorGroups[1].prefix} {value} + + +
+ ))} +
+
+ +
+

Neutral Colors

+
+ {colorGroups[2].values.map((value) => ( +
+ + {colorGroups[2].prefix} {value} + + +
+ ))} +
+
+
+
+
+ )) + } +
+
+
+ + + + diff --git a/src/components/ContentMedia.astro b/src/components/ContentMedia.astro index 2a667c92..cf25112d 100644 --- a/src/components/ContentMedia.astro +++ b/src/components/ContentMedia.astro @@ -1,7 +1,24 @@ --- import { Media } from 'accessible-astro-components' -const { imgSrc, reverseImg = false } = Astro.props +/** + * ContentMedia Component + * + * @description A component that displays content alongside media, with the option to reverse the image position + */ +interface Props { + /** + * The source URL for the image + */ + imgSrc: string + /** + * Whether to display the image on the right side instead of the left + * @default false + */ + reverseImg?: boolean +} + +const { imgSrc, reverseImg = false }: Props = Astro.props ---
diff --git a/src/components/Counter.astro b/src/components/Counter.astro index de5513f1..946ddbc2 100644 --- a/src/components/Counter.astro +++ b/src/components/Counter.astro @@ -1,4 +1,24 @@ --- +/** + * Counter Component + * + * @description A component that displays a number with a title and subtitle + */ +interface Props { + /** + * The number to display + */ + count: string | number + /** + * The title text to display below the count + */ + title: string + /** + * The subtitle text to display below the title + */ + sub: string +} + const { count, title, sub } = Astro.props --- @@ -10,6 +30,6 @@ const { count, title, sub } = Astro.props diff --git a/src/components/ExternalLink.astro b/src/components/ExternalLink.astro new file mode 100644 index 00000000..99ceab5b --- /dev/null +++ b/src/components/ExternalLink.astro @@ -0,0 +1,35 @@ +--- +import { Icon } from 'astro-icon/components' + +/** + * ExternalLink Component + * + * @description ExternalLink description + */ +interface Props { + /** + * Additional classes to apply to the ExternalLink + */ + class?: string + /** + * The URL to link to + */ + href: string +} + +const { class: className, href } = Astro.props +--- + + + + + Opens in a new tab + + + diff --git a/src/components/Feature.astro b/src/components/Feature.astro index 98cc7fb8..3794e311 100644 --- a/src/components/Feature.astro +++ b/src/components/Feature.astro @@ -1,13 +1,29 @@ --- import { Icon } from 'astro-icon/components' -const { icon = 'mdi:rocket', title = 'Title' } = Astro.props +/** + * Feature Component + * + * @description A component that displays a feature with an icon, title, and description + */ +interface Props { + /** + * The icon to display + */ + icon: string + /** + * The title to display + */ + title: string +} + +const { icon = 'mdi:rocket', title = 'Title' }: Props = Astro.props ---
-

{title}

+

{title}

Lorem ipsum dolor sit amet consectetur adipisicing elit. Hic, corporis.

@@ -19,49 +35,49 @@ const { icon = 'mdi:rocket', title = 'Title' } = Astro.props .feature { position: relative; - width: calc(100% - 0.5rem); - padding: 2rem; + padding: var(--space-l); + inline-size: calc(100% - var(--space-l)); > * { position: relative; z-index: 2; } - @include breakpoint(large) { - width: 100%; + @include breakpoint(xl) { + inline-size: 100%; } &::before, &::after { - content: ''; position: absolute; + content: ''; } &::before { - inset: 0; - background-color: var(--neutral-100); - border: 3px solid var(--neutral-700); - border-radius: 1rem; - box-shadow: 0 0 0 6px var(--neutral-100); z-index: 1; + inset: 0; + box-shadow: 0 0 0 6px var(--color-neutral-100); + border: 3px solid var(--color-neutral-700); + border-radius: var(--radius-l); + background-color: var(--color-neutral-100); } &::after { - background-color: var(--action-color); - inset: 1rem -0.85rem -0.85rem 1rem; - border-radius: 1rem; z-index: 0; + inset: var(--space-m) -0.85rem -0.85rem 1rem; + border-radius: var(--radius-l); + background-color: var(--link-color); } } :global(.feature [data-icon]) { - height: auto; - width: 4rem; - color: var(--action-color); + inline-size: 4rem; + block-size: auto; + color: var(--link-color); } :global(.darkmode .feature::before) { - background-color: var(--dark-100); - box-shadow: 0 0 0 6px var(--dark-100); + box-shadow: 0 0 0 6px var(--color-neutral-900); + background-color: var(--color-neutral-900); } diff --git a/src/components/Footer.astro b/src/components/Footer.astro index 073b46ec..ae974fbf 100644 --- a/src/components/Footer.astro +++ b/src/components/Footer.astro @@ -1,18 +1,88 @@ --- import CallToAction from './CallToAction.astro' +import ExternalLink from './ExternalLink.astro' +import Logo from './Logo.astro' +/** + * Footer Component + * + * @description A component that displays the footer of the website + */ const currentYear = new Date().getFullYear() --- + + diff --git a/src/components/Header.astro b/src/components/Header.astro index c7c198a7..f18a5d49 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -1,7 +1,13 @@ --- import Navigation from '../components/Navigation.astro' -import { SkipLink } from 'accessible-astro-components' +import { DarkMode, SkipLink } from 'accessible-astro-components' import { Icon } from 'astro-icon/components' + +/** + * Header Component + * + * @description A component that displays the header of the website + */ ---
@@ -17,51 +23,58 @@ import { Icon } from 'astro-icon/components' Portfolio - - +
diff --git a/src/components/Navigation.astro b/src/components/Navigation.astro index def86a9f..3008eb7e 100644 --- a/src/components/Navigation.astro +++ b/src/components/Navigation.astro @@ -1,23 +1,23 @@ --- import ResponsiveToggle from './ResponsiveToggle.astro' -import { DarkMode } from 'accessible-astro-components' -import { Image } from 'astro:assets' -import logo from '../assets/img/logo.svg' +import Logo from './Logo.astro' + +/** + * Navigation Component + * + * @description A component that displays the navigation menu for the website + */ ---
-
+
+
+

Our community

+

+ We're a community of developers who are passionate about making the web more accessible. We're always looking + for new ways to improve the accessibility of the web. +

+ + + + + + + + + + + +
+
+
-

Counters

+

Impact in numbers

- - - - + + + +
+ + diff --git a/src/pages/mdx-page.mdx b/src/pages/mdx-page.mdx index 64a9db1c..89d8a96e 100644 --- a/src/pages/mdx-page.mdx +++ b/src/pages/mdx-page.mdx @@ -9,7 +9,7 @@ import { Notification } from 'accessible-astro-components' # MDX Page - +

Info: This page utilizes Astro's MDX feature which let's you use components in a markdown file and supports out-of-the-box syntax highlighting with Shiki. diff --git a/src/pages/portfolio/[...page].astro b/src/pages/portfolio/[...page].astro index f19d7727..c2e81858 100644 --- a/src/pages/portfolio/[...page].astro +++ b/src/pages/portfolio/[...page].astro @@ -1,39 +1,63 @@ --- -import DefaultLayout from '../../layouts/DefaultLayout.astro' +import DefaultLayout from '@layouts/DefaultLayout.astro' +import PageHeader from '@components/PageHeader.astro' import { Card, Pagination } from 'accessible-astro-components' import { getCollection } from 'astro:content' import type { GetStaticPaths, Page } from 'astro' import type { CollectionEntry } from 'astro:content' +// Import images directly for optimization +import projectImage1 from '@assets/images/projects/project-image-1.png' +import projectImage2 from '@assets/images/projects/project-image-2.png' +import projectImage3 from '@assets/images/projects/project-image-3.png' +import projectImage4 from '@assets/images/projects/project-image-4.png' +import projectImage5 from '@assets/images/projects/project-image-5.png' +import projectImage6 from '@assets/images/projects/project-image-6.png' + export const getStaticPaths = (async ({ paginate }) => { const projects = await getCollection('projects') - return paginate(projects, { pageSize: 6 }) + + const projectImages = [projectImage1, projectImage2, projectImage3, projectImage4, projectImage5, projectImage6] + + const projectsWithImages = projects.map((project, index) => { + return { + ...project, + featuredImage: projectImages[index % projectImages.length], + } + }) + + return paginate(projectsWithImages, { pageSize: 6 }) }) satisfies GetStaticPaths interface Props { - page: Page> + page: Page & { featuredImage: any }> } const { page } = Astro.props + +// Prepare pagination props +const currentPage = page.currentPage +const totalPages = Math.ceil(page.total / page.size) --- - -

-
-

Portfolio

-

- An example of a portfolio built using Astro Content Collections, showcasing how to organize and display projects dynamically. Check out Astro Content Collections in the Astro Docs to learn more. -

-
-
+ +

Project {page.start + 1} through {page.end + 1} of {page.total} total projects

-
    +
      { page.data.map((project) => (
- diff --git a/src/pages/portfolio/[project].astro b/src/pages/portfolio/[project].astro index bbc75ee3..9c374d55 100644 --- a/src/pages/portfolio/[project].astro +++ b/src/pages/portfolio/[project].astro @@ -1,63 +1,74 @@ --- -import DefaultLayout from '../../layouts/DefaultLayout.astro' -import { Breadcrumbs, BreadcrumbsItem } from 'accessible-astro-components' +import DefaultLayout from '@layouts/DefaultLayout.astro' +import PageHeader from '@components/PageHeader.astro' +import SocialShares from '@components/SocialShares.astro' import { getCollection, render } from 'astro:content' import type { CollectionEntry } from 'astro:content' export async function getStaticPaths() { const projects = await getCollection('projects') - return projects.map((project) => { + + const projectImages = [ + { src: '/projects/project-image-1.png' }, + { src: '/projects/project-image-2.png' }, + { src: '/projects/project-image-3.png' }, + { src: '/projects/project-image-4.png' }, + { src: '/projects/project-image-5.png' }, + { src: '/projects/project-image-6.png' }, + ] + + return projects.map((project, index) => { + const projectWithImage = { + ...project, + featuredImage: projectImages[index % projectImages.length].src, + } + return { params: { project: project.id }, - props: { project }, + props: { project: projectWithImage }, } }) } interface Props { - project: CollectionEntry<'projects'> + project: CollectionEntry<'projects'> & { featuredImage: string } } const { project } = Astro.props const { Content } = await render(project) + +const author = { + name: project.data.author, + image: '/projects/project-image-1.png', + bio: 'Project Creator', +} --- - -
-
- - - - - -
-
+ +
-
-

{project.data.title}


-

By author: {project.data.author}

+
+
-
- +
+

Share this project

+

Like this project? Share it with your network!

+
- diff --git a/src/styles/tailwind.css b/src/styles/tailwind.css new file mode 100644 index 00000000..d4b50785 --- /dev/null +++ b/src/styles/tailwind.css @@ -0,0 +1 @@ +@import 'tailwindcss'; diff --git a/tailwind.config.js b/tailwind.config.js index 0ffce838..ff40af37 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,5 +1,5 @@ /** @type {import('tailwindcss').Config} */ -module.exports = { +export default { content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], theme: { extend: {}, diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..7dc61629 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@components/*": ["src/components/*"], + "@layouts/*": ["src/layouts/*"], + "@assets/*": ["src/assets/*"] + } + } +}