├── .astro └── types.d.ts ├── .github ├── FUNDING.yml └── workflows │ └── deploy.yml ├── .gitignore ├── .idx └── dev.nix ├── .npmrc ├── .prettierignore ├── .prettierrc.json ├── .stackblitzrc ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── assets ├── discord-badge.svg ├── gh-banner.png ├── lh-screenshot.png ├── readme-banner.png ├── sponsor-badge.svg └── twitter-badge.svg ├── astro.config.mjs ├── netlify.toml ├── package-lock.json ├── package.json ├── public ├── assets │ ├── fonts │ │ ├── lato-v23-latin-300.woff │ │ ├── lato-v23-latin-300.woff2 │ │ ├── lato-v23-latin-700.woff │ │ ├── lato-v23-latin-700.woff2 │ │ ├── lato-v23-latin-700italic.woff │ │ ├── lato-v23-latin-700italic.woff2 │ │ ├── lato-v23-latin-regular.woff │ │ ├── lato-v23-latin-regular.woff2 │ │ ├── roboto-serif-v8-latin-600.woff │ │ ├── roboto-serif-v8-latin-600.woff2 │ │ ├── roboto-serif-v8-latin-700.woff │ │ └── roboto-serif-v8-latin-700.woff2 │ └── images │ │ ├── badges │ │ ├── open-in-codesandbox.svg │ │ └── open-in-gitpod.svg │ │ ├── blog-page-screenshot.png │ │ ├── blog-post-screenshot.png │ │ ├── blog │ │ ├── consider-hybrid-work │ │ │ └── featured.jpg │ │ ├── odyssey-theme-officially-released │ │ │ └── featured.jpg │ │ └── remote-work-mental-health │ │ │ └── featured.jpg │ │ ├── company-legal-screenshot.png │ │ ├── hero-waves.jpg │ │ ├── home │ │ ├── classic-hero.jpg │ │ ├── dark-hero.jpg │ │ ├── earth-hero.jpg │ │ ├── ocean-hero.jpg │ │ ├── sand-hero.jpg │ │ └── screenshots │ │ │ ├── about.png │ │ │ ├── about.webp │ │ │ ├── blog-post.png │ │ │ ├── blog-post.webp │ │ │ ├── blog.png │ │ │ ├── blog.webp │ │ │ ├── contact.png │ │ │ ├── contact.webp │ │ │ ├── get-started.png │ │ │ ├── get-started.webp │ │ │ ├── landing-1.png │ │ │ ├── landing-1.webp │ │ │ ├── landing-2.png │ │ │ ├── landing-2.webp │ │ │ ├── landing-3.png │ │ │ ├── landing-3.webp │ │ │ ├── legal.png │ │ │ ├── legal.webp │ │ │ ├── style-guide.png │ │ │ └── style-guide.webp │ │ ├── landing-1 │ │ ├── landing-hero-1.jpg │ │ └── landing-sticky.jpg │ │ └── placeholder-screenshot.png ├── favicon.png └── social.png ├── sandbox.config.json ├── src ├── components │ ├── Logo.astro │ ├── blog │ │ ├── BlogPostPreview.astro │ │ └── BlogPostsList.astro │ ├── buttons │ │ └── Button.astro │ ├── cards │ │ └── FeatureCard.astro │ ├── core │ │ ├── AnnouncementBar.astro │ │ ├── Container.astro │ │ ├── Footer.astro │ │ ├── Header.astro │ │ ├── Nav.astro │ │ ├── Plug.astro │ │ ├── SkipLink.astro │ │ └── YouTubeEmbed.astro │ ├── form-fields │ │ ├── FormInput.astro │ │ ├── FormSelect.astro │ │ └── FormTextarea.astro │ ├── forms │ │ ├── ContactForm.astro │ │ ├── LandingContactForm.astro │ │ └── NewsletterForm.astro │ ├── head │ │ └── BaseHead.astro │ ├── odyssey-theme.js │ ├── sections │ │ ├── CtaCardSection.astro │ │ ├── CustomerQuoteSection.astro │ │ ├── StickyTextImageSection.astro │ │ ├── TextCardSection.astro │ │ ├── TextSection.astro │ │ ├── ThreeColumnTextSection.astro │ │ ├── YouTubeEmbedSection.astro │ │ └── heros │ │ │ ├── HeroSection.astro │ │ │ ├── HomeHeroSection.astro │ │ │ └── TextAndImageHero.astro │ └── theme-switcher │ │ ├── ThemeProvider.astro │ │ ├── icons.ts │ │ └── theme-switcher.ts ├── config │ ├── footer.js │ ├── nav.js │ └── settings.js ├── env.d.ts ├── icons │ └── icons.js ├── layouts │ ├── Base.astro │ ├── Page.astro │ └── Post.astro ├── pages │ ├── 404.astro │ ├── blog │ │ ├── index.astro │ │ ├── posts │ │ │ ├── consider-hybrid-work.mdx │ │ │ ├── odyssey-theme-officially-released.mdx │ │ │ └── remote-work-mental-health.mdx │ │ └── tags │ │ │ ├── [slug].astro │ │ │ └── index.astro │ ├── company │ │ ├── about.astro │ │ ├── contact.astro │ │ └── legal.astro │ ├── index.astro │ ├── landing-pages │ │ ├── landing-1.astro │ │ └── landing-2.astro │ └── theme │ │ ├── customizing-odyssey.mdx │ │ ├── get-started.astro │ │ ├── style-guide.astro │ │ └── theme-setup.mdx ├── styles │ ├── global.css │ ├── index.css │ ├── reset.css │ ├── theme.css │ └── typography.css └── utils │ └── helpers.js └── tsconfig.json /.astro/types.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: https://sapling.lemonsqueezy.com/checkout/buy/9b78751f-6382-442d-ac99-32c2318b70a0 14 | 15 | # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | on: 3 | push: 4 | branches: main 5 | pull_request: 6 | branches: main 7 | 8 | jobs: 9 | deploy: 10 | name: Deploy 11 | runs-on: ubuntu-latest 12 | 13 | permissions: 14 | id-token: write # Needed for auth with Deno Deploy 15 | contents: read # Needed to clone the repository 16 | 17 | steps: 18 | - name: Clone repository 19 | uses: actions/checkout@v4 20 | 21 | - name: Install Deno 22 | uses: denoland/setup-deno@v1 23 | with: 24 | deno-version: v1.x 25 | 26 | - name: Install Node.js 27 | uses: actions/setup-node@v4 28 | with: 29 | node-version: lts/* 30 | 31 | - name: Install step 32 | run: "npm install" 33 | 34 | - name: Build step 35 | run: "npm run build" 36 | 37 | - name: Upload to Deno Deploy 38 | uses: denoland/deployctl@v1 39 | with: 40 | project: "odyssey-theme" 41 | entrypoint: "https://jsr.io/@std/http/1.0.7/file_server.ts" 42 | root: "dist" 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | .output/ 4 | 5 | # dependencies 6 | node_modules/ 7 | 8 | # logs 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | pnpm-debug.log* 13 | 14 | 15 | # environment variables 16 | .env 17 | .env.production 18 | 19 | # macOS-specific files 20 | .DS_Store 21 | 22 | icon.d.ts 23 | *.cache -------------------------------------------------------------------------------- /.idx/dev.nix: -------------------------------------------------------------------------------- 1 | # To learn more about how to use Nix to configure your environment 2 | # see: https://developers.google.com/idx/guides/customize-idx-env 3 | { pkgs, ... }: { 4 | # Which nixpkgs channel to use. 5 | channel = "stable-23.11"; # or "unstable" 6 | 7 | # Use https://search.nixos.org/packages to find packages 8 | packages = [ 9 | # pkgs.go 10 | # pkgs.python311 11 | # pkgs.python311Packages.pip 12 | # pkgs.nodejs_20 13 | # pkgs.nodePackages.nodemon 14 | ]; 15 | 16 | # Sets environment variables in the workspace 17 | env = {}; 18 | idx = { 19 | # Search for the extensions you want on https://open-vsx.org/ and use "publisher.id" 20 | extensions = [ 21 | # "vscodevim.vim" 22 | ]; 23 | 24 | # Enable previews 25 | previews = { 26 | enable = true; 27 | previews = { 28 | # web = { 29 | # # Example: run "npm run dev" with PORT set to IDX's defined port for previews, 30 | # # and show it in IDX's web preview panel 31 | # command = ["npm" "run" "dev"]; 32 | # manager = "web"; 33 | # env = { 34 | # # Environment variables to set for your server 35 | # PORT = "$PORT"; 36 | # }; 37 | # }; 38 | }; 39 | }; 40 | 41 | # Workspace lifecycle hooks 42 | workspace = { 43 | # Runs when a workspace is first created 44 | onCreate = { 45 | # Example: install JS dependencies from NPM 46 | # npm-install = "npm install"; 47 | }; 48 | # Runs when the workspace is (re)started 49 | onStart = { 50 | # Example: start a background task to watch and re-build backend code 51 | # watch-backend = "npm run watch-backend"; 52 | }; 53 | }; 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Expose Astro dependencies for `pnpm` users 2 | shamefully-hoist=true 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | package-lock.json -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "semi": true, 4 | "singleQuote": true, 5 | "arrowParens": "avoid", 6 | "plugins": ["prettier-plugin-astro"], 7 | "overrides": [ 8 | { 9 | "files": "**/*.astro", 10 | "options": { "parser": "astro" } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.stackblitzrc: -------------------------------------------------------------------------------- 1 | { 2 | "startCommand": "npm start", 3 | "env": { 4 | "ENABLE_CJS_IMPORTS": true 5 | } 6 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IDX.aI.enableInlineCompletion": true, 3 | "IDX.aI.enableCodebaseIndexing": true 4 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Treefarm Studio LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Odyssey Theme Banner 3 |

4 | 5 |
6 |
7 | 8 | Follow Jaydan Urwin on Twitter 9 | 10 | 11 | Sponsor This Repo 12 | 13 |
14 |
15 | 16 | # Odyssey Theme 17 | 18 | Odyssey Theme is a modern theme/starter for a business or startup's marketing website. It provides landing page examples, a full-featured blog, contact forms, and more. It is fully themeable to match your business' branding and style. It even includes a theme switcher component to show how easily the entire style of the site can be changed with only a few lines of CSS. 19 | 20 | ## Features 21 | 22 |

23 | Screenshot of perfect score in Lighthouse benchmark 24 |

25 | 26 | 27 | - ✅ **A perfect score in Lighthouse** 28 | - ✅ **Blazing fast performance thanks to Astro 🚀** 29 | - ✅ **A Full Featured Blog with Tagging** 30 | - ✅ **Fully theme-able styles with for buttons, shapes, backgrounds, surfaces, etc.** 31 | - ✅ **Responsive, mobile-friendly landing pages** 32 | - ✅ **SEO Best Practices (Open Graph, Canonical URLs, sitemap)** 33 | - ✅ **Performant Local Fonts Setup** 34 | - ✅ **Contact Forms Setup for Netlify, Formspree, Formspark, etc.** 35 | - ✅ **A package of ready-to-use UI components** 36 | 37 | 38 | ## Demo 39 | 40 | View a [live demo](https://odyssey-theme.sapling.supply/) of the Odyssey Theme. 41 | 42 | ## Documentation 43 | 44 | 1. View the [Theme Setup Guide](https://odyssey-theme.sapling.supply/theme/theme-setup) 45 | 2. View the [Customizing the Theme Guide](https://odyssey-theme.sapling.supply/theme/customizing-odyssey) 46 | 47 | ## Usage 48 | 49 | ```bash 50 | cd theme 51 | 52 | npm install 53 | 54 | npm start 55 | ``` 56 | 57 | ## Deploy 58 | 59 | Feel free to deploy and host your site on your favorite static hosting service such as Netlify, Firebase Hosting, Vercel, GitHub Pages, etc. 60 | 61 | Astro has [an in-depth guide](https://docs.astro.build/en/guides/deploy/) on how to deploy an Astro project to each service. 62 | 63 | ## Sponsor 64 | 65 | If you find this theme useful, please consider donating to support the continued development of it with the link below 66 | 67 | [Donate to Odyssey Theme](https://sapling.lemonsqueezy.com/checkout/buy/9b78751f-6382-442d-ac99-32c2318b70a0) 68 | 69 | ## Support 70 | 71 | Please feel free to post issues or submit PRs to this repo and we will do our best to respond in a timely manner, keeping in mind this template is offered for free as is on GitHub. 72 | -------------------------------------------------------------------------------- /assets/discord-badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /assets/gh-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/assets/gh-banner.png -------------------------------------------------------------------------------- /assets/lh-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/assets/lh-screenshot.png -------------------------------------------------------------------------------- /assets/readme-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/assets/readme-banner.png -------------------------------------------------------------------------------- /assets/sponsor-badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /assets/twitter-badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'astro/config'; 2 | import sitemap from "@astrojs/sitemap"; 3 | import mdx from "@astrojs/mdx"; 4 | import icon from "astro-icon"; 5 | import lit from "@astrojs/lit"; 6 | 7 | // https://astro.build/config 8 | export default defineConfig({ 9 | site: 'https://odyssey-theme.sapling.supply/', // Your public domain, e.g.: https://my-site.dev/. Used to generate sitemaps and canonical URLs. 10 | sitemap: true, // Generate sitemap (set to "false" to disable) 11 | integrations: [sitemap(), mdx(), lit(), icon()], // Add renderers to the config 12 | }); -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "dist/" 3 | command = "npm run build" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "odyssey-theme", 3 | "version": "3.1.0", 4 | "private": false, 5 | "repository": { 6 | "type": "git", 7 | "url": "git@github.com:treefarmstudio/odyssey-theme" 8 | }, 9 | "scripts": { 10 | "dev": "astro dev", 11 | "start": "astro dev", 12 | "build": "astro build", 13 | "preview": "astro preview", 14 | "format": "npx prettier -w ." 15 | }, 16 | "devDependencies": { 17 | "@astrojs/lit": "^4.0.1", 18 | "@astrojs/mdx": "^2.1.1", 19 | "@astrojs/sitemap": "^0.1.0", 20 | "@iconify-json/ic": "^1.1.17", 21 | "@iconify-json/mdi": "^1.1.64", 22 | "@webcomponents/template-shadowroot": "^0.2.1", 23 | "astro": "^4.15.9", 24 | "astro-icon": "^1.1.0", 25 | "date-fns": "^2.28.0", 26 | "lit": "^3.1.2", 27 | "prettier-plugin-astro": "^0.0.12" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /public/assets/fonts/lato-v23-latin-300.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/lato-v23-latin-300.woff -------------------------------------------------------------------------------- /public/assets/fonts/lato-v23-latin-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/lato-v23-latin-300.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/lato-v23-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/lato-v23-latin-700.woff -------------------------------------------------------------------------------- /public/assets/fonts/lato-v23-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/lato-v23-latin-700.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/lato-v23-latin-700italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/lato-v23-latin-700italic.woff -------------------------------------------------------------------------------- /public/assets/fonts/lato-v23-latin-700italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/lato-v23-latin-700italic.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/lato-v23-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/lato-v23-latin-regular.woff -------------------------------------------------------------------------------- /public/assets/fonts/lato-v23-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/lato-v23-latin-regular.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/roboto-serif-v8-latin-600.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/roboto-serif-v8-latin-600.woff -------------------------------------------------------------------------------- /public/assets/fonts/roboto-serif-v8-latin-600.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/roboto-serif-v8-latin-600.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/roboto-serif-v8-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/roboto-serif-v8-latin-700.woff -------------------------------------------------------------------------------- /public/assets/fonts/roboto-serif-v8-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/fonts/roboto-serif-v8-latin-700.woff2 -------------------------------------------------------------------------------- /public/assets/images/badges/open-in-codesandbox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /public/assets/images/badges/open-in-gitpod.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/assets/images/blog-page-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/blog-page-screenshot.png -------------------------------------------------------------------------------- /public/assets/images/blog-post-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/blog-post-screenshot.png -------------------------------------------------------------------------------- /public/assets/images/blog/consider-hybrid-work/featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/blog/consider-hybrid-work/featured.jpg -------------------------------------------------------------------------------- /public/assets/images/blog/odyssey-theme-officially-released/featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/blog/odyssey-theme-officially-released/featured.jpg -------------------------------------------------------------------------------- /public/assets/images/blog/remote-work-mental-health/featured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/blog/remote-work-mental-health/featured.jpg -------------------------------------------------------------------------------- /public/assets/images/company-legal-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/company-legal-screenshot.png -------------------------------------------------------------------------------- /public/assets/images/hero-waves.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/hero-waves.jpg -------------------------------------------------------------------------------- /public/assets/images/home/classic-hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/classic-hero.jpg -------------------------------------------------------------------------------- /public/assets/images/home/dark-hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/dark-hero.jpg -------------------------------------------------------------------------------- /public/assets/images/home/earth-hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/earth-hero.jpg -------------------------------------------------------------------------------- /public/assets/images/home/ocean-hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/ocean-hero.jpg -------------------------------------------------------------------------------- /public/assets/images/home/sand-hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/sand-hero.jpg -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/about.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/about.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/about.webp -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/blog-post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/blog-post.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/blog-post.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/blog-post.webp -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/blog.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/blog.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/blog.webp -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/contact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/contact.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/contact.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/contact.webp -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/get-started.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/get-started.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/get-started.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/get-started.webp -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/landing-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/landing-1.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/landing-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/landing-1.webp -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/landing-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/landing-2.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/landing-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/landing-2.webp -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/landing-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/landing-3.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/landing-3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/landing-3.webp -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/legal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/legal.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/legal.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/legal.webp -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/style-guide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/style-guide.png -------------------------------------------------------------------------------- /public/assets/images/home/screenshots/style-guide.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/home/screenshots/style-guide.webp -------------------------------------------------------------------------------- /public/assets/images/landing-1/landing-hero-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/landing-1/landing-hero-1.jpg -------------------------------------------------------------------------------- /public/assets/images/landing-1/landing-sticky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/landing-1/landing-sticky.jpg -------------------------------------------------------------------------------- /public/assets/images/placeholder-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/assets/images/placeholder-screenshot.png -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/favicon.png -------------------------------------------------------------------------------- /public/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/public/social.png -------------------------------------------------------------------------------- /sandbox.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "infiniteLoopProtection": true, 3 | "hardReloadOnChange": false, 4 | "view": "browser", 5 | "template": "node", 6 | "container": { 7 | "port": 3000, 8 | "startScript": "start", 9 | "node": "14" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Logo.astro: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | 6 | 19 | -------------------------------------------------------------------------------- /src/components/blog/BlogPostPreview.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const {post} = Astro.props; 3 | --- 4 | 5 |
  • 6 | 7 | 8 |

    {post.title}

    9 | {post.excerpt &&

    {post.excerpt}

    } 10 |
    11 |
  • 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/blog/BlogPostsList.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import BlogPostPreview from './BlogPostPreview.astro'; 3 | 4 | const {posts} = Astro.props; 5 | --- 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /src/components/buttons/Button.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { href, unelevated, outlined, customIcon, onPrimary, newTab } = 3 | Astro.props; 4 | 5 | const Tag = href ? 'a' : 'button'; 6 | --- 7 | 8 | 16 | 17 | {customIcon && custom_icon} 18 | 19 | 20 | 74 | -------------------------------------------------------------------------------- /src/components/cards/FeatureCard.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const {href, imgSrc, title} = Astro.props; 3 | --- 4 | 5 | 45 | 46 | 47 |
    48 | 49 | 57 | 58 |
    59 | 60 | -------------------------------------------------------------------------------- /src/components/core/AnnouncementBar.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const {text, href, newTab} = Astro.props; 3 | --- 4 | 5 |
    6 |

    7 | {newTab ? 8 | 9 | {text} 10 | : 11 | 12 | {text} 13 | } 14 |

    15 |
    16 | 17 | -------------------------------------------------------------------------------- /src/components/core/Container.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const {narrow} = Astro.props; 3 | --- 4 | 5 |
    6 | 7 |
    8 | 9 | -------------------------------------------------------------------------------- /src/components/core/Footer.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from 'astro-icon/components'; 3 | import Container from '../core/Container.astro'; 4 | import Plug from './Plug.astro'; 5 | 6 | const { footerSocials, footerLists, copyrightName, background, color, showPlug: showPlug = true } = 7 | Astro.props; 8 | --- 9 | 10 | 59 | 60 | -------------------------------------------------------------------------------- /src/components/core/Header.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from 'astro-icon/components' 3 | const { navData, rightMenu } = Astro.props; 4 | --- 5 | 6 | 41 | 42 |
    43 |
    44 | 52 | 53 | 54 | 55 | 56 |
    57 |
    58 | 59 | {navData && } 66 | 67 |
    68 |
    69 | 70 | 71 |
    72 |
    73 | 74 | -------------------------------------------------------------------------------- /src/components/core/Nav.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const {navData} = Astro.props; 3 | --- 4 | 5 | {navData && } 12 | 13 | -------------------------------------------------------------------------------- /src/components/core/Plug.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from 'astro-icon/components'; 3 | --- 4 | 5 | Get This Template 6 | 7 | -------------------------------------------------------------------------------- /src/components/core/SkipLink.astro: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | --- 4 | 5 | Skip to main content 6 | 7 | 46 | -------------------------------------------------------------------------------- /src/components/core/YouTubeEmbed.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { url, rounded, loading = 'lazy' } = Astro.props; 3 | 4 | function getYouTubeId(url) { 5 | const regExp = 6 | /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/; 7 | const match = url.match(regExp); 8 | 9 | return match && match[2].length === 11 ? match[2] : null; 10 | } 11 | --- 12 | 13 | 47 | 48 |
    53 | 62 |
    63 | -------------------------------------------------------------------------------- /src/components/form-fields/FormInput.astro: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | const {type = "text", label, name, placeholder, required} = Astro.props; 4 | --- 5 | 6 |
    7 | {label && } 8 | 9 |
    10 | 11 | 27 | -------------------------------------------------------------------------------- /src/components/form-fields/FormSelect.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { label, name, options, required} = Astro.props; 3 | --- 4 | 5 | 22 | 23 |
    24 | {label && } 25 | 31 |
    32 | 33 | 34 | -------------------------------------------------------------------------------- /src/components/form-fields/FormTextarea.astro: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | const { label, name, placeholder, rows = 4, required} = Astro.props; 4 | --- 5 | 6 |
    7 | {label && } 8 | 9 |
    10 | 11 | 25 | -------------------------------------------------------------------------------- /src/components/forms/ContactForm.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Button, FormInput, FormSelect, FormTextarea } from '@components/odyssey-theme'; 3 | 4 | const selectOptions = [ 5 | "Google Search", 6 | "Social Media", 7 | "Email", 8 | ] 9 | 10 | --- 11 | 12 |
    13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/components/forms/LandingContactForm.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {Icon} from 'astro-icon/components' 3 | import { Button, FormInput } from '@components/odyssey-theme'; 4 | 5 | const selectOptions = [ 6 | "Google Search", 7 | "Social Media", 8 | "Email", 9 | ] 10 | 11 | --- 12 | 13 |
    14 | 15 | 16 | 17 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/components/forms/NewsletterForm.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {Icon} from 'astro-icon/components' 3 | import {Button, FormInput } from "@components/odyssey-theme"; 4 | 5 | --- 6 | 7 |
    8 | 16 |
    17 | 18 | -------------------------------------------------------------------------------- /src/components/head/BaseHead.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import settings from '../../config/settings.js'; 3 | import ThemeProvider from '../theme-switcher/ThemeProvider.astro'; 4 | 5 | import '../../styles/index.css'; 6 | 7 | export interface Props { 8 | title?: string; 9 | description?: string; 10 | canonicalURL?: URL | string; 11 | image?: string; 12 | } 13 | 14 | const title = Astro.props.title || settings.title; 15 | const description = Astro.props.description || settings.description; 16 | const canonicalURL = Astro.props.canonicalURL || new URL(Astro.url.pathname, Astro.site); 17 | const image = new URL(Astro.props.image || './social.png', Astro.site); 18 | --- 19 | 20 | 21 | 22 | 23 | 24 | 25 | {title} 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {settings.enableThemeSwitcher && } 47 | 48 | 49 | 55 | -------------------------------------------------------------------------------- /src/components/odyssey-theme.js: -------------------------------------------------------------------------------- 1 | // Core 2 | export { default as Container } from './core/Container.astro'; 3 | export { default as SkipLink } from './core/SkipLink.astro'; 4 | export { default as Header } from './core/Header.astro'; 5 | export { default as Footer } from './core/Footer.astro'; 6 | export { default as YouTubeEmbed } from './core/YouTubeEmbed.astro'; 7 | export { default as AnnouncementBar } from './core/AnnouncementBar.astro'; 8 | export { default as Plug} from './core/Plug.astro'; 9 | 10 | // Buttons 11 | export { default as Button } from './buttons/Button.astro'; 12 | 13 | // Cards 14 | export { default as FeatureCard } from './cards/FeatureCard.astro'; 15 | 16 | // Sections 17 | export { default as TextSection } from './sections/TextSection.astro'; 18 | export { default as TextCardSection } from './sections/TextCardSection.astro'; 19 | export { default as CustomerQuoteSection } from './sections/CustomerQuoteSection.astro'; 20 | export { default as ThreeColumnTextSection } from './sections/ThreeColumnTextSection.astro'; 21 | export { default as YouTubeEmbedSection } from './sections/YouTubeEmbedSection.astro'; 22 | export { default as StickyTextImageSection } from './sections/StickyTextImageSection.astro'; 23 | export { default as CtaCardSection } from './sections/CtaCardSection.astro'; 24 | 25 | // Blog 26 | export { default as BlogPostsList } from './blog/BlogPostsList.astro'; 27 | export { default as BlogPostPreview } from './blog/BlogPostPreview.astro'; 28 | 29 | // Form Fields 30 | export { default as FormInput } from './form-fields/FormInput.astro'; 31 | export { default as FormTextarea } from './form-fields/FormTextarea.astro'; 32 | export { default as FormSelect } from './form-fields/FormSelect.astro'; -------------------------------------------------------------------------------- /src/components/sections/CtaCardSection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Container from '../core/Container.astro'; 3 | 4 | const {background, color} = Astro.props; 5 | --- 6 | 7 |
    8 |
    9 | 10 |
    11 |
    12 |
    13 | 14 | 33 | -------------------------------------------------------------------------------- /src/components/sections/CustomerQuoteSection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Container from '../core/Container.astro'; 3 | 4 | const {quoteText, customerName} = Astro.props; 5 | --- 6 | 7 |
    8 | 9 |
    "{quoteText}"
    10 |

    — {customerName}

    11 |
    12 |
    13 | 14 | -------------------------------------------------------------------------------- /src/components/sections/StickyTextImageSection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Container from '../core/Container.astro'; 3 | 4 | const {reversed} = Astro.props; 5 | --- 6 | 7 | 8 |
    9 |
    10 | 11 |
    12 |
    13 | 14 |
    15 |
    16 |
    17 | 18 | 19 | -------------------------------------------------------------------------------- /src/components/sections/TextCardSection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Container from '../core/Container.astro'; 3 | 4 | const {surfaceNumber = 1} = Astro.props; 5 | --- 6 | 7 |
    8 | 9 | 10 | 11 |
    12 | 13 | -------------------------------------------------------------------------------- /src/components/sections/TextSection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Container from '../core/Container.astro'; 3 | 4 | const {narrow} = Astro.props; 5 | --- 6 | 7 | 8 |
    9 | 10 |
    11 |
    12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /src/components/sections/ThreeColumnTextSection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Container from '../core/Container.astro'; 3 | --- 4 | 5 | 6 |
    7 |
    8 | 9 | 10 |
    11 |
    12 | 13 | 14 |
    15 |
    16 | 17 | 18 |
    19 |
    20 |
    21 | 22 | -------------------------------------------------------------------------------- /src/components/sections/YouTubeEmbedSection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Container from '../core/Container.astro'; 3 | import YouTubeEmbed from '../core/YouTubeEmbed.astro'; 4 | 5 | const {url, rounded} = Astro.props; 6 | --- 7 | 8 | 9 |
    10 | 11 |
    12 |
    13 | 14 | -------------------------------------------------------------------------------- /src/components/sections/heros/HeroSection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Container } from '@components/odyssey-theme'; 3 | --- 4 | 5 | 6 |
    7 |
    8 | 9 |
    10 |
    11 | 12 | 13 |
    14 |
    15 |
    16 | 17 | 55 | -------------------------------------------------------------------------------- /src/components/sections/heros/HomeHeroSection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from 'astro-icon/components'; 3 | import { Container, Button } from '@components/odyssey-theme'; 4 | import settings from '../../../config/settings.js'; 5 | import {ThemeSwitcher} from '../../theme-switcher/theme-switcher'; 6 | --- 7 | 8 | 9 |
    10 |
    11 |

    Welcome to Odyssey

    12 |

    13 | A marketing website theme built with Astro and carefully crafted for startups and businesses. 18 |

    19 |
    20 | 27 | 28 |
    29 | {settings.enableThemeSwitcher && } 30 |
    31 |
    32 | 33 | Astro Odyssey 38 | 39 |
    40 |
    41 |
    42 | 43 | -------------------------------------------------------------------------------- /src/components/sections/heros/TextAndImageHero.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Container } from '@components/odyssey-theme'; 3 | 4 | const { reversed } = Astro.props; 5 | --- 6 | 7 | 8 |
    13 |
    14 | 15 |
    16 | 17 |
    18 |
    19 |
    20 | 21 |
    22 |
    23 |
    24 | 25 | 59 | -------------------------------------------------------------------------------- /src/components/theme-switcher/ThemeProvider.astro: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | 5 | 13 | -------------------------------------------------------------------------------- /src/components/theme-switcher/icons.ts: -------------------------------------------------------------------------------- 1 | import { html } from 'lit'; 2 | 3 | export const classicThemeIcon = html` 10 | 11 | 15 | 19 | 23 | `; 24 | 25 | export const darkThemeIcon = html` 32 | 33 | 37 | 41 | 45 | `; 46 | 47 | export const earthThemeIcon = html` 54 | 55 | 59 | 63 | 67 | `; 68 | 69 | export const blueThemeIcon = html` 76 | 77 | 81 | 85 | 89 | `; 90 | 91 | export const orangeThemeIcon = html` 98 | 99 | 103 | 107 | 111 | `; 112 | -------------------------------------------------------------------------------- /src/components/theme-switcher/theme-switcher.ts: -------------------------------------------------------------------------------- 1 | import { LitElement, html, css } from 'lit'; 2 | import { customElement, property } from 'lit/decorators.js'; 3 | 4 | import { 5 | classicThemeIcon, 6 | darkThemeIcon, 7 | earthThemeIcon, 8 | blueThemeIcon, 9 | orangeThemeIcon, 10 | } from './icons'; 11 | 12 | const themes = [ 13 | { 14 | name: 'default', 15 | icon: classicThemeIcon, 16 | label: 'Classic', 17 | }, 18 | { 19 | name: 'dark', 20 | icon: darkThemeIcon, 21 | label: 'Dark', 22 | }, 23 | { 24 | name: 'earth', 25 | icon: earthThemeIcon, 26 | label: 'Earth', 27 | }, 28 | { 29 | name: 'ocean', 30 | icon: blueThemeIcon, 31 | label: 'Ocean', 32 | }, 33 | { 34 | name: 'sand', 35 | icon: orangeThemeIcon, 36 | label: 'Sand', 37 | } 38 | ] 39 | 40 | @customElement('theme-switcher') 41 | export class ThemeSwitcher extends LitElement { 42 | static styles = [ 43 | css` 44 | :host { 45 | display: block; 46 | } 47 | button { 48 | display: inline-flex; 49 | outline: none; 50 | border: none; 51 | background-color: transparent; 52 | border: 2px solid transparent; 53 | border-radius: 20rem; 54 | padding: 1px; 55 | cursor: pointer; 56 | transition: border var(--theme-transition); 57 | } 58 | button[active] { 59 | border: 2px solid var(--theme-primary); 60 | box-shadow: 0 0 12px 1px var(--theme-primary); 61 | } 62 | button:hover { 63 | border: 2px solid var(--theme-primary); 64 | } 65 | .theme-switcher__container { 66 | margin: 2rem 0; 67 | display: grid; 68 | grid-template-columns: repeat(5, 1fr); 69 | } 70 | .theme-select__container { 71 | display: flex; 72 | flex-direction: column; 73 | align-items: center; 74 | justify-content: center; 75 | } 76 | .theme-select__container p { 77 | font-size: var(--font-size-sm); 78 | } 79 | `, 80 | ]; 81 | 82 | // set the _doc element 83 | private _doc = document.firstElementChild; 84 | 85 | @property({ type: String }) 86 | theme: string | null = null; 87 | 88 | private _getCurrentTheme() { 89 | // check for a local storage theme first 90 | const localStorageTheme = localStorage.getItem('theme'); 91 | if (localStorageTheme !== null) { 92 | this._setTheme(localStorageTheme); 93 | } else { 94 | // Set default theme to dark if the operating system specifies this preference 95 | if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { 96 | this._setTheme('dark'); 97 | } else{ // Set to default/light theme if no specification, or light theme is specified 98 | this._setTheme('default'); 99 | } 100 | 101 | } 102 | } 103 | 104 | firstUpdated() { 105 | this._getCurrentTheme(); 106 | } 107 | 108 | private _setTheme(theme) { 109 | this._doc.setAttribute('data-theme', theme); 110 | 111 | const _heroImage = document.querySelector('#home-hero-image') as HTMLImageElement; 112 | if (theme === 'default') { 113 | _heroImage.src = '/assets/images/home/classic-hero.jpg'; 114 | } 115 | if (theme === 'dark') { 116 | _heroImage.src = '/assets/images/home/dark-hero.jpg'; 117 | } 118 | if (theme === 'earth') { 119 | _heroImage.src = '/assets/images/home/earth-hero.jpg'; 120 | } 121 | if (theme === 'ocean') { 122 | _heroImage.src = '/assets/images/home/ocean-hero.jpg'; 123 | } 124 | if (theme === 'sand') { 125 | _heroImage.src = '/assets/images/home/sand-hero.jpg'; 126 | } 127 | localStorage.setItem('theme', theme); 128 | this.theme = theme; 129 | } 130 | 131 | render() { 132 | const themeButtons = html`${themes.map((theme) => { 133 | return html` 134 |
    135 | 142 |

    ${theme.label}

    143 |
    144 | ` 145 | })}` 146 | 147 | return html` 148 |
    149 | ${themeButtons} 150 |
    151 | `; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/config/footer.js: -------------------------------------------------------------------------------- 1 | export const footerSocials = [ 2 | { 3 | name: 'Twitter', 4 | url: 'https://twitter.com/jaydanurwin', 5 | icon: "mdi:twitter", 6 | }, 7 | { 8 | name: 'Youtube', 9 | url: 'https://youtube.com/@jaydanurwin', 10 | icon: "mdi:youtube", 11 | }, 12 | { 13 | name: 'Github', 14 | url: 'https://github.com/jaydanurwin', 15 | icon: "mdi:github", 16 | }, 17 | { 18 | name: 'Discord', 19 | url: 'https://astro.build/chat', 20 | icon: "ic:baseline-discord", 21 | }, 22 | ] 23 | 24 | export const footerLists = [ 25 | { 26 | title: 'Landing Pages', 27 | items: [ 28 | { 29 | title: 'Landing Page 1', 30 | slug: '/landing-pages/landing-1', 31 | }, 32 | { 33 | title: 'Landing Page 2', 34 | slug: '/landing-pages/landing-2', 35 | }, 36 | // { 37 | // title: 'Landing Page 3', 38 | // slug: '/landing-pages/landing-3', 39 | // }, 40 | ], 41 | }, 42 | { 43 | title: 'Company', 44 | items: [ 45 | { 46 | title: 'About', 47 | slug: '/company/about', 48 | }, 49 | { 50 | title: 'Blog', 51 | slug: '/blog', 52 | }, 53 | { 54 | title: 'Contact', 55 | slug: '/company/contact', 56 | }, 57 | ], 58 | }, 59 | { 60 | title: 'Theme', 61 | items: [ 62 | { 63 | title: 'Get Started', 64 | slug: '/theme/get-started', 65 | }, 66 | { 67 | title: 'Style Guide', 68 | slug: '/theme/style-guide', 69 | }, 70 | { 71 | title: 'Theme Setup', 72 | slug: '/theme/theme-setup', 73 | }, 74 | { 75 | title: 'Customizing Odyssey', 76 | slug: '/theme/customizing-odyssey', 77 | } 78 | ], 79 | }, 80 | ]; 81 | -------------------------------------------------------------------------------- /src/config/nav.js: -------------------------------------------------------------------------------- 1 | export const nav = [ 2 | { 3 | title: 'Home', 4 | slug: '/', 5 | }, 6 | { 7 | title: 'Blog', 8 | slug: '/blog', 9 | }, 10 | { 11 | title: 'About', 12 | slug: '/company/about', 13 | }, 14 | { 15 | title: 'Contact', 16 | slug: '/company/contact', 17 | }, 18 | ]; 19 | -------------------------------------------------------------------------------- /src/config/settings.js: -------------------------------------------------------------------------------- 1 | export default { 2 | title: `Odyssey Astro Theme | A Marketing Website Theme for Startups and Businesses`, 3 | description: `A simple, clean, and modern theme for a startup or businesses' marketing website.`, 4 | url: `https://odyssey-theme.sapling.supply`, // No trailing slash! 5 | name: `Odyssey`, // The short name of the business or brand name. Used for things like the copyright in the footer. 6 | enableThemeSwitcher: true, 7 | showPlug: true, // Disable this if you want to remove the plug from the footer. (╯°□°)╯︵ ┻━┻ 8 | }; 9 | -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// -------------------------------------------------------------------------------- /src/icons/icons.js: -------------------------------------------------------------------------------- 1 | export const twitterIcon = ` 2 | 3 | ` 4 | 5 | export const youtubeIcon = ` 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | `; 15 | 16 | export const githubIcon = ` 17 | 18 | ` 19 | 20 | export const instagramIcon = ` 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ` -------------------------------------------------------------------------------- /src/layouts/Base.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { SkipLink } from '@components/odyssey-theme'; 3 | import BaseHead from '../components/head/BaseHead.astro'; 4 | import type { Props as BaseHeadProps } from '../components/head/BaseHead.astro'; 5 | 6 | export interface Props { 7 | seo?: BaseHeadProps; 8 | } 9 | 10 | const { seo } = Astro.props; 11 | --- 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
    22 | 23 |
    24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/layouts/Page.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Header, Button, Footer } from '@components/odyssey-theme'; 3 | import Layout from './Base.astro'; 4 | import type { Props as BaseHeadProps } from '../components/head/BaseHead.astro'; 5 | import Logo from '../components/Logo.astro'; 6 | import settings from '../config/settings'; 7 | import { footerLists, footerSocials } from '../config/footer'; 8 | 9 | 10 | export interface Props { 11 | seo?: BaseHeadProps; 12 | } 13 | 14 | import { nav } from '../config/nav.js'; 15 | 16 | const { seo } = Astro.props as Props; 17 | --- 18 | 19 | 20 |
    21 | 22 | 23 | 24 | 25 |
    26 |
    27 | 28 |
    29 |
    38 | 39 |
    40 |
    41 | -------------------------------------------------------------------------------- /src/layouts/Post.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Container } from '@components/odyssey-theme'; 3 | import Layout from './Page.astro'; 4 | import { generateTagData } from '../utils/helpers'; 5 | 6 | const {content: {title, description, publishDate, canonicalURL, featuredImage, tags} } = Astro.props; 7 | 8 | let allTagsData = []; 9 | 10 | if(tags && tags.length > 0){ 11 | allTagsData = generateTagData(tags); 12 | } 13 | 14 | const seo = { 15 | title, 16 | description, 17 | publishDate, 18 | canonicalURL, 19 | image: featuredImage, 20 | }; 21 | --- 22 | 23 |
    24 | 33 |

    {title}

    34 |

    35 | 36 |

    37 | {featuredImage && {title}} 38 |
    39 | 40 |
    41 | 42 |
    43 |
    44 |
    45 | 46 | -------------------------------------------------------------------------------- /src/pages/404.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Button, Container, TextCardSection } from '@components/odyssey-theme'; 3 | import Layout from '../layouts/Page.astro'; 4 | 5 | const seo = { 6 | title: 'Get Started using the Astro Odyssey Theme', 7 | description: 'Get started on how to setup and use this Astro theme.', 8 | }; 9 | --- 10 | 11 | 12 | 13 | 14 |

    404

    15 |

    Page Not Found 👀

    16 |
    17 | 18 |
    19 |
    20 |
    21 |
    22 | 23 | 42 | -------------------------------------------------------------------------------- /src/pages/blog/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { parse, isBefore } from 'date-fns'; 3 | import { 4 | Container, 5 | TextCardSection, 6 | BlogPostsList, 7 | } from '@components/odyssey-theme'; 8 | import Layout from '../../layouts/Page.astro'; 9 | import NewsletterForm from '../../components/forms/NewsletterForm.astro'; 10 | 11 | const posts = await Astro.glob('./posts/*.mdx').then(posts => 12 | posts 13 | .map(({ frontmatter, url }) => ({ 14 | title: frontmatter.title, 15 | description: frontmatter.description, 16 | authors: frontmatter.authors, 17 | publishDate: parse(frontmatter.publishDate, 'MMMM d, yyyy', new Date()), 18 | featuredImage: frontmatter.featuredImage, 19 | excerpt: frontmatter.excerpt, 20 | href: url, 21 | })) 22 | .sort((a, b) => { 23 | if (isBefore(a.publishDate, b.publishDate)) return 1; 24 | if (isBefore(b.publishDate, a.publishDate)) return -1; 25 | return 0; 26 | }) 27 | ); 28 | 29 | const seo = { 30 | title: 'Blog | Astro Odyssey Theme', 31 | description: 'Astro Odyssey Theme Blog Page', 32 | }; 33 | --- 34 | 35 | 36 | 37 | 38 |

    Odyssey Blog

    39 |

    40 | View our blog to stay up to date on the latest news about our business. 41 | Want to be the first to hear about a new blog post? Join our newsletter! 42 |

    43 | 44 |
    45 |
    46 |

    Recent Posts

    47 | 48 |
    49 |
    50 |
    51 | 52 | 57 | -------------------------------------------------------------------------------- /src/pages/blog/posts/consider-hybrid-work.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../../../layouts/Post.astro' 3 | title: Top 10 Reasons To Consider A Hybrid Work Model 4 | description: This is a sample blog post for Odyssey 5 | publishDate: February 22, 2021 6 | featuredImage: '/assets/images/blog/consider-hybrid-work/featured.jpg' 7 | excerpt: 'This is also a sample blog post for the Odyssey Theme.' 8 | tags: ['Remote Work'] 9 | --- 10 | 11 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Quis risus sed vulputate odio ut enim blandit volutpat maecenas. Ipsum a arcu cursus vitae congue mauris rhoncus aenean vel. Nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum. Fames ac turpis egestas sed tempus urna et pharetra pharetra. Donec ultrices tincidunt arcu non sodales. Diam in arcu cursus euismod quis viverra nibh cras. Lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare. Vitae congue mauris rhoncus aenean vel elit scelerisque mauris pellentesque. Sit amet volutpat consequat mauris. Venenatis tellus in metus vulputate eu scelerisque felis. Diam phasellus vestibulum lorem sed. Nisl nunc mi ipsum faucibus vitae. Tortor vitae purus faucibus ornare. Eget nunc scelerisque viverra mauris in aliquam. Quisque sagittis purus sit amet volutpat consequat mauris. Donec enim diam vulputate ut pharetra sit amet. 12 | 13 | Dis parturient montes nascetur ridiculus mus mauris vitae. Nunc consequat interdum varius sit amet mattis. Sit amet porttitor eget dolor morbi non arcu. Eu scelerisque felis imperdiet proin fermentum leo. Blandit volutpat maecenas volutpat blandit aliquam etiam. Quis varius quam quisque id diam. Tincidunt nunc pulvinar sapien et ligula ullamcorper. Mattis rhoncus urna neque viverra justo nec. Venenatis tellus in metus vulputate eu scelerisque. Mollis aliquam ut porttitor leo a diam sollicitudin tempor. Quis lectus nulla at volutpat diam. Lorem ipsum dolor sit amet consectetur adipiscing elit duis. 14 | 15 | Fames ac turpis egestas sed tempus. Condimentum mattis pellentesque id nibh tortor id aliquet lectus. Neque egestas congue quisque egestas diam. Arcu cursus vitae congue mauris. Faucibus vitae aliquet nec ullamcorper. Mi eget mauris pharetra et ultrices neque. Neque aliquam vestibulum morbi blandit cursus risus at ultrices mi. Porttitor leo a diam sollicitudin tempor id eu. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. A condimentum vitae sapien pellentesque habitant morbi tristique senectus. Molestie nunc non blandit massa enim nec dui. Ac tortor dignissim convallis aenean et tortor at risus viverra. Facilisis mauris sit amet massa. Elementum nibh tellus molestie nunc non blandit massa enim nec. Commodo odio aenean sed adipiscing diam donec. Posuere lorem ipsum dolor sit amet consectetur adipiscing elit. Nec sagittis aliquam malesuada bibendum arcu vitae. Velit euismod in pellentesque massa placerat. Id eu nisl nunc mi. 16 | 17 | Sit amet massa vitae tortor condimentum. Mattis nunc sed blandit libero volutpat sed cras. Lectus magna fringilla urna porttitor rhoncus. Id velit ut tortor pretium viverra. Sit amet nisl suscipit adipiscing bibendum est ultricies integer. Enim praesent elementum facilisis leo vel fringilla est ullamcorper eget. Sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque. Habitant morbi tristique senectus et netus et malesuada fames ac. Maecenas ultricies mi eget mauris pharetra et ultrices neque ornare. Mauris ultrices eros in cursus turpis. Sit amet dictum sit amet justo donec enim diam. Ut lectus arcu bibendum at varius vel pharetra vel turpis. Eu facilisis sed odio morbi quis commodo. Adipiscing bibendum est ultricies integer. Nisi vitae suscipit tellus mauris a diam maecenas sed enim. Quam viverra orci sagittis eu volutpat. 18 | 19 | Pellentesque habitant morbi tristique senectus. Ut tellus elementum sagittis vitae et leo. Quis blandit turpis cursus in hac habitasse platea dictumst. Posuere lorem ipsum dolor sit amet consectetur adipiscing elit duis. At volutpat diam ut venenatis tellus in metus. Sagittis eu volutpat odio facilisis mauris sit amet. Et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit. Felis eget nunc lobortis mattis aliquam. Facilisis magna etiam tempor orci eu. Aliquam faucibus purus in massa tempor nec feugiat nisl. Quis hendrerit dolor magna eget est lorem ipsum dolor. Proin libero nunc consequat interdum. Mauris cursus mattis molestie a. 20 | -------------------------------------------------------------------------------- /src/pages/blog/posts/odyssey-theme-officially-released.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../../../layouts/Post.astro' 3 | title: Odyssey Theme Has Officially Been Released! 4 | description: This is a sample blog post for Odyssey 5 | publishDate: May 15, 2022 6 | featuredImage: '/assets/images/blog/odyssey-theme-officially-released/featured.jpg' 7 | excerpt: 'The time has come to officially release Odyssey Theme to the world. Learn more about what it is and how you can start using it today.' 8 | tags: 9 | - Odyssey Theme 10 | --- 11 | 12 | import {Button} from '@components/odyssey-theme' 13 | 14 | ## Getting Started 15 | 16 | To get started with the Odyssey Theme clone the [Odyssey Theme Repository](https://gixthub.com/treefarmstudio/odyssey-theme) directly from GitHub . -------------------------------------------------------------------------------- /src/pages/blog/posts/remote-work-mental-health.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../../../layouts/Post.astro' 3 | title: Is Remote Work Better For Your Mental Health? 4 | description: This is a sample blog post for Odyssey 5 | publishDate: July 4, 2021 6 | featuredImage: '/assets/images/blog/remote-work-mental-health/featured.jpg' 7 | excerpt: 'This is a sample blog post for the Odyssey Theme. If an excerpt is provided it will appear in the preview.' 8 | tags: ['Remote Work'] 9 | --- 10 | 11 | import {YouTubeEmbed} from '@components/odyssey-theme' 12 | 13 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Quis risus sed vulputate odio ut enim blandit volutpat maecenas. Ipsum a arcu cursus vitae congue mauris rhoncus aenean vel. Nunc eget lorem dolor sed viverra ipsum nunc aliquet bibendum. Fames ac turpis egestas sed tempus urna et pharetra pharetra. Donec ultrices tincidunt arcu non sodales. Diam in arcu cursus euismod quis viverra nibh cras. Lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi tincidunt ornare. Vitae congue mauris rhoncus aenean vel elit scelerisque mauris pellentesque. Sit amet volutpat consequat mauris. Venenatis tellus in metus vulputate eu scelerisque felis. Diam phasellus vestibulum lorem sed. Nisl nunc mi ipsum faucibus vitae. Tortor vitae purus faucibus ornare. Eget nunc scelerisque viverra mauris in aliquam. Quisque sagittis purus sit amet volutpat consequat mauris. Donec enim diam vulputate ut pharetra sit amet. 14 | 15 | 16 | 17 | Dis parturient montes nascetur ridiculus mus mauris vitae. Nunc consequat interdum varius sit amet mattis. Sit amet porttitor eget dolor morbi non arcu. Eu scelerisque felis imperdiet proin fermentum leo. Blandit volutpat maecenas volutpat blandit aliquam etiam. Quis varius quam quisque id diam. Tincidunt nunc pulvinar sapien et ligula ullamcorper. Mattis rhoncus urna neque viverra justo nec. Venenatis tellus in metus vulputate eu scelerisque. Mollis aliquam ut porttitor leo a diam sollicitudin tempor. Quis lectus nulla at volutpat diam. Lorem ipsum dolor sit amet consectetur adipiscing elit duis. 18 | 19 | > “If life were predictable it would cease to be life, and be without flavor.” – Eleanor Roosevelt 20 | 21 | Fames ac turpis egestas sed tempus. Condimentum mattis pellentesque id nibh tortor id aliquet lectus. Neque egestas congue quisque egestas diam. Arcu cursus vitae congue mauris. Faucibus vitae aliquet nec ullamcorper. Mi eget mauris pharetra et ultrices neque. Neque aliquam vestibulum morbi blandit cursus risus at ultrices mi. Porttitor leo a diam sollicitudin tempor id eu. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. A condimentum vitae sapien pellentesque habitant morbi tristique senectus. Molestie nunc non blandit massa enim nec dui. Ac tortor dignissim convallis aenean et tortor at risus viverra. Facilisis mauris sit amet massa. Elementum nibh tellus molestie nunc non blandit massa enim nec. Commodo odio aenean sed adipiscing diam donec. Posuere lorem ipsum dolor sit amet consectetur adipiscing elit. Nec sagittis aliquam malesuada bibendum arcu vitae. Velit euismod in pellentesque massa placerat. Id eu nisl nunc mi. 22 | 23 | Sit amet massa vitae tortor condimentum. Mattis nunc sed blandit libero volutpat sed cras. Lectus magna fringilla urna porttitor rhoncus. Id velit ut tortor pretium viverra. Sit amet nisl suscipit adipiscing bibendum est ultricies integer. Enim praesent elementum facilisis leo vel fringilla est ullamcorper eget. Sollicitudin ac orci phasellus egestas tellus rutrum tellus pellentesque. Habitant morbi tristique senectus et netus et malesuada fames ac. Maecenas ultricies mi eget mauris pharetra et ultrices neque ornare. Mauris ultrices eros in cursus turpis. Sit amet dictum sit amet justo donec enim diam. Ut lectus arcu bibendum at varius vel pharetra vel turpis. Eu facilisis sed odio morbi quis commodo. Adipiscing bibendum est ultricies integer. Nisi vitae suscipit tellus mauris a diam maecenas sed enim. Quam viverra orci sagittis eu volutpat. 24 | 25 | Pellentesque habitant morbi tristique senectus. Ut tellus elementum sagittis vitae et leo. Quis blandit turpis cursus in hac habitasse platea dictumst. Posuere lorem ipsum dolor sit amet consectetur adipiscing elit duis. At volutpat diam ut venenatis tellus in metus. Sagittis eu volutpat odio facilisis mauris sit amet. Et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit. Felis eget nunc lobortis mattis aliquam. Facilisis magna etiam tempor orci eu. Aliquam faucibus purus in massa tempor nec feugiat nisl. Quis hendrerit dolor magna eget est lorem ipsum dolor. Proin libero nunc consequat interdum. Mauris cursus mattis molestie a. 26 | -------------------------------------------------------------------------------- /src/pages/blog/tags/[slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../../../layouts/Page.astro' 3 | import { Container } from '@components/odyssey-theme'; 4 | import {generateTagData} from '../../../utils/helpers.js' 5 | 6 | 7 | export async function getStaticPaths() { 8 | const allPosts = await Astro.glob('../posts/*.mdx'); 9 | const sortedPosts = allPosts.sort((a, b) => new Date(b.frontmatter.date).valueOf() - new Date(a.frontmatter.date).valueOf()); 10 | const allCategoriesUnique = new Set(); 11 | 12 | sortedPosts.forEach(post => { 13 | post.frontmatter.tags && post.frontmatter.tags.map(tag => { 14 | allCategoriesUnique.add(tag); 15 | }) 16 | }) 17 | 18 | const allCategoriesData = generateTagData(allCategoriesUnique); 19 | // map through the categories array 20 | return allCategoriesData.map((tag) => { 21 | // filter the posts that match the given category 22 | const posts = sortedPosts.filter((post) => post.frontmatter.tags.includes(tag.title)) 23 | return { 24 | params: {slug: tag.slug}, 25 | props: { 26 | tag: tag.title, 27 | posts: posts 28 | } 29 | }; 30 | }); 31 | } 32 | 33 | const {tag, posts} = Astro.props; 34 | 35 | const seo ={ 36 | title: `${tag} | Astro Odyssey`, 37 | } 38 | --- 39 | 40 | 41 | 42 |
    43 |

    Posts Tagged with "{tag}"

    44 | 49 |
    50 |
    51 |
    52 | 53 | -------------------------------------------------------------------------------- /src/pages/blog/tags/index.astro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treefarmstudio/odyssey-theme/d191e5715a2519e25be4629b933189c421b30a1a/src/pages/blog/tags/index.astro -------------------------------------------------------------------------------- /src/pages/company/about.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { TextSection } from '@components/odyssey-theme'; 3 | import Layout from '../../layouts/Page.astro'; 4 | import HeroSection from '../../components/sections/heros/HeroSection.astro'; 5 | 6 | const seo = { 7 | title: 'About | Astro Odyssey Theme', 8 | description: 'About Page', 9 | }; 10 | --- 11 | 12 | 13 | 14 |
    15 |

    About Odyssey

    16 |

    17 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet, nisi 18 | recusandae? Quidem dignissimos nobis, dicta unde, aperiam voluptate 19 | autem iste reprehenderit, aliquam ducimus illo ea ipsum qui animi sequi. 20 | Numquam. 21 |

    22 |
    23 | 24 | Astro Odyssee 29 | 30 |
    31 | 32 |

    33 | Lorem ipsum dolor sit amet consectetur, adipisicing elit. Explicabo asperiores alias illo accusamus voluptatem ea cum nemo odit! Consequatur quidem quo iusto quam ea neque nisi dolorum quod, recusandae id! 34 | Repudiandae, fugit labore voluptatum beatae modi omnis adipisci corrupti aut aliquid cumque inventore iure possimus doloremque iste incidunt nulla architecto. Nobis iusto sunt voluptatem necessitatibus laborum, earum doloremque fugit rerum! 35 |

    36 |

    Fugit asperiores harum consectetur sapiente deleniti. Optio enim tenetur impedit reprehenderit labore, illo eius in, consequatur odio dolore iste assumenda explicabo, nisi similique qui obcaecati possimus delectus reiciendis quod modi.

    37 | 38 |

    39 | Vel tempore rem omnis esse officiis optio, explicabo, quod deleniti adipisci ullam cum necessitatibus eius minus vero saepe ad, dicta rerum praesentium deserunt illo itaque odio corrupti voluptatum quibusdam. Pariatur. 40 | Porro neque tempore, illum eligendi deleniti iure dolorem amet magnam at dolores veniam nemo cumque aut alias repellat est dicta sit repellendus facilis officia? Minima dolorum quo ducimus adipisci perferendis. 41 |

    42 |

    43 | Quis distinctio tempora sequi sit repudiandae cumque nostrum deserunt, voluptatibus rem eum fuga modi beatae cum ullam delectus dicta atque eius nam quos corporis. Animi praesentium quae nobis. Odit, mollitia. Voluptatum, hic explicabo. Ex accusamus ipsa ea dolor commodi quas esse ipsum alias et adipisci error necessitatibus atque facere rerum ratione consequatur aspernatur repudiandae minima consectetur fuga, doloremque dolorum pariatur. 44 | Ipsam error eaque velit possimus porro eum quod illo iusto officia magnam magni, beatae nisi voluptate praesentium? Saepe distinctio adipisci quas hic quae facilis? Sequi eum hic aperiam impedit minus? 45 |

    46 |
    47 |
    48 | -------------------------------------------------------------------------------- /src/pages/company/contact.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import ContactForm from '../../components/forms/ContactForm.astro'; 3 | import Layout from '../../layouts/Page.astro'; 4 | import { Container } from '@components/odyssey-theme'; 5 | 6 | const seo = { 7 | title: 'Contact | Astro Odyssey Theme', 8 | description: 'Contact Page', 9 | }; 10 | --- 11 | 12 | 13 | 14 |
    15 |
    16 |

    Contact Us

    17 |

    18 | This is a contact form using Odyssey's form components to create a 19 | contact form component. The contact form is setup to use Netlify's 20 | form detection; however, it can easily be translated to other popular 21 | form services such as Formspree, Getform, Formspark, etc. 22 |

    23 |
    24 |

    25 | (800) 867-5309hello@ourcompany.com 29 |

    30 |
    31 |
    32 |
    33 | 34 |
    35 |
    36 |
    37 |
    38 | 39 | 66 | -------------------------------------------------------------------------------- /src/pages/company/legal.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { TextSection } from '@components/odyssey-theme'; 3 | import Layout from '../../layouts/Page.astro'; 4 | 5 | const seo = { 6 | title: `Legal Page | Astro Odyssey Theme`, 7 | description: `This is the legal page template. It is a great starter for your company's Terms of Service, Terms & Conditions, Privacy Policy, etc.`, 8 | }; 9 | --- 10 | 11 | 12 | 13 |

    Legal Page

    14 | 15 |

    This is the legal page template. It is a great starter for your company's Terms of Service, Terms & Conditions, 16 | Privacy Policy, etc.

    17 | 18 |

    Terms of Service

    19 | 20 |

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore, obcaecati. Aspernatur facilis molestias 21 | vitae. Aliquid debitis eum quis repudiandae pariatur possimus provident accusantium reiciendis nemo, culpa labore 22 | laborum, dolorum ea.

    23 | 24 |

    Corrupti impedit perferendis, libero in, voluptates quod ratione repudiandae veniam sapiente necessitatibus, eius 25 | illo. Impedit quibusdam esse saepe placeat incidunt voluptatibus soluta dolore blanditiis ad provident animi 26 | illum, est adipisci?

    27 | 28 |

    Ratione optio necessitatibus numquam dignissimos sunt molestiae ipsum fugiat quae maxime veniam aspernatur eius 29 | quidem vel reprehenderit sequi, molestias perspiciatis, illo architecto perferendis nobis, in dolore! Nam 30 | asperiores eaque totam.

    31 | 32 |

    Repudiandae, labore alias. Voluptatem quia itaque sequi, aperiam, reprehenderit ipsum libero quae adipisci 33 | possimus eum esse corrupti sapiente harum dignissimos eligendi cum iure tempora magnam nemo, sunt provident vero. 34 | Voluptatibus.

    35 | 36 |

    Privacy Policy

    37 | 38 |

    39 | Lorem ipsum, dolor sit amet consectetur adipisicing elit. Natus eveniet quibusdam ipsa, veniam adipisci rerum 40 | temporibus inventore! Sit quas vero laboriosam tempora alias! Fugit, saepe earum quod modi harum qui. 41 | Expedita, pariatur consequuntur! Modi, maiores. Quaerat voluptatibus nostrum non harum rerum dolorem totam qui 42 | repellendus, itaque dignissimos eveniet consequuntur ducimus! Non commodi magnam nemo, pariatur facilis 43 | repellendus sunt fuga ipsa. 44 |

    45 | 46 |

    Consequuntur similique ab ea tenetur, quo aperiam molestias sed facilis minus eaque eveniet libero quis 47 | accusantium deleniti tempore? Qui vel reiciendis voluptates corporis eum repellat maiores fugit, eveniet sapiente 48 | ad.

    49 |
    50 |
    -------------------------------------------------------------------------------- /src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Container, FeatureCard } from '@components/odyssey-theme'; 3 | 4 | import Layout from '../layouts/Page.astro'; 5 | import HomeHeroSection from '../components/sections/heros/HomeHeroSection.astro'; 6 | --- 7 | 8 | 9 | 10 | 11 |
    12 |

    Landing Pages

    13 |

    14 | Use one of our landing pages to jumpstart your website or 15 | ad campaign. 16 |

    17 |
    18 | 19 | 20 | 21 | 22 |
    23 |
    24 |
    25 | 26 | 27 |
    28 |

    Company Pages

    29 |

    30 | Use one of our prebuilt company pages for your about page, contact page, 31 | legal pages, blog posts, etc. 32 |

    33 |
    34 | 35 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 51 | 52 |
    53 |
    54 |
    55 | 56 | 57 |
    58 |

    Theme Pages

    59 |

    Learn more about how to set up and use the Odyssey Theme.

    60 |
    61 | 66 | 67 | 72 | 73 |
    74 |
    75 |
    76 |
    77 | 78 | 93 | -------------------------------------------------------------------------------- /src/pages/landing-pages/landing-1.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from 'astro-icon/components'; 3 | import { 4 | AnnouncementBar, 5 | Button, 6 | CustomerQuoteSection, 7 | ThreeColumnTextSection, 8 | YouTubeEmbedSection, 9 | StickyTextImageSection, 10 | CtaCardSection, 11 | } from '@components/odyssey-theme'; 12 | import Layout from '../../layouts/Page.astro'; 13 | import TextAndImageHero from '../../components/sections/heros/TextAndImageHero.astro'; 14 | 15 | const seo = { 16 | title: 'Landing Page #1 | Astro Odyssey Theme', 17 | description: 'Landing Page #1 | Astro Odyssey Theme', 18 | }; 19 | --- 20 | 21 | 26 | 27 | 28 |
    29 |

    Don't Reinvent the Wheel

    30 |

    Use Odyssey Theme to jumpstart your company's marketing website.

    31 |
    32 |
    33 | 38 |
    39 | 40 | Astro Odyssee 45 | 46 |
    47 | 48 | 52 | 53 | 54 |
    55 |

    Why?

    56 |

    57 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolorem 58 | tempore odio! Nemo consectetur ipsa aperiam similique maxime maiores 59 | consequatur explicabo ut quibusdam fugiat corporis, dignissimos tenetur, 60 | mollitia cumque. Velit. 61 |

    62 |
    63 | 64 |
    65 |

    How?

    66 |

    67 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolorem 68 | tempore odio! Nemo consectetur ipsa aperiam similique maxime maiores 69 | consequatur explicabo ut quibusdam fugiat corporis, dignissimos tenetur, 70 | mollitia cumque. Velit. 71 |

    72 |
    73 | 74 |
    75 |

    What?

    76 |

    77 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolorem 78 | tempore odio! Nemo consectetur ipsa aperiam similique maxime maiores 79 | consequatur explicabo ut quibusdam fugiat corporis, dignissimos tenetur, 80 | mollitia cumque. Velit. 81 |

    82 |
    83 | 84 |
    85 | 86 | 88 | 89 | 90 |
    91 |

    Features

    92 |

    SEO

    93 |

    94 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolorem 95 | tempore odio! Nemo consectetur ipsa aperiam similique maxime maiores 96 | consequatur explicabo ut quibusdam fugiat corporis, dignissimos tenetur, 97 | mollitia cumque. Velit. 98 |

    99 |

    Responsive

    100 |

    101 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolorem 102 | tempore odio! Nemo consectetur ipsa aperiam similique maxime maiores 103 | consequatur explicabo ut quibusdam fugiat corporis, dignissimos tenetur, 104 | mollitia cumque. Velit. 105 |

    106 |

    Themeable

    107 |

    108 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolorem 109 | tempore odio! Nemo consectetur ipsa aperiam similique maxime maiores 110 | consequatur explicabo ut quibusdam fugiat corporis, dignissimos tenetur, 111 | mollitia cumque. Velit. 112 |

    113 |
    114 | 115 | Astro Odyssey 120 | 121 |
    122 | 123 | 127 |

    Start Your Website Today

    128 |

    129 | It only takes a couple clicks to have a new, modern website for your 130 | business or startup. 131 |

    132 | 137 |
    138 |
    139 | -------------------------------------------------------------------------------- /src/pages/landing-pages/landing-2.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../../layouts/Base.astro'; 3 | import LandingContactForm from '../../components/forms/LandingContactForm.astro'; 4 | import Logo from '../../components/Logo.astro'; 5 | 6 | const seo = { 7 | title: 'Landing Page #2 | Astro Odyssey Theme', 8 | description: 'Landing Page #2 | Astro Odyssey Theme', 9 | }; 10 | --- 11 | 12 | 13 |
    14 |
    15 | 20 | 21 | Astro Odyssey 26 | 27 |
    28 |
    29 |
    30 |

    Contact Us For a Free Consultation

    31 |

    Fill out the form below to schedule a free consultation on your business' website needs.

    32 | 33 |
    34 |
    35 |
    36 |
    37 | 38 | 91 | 92 | -------------------------------------------------------------------------------- /src/pages/theme/customizing-odyssey.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../../layouts/Post.astro' 3 | title: Customizing Odyssey Theme 4 | description: Learn how to customize Odyssey Theme's theme styles. 5 | --- 6 | 7 | This is one of the core features of Odyssey Theme and we've made it super easy to make the overall look and feel of the site your own with just a few top-level CSS custom properties. These custom properties and demo themes will be found in the `theme.css` file under `src/styles/`. 8 | 9 | First, If you are not planning on using the theme switcher found on the demo's home page we would recommend you go to the `settings.js` file under `src/config/` and set `enableThemeSwitcher` to false. This will remove the theme switcher components and javascript from your website. 10 | 11 | It should look something like this. 12 | 13 | ```js 14 | export default { 15 | title: `Odyssey Astro Theme | A Marketing Website Theme for Startups and Businesses`, 16 | description: `A simple, clean, and modern theme a startup or businesses' marketing website.`, 17 | ... 18 | enableThemeSwitcher: false, 19 | }; 20 | ``` 21 | 22 | Second, if you are only going to have one theme on your site (most common) then you can delete all of the `[data-theme]` rules from the file and only keep the `:root` theme that looks something like this. 23 | 24 | ```css 25 | :root { 26 | /* Theme Colors */ 27 | --theme-primary: hsl(0, 0%, 0%); 28 | --theme-primary-hover: hsl(0, 0%, 20%); 29 | --theme-on-primary: #fff; 30 | 31 | --theme-bg: #fff; 32 | --theme-on-bg: #000; 33 | 34 | --theme-surface-1: #f2f2f2; 35 | --theme-on-surface-1: #000; 36 | 37 | --theme-surface-2: #cce6d0; 38 | --theme-on-surface-2: #000; 39 | 40 | /* Theme Shapes */ 41 | /* Set this to 0 if you want all of the rounded cards, images, etc to be straight edges */ 42 | --theme-shape-radius: clamp(1rem, 2rem, 3rem); 43 | --theme-button-border-radius: 3rem; 44 | 45 | /* Theme Transition */ 46 | --theme-transition: 0.2s ease-in-out; 47 | 48 | /* Theme Layout */ 49 | --section-margin: 3rem; 50 | --theme-grid-gap: 1rem; 51 | --container-max-width: 1440px; 52 | --container-max-width-narrow: 960px; 53 | --container-padding: 0 1rem; 54 | 55 | --theme-blog-post-header-width: 1200px; 56 | 57 | /* Theme Fonts */ 58 | --theme-font-family-serif: 'Roboto Serif', Georgia, Cambria, 'Times New Roman', 59 | Times, serif; 60 | --theme-font-family-sans: 'Lato', -apple-system, BlinkMacSystemFont, 61 | sans-serif; 62 | } 63 | ``` 64 | 65 | Look below for a breakdown of each property. 66 | 67 | ## Colors 68 | 69 | Here is a quick breakdown of the color properties: 70 | 71 | - `--theme-primary` - The primary color of the theme. This would be the color used for the button backgrounds. 72 | - `--theme-primary-hover` - The color you would like the primary color to change to when hovered over. 73 | - `--theme-on-primary` - The color of text layered on top of the primary color. 74 | - `--theme-bg` - The background color of the site 75 | - `--theme-on-bg` - Default body text color 76 | - `--theme-surface-1` - The color used for cards layered on top of the background. Think of it like a global accent color or a secondary background color. 77 | - `--theme-on-surface-1` - The color used for text on top of the surface-1 color 78 | - `--theme-surface-2` - Similar to the surface-1 color but used less often. Feel free to be more creative with this surface to make it pop on the page. 79 | - `--theme-on-surface-2` - The color used for text on top of the surface-2 color 80 | 81 | ## Shapes 82 | 83 | You'll notice a lot of rounded corners on the Odyssey Theme but if you look closely when the "Dark" theme is enabled the corners are all hard edges. This is because of the global `--theme-shape-radius` property. It will determine the shape of things like cards and images. 84 | 85 | ## Transition 86 | 87 | Sometimes you want the animations to be consistent, especially on hover effects. This is where you would use the `--theme-transition` property. 88 | 89 | ## Layouts 90 | 91 | - `--section-margin` - The default top and bottom margin between sections 92 | - `--theme-grid-gap` - The default gap between items in a grid of cards, images, etc. 93 | - `--container-max-width` - The default container max width for content 94 | - `--container-max-width-narrow` - The narrow container max width for content 95 | - `--container-padding` - The default gutter padding on the container 96 | 97 | ## Custom Font(s) 98 | 99 | 1. Add our own fonts to the `/public/assets/fonts` directory 100 | 101 | 2. Update the `@font-face` rules in the `src/styles/typography.css` file 102 | 103 | 3. Update your font stack with the `--theme-font-family-serif` and `--theme-font-family-sans` custom properties. 104 | 105 | -------------------------------------------------------------------------------- /src/pages/theme/get-started.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import {Icon} from 'astro-icon/components'; 3 | import { Button, Container, TextCardSection } from '@components/odyssey-theme'; 4 | import Layout from '../../layouts/Page.astro'; 5 | 6 | const seo = { 7 | title: 'Get Started using the Astro Odyssey Theme', 8 | description: 'Get started on how to setup and use this Astro theme.', 9 | }; 10 | --- 11 | 12 | 13 | 14 | 15 |

    Get Started with Odyssey

    16 |
    17 | 28 | 37 | 46 |
    47 |
    48 |
    49 |
    50 | 51 | 61 | -------------------------------------------------------------------------------- /src/pages/theme/style-guide.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from 'astro-icon/components'; 3 | import { 4 | TextCardSection, 5 | Container, 6 | Button, 7 | FormInput, 8 | FormSelect, 9 | FormTextarea, 10 | } from '@components/odyssey-theme'; 11 | import Layout from '../../layouts/Page.astro'; 12 | 13 | const seo = { 14 | title: 'Astro Odyssey Theme Style Guide', 15 | description: 'Get started on how to setup and use this Astro theme.', 16 | }; 17 | 18 | const selectOptions = ['Option 1', 'Option 2', 'Option 3']; 19 | --- 20 | 21 | 22 | 23 | 24 |

    Style Guide

    25 |

    26 | This is the style guide for the Odyssey Theme. Everything you'll find in the theme's starter repo is either a 31 | component from the Odyssey Components Package or built using a component. Not only does this allow for a fully modular 36 | setup that receives updates and improvements over time but also allows you 37 | to use bits and pieces as needed to create your own unique website with Odyssey 38 | as the foundation. 39 |

    40 |
    41 |
    42 |
    43 |

    Colors

    44 |
    45 |
    46 |
    47 |

    Primary

    48 |
    49 |
    50 |

    Surface 1

    51 |
    52 |
    53 |

    Surface 2

    54 |
    55 |
    56 |
    57 |
    58 |
    59 |

    Typography

    60 |
    61 |
    62 |

    Heading 1

    63 |

    Heading 2

    64 |

    Heading 3

    65 |

    Heading 4

    66 |
    Heading 5
    67 |
    Heading 6
    68 |

    Body Text

    69 |
    70 | “Don’t settle for what life gives you; make life better and build 71 | something.” — Ashton Kutcher 72 |
    73 |
    74 |
    75 |
    76 |
    77 |

    Buttons

    78 |
    79 |
    80 |

    Button

    81 |

    82 | 83 |

    84 |

    Unelevated Button

    85 |

    86 | 87 |

    88 |

    Outlined Button

    89 |

    90 | 91 |

    92 |

    Button With Custom Icon

    93 | 99 |
    100 |
    101 |
    102 |
    103 |

    Forms

    104 |
    105 |
    106 |
    107 |

    Input With Label

    108 | 110 |
    111 |
    112 |

    Input Without Label

    113 | 114 |
    115 |
    116 |

    Select Dropdown

    117 | 118 |
    119 |
    120 |

    Textarea

    121 | 122 |
    123 |
    124 |
    125 |
    126 |
    127 | 128 | 167 | -------------------------------------------------------------------------------- /src/pages/theme/theme-setup.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | layout: '../../layouts/Post.astro' 3 | title: Theme Setup 4 | description: Learn how to setup Odyssey Theme's seo, logo, favicon, nav items, etc. 5 | --- 6 | 7 | After you've had some time to familiarize yourself with the the theme files you're probably wondering "How do I make it my own?" This guide will help you swap out titles, descriptions, logos, etc. 8 | 9 | 10 | ## Global SEO 11 | 12 | In the theme files you'll find a `settings.js` file under the `src/config/` folder. The contents of the file should look something like this: 13 | 14 | ```js 15 | export default { 16 | title: `Odyssey Astro Theme | A Marketing Website Theme for Startups and Businesses`, 17 | description: `A simple, clean, and modern theme a startup or businesses' marketing website.`, 18 | url: `https://odyssey-theme.sapling.supply`, // No trailing slash! 19 | name: `Odyssey`, // The short name of the business or brand name. Used for things like the copyright in the footer. 20 | enableThemeSwitcher: true, 21 | }; 22 | ``` 23 | 24 | The title and description fields here are used as the global defaults if one is not provided at the page level. 25 | 26 | ## Adding Your Own Logo 27 | 28 | Under `src/components/` you'll see a `Logo.astro` file that should look something like this: 29 | 30 | ```astro 31 | 32 | 33 | 46 | ``` 47 | 48 | The easiest way to swap out the Odyssey logo across the site is to replace this code with the SVG code for your company's logo or using an `` tag linked to your company logo. 49 | 50 | You should see that the Odyssey logo changes across the theme once this is updated. 51 | 52 | If you would like more control or don't like this method of using a `` component you will find most of the components also include a `` for the logo which will let you completely replace it. 53 | 54 | ## Favicon 55 | 56 | To replace the favicon you simply need to create your own `favicon.png` file and replace the one found under the `public/` folder. 57 | 58 | If you don't want to use a `.png` file you will need to go to the `BaseHead.astro` component under `src/components/head/` and find this line to replace with your own favicon file. 59 | 60 | ```html 61 | 62 | ``` 63 | 64 | ## Open Graph / Social Image 65 | 66 | To replace the default Open Graph image that displays when the link to your website is shared create your own `social.png` file and replace the one found under the `public/` folder. 67 | 68 | ## Navigation Items 69 | 70 | Customizing the navigation items is easily done by editing the array of items in the `nav.js` file found under the `src/config/` folder. 71 | 72 | It will look something like this: 73 | 74 | ```js 75 | export const nav = [ 76 | { 77 | title: 'Home', 78 | slug: '/', 79 | }, 80 | { 81 | title: 'Blog', 82 | slug: '/blog', 83 | }, 84 | { 85 | title: 'About', 86 | slug: '/company/about', 87 | }, 88 | { 89 | title: 'Contact', 90 | slug: '/company/contact', 91 | }, 92 | ]; 93 | ``` 94 | 95 | ## Footer Links 96 | 97 | In the `src/config/` folder you'll find at `footer.js` file which is where the footer social icons, social links, and the footer nav items are updated. 98 | 99 | ### Social Links 100 | 101 | The social links list will look something like this. 102 | 103 | ```js 104 | export const footerSocials = [ 105 | { 106 | url: 'https://instagram.com/', 107 | icon: instagramIcon, 108 | }, 109 | { 110 | url: 'https://youtube.com/', 111 | icon: youtubeIcon, 112 | }, 113 | { 114 | url: 'https://twitter.com/jaydanurwin', 115 | icon: twitterIcon, 116 | }, 117 | { 118 | url: 'https://github.com/treefarmstudio/odyssey-theme', 119 | icon: githubIcon, 120 | }, 121 | ]; 122 | ``` 123 | 124 | The URLs are already set to safely open a new tab for the user when clicked so simply change our the URLs if you're happy with the icons provided. 125 | 126 | However, if you'd like to customize the icons you can do this by providing your own icon SVGs in the `icons.js` file under the `src/icons/` folder. 127 | 128 | ### Footer Link Lists 129 | 130 | Similar to the top-level nav items you'll see a `footerLists` array in `footer.js` 131 | 132 | ```js 133 | export const footerLists = [ 134 | { 135 | title: 'Landing Pages', 136 | items: [ 137 | { 138 | title: 'Landing Page 1', 139 | slug: '/landing-pages/landing-1', 140 | }, 141 | { 142 | title: 'Landing Page 2', 143 | slug: '/landing-pages/landing-2', 144 | }, 145 | ], 146 | }, 147 | ... 148 | ``` 149 | 150 | The title is the non-clickable title of the list and the nested items array is the list of links under that title. Feel free to customize the lists as needed. 151 | 152 | ## Sitemap 153 | 154 | Odyssey Theme will automatically generate a `sitemap.xml` file for you using Astro's `@astrojs/sitemap` integration. 155 | 156 | To setup the sitemap with the correct URLs you will need to open the `astro.config.mjs` at the base level of the theme files which should look something like this 157 | 158 | ```js 159 | import { defineConfig } from 'astro/config'; 160 | import lit from '@astrojs/lit'; 161 | import sitemap from "@astrojs/sitemap"; 162 | 163 | // https://astro.build/config 164 | export default defineConfig({ 165 | site: 'https://odyssey-theme.sapling.supply/', 166 | // Your public domain, e.g.: https://my-site.dev/. Used to generate sitemaps and canonical URLs. 167 | sitemap: true, 168 | // Generate sitemap (set to "false" to disable) 169 | integrations: [lit(), sitemap()] // Add renderers to the config 170 | 171 | }); 172 | ``` 173 | 174 | Simply edit the `site:` field with the live URL that your website will be hosted on and you're all set! -------------------------------------------------------------------------------- /src/styles/global.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | } 5 | 6 | body { 7 | max-width: 1920px; 8 | margin: 0 auto; 9 | background-color: var(--theme-bg); 10 | position: relative; 11 | } 12 | 13 | pre { 14 | padding: 1em; 15 | border-radius: 0.5em; 16 | overflow: auto; 17 | } 18 | 19 | pre .language-id { 20 | display: none; 21 | } -------------------------------------------------------------------------------- /src/styles/index.css: -------------------------------------------------------------------------------- 1 | @import url('./reset.css'); 2 | @import url('./theme.css'); 3 | @import url('./typography.css'); 4 | @import url('./global.css'); 5 | -------------------------------------------------------------------------------- /src/styles/reset.css: -------------------------------------------------------------------------------- 1 | /* Box sizing rules */ 2 | *, 3 | *::before, 4 | *::after { 5 | box-sizing: border-box; 6 | } 7 | 8 | /* Remove default margin */ 9 | body, 10 | h1, 11 | h2, 12 | h3, 13 | h4, 14 | p, 15 | figure, 16 | blockquote, 17 | dl, 18 | dd { 19 | margin: 0; 20 | } 21 | 22 | /* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */ 23 | ul[role='list'], 24 | ol[role='list'] { 25 | list-style: none; 26 | } 27 | 28 | /* Set core root defaults */ 29 | html:focus-within { 30 | scroll-behavior: smooth; 31 | } 32 | 33 | /* Set core body defaults */ 34 | body { 35 | min-height: 100vh; 36 | text-rendering: optimizeSpeed; 37 | line-height: 1.5; 38 | } 39 | 40 | /* A elements that don't have a class get default styles */ 41 | a:not([class]) { 42 | text-decoration-skip-ink: auto; 43 | } 44 | 45 | /* A elements should be color inherit */ 46 | a { 47 | color: inherit; 48 | -webkit-tap-highlight-color: transparent; 49 | } 50 | 51 | /* Make images easier to work with */ 52 | img, 53 | picture { 54 | max-width: 100%; 55 | display: block; 56 | } 57 | 58 | /* Inherit fonts for inputs and buttons */ 59 | input, 60 | button, 61 | textarea, 62 | select { 63 | font: inherit; 64 | } 65 | 66 | /* Remove all animations, transitions and smooth scroll for people that prefer not to see them */ 67 | @media (prefers-reduced-motion: reduce) { 68 | html:focus-within { 69 | scroll-behavior: auto; 70 | } 71 | 72 | *, 73 | *::before, 74 | *::after { 75 | animation-duration: 0.01ms !important; 76 | animation-iteration-count: 1 !important; 77 | transition-duration: 0.01ms !important; 78 | scroll-behavior: auto !important; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/styles/theme.css: -------------------------------------------------------------------------------- 1 | :root { 2 | /* Theme Colors */ 3 | --theme-primary: hsl(0, 0%, 0%); 4 | --theme-primary-hover: hsl(0, 0%, 20%); 5 | --theme-on-primary: #fff; 6 | 7 | --theme-bg: #fff; 8 | --theme-on-bg: #000; 9 | 10 | --theme-surface-1: #f2f2f2; 11 | --theme-on-surface-1: #000; 12 | 13 | --theme-surface-2: #cce6d0; 14 | --theme-on-surface-2: #000; 15 | 16 | /* Theme Shapes */ 17 | /* Set this to 0 if you want all of the rounded cards, images, etc to be straight edges */ 18 | --theme-shape-radius: clamp(1rem, 2rem, 3rem); 19 | --theme-button-border-radius: 3rem; 20 | 21 | /* Theme Transition */ 22 | --theme-transition: 0.2s ease-in-out; 23 | 24 | /* Theme Layout */ 25 | --section-margin: 3rem; 26 | --theme-grid-gap: 1rem; 27 | --container-max-width: 1440px; 28 | --container-max-width-narrow: 960px; 29 | --container-padding: 0 1rem; 30 | 31 | --theme-blog-post-header-width: 1200px; 32 | 33 | /* Theme Fonts */ 34 | --theme-font-family-serif: 'Roboto Serif', Georgia, Cambria, 'Times New Roman', 35 | Times, serif; 36 | --theme-font-family-sans: 'Lato', -apple-system, BlinkMacSystemFont, 37 | sans-serif; 38 | } 39 | 40 | [data-theme='default'] { 41 | color-scheme: light; 42 | /* Theme Colors */ 43 | --theme-primary: hsl(0, 0%, 0%); 44 | --theme-primary-hover: hsl(0, 0%, 20%); 45 | --theme-on-primary: #fff; 46 | 47 | --theme-bg: #fff; 48 | --theme-on-bg: #000; 49 | 50 | --theme-surface-1: #f2f2f2; 51 | --theme-on-surface-1: #000; 52 | 53 | --theme-surface-2: #cce6d0; 54 | --theme-on-surface-2: #000; 55 | 56 | /* Theme Shape */ 57 | /* Set this to 0 if you want all of the rounded cards, images, etc to be straight edges */ 58 | --theme-shape-radius: clamp(1rem, 2rem, 3rem); 59 | --theme-button-border-radius: 3rem; 60 | 61 | /* Theme Transition */ 62 | --theme-transition: 0.2s ease-in-out; 63 | 64 | /* Theme Layout */ 65 | --section-margin: 3rem; 66 | --theme-grid-gap: 1rem; 67 | --container-max-width: 1440px; 68 | --container-max-width-narrow: 960px; 69 | --container-padding: 0 1rem; 70 | 71 | --theme-blog-post-header-width: 1200px; 72 | } 73 | 74 | [data-theme='dark'] { 75 | color-scheme: dark; 76 | /* Theme Colors */ 77 | --theme-primary: hsl(0, 0%, 100%); 78 | --theme-primary-hover: hsl(0, 0%, 90%); 79 | --theme-on-primary: hsl(0, 0%, 0%); 80 | 81 | --theme-bg: hsl(0, 0%, 2%); 82 | --theme-on-bg: hsl(0, 0%, 100%); 83 | 84 | --theme-surface-1: hsl(0, 0%, 20%); 85 | --theme-on-surface-1: hsl(0, 0%, 100%); 86 | 87 | --theme-surface-2: #203422; 88 | --theme-on-surface-2: #ffffff; 89 | 90 | --theme-shape-radius: 0; 91 | 92 | --form-field-input-color: var(--theme-on-bg); 93 | } 94 | 95 | [data-theme='earth'] { 96 | /* Theme Colors */ 97 | --theme-primary: #2c3e2d; 98 | --theme-primary-hover: #395a3b; 99 | --theme-on-primary: hsl(0, 0%, 100%); 100 | 101 | --theme-bg: #eeeff1; 102 | --theme-on-bg: #272f27; 103 | 104 | --theme-surface-1: #e6e4e0; 105 | --theme-on-surface-1: #272f27; 106 | 107 | --theme-surface-2: #c3d9c4; 108 | --theme-on-surface-2: #000; 109 | 110 | --theme-button-border-radius: 0.5rem; 111 | } 112 | 113 | [data-theme='ocean'] { 114 | /* Theme Colors */ 115 | /* Theme Colors */ 116 | --theme-primary: #1556ac; 117 | --theme-primary-hover: #2569c3; 118 | --theme-on-primary: hsl(0, 0%, 100%); 119 | 120 | --theme-bg: #fafafa; 121 | --theme-on-bg: #0c0d0d; 122 | 123 | --theme-surface-1: #eef1f3; 124 | --theme-on-surface-1: #0c0d0d; 125 | 126 | --theme-surface-2: #072650; 127 | --theme-on-surface-2: #ffffff; 128 | } 129 | 130 | [data-theme='sand'] { 131 | /* Theme Colors */ 132 | /* Theme Colors */ 133 | --theme-primary: #e38a20; 134 | --theme-primary-hover: #eb870f; 135 | --theme-on-primary: hsl(0, 0%, 100%); 136 | 137 | --theme-bg: #fffffe; 138 | --theme-on-bg: #5e4536; 139 | 140 | --theme-surface-1: #ffecd9; 141 | --theme-on-surface-1: #5e4536; 142 | 143 | --theme-surface-2: #6a4d34; 144 | --theme-on-surface-2: #ffffff; 145 | 146 | --theme-button-border-radius: 0.5rem; 147 | } 148 | -------------------------------------------------------------------------------- /src/styles/typography.css: -------------------------------------------------------------------------------- 1 | /* Special thanks to this tool for local fonts CSS generation: 2 | https://google-webfonts-helper.herokuapp.com/fonts/lato?subsets=latin 3 | */ 4 | 5 | /* roboto-serif-600 - latin */ 6 | @font-face { 7 | font-family: 'Roboto Serif'; 8 | font-style: normal; 9 | font-weight: 600; 10 | font-display: swap; 11 | src: local(''), 12 | url('/assets/fonts/roboto-serif-v8-latin-600.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ 13 | url('/assets/fonts/roboto-serif-v8-latin-600.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 14 | } 15 | /* roboto-serif-700 - latin */ 16 | @font-face { 17 | font-family: 'Roboto Serif'; 18 | font-style: normal; 19 | font-weight: 700; 20 | font-display: swap; 21 | src: local(''), 22 | url('/assets/fonts/roboto-serif-v8-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ 23 | url('/assets/fonts/roboto-serif-v8-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 24 | } 25 | 26 | /* lato-300 - latin */ 27 | @font-face { 28 | font-family: 'Lato'; 29 | font-style: normal; 30 | font-weight: 300; 31 | font-display: swap; 32 | src: local(''), 33 | url('/assets/fonts/lato-v23-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ 34 | url('/assets/fonts/lato-v23-latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 35 | } 36 | /* lato-regular - latin */ 37 | @font-face { 38 | font-family: 'Lato'; 39 | font-style: normal; 40 | font-weight: 400; 41 | font-display: swap; 42 | src: local(''), 43 | url('/assets/fonts/lato-v23-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ 44 | url('/assets/fonts/lato-v23-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 45 | } 46 | /* lato-700 - latin */ 47 | @font-face { 48 | font-family: 'Lato'; 49 | font-style: normal; 50 | font-weight: 700; 51 | font-display: swap; 52 | src: local(''), 53 | url('/assets/fonts/lato-v23-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ 54 | url('/assets/fonts/lato-v23-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 55 | } 56 | /* lato-700italic - latin */ 57 | @font-face { 58 | font-family: 'Lato'; 59 | font-style: italic; 60 | font-weight: 700; 61 | font-display: swap; 62 | src: local(''), 63 | url('/assets/fonts/lato-v23-latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ 64 | url('/assets/fonts/lato-v23-latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 65 | } 66 | :root { 67 | --font-size-sm: clamp(14.4px, 0.07vw + 14.13px, 15px); 68 | --font-size-base: clamp(18px, 0.23vw + 17.09px, 20px); 69 | --font-size-md: clamp(22.5px, 0.47vw + 20.61px, 26.66px); 70 | --font-size-lg: clamp(28.13px, 0.84vw + 24.76px, 35.54px); 71 | --font-size-xl: clamp(35.16px, 1.39vw + 29.6px, 47.37px); 72 | --font-size-xxl: clamp(43.95px, 2.18vw + 35.22px, 63.15px); 73 | --font-size-xxxl: clamp(54.93px, 3.32vw + 41.64px, 84.17px); 74 | } 75 | 76 | html, 77 | body { 78 | line-height: 1.5; 79 | font-family: var(--theme-font-family-sans); 80 | font-size: var(--font-size-base); 81 | color: var(--theme-on-bg); 82 | } 83 | 84 | h1, 85 | h2, 86 | h3 { 87 | font-family: var(--theme-font-family-serif); 88 | font-weight: 700; 89 | } 90 | 91 | h1 { 92 | font-size: var(--font-size-xxl); 93 | } 94 | 95 | h2 { 96 | font-size: var(--font-size-xl); 97 | } 98 | 99 | h3 { 100 | font-size: var(--font-size-lg); 101 | } 102 | 103 | h1, 104 | h2 { 105 | line-height: 1.1; 106 | font-weight: 700; 107 | } 108 | 109 | h3 { 110 | font-weight: 500; 111 | } 112 | 113 | h6 { 114 | font-size: var(--font-size-sm); 115 | } 116 | 117 | h1, 118 | h2, 119 | h3, 120 | h4, 121 | h5, 122 | h6, 123 | p { 124 | margin: 0 0 1rem 0; 125 | } 126 | 127 | blockquote { 128 | font-style: italic; 129 | font-size: var(--font-size-base); 130 | font-weight: 500; 131 | margin-bottom: 1rem; 132 | padding-left: 1.5rem; 133 | border-left: 0.25rem solid var(--theme-on-bg); 134 | } -------------------------------------------------------------------------------- /src/utils/helpers.js: -------------------------------------------------------------------------------- 1 | export function generateSlug(string) { 2 | return string 3 | .toString() 4 | .trim() 5 | .toLowerCase() 6 | .replace(/\s+/g, '-') 7 | .replace(/[^\w\-]+/g, '') 8 | .replace(/\-\-+/g, '-') 9 | .replace(/^-+/, '') 10 | .replace(/-+$/, ''); 11 | } 12 | 13 | export function generateTagData(categories) { 14 | let categoryData = []; 15 | categories.forEach(category => { 16 | categoryData.push({ 17 | title: category, 18 | slug: `${generateSlug(category)}`, 19 | }); 20 | }); 21 | return categoryData; 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true, 4 | "useDefineForClassFields": false, 5 | "baseUrl": "src", 6 | // Add type definitions for our Vite runtime. 7 | "types": ["astro/client"], 8 | "paths": { 9 | "@config": ["config/*"], 10 | "@icons": ["icons/*"], 11 | "@lib/*": ["lib/*"], 12 | "@utils/*": ["utils/*"], 13 | "@components/*": ["components/*"], 14 | "@layouts/*": ["layouts/*"], 15 | "@assets/*": ["assets/*"], 16 | "@pages/*": ["pages/*"], 17 | "@styles/*": ["styles/*"] 18 | } 19 | } 20 | } 21 | --------------------------------------------------------------------------------