Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3b73378
Initial plan
Copilot Mar 3, 2026
9879c5c
Initial assessment and plan for continuing implementation
Copilot Mar 3, 2026
3f70559
Fix filter.js selector bugs and validation script duplicate detection
Copilot Mar 3, 2026
574d198
Add comparison buttons to provider cards and improve navigation styles
Copilot Mar 3, 2026
84934d9
Add i18n translations for UI strings and enhance homepage content
Copilot Mar 3, 2026
a409e8f
Do not check external links at build stage
trotro Mar 3, 2026
913f82c
Address PR feedback: simplify homepage description and enable interna…
Copilot Mar 3, 2026
93aa422
Apply suggestions from code review
trotro Mar 3, 2026
28c08e9
Fix CSS selector collision and translation access in templates
Copilot Mar 3, 2026
83f083b
Update uv action
trotro Mar 3, 2026
ac6b384
Refactor to use Zola's built-in trans() function instead of condition…
Copilot Mar 3, 2026
fd52857
Add PR write permission
trotro Mar 3, 2026
6a096f6
Create requirements.txt
trotro Mar 3, 2026
6d4b9e6
Move dependencies into requirements.txt
trotro Mar 3, 2026
03aad30
Update accessibility.yml
trotro Mar 3, 2026
1e5f4fb
Fix WCAG 2 AA color contrast violation on .btn-primary
Copilot Mar 3, 2026
b4158e3
Remove venv in validate.yml
trotro Mar 3, 2026
8f56c2b
Add back dependencies installation step
trotro Mar 3, 2026
8301456
Update .btn-primary to meet WCAG 2 AA minimum contrast ratio
trotro Mar 4, 2026
8102888
More secure validate workflow
trotro Mar 4, 2026
27443f4
Update validate.yml: add back venv
trotro Mar 4, 2026
5f0d670
Update build.yml: least permissions
trotro Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/accessibility.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ jobs:
- name: Install axe-core CLI
run: npm install -g @axe-core/cli

- name: Install chrome with browser-driver-manager
run: npx browser-driver-manager install chrome

- name: Serve site and run axe-core
run: |
cd public
Expand Down
12 changes: 8 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ on:
branches:
- main

permissions:
contents: read
pages: write
id-token: write
permissions: {}

concurrency:
group: "pages"
Expand All @@ -16,6 +13,8 @@ concurrency:
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v6.0.1
Expand All @@ -25,9 +24,14 @@ jobs:
with:
zola_version: v0.22.1
check_links: true
check_flags: "--skip-external-links"

deploy:
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
needs: build
environment:
name: github-pages
Expand Down
15 changes: 8 additions & 7 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,25 @@ on:
- 'content/providers/**'
- 'docs/provider-schema.json'
- 'docs/validate_providers.py'

permissions: {}
jobs:
validate:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v6.0.1

- name: Set up uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v7
with:
enable-cache: true

- name: Set up Python
run: uv python install
python-version: "3.14"
activate-environment: true
enable-cache: auto

- name: Install dependencies
run: uv pip install tomli
run: uv pip install -r docs/requirements.txt

- name: Validate provider data
id: validate
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ _bmad/*
# Generated static pages
public


# Build artifacts
artifacts/
*.tar.gz
zola
948 changes: 287 additions & 661 deletions LICENSE

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions content/_index.en.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
+++
title = "Home"
+++

Welcome to Cloud Landscape, the reference directory for cloud providers. Our mission is to facilitate cloud service discovery and comparison by providing a unified and accessible view.

## Features

- **Discovery**: Explore cloud providers by service, certification, or geographic location
- **Comparison**: Compare up to 4 providers side-by-side to make informed decisions
- **Certifications**: Identify providers certified with SecNumCloud, HDS, or EUCS
- **Bilingual**: Content available in both French and English

## Get Started

<a href="providers/" class="btn btn-primary">Explore Providers →</a>
13 changes: 13 additions & 0 deletions content/_index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
+++
title = "Accueil"
+++

Bienvenue sur Cloud Landscape, l'annuaire de référence des fournisseurs cloud. Notre mission est de faciliter la découverte et la comparaison des services cloud en proposant une vue unifiée et accessible.

## Fonctionnalités

- **Découverte** : Explorez les fournisseurs cloud par service, certification ou localisation géographique
- **Comparaison** : Comparez jusqu'à 4 fournisseurs côte à côte pour prendre des décisions éclairées
- **Certifications** : Identifiez les fournisseurs certifiés SecNumCloud, HDS ou EUCS
- **Bilingue** : Contenu disponible en français et en anglais

## Commencer

<a href="/providers/" class="btn btn-primary">Explorer les fournisseurs →</a>
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tomli
10 changes: 8 additions & 2 deletions docs/validate_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def validate_url(url):
return False

def check_duplicate_slugs(provider_files):
"""Check for duplicate provider slugs"""
"""Check for duplicate provider slugs across different provider directories"""
slugs = {}
duplicates = []

Expand All @@ -53,8 +53,14 @@ def check_duplicate_slugs(provider_files):
data = toml_to_dict(frontmatter)
slug = data.get('slug')
if slug:
# Get the provider directory (parent of the file)
provider_dir = provider_file.parent

# Check if this slug exists in a different provider directory
if slug in slugs:
duplicates.append((slug, slugs[slug], provider_file))
# Only flag as duplicate if it's in a different directory
if slugs[slug].parent != provider_dir:
duplicates.append((slug, slugs[slug], provider_file))
else:
slugs[slug] = provider_file
except:
Expand Down
26 changes: 17 additions & 9 deletions static/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
.map(badge => badge.textContent.trim());
const certifications = Array.from(card.querySelectorAll('.provider-certifications .badge'))
.map(badge => badge.textContent.trim());
const country = card.querySelector('.provider-meta p strong')?.nextSibling?.textContent?.trim() || '';
const title = card.querySelector('h3')?.textContent?.trim() || '';
const description = card.querySelector('p')?.textContent?.trim() || '';
const country = card.querySelector('.provider-meta p strong')?.nextElementSibling?.textContent?.trim() || '';
const title = card.querySelector('h2')?.textContent?.trim() || '';
const description = card.querySelector('.provider-description')?.textContent?.trim() || '';

providers.push({
element: card,
Expand Down Expand Up @@ -140,14 +140,19 @@
const filterType = this.dataset.filterType;
const filterValue = this.dataset.filterValue;

// Map filter types to activeFilters keys
const filterKey = filterType === 'service' ? 'services' :
filterType === 'cert' ? 'certifications' :
filterType === 'country' ? 'countries' : filterType;

if (this.checked) {
if (!activeFilters[filterType].includes(filterValue)) {
activeFilters[filterType].push(filterValue);
if (!activeFilters[filterKey].includes(filterValue)) {
activeFilters[filterKey].push(filterValue);
}
} else {
const index = activeFilters[filterType].indexOf(filterValue);
const index = activeFilters[filterKey].indexOf(filterValue);
if (index > -1) {
activeFilters[filterType].splice(index, 1);
activeFilters[filterKey].splice(index, 1);
}
}

Expand All @@ -157,9 +162,12 @@
});

// Check initial state from URL
const filterType = checkbox.dataset.filterType + 's';
const filterType = checkbox.dataset.filterType;
const filterValue = checkbox.dataset.filterValue;
if (activeFilters[filterType] && activeFilters[filterType].includes(filterValue)) {
const filterKey = filterType === 'service' ? 'services' :
filterType === 'cert' ? 'certifications' :
filterType === 'country' ? 'countries' : filterType;
if (activeFilters[filterKey] && activeFilters[filterKey].includes(filterValue)) {
checkbox.checked = true;
}
});
Expand Down
102 changes: 100 additions & 2 deletions static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ nav {
background: #2c3e50;
padding: 1rem;
margin: -1rem -1rem 2rem -1rem;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
}

nav a {
Expand Down Expand Up @@ -96,6 +100,42 @@ h2 {
margin: 0.5rem 0;
}

.provider-card .provider-actions {
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid #ecf0f1;
}

.btn-compare-add {
width: 100%;
padding: 0.6rem 1rem;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 0.9rem;
font-weight: 600;
transition: background 0.2s;
}

.btn-compare-add:hover {
background: #2980b9;
}

.btn-compare-add.in-comparison {
background: #27ae60;
}

.btn-compare-add.in-comparison:hover {
background: #229954;
}

.btn-compare-add:disabled {
background: #95a5a6;
cursor: not-allowed;
}

/* Badges */
.badge {
display: inline-block;
Expand Down Expand Up @@ -431,12 +471,12 @@ h2 {
}

.btn-primary {
background: #3498db;
background: #1255b5;
color: white;
}

.btn-primary:hover {
background: #2980b9;
background: #104989;
}

.btn-secondary {
Expand Down Expand Up @@ -679,3 +719,61 @@ textarea:focus {
outline: 2px solid #3498db;
outline-offset: 2px;
}

/* Home Page Styles */
.home-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}

.home-content .tagline {
font-size: 1.2rem;
color: #666;
margin-bottom: 2rem;
}

.home-content .content {
text-align: left;
margin: 3rem auto;
}

.home-content h2 {
color: #2c3e50;
margin-top: 2rem;
}

.home-content ul {
list-style: none;
padding: 0;
}

.home-content ul li {
margin: 1rem 0;
padding-left: 1.5rem;
position: relative;
}

.home-content ul li::before {
content: "✓";
position: absolute;
left: 0;
color: #27ae60;
font-weight: bold;
}

.home-content .btn {
display: inline-block;
margin-top: 2rem;
padding: 1rem 2rem;
background: #3498db;
color: white;
text-decoration: none;
border-radius: 6px;
font-weight: 600;
transition: background 0.2s;
}

.home-content .btn:hover {
background: #2980b9;
}
15 changes: 10 additions & 5 deletions templates/index.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
{% extends "base.html" %}

{% block title %}{{ config.title }} - Home{% endblock %}
{% block title %}{{ config.title }} - {{ section.title }}{% endblock %}

{% block content %}
<h1>{{ config.title }}</h1>
<p>{{ config.description }}</p>
<div class="home-content">
<h1>{{ config.title }}</h1>
<p class="tagline">{{ config.description }}</p>

<h2>Providers</h2>
<p><a href="/providers/">Browse all cloud providers</a></p>
{% if section.content %}
<div class="content">
{{ section.content | safe }}
</div>
{% endif %}
</div>
{% endblock %}
Loading
Loading