Skip to content

zoasr/machlist

Repository files navigation

Machlist - Industrial Equipment Showcase

Built with Astro i18n Ready

A modern, high-performance website for showcasing industrial machinery and equipment. Built with Astro for optimal performance and SEO, featuring full internationalization support for both English and Arabic languages.

🌟 Features

  • Blazing Fast - Built with Astro for optimal performance and minimal JavaScript
  • Bilingual Support - Full Arabic and English language support with RTL layout switching
  • Modern UI - Responsive design with smooth animations and transitions
  • Type Safety - Built with TypeScript for better developer experience
  • Content Management - Easy-to-update content collections for products and services
  • SEO Optimized - Server-side rendering and semantic HTML for better search engine visibility

🚀 Getting Started

This project uses pnpm as its package manager. Using it is recommended for the best development experience.

# Install dependencies
pnpm i

# Start development server
pnpm run dev

# Build for production
pnpm run build

Warning

If you want to switch to another package manager, just delete the pnpm-lock.yaml file, then install with your preferred package manager.

📦 Project Structure

/
├── src/
│   ├── components/     # Reusable UI components
│   ├── content/        # Content collections
│   ├── i18n/          # Internationalization config and strings
│   ├── layouts/        # Page layouts
│   ├── pages/          # Page components
│   └── styles/         # Global styles and themes

🌐 Internationalization

The website supports both English and Arabic with automatic RTL layout switching. All UI strings are managed through the i18n system.

📄 Table of Contents

Machlist

This project uses pnpm as its package manager using it is recommended

pnpm i

Warning

If you you want to switch to another package manager just delete the pnpm-lock.yaml then install with your favourite package manager

Building

To build the site just run pnpm run build which will build the site to ./dist/ or ./.vercel folder depending on the current git branch.

Branches

  • main - a branch that contains the vercel ssr integration
  • static - a branch that contains the static config for building static html files

Merging changes between branches

  • merging from main to static:
pnpm run mergeto:static
  • merging from static to main:
pnpm run mergeto:main

Project Structure

Inside of this Astro project, you'll see the following folders and files:

/
├── src/
│   ├───assets
│   ├───article_images
│   │   └───...				// images embedded inside every content page
│   └───product_thumbs // thumbnails for each product
├───components
│   ├───sections
│   └───svelte
├───content
│   │   config.ts //  content schema and config
│   └───products // contains all the markdown files for the content
│       ├───ar
│       └───en
├───i18n		// all internationalized strings and utility functions
│       ui.ts
│       utils.ts
├───js
│       aos.js
├───layouts
│       ContentLayout.astro
│       Layout.astro
│       SectionLayout.astro
├───pages
│   │   index.astro
│   ├───ar
│   │   │   index.astro
│   │   │
│   │   ├───about
│   │   │       index.astro
│   │   ├───contact
│   │   │       index.astro
│   │   └───products
│   │       │   index.astro
│   │       └───[...product]
│   │               index.astro
│   └───en
│       │   index.astro
│       ├───about
│       │       index.astro
│       ├───contact
│       │       index.astro
│       └───products
│           │   index.astro
│           └───[...product]
│                   index.astro
└───utils
        utils.ts

Astro looks for .astro or .md files in the src/pages/ directory. Each page is exposed as a route based on its file name.

There's nothing special about src/components/, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.

Any static assets, like images, can be placed in the public/ directory.

Astro docs

Feel free to check Astro's documentation

Commands

All commands are run from the root of the project, from a terminal:

Command Action Usage
pnpm install Installs dependencies
pnpm run dev Starts local dev server at localhost:4321
pnpm run build Build your production site to "./dist/", ".vercel"
pnpm run preview Preview your build locally, before deploying
pnpm run check Check for linting and formatting errors before building
pnpm run astro ... Run CLI commands like astro add, astro check
pnpm run astro -- --help Get help using the Astro CLI
pnpm run create:machine Creates all the files necessary for a new product with nested routes (eg.: catalog.mdx, design.mdx, ...etc ) and pages inside the ./src/content/products & ./src/assets folders pnpm run create:machine --name=[name] --titleen=[titleen] --titlear=[titlear] --model=[model] --order=[order] --isLine=[isLine]
pnpm run create:old-machine Creates all the files necessary for a new product (only .md files) inside the ./src/content/products & ./src/assets folders pnpm run create:old-machine --name=[name] --titleen=[titleen] --titlear=[titlear] --model=[model] --order=[order] --isLine=[isLine]
pnpm run mergeto:main Merges changes from static branch to main branch
pnpm run mergeto:static Merges changes from main branch to static branch

Ui

This Project uses the following frameworks and libraries for building the ui:

  • Tailwind
  • Sass
  • astro-icon
  • AOS
  • Svelte
    • bits-ui

Tailwind

The tailwind config uses an opinionated system of ui colors try to not go outside of using these colors as much as possible

colors: {
    skin: {
    	primary: withOpacity("--color-primary"),
    	secondary: withOpacity("--color-secondary"),
    	neutral: withOpacity("--color-neutral"),
    	accent: withOpacity("--color-accent"),
    	"accent-1": withOpacity("--color-accent-1"),
    	"accent-2": withOpacity("--color-accent-2"),
    	"accent-3": withOpacity("--color-accent-3"),
    	purple: withOpacity("--color-purple"),
    	teal: withOpacity("--color-teal"),
    	magenta: withOpacity("--color-magenta"),
    	background: withOpacity("--color-background"),
    	base: withOpacity("--color-text-base"),
    	"text-dark": withOpacity("--color-text-dark"),
    	muted: withOpacity("--color-text-muted")
    }
}

you'll find these colors defined in tailwind.config.mjs all these colors correspond to css variables defined inside the main layout component

:root {
	--color-neutral: 0, 0%, 13%; /* hsl(0, 0%, 13%) */
	--color-primary: 213, 100%, 85%; /* hsl(213, 100%, 85%) */
	--color-secondary: 0, 0%, 30%; /* hsl(0, 0%, 30%) */
	--color-accent: 51, 100%, 50%; /* hsl(51, 80%, 50%) */
	--color-accent-1: 12, 100%, 50%; /* hsl(12, 100%, 50%) */
	--color-accent-2: 49, 90%, 40%; /* hsl(49, 90%, 50%) */
	--color-accent-3: 145, 63%, 49%; /* hsl(145, 63%, 49%) */
	--color-background: 0, 0%, 95%; /* hsl(0, 0%, 95%) */
	--color-purple: 277, 70%, 35%; /* hsl(277, 70%, 35%) */
	--color-teal: 180, 100%, 25%; /* hsl(180, 100%, 25%) */
	--color-magenta: 326, 100%, 50%; /* hsl(326, 100%, 50%) */
	--color-text-base: 213, 34%, 15%;
	--color-text-muted: var(--color-secondary);
}

Sass

Using Sass inside an Astro component is as simple as:

<style lang="scss">
	...
</style>

astro-icon

astro-icon is a component for using icons in Astro projects.

You can utilize any icon inside the Iconify icon collection in the form of:

<Icon name="[icon-collection]:[icon-name]" />

Note

You need to install the icon collection that you wanna use first by running pnpm add @iconify-json/[icon-collection]

Note

This project already has these following icon collections installed: ic, ri, radix-icons

AOS

AOS is a library for animating elements on scroll

  • You'll find it used in the homepage to animate some sections
  • You can learn more about how to use it here

To include it in your Astro project just add script with the following code:

import AOS from "aos";
import "aos/dist/aos.css";
AOS.init();

this script is already configured inside aos.js and imported inside the pages layout, there is no need to do anything else.

Content Collection

You'll find the config for the content collection in src\content\config.ts. there is only one collection for this project called products

Adding a product

To add a new product to the collection products you can do it by running:

pnpm run create:machine ...

or

pnpm run create:old-machine ...

create:machine:

by running the follwowing command:

pnpm run create:machine --name=example-name --titleen="Example name" --titlear="مثال" --model=ABCDE  --order=10 --isLine=false

This will create the following files inside the ./src/content/products folder:

  • en:

    • ./src/content/products/en/example-name.mdx
    • ./src/content/products/en/example-name/catalog.mdx
    • ./src/content/products/en/example-name/design.mdx
    • ./src/content/products/en/example-name/gallery.mdx
    • ./src/content/products/en/example-name/drawings.mdx
  • ar

    • ./src/content/products/ar/example-name.mdx
    • ./src/content/products/ar/example-name/catalog.mdx
    • ./src/content/products/ar/example-name/design.mdx
    • ./src/content/products/ar/example-name/gallery.mdx
    • ./src/content/products/ar/example-name/drawings.mdx
  • images folders:

    • ./src/assets/product_thumbs/example-name.jpg
    • ./src/assets/article_images/example-name/

Warning

The script creates jpg files but they have no actual data you'll have to replace them with your own of course otherwise astro will throw an error

Files contents:

catalog.mdx, design.mdx, gallery.mdx and drawings.mdx will have this content that matches the schema (note the nested flag is set to true):

---
title: Example name
model: ABCDE
cover: "@assets/product_thumbs/example-name.jpg"
order: 10
isLine: false
nested: true
---

import ProductTabs from "@components/ProductTabs.astro";

<ProductTabs />

example-name.mdx will have this content that matches the schema (note the nested flag is set to false):

---
title: Example name
model: ABCDE
cover: "@assets/product_thumbs/example-name.jpg"
order: 10
isLine: false
nested: false
---

import ProductTabs from "@components/ProductTabs.astro";

<ProductTabs />

create:old-machine:

by running the follwowing command:

pnpm run create:old-machine --name=example-name --titleen="Example name" --titlear="مثال" --model=ABCDE  --order=10 --isLine=false

This will create the following files inside the ./src/content/products folder:

  • en:

    • ./src/content/products/en/example-name.md
  • ar

    • ./src/content/products/ar/example-name.md
  • images folders:

    • ./src/assets/product_thumbs/example-name.jpg
    • ./src/assets/article_images/example-name/

Files contents:

example-name.md will have this content that matches the schema:

---
title: Example name
model: ABCDE
cover: "@assets/product_thumbs/example-name.jpg"
order: 10
isLine: false
nested: false
---

Rendering the collection

inside the path [locale]/products/[locale]/[...product]:

we will do the follwoing:

  1. define a getStaticPaths function to generate all the pages for all of the files in the collection":
export async function getStaticPaths() {
	const productEntries = await getCollection("products");
	return productEntries.map((entry) => ({
		params: { product: entry.slug }
	}));
}
  1. get the parameter from the current path:
const { product } = Astro.params;
  1. we get the entry from the collection based on the parameter:
const entry = await getEntry("products", product);
const { Content } = await entry.render();
  1. render the content:
<Layout title={entry.data.title}>
	<ProductHead />
	<article>
		<ContentLayout>
			<Content />
		</ContentLayout>
	</article>
</Layout>

Note

The <Content> element is destructured from the entry.render() function

Internationalization (i18n)

Config

to define the locales for this project you can do it by changing the i18n config in astro.config.mjs:

export default defineConfig({
	// ...
	i18n: {
		defaultLocale: "ar",
		locales: ["en", "ar"],
		routing: {
			prefixDefaultLocale: true
		}
	}
});

the prefixDefaultLocale is used to prefix the current locale in the URL, which makes routing a bit easier to handle.

UI strings

inside @i18n/ui.ts you'll find the following:

export const languages = {
	en: "English",
	ar: "العربية"
};

export const defaultLang = "ar";

export const ui = {
	en: {
		// ...
	},
	ar: {
		// ...
	}
} as const;

the ui object is used to define the ui strings for each locale with keys for every ui string.

Note

both en and ar objects need to have the same keys for the translation to work correctly.

Utilty functions

  • getLangFromUrl(): takes the current URL and returns the locale of the current page.
  • useTranslations() : takes the locale and returns a function that can be used to translate strings.

you can import these functions anywhere even in astro islands, and they'll be typically like so:

import { getLangFromUrl, useTranslations } from "@i18n/utils";

const locale = getLangFromUrl(Astro.url);
const t = useTranslations(locale);

Note

the Astro object is only available inside .astro files. so you might want to pass the locale as a prop to any client component if you need access to translated ui strings inside that component.

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published