project first commit

This commit is contained in:
Yves Gatesoupe 2020-06-19 23:47:44 +02:00
commit 3cd8fef0f0
94 changed files with 12647 additions and 0 deletions

90
.eleventy.js Normal file
View File

@ -0,0 +1,90 @@
const rssPlugin = require('@11ty/eleventy-plugin-rss');
const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight');
const fs = require('fs');
// Import filters
const dateFilter = require('./src/filters/date-filter.js');
const markdownFilter = require('./src/filters/markdown-filter.js');
const w3DateFilter = require('./src/filters/w3-date-filter.js');
// Import transforms
const htmlMinTransform = require('./src/transforms/html-min-transform.js');
const parseTransform = require('./src/transforms/parse-transform.js');
// Import data files
const site = require('./src/_data/site.json');
module.exports = function(config) {
// Filters
config.addFilter('dateFilter', dateFilter);
config.addFilter('markdownFilter', markdownFilter);
config.addFilter('w3DateFilter', w3DateFilter);
// Layout aliases
config.addLayoutAlias('home', 'layouts/home.njk');
// Transforms
config.addTransform('htmlmin', htmlMinTransform);
config.addTransform('parse', parseTransform);
// Passthrough copy
config.addPassthroughCopy('src/fonts');
config.addPassthroughCopy('src/images');
config.addPassthroughCopy('src/js');
config.addPassthroughCopy('src/admin/config.yml');
config.addPassthroughCopy('src/admin/previews.js');
config.addPassthroughCopy('node_modules/nunjucks/browser/nunjucks-slim.js');
config.addPassthroughCopy('src/robots.txt');
const now = new Date();
// Custom collections
const livePosts = post => post.date <= now && !post.data.draft;
config.addCollection('posts', collection => {
return [
...collection.getFilteredByGlob('./src/posts/*.md').filter(livePosts)
].reverse();
});
config.addCollection('postFeed', collection => {
return [...collection.getFilteredByGlob('./src/posts/*.md').filter(livePosts)]
.reverse()
.slice(0, site.maxPostsPerPage);
});
config.addCollection('newsFeed', collection => {
return [...collection.getFilteredByGlob('./src/posts/*.md').filter(livePosts)]
.reverse()
.slice(0, site.maxNewsPerPage);
});
// Plugins
config.addPlugin(rssPlugin);
config.addPlugin(syntaxHighlight);
// 404
config.setBrowserSyncConfig({
callbacks: {
ready: function(err, browserSync) {
const content_404 = fs.readFileSync('dist/404.html');
browserSync.addMiddleware('*', (req, res) => {
// Provides the 404 content without redirect.
res.write(content_404);
res.end();
});
}
}
});
// Watch sass
// config.addWatchTarget("./src/scss/");
return {
dir: {
input: 'src',
output: 'dist'
},
passthroughFileCopy: true,
pathPrefix: '/preprod' //TODO remove when prod
};
};

19
.gitignore vendored Normal file
View File

@ -0,0 +1,19 @@
*.log
npm-debug.*
*.scssc
*.log
*.swp
.DS_Store
.sass-cache
node_modules
dist/*
deploy-prod.js
deploy-preprod.js
# Specifics
# Hide design tokens
src/scss/_tokens.scss
# Hide compiled CSS
src/_includes/assets/*

6
.prettierrc Normal file
View File

@ -0,0 +1,6 @@
{
"printWidth": 90,
"tabWidth": 2,
"singleQuote": true,
"bracketSpacing": false
}

18
.stylelintrc.json Normal file
View File

@ -0,0 +1,18 @@
{
"extends": "stylelint-config-sass-guidelines",
"rules": {
"order/properties-alphabetical-order": null,
"property-no-vendor-prefix": null,
"selector-class-pattern": [
"^[a-z0-9\\-_]+$",
{
"message":
"Selector should be written in lowercase (selector-class-pattern)"
}
],
"max-nesting-depth": 4,
"number-leading-zero": "never",
"selector-no-qualifying-type": null,
"selector-max-compound-selectors": 4
}
}

21
LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 andy-bell.design and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

30
deploy.js Normal file
View File

@ -0,0 +1,30 @@
var FtpDeploy = require("ftp-deploy");
var ftpDeploy = new FtpDeploy();
var config = {
user: "user",
// Password optional, prompted if none given
password: "password",
host: "ftp.someserver.com",
port: 21,
localRoot: __dirname + "/local-folder",
remoteRoot: "/public_html/remote-folder/",
// include: ["*", "**/*"], // this would upload everything except dot files
include: ["*.php", "dist/*", ".*"],
// e.g. exclude sourcemaps, and ALL files in node_modules (including dot files)
exclude: ["dist/**/*.map", "node_modules/**", "node_modules/**/.*", ".git/**"],
// delete ALL existing files at destination before uploading, if true
deleteRemote: false,
// Passive mode is forced (EPSV command is not sent)
forcePasv: true
};
// use with promises
ftpDeploy
.deploy(config)
.then(res => console.log("finished:", res))
.catch(err => console.log(err));
ftpDeploy.on("uploading", function(data) {
console.log(data.filename); // partial path with filename being uploaded
});

9665
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

56
package.json Executable file
View File

@ -0,0 +1,56 @@
{
"name": "astrolabe-website",
"version": "0.1.0",
"description": "Site web de la coopérative Astrolabe CAE",
"main": "index.js",
"dependencies": {
"@11ty/eleventy": "^0.10.0",
"@11ty/eleventy-plugin-rss": "^1.0.7",
"@11ty/eleventy-plugin-syntaxhighlight": "^2.0.3",
"@tbranyen/jsdom": "^13.0.0",
"concurrently": "^4.1.2",
"html-minifier": "^4.0.0",
"image-size": "^0.8.3",
"json-to-scss": "^1.5.0",
"sass": "^1.26.3",
"semver": "^6.3.0",
"slugify": "^1.4.0",
"stalfos": "github:hankchizljaw/stalfos#c8971d22726326cfc04089b2da4d51eeb1ebb0eb"
},
"devDependencies": {
"@erquhart/rollup-plugin-node-builtins": "^2.1.5",
"bl": "^3.0.0",
"chokidar-cli": "^2.1.0",
"cross-env": "^5.2.1",
"ftp-deploy": "^2.3.7",
"make-dir-cli": "^2.0.0",
"prettier": "^1.19.1",
"rollup": "^1.32.1",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"stylelint": "^13.6.1",
"stylelint-config-sass-guidelines": "^7.0.0"
},
"scripts": {
"sass:tokens": "npx json-to-scss src/_data/tokens.json src/scss/_tokens.scss",
"sass:lint": "npx stylelint src/scss/**/*.scss",
"sass:process": "npm run sass:tokens && npm run sass:lint && sass src/scss/global.scss src/_includes/assets/css/global.css --style=compressed",
"start": "concurrently \"npm run sass:process -- --watch\" \"npm run serve\"",
"serve": "cross-env ELEVENTY_ENV=development npx eleventy --serve",
"preprod": "cross-env ELEVENTY_ENV=preprod npm run sass:process && npx eleventy",
"deploy-preprod": "npm run preprod && node deploy-preprod",
"prod": "cross-env ELEVENTY_ENV=prod npm run sass:process && npx eleventy"
},
"repository": {
"type": "git",
"url": "git+https://git.ouvaton.coop/astrolabe/SiteWebAstrolabe.git"
},
"keywords": [],
"author": "",
"license": "MIT",
"bugs": {
"url": "https://git.ouvaton.coop/astrolabe/SiteWebAstrolabe/issues"
},
"homepage": "https://git.ouvaton.coop/astrolabe/SiteWebAstrolabe"
}

17
src/404.md Normal file
View File

@ -0,0 +1,17 @@
---
title: '404 - not found'
layout: layouts/page.njk
permalink: 404.html
eleventyExcludeFromCollections: true
---
Were sorry, but that content cant be found. Please go [back to home](/).
{% comment %}
Read more: https://www.11ty.io/docs/quicktips/not-found/
This will work for both GitHub pages and Netlify:
- https://help.github.com/articles/creating-a-custom-404-page-for-your-github-pages-site/
- https://www.netlify.com/docs/redirects/#custom-404
{% endcomment %}

9
src/_data/global.js Normal file
View File

@ -0,0 +1,9 @@
module.exports = {
random() {
const segment = () => {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
return `${segment()}-${segment()}-${segment()}`;
},
now: Date.now()
};

10
src/_data/helpers.js Normal file
View File

@ -0,0 +1,10 @@
module.exports = {
getNextHeadingLevel(currentLevel) {
return parseInt(currentLevel, 10) + 1;
},
getReadingTime(text) {
const wordsPerMinute = 200;
const numberOfWords = text.split(/\s/g).length;
return Math.ceil(numberOfWords / wordsPerMinute);
}
};

29
src/_data/navigation.json Normal file
View File

@ -0,0 +1,29 @@
{
"items": [
{
"text": "Comprendre la CAE",
"url": "/comprendre",
"external": false
},
{
"text": "Nous rejoindre",
"url": "/rejoindre",
"external": false
},
{
"text": "L'équipe",
"url": "/equipe",
"external": false
},
{
"text": "Actualité",
"url": "/actualite",
"external": false
},
{
"text": "Nous contacter",
"url": "/contact",
"external": false
}
]
}

23
src/_data/site.json Normal file
View File

@ -0,0 +1,23 @@
{
"showThemeCredit": true,
"name": "Astrolabe CAE",
"shortDesc": "Site web de la coopérative Astrolabe CAE",
"url": "https://astrolabe.coop/preprod",
"authorEmail": "contacte@astrolabe.coop",
"authorHandle": "@AstrolabeCae",
"authorName": "Astrolabe CAE",
"authorAddress": "34 La Ville Allée",
"authorCity": "35630 HEDE BAZOUGES",
"authorSocial": {
"mastodon": "https://framapiaf.org/@AstrolabeCAE",
"twitter": "https://twitter.com/AstrolabeCae",
"linkedin": "https://www.linkedin.com/company/astrolabe-cae/"
},
"designerName": "Yves Gatesoupe",
"designerHandle": "https://twitter.com/YGdsgn",
"illustrators": "Igé Maulana, Leopold Merleau",
"enableThirdPartyComments": false,
"maxPostsPerPage": 5,
"maxNewsPerPage": 4,
"faviconPath": "/images/favicon.png"
}

28
src/_data/styleguide.js Normal file
View File

@ -0,0 +1,28 @@
const tokens = require('./tokens.json');
module.exports = {
colors() {
let response = [];
Object.keys(tokens.colors).forEach(key => {
response.push({
value: tokens.colors[key],
key
});
});
return response;
},
sizes() {
let response = [];
Object.keys(tokens['size-scale']).forEach(key => {
response.push({
value: tokens['size-scale'][key],
key
});
});
return response;
}
};

28
src/_data/tokens.json Normal file
View File

@ -0,0 +1,28 @@
{
"size-scale": {
"base": "1rem",
"300": "0.8rem",
"500": "1.25rem",
"600": "1.56rem",
"700": "1.95rem",
"800": "2.44rem",
"900": "3.05rem",
"max": "4rem"
},
"colors": {
"primary": "#d6f253",
"primary-shade": "#102538",
"primary-glare": "#22547c",
"secondary": "#282156",
"highlight": "#d6f253",
"light-gray": "#f1f0f7",
"light": "#fff",
"mid": "#ccc",
"dark": "#111",
"slate": "#404040"
},
"fonts": {
"base": "\"'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'\"",
"brand": "\"'Varela', sans-serif\""
}
}

View File

@ -0,0 +1,13 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
focusable="false"
aria-hidden="true"
fill="currentColor"
>
<path
d="M9.707 18.707l6-6a.999.999 0 0 0 0-1.414l-6-6a.999.999 0 1 0-1.414 1.414L13.586 12l-5.293 5.293a.999.999 0 1 0 1.414 1.414z"
/>
</svg>

After

Width:  |  Height:  |  Size: 310 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -0,0 +1,16 @@
{% extends 'layouts/base.njk' %}
{# Intro content #}
{% set introHeading = title %}
{% set introSummary %}{{ content | safe }}{% endset %}
{# Post list content #}
{% set postListHeading = 'All posts' %}
{% set postListItems = collections.posts %}
{% block content %}
<main id="main-content" tabindex="-1">
{% include "partials/components/intro.njk" %}
{% include "partials/components/post-list.njk" %}
</main>
{% endblock %}

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="alternate" type="application/rss+xml" title="{{ site.title }}" href="{{ site.url }}/feed.xml" />
<link rel="icon" href="{{ site.faviconPath }}" type="image/png" />
{% include "partials/global/meta-info.njk" %}
<script>document.documentElement.classList.remove('no-js');</script>
<style>{% include "assets/css/global.css" %}</style>
{% block head %}
{% endblock %}
</head>
<body>
{% include "partials/global/site-head.njk" %}
{% block content %}
{% endblock content %}
{% include "partials/global/site-foot.njk" %}
{% block foot %}
{% endblock %}
{# <script type="module" src="/js/components/theme-toggle.js" async defer></script> #}
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js');
});
}
</script>
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js" defer></script>
</body>
</html>

View File

@ -0,0 +1,18 @@
{% extends 'layouts/base.njk' %}
{# Intro content #}
{% set introHeading = title %}
{% block content %}
<main id="main-content" tabindex="-1">
<article class="[ post ] [ h-entry ]">
{% include "partials/components/intro.njk" %}
<div class="[ post__body ] [ inner-wrapper ] [ leading-loose pad-top-900 pad-bottom-900 text-500 ] [ sf-flow ] [ e-content ]">
{{ content | safe }}
{% include "partials/components/contact-form.njk" %}
</div>
</article>
</main>
{% endblock %}
{{ content | safe }}

View File

@ -0,0 +1,19 @@
{% extends 'layouts/base.njk' %}
{# Post list content #}
{% set newsListHeading = newsHeading %}
{% set newsListItems = collections.newsFeed %}
{# Presentation content #}
{% set presentation %}
{{ content | safe }}
{% endset %}
{% block content %}
<main id="main-content" tabindex="-1">
{% include "partials/components/intro.njk" %}
{% include "partials/components/news-list.njk" %}
{% include "partials/components/post-list.njk" %}
{% include "partials/components/presentation.njk" %}
</main>
{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends 'layouts/base.njk' %}
{# Intro content #}
{% set introHeading = title %}
{% block content %}
<main id="main-content" tabindex="-1">
<article class="[ post ] [ h-entry ]">
{% include "partials/components/intro.njk" %}
<div class="[ post__body ] [ inner-wrapper ] [ leading-loose pad-top-900 pad-bottom-900 text-500 ] [ sf-flow ] [ e-content ]">
{{ content | safe }}
</div>
</article>
</main>
{% endblock %}
{{ content | safe }}

View File

@ -0,0 +1,47 @@
{% extends 'layouts/base.njk' %}
{# Intro content #}
{% set introHeading = title %}
{% set introSummary %}
<p class="[ intro__meta ] [ text-500 leading-tight ]">
{% if date %}
<time datetime="{{ date | w3DateFilter }}" class="dt-published">{{ date | dateFilter }}</time>
{% endif %}
<span>— {{ helpers.getReadingTime(content) }} minute read</span>
</p>
{% endset %}
{% block content %}
<main id="main-content" tabindex="-1">
<article class="[ post ] [ h-entry ]">
{% include "partials/components/intro.njk" %}
<div class="[ post__body ] [ inner-wrapper ] [ leading-loose pad-top-900 {{ 'pad-bottom-900' if not site.enableThirdPartyComments }} text-500 ] [ sf-flow ] [ e-content ]">
{{ content | safe }}
</div>
{% if site.enableThirdPartyComments %}
<hr />
<aside class="[ post__body ] [ inner-wrapper ] [ pad-bottom-900 text-500 ]">
{% include "partials/global/third-party-comments.njk" %}
</aside>
{% endif %}
{% if tags %}
<footer class="[ post__footer ] [ pad-top-500 pad-bottom-500 ]">
<div class="inner-wrapper">
<div class="[ nav ] [ box-flex align-center ]">
<h2 class="font-base text-600 weight-mid">Filed under</h2>
<ul class="[ nav__list ] [ box-flex align-center pad-left-400 ] [ p-category ]">
{% for item in tags %}
<li class="nav__item">
<a href="/tags/{{ item }}">{{ item }}</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</footer>
{% endif %}
</article>
</main>
{% endblock %}
{{ content | safe }}

View File

@ -0,0 +1,181 @@
{# ===================
Forms
=================== #}
{% macro label( text, name ) %}
<label class="question__label" for="field-{{ name }}">{{ text }}</label>
{% endmacro %}
{% macro field( type, name, data ) %}
<br>
<input class="question__field"
type="{{ type }}"
name="{{ name }}"
id="field-{{ name }}"
{% if data.required %}required aria-required="true"{% endif %}
{% if data.placeholder %}placeholder="{{ data.placeholder }}"{% endif %}
{% if data.pattern %}pattern="{{ data.pattern }}"{% endif %}
{% if data.description %}aria-describedby="description-{{ name }}"{% endif %}
{% if data.autocomplete %}autocomplete="{{ data.autocomplete }}"{% endif %}
{% if data.autocorrect %}autocorrect="{{ data.autocorrect }}"{% endif %}
{% if data.spellcheck %}spellcheck="{{ data.spellcheck }}"{% endif %}
{% if data.autocapitalize %}autocapitalize="{{ data.autocapitalize }}"{% endif %}
>
{% if data.description %}
<br>
{{ description( name, data.description ) }}
{% endif %}
{% endmacro %}
{% macro confirm( text, name, data ) %}
<label for="field-{{ name }}" class="question--confirm">
<input class="question__field question__field--confirm"
type="checkbox"
name="{{ name }}"
id="field-{{ name }}"
value="1"
{% if data.required %}required aria-required="true"{% endif %}
{% if data.description %}aria-describedby="description-{{ name }}"{% endif %}
>
{{ text }}
</label>
{% if data.description %}
<br>
{{ description( name, data.description ) }}
{% endif %}
{% endmacro %}
{% macro select( name, options, data ) %}
<br>
<select id="field-{{ name }}"
name="{{ name }}"
{% if data.required %}required aria-required="true"{% endif %}
{% if data.multiple %}multiple{% endif %}
{% if data.description %}aria-describedby="description-{{ name }}"{% endif %}
>
{% for opt in data.options_before %}
{{ option( opt ) }}
{% endfor %}
{% for opt in options %}
{{ option( opt ) }}
{% endfor %}
{% for opt in data.options_after %}
{{ option( opt ) }}
{% endfor %}
</select>
{% if data.description %}
<br>
{{ description( name, data.description ) }}
{% endif %}
{% endmacro %}
{% macro option( data ) %}
{% if data.value %}
<option value="{{ data.value }}">{{ data.label }}</option>
{% else %}
<option>{{ data }}</option>
{% endif %}
{% endmacro %}
{% macro textarea( name, data ) %}
<br>
<textarea id="field-{{ name }}"
name="{{ name }}"
{% if data.rows %}rows="{{ data.rows }}"{% else %}rows="5"{% endif %}
cols="100"
{% if data.required %}required aria-required="true"{% endif %}
{% if data.autocorrect %}autocorrect="{{ data.autocorrect }}"{% endif %}
{% if data.spellcheck %}spellcheck="{{ data.spellcheck }}"{% endif %}
{% if data.autocapitalize %}autocapitalize="{{ data.autocapitalize }}"{% endif %}
{% if data.description %}aria-describedby="description-{{ name }}"{% endif %}
></textarea>
{% if data.description %}
{{ description( name, data.description ) }}
{% endif %}
{% endmacro %}
{% macro radios( label, name, options, data ) %}
<fieldset>
<legend
{% if data.description %}aria-describedby="description-{{ name }}"{% endif %}
>{{ label }}</legend>
<ul class="field-list__field-group__list">
{% for option in options %}
<li>
{% if option.value %}
<label for="field-{{ name }}-{{ option.value }}">
<input type="radio"
name="{{ name }}"
id="field-{{ name }}-{{ option.value }}"
value="{{ option.value }}"
{% if option.note %}aria-describedby="description-{{ name }}-{{ option.value }}"{% endif %}
>{{ option.label }}</label>
{% else %}
<label for="field-{{ name }}-{{ option }}">
<input type="radio"
name="{{ name }}"
id="field-{{ name }}-{{ option }}"
value="{{ option }}"
>{{ option }}</label>
{% endif %}
{% if option.note %}
<br>
{{ description( ( name + '-' + option.value ), option.note ) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% if data.description %}
{{ description( name, data.description ) }}
{% endif %}
</fieldset>
{% endmacro %}
{% macro checkboxes( label, name, options, data ) %}
<fieldset>
<legend
{% if data.description %}aria-describedby="description-{{ name }}"{% endif %}
>{{ label }}</legend>
<ul class="field-list__field-group__list">
{% for option in options %}
<li>
{% if option.value %}
<label for="field-{{ name }}-{{ option.value }}">
<input type="checkbox"
name="{{ name }}[]"
id="field-{{ name }}-{{ option.value }}"
value="{{ option.value }}"
{% if option.note %}aria-describedby="description-{{ name }}-{{ option.value }}"{% endif %}
>{{ option.label }}</label>
{% else %}
<label for="field-{{ name }}-{{ option }}">
<input type="checkbox"
name="{{ name }}[]"
id="field-{{ name }}-{{ option }}"
value="{{ option }}"
>{{ option }}</label>
{% endif %}
{% if option.note %}
<br>
{{ description( ( name + '-' + option.value ), option.note ) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% if data.description %}
{{ description( name, data.description ) }}
{% endif %}
</fieldset>
{% endmacro %}
{% macro description( id, html ) %}
<em class="[ field-list__field-group__description ]" id="description-{{ id }}">{{ html | safe }}</em>
{% endmacro %}
{% macro hidden_field( name, value ) %}
<input type="hidden" name="{{ name }}" id="field-{{ name }}" value="{{ value }}">
{% endmacro %}
{% macro button( text ) %}
<button type="submit" class="[ button ] [ font-base text-base weight-bold ]">{{ text }}</button>
{% endmacro %}

View File

@ -0,0 +1,4 @@
{# ========================
Site-specific Macros
======================== #}

View File

@ -0,0 +1,22 @@
{% from "macros/form.njk" import label, field, textarea, button %}
<form name="contact" method="POST" data-netlify="true" action="/thank-you" netlify-honeypot="bot-field">
<ol class="[ field-list ]">
<li class="[ field-list__field-group ]">
{{ label("Whats your name?", "name") }}
{{ field( "text", "name", { required: true, placeholder: "Katherine Johnson", autocomplete: "name", autocorrect: "off", autocapitalize: "off" } ) }}
</li>
<li class="[ field-list__field-group ]">
{{ label("Whats your email address?", "email") }}
{{ field( "email", "email", { required: true, placeholder: "katherine@johnson.tld", autocomplete: "email" } ) }}
</li>
<li class="[ field-list__field-group ]">
{{ label("Whats on your mind?", "message") }}
{{ textarea( "message", { required: true, autocapitalize: "sentences", spellcheck: "true" } ) }}
</li>
<li hidden>
<label>Dont fill this out if you're human: <input name="bot-field" /></label>
</li>
</ol>
{{ button("Send message") }}
</form>

View File

@ -0,0 +1,10 @@
<header class="[ intro ]">
<div class="[ inner-wrapper ]">
<h1 class="[ intro__heading ]">{{ brandHeading }}</h1>
{% if introSummary %}
<div class="[ intro__summary ] [ sf-flow ] [ leading-mid measure-short ]">{{ introSummary | safe }}</div>
{% endif %}
<a role="button" href="/README" class="btn btn-secondary">Une CAE c'est quoi ?</button>
<a role="button" href="/README" class="btn btn-primary">Nous rejoindre</button>
</div>
</header>

View File

@ -0,0 +1,22 @@
{% if navigation.items %}
<nav class="nav" aria-label="{{ariaLabel}}">
<ul class="[ nav__list ] [ box-flex align-center md:space-before ]">
{% for item in navigation.items %}
{% set relAttribute = '' %}
{% set currentAttribute = '' %}
{% if item.rel %}
{% set relAttribute = ' rel="' + item.rel + '"' %}
{% endif %}
{% if page.url == item.url %}
{% set currentAttribute = ' aria-current="page"' %}
{% endif %}
<li class="nav__item">
<a href="{{ item.url | url }}"{{ relAttribute | safe }}{{ currentAttribute | safe }}>{{ item.text }}</a>
</li>
{% endfor %}
</ul>
</nav>
{% endif %}

View File

@ -0,0 +1,25 @@
{% if newsListItems.length %}
<section class="[ news-list ]">
<svg aria-hidden="true" viewBox="0 0 1440 349" width="auto" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="#282156" d="M1440 154H0v195h1440z"/><path d="M1440 54.078l-48 12.41c-48 12.41-144 37.23-240 45.53-96 7.989-192 .232-288-29.01C768 54.079 672 4.438 576 .327c-96-4.421-192 37.463-288 45.452-96 8.3-192-16.52-240-28.931L0 4.437V203h1440V54.078z" fill="#282156"/></svg>
<div class="[ wrapper ]">
<div class="news-list__inner">
<h2 class="[ news-list__heading ]">{{ newsListHeading }}</h2>
<ol class="[ news-list__items ]" reversed>
{% for item in newsListItems %}
{% if item.date.getTime() <= global.now %}
<li class="news-list__item">
<h3 class="news-list__item-heading">
<a href="{{ item.url | url }}" class="news-list__link" rel="bookmark">{{ item.data.title }}</a>
</h3>
<p class="news-list__item-date">
<time datetime="{{ item.date | w3DateFilter }}">{{ item.date | dateFilter }}</time>
</p>
</li>
{% endif %}
{% endfor %}
</ol>
<a href="/" class="news-list__see-all">Voir tout</a>
</div>
</div>
</section>
{% endif %}

View File

@ -0,0 +1,23 @@
{% set paginationLinkTokens = 'leading-tight text-500 weight-mid box-inline-flex align-center pad-bottom-300' %}
{% if paginationNextUrl or paginationPrevUrl %}
<hr />
<div class="inner-wrapper">
<footer class="[ pagination ] [ pad-bottom-900 ]">
<nav class="[ pagination__nav ] [ box-flex space-between align-center ]">
{% if paginationPrevUrl %}
<a href="{{ paginationPrevUrl }}" class="{{ paginationLinkTokens }}" data-direction="backwards">
<span>{{ paginationPrevText if paginationPrevText else 'Previous' }}</span>
{% include "icons/arrow.svg" %}
</a>
{% endif %}
{% if paginationNextUrl %}
<a href="{{ paginationNextUrl }}" class="{{ paginationLinkTokens }}" data-direction="forwards">
<span>{{ paginationNextText if paginationNextText else 'Next' }}</span>
{% include "icons/arrow.svg" %}
</a>
{% endif %}
</nav>
</footer>
</div>
{% endif %}

View File

@ -0,0 +1,21 @@
{% if postListItems.length %}
<section class="[ post-list ] [ pad-top-700 gap-bottom-900 ]">
<div class="[ inner-wrapper ] [ sf-flow ]">
<h2 class="[ post-list__heading ]">{{ postListHeading }}</h2>
<ol class="[ post-list__items ] [ sf-flow ] [ pad-top-300 ]" reversed>
{% for item in postListItems %}
{% if item.date.getTime() <= global.now %}
<li class="post-list__item">
<h3 class="font-base leading-tight text-600 weight-mid">
<a href="{{ item.url }}" class="post-list__link" rel="bookmark">{{ item.data.title }}</a>
</h3>
<p class="text-500 gap-top-300 weight-mid">
<time datetime="{{ item.date | w3DateFilter }}">{{ item.date | dateFilter }}</time>
</p>
</li>
{% endif %}
{% endfor %}
</ol>
</div>
</section>
{% endif %}

View File

@ -0,0 +1,5 @@
<section class="[ presentation ]">
<div class="[ wrapper ]">
{{ presentation | safe }}
</div>
</section>

View File

@ -0,0 +1,41 @@
{% set pageTitle = site.name + ' - ' + title %}
{% set pageDesc = '' %}
{% set siteTitle = site.name %}
{% set currentUrl = site.url + page.url %}
{% if metaTitle %}
{% set pageTitle = metaTitle %}
{% endif %}
{% if metaDesc %}
{% set pageDesc = metaDesc %}
{% endif %}
<title>{{ pageTitle }}</title>
<link rel="canonical" href="{{ currentUrl }}" />
<meta property="og:site_name" content="{{ siteTitle }}" />
<meta property="og:title" content="{{ pageTitle }}" />
<meta property="og:type" content="website" />
<meta property="og:url" content="{{ currentUrl }}" />
{% if site.authorHandle %}
<meta name="twitter:creator" content="@{{ site.authorHandle | replace('@', '') }}" />
{% endif %}
{% if metaDesc %}
<meta name="description" content="{{ metaDesc }}" />
<meta name="twitter:description" content="{{ metaDesc }}" />
<meta property="og:description" content="{{ metaDesc }}" />
{% endif %}
{% if socialImage %}
<meta property="og:image" content="{{ socialImage }}" />
<meta name="twitter:image" content="{{ socialImage }}" />
<meta property="og:image:alt" content="Page image for {{ site.name }}" />
<meta name="twitter:image:alt" content="Page image for {{ site.name }}" />
{% endif %}
{% if site.paymentPointer %}
<meta name="monetization" content="{{ site.paymentPointer }}" />
{% endif %}

View File

@ -0,0 +1,92 @@
const CACHE_KEYS = {
PRE_CACHE: `precache-${VERSION}`,
RUNTIME: `runtime-${VERSION}`
};
// URLS that we dont want to end up in the cache
const EXCLUDED_URLS = [
'admin',
'.netlify',
'https://identity.netlify.com/v1/netlify-identity-widget.js',
'https://unpkg.com/netlify-cms@^2.9.3/dist/netlify-cms.js',
'/contact',
'/thank-you'
];
// URLS that we want to be cached when the worker is installed
const PRE_CACHE_URLS = ['/', '/fonts/VarelaRound-Regular.ttf', '/fonts/OpenSans-Bold.ttf', '/fonts/OpenSans-SemiBold.ttf', '/fonts/OpenSans-Regular.ttf'];
// You might want to bypass a certain host
const IGNORED_HOSTS = ['localhost', 'unpkg.com', ];
/**
* Takes an array of strings and puts them in a named cache store
*
* @param {String} cacheName
* @param {Array} items=[]
*/
const addItemsToCache = function(cacheName, items = []) {
caches.open(cacheName).then(cache => cache.addAll(items));
};
self.addEventListener('install', evt => {
self.skipWaiting();
addItemsToCache(CACHE_KEYS.PRE_CACHE, PRE_CACHE_URLS);
});
self.addEventListener('activate', evt => {
// Look for any old caches that don't match our set and clear them out
evt.waitUntil(
caches
.keys()
.then(cacheNames => {
return cacheNames.filter(item => !Object.values(CACHE_KEYS).includes(item));
})
.then(itemsToDelete => {
return Promise.all(
itemsToDelete.map(item => {
return caches.delete(item);
})
);
})
.then(() => self.clients.claim())
);
});
self.addEventListener('fetch', evt => {
const {hostname} = new URL(evt.request.url);
// Check we don't want to ignore this host
if (IGNORED_HOSTS.indexOf(hostname) >= 0) {
return;
}
// Check we don't want to ignore this URL
if (EXCLUDED_URLS.some(page => evt.request.url.indexOf(page) > -1)) {
return;
}
evt.respondWith(
caches.match(evt.request).then(cachedResponse => {
// Item found in cache so return
if (cachedResponse) {
return cachedResponse;
}
// Nothing found so load up the request from the network
return caches.open(CACHE_KEYS.RUNTIME).then(cache => {
return fetch(evt.request)
.then(response => {
// Put the new response in cache and return it
return cache.put(evt.request, response.clone()).then(() => {
return response;
});
})
.catch(ex => {
return;
});
});
})
);
});

View File

@ -0,0 +1,24 @@
<footer role="contentinfo" class="[ site-foot ]">
<div class="wrapper">
<div class="[ site-foot__inner ]">
<div class="">
<h3>Mentions légales</h3>
<p>Protection des données</p>
</div>
<div class="">
<h3>Crédits</h3>
<p>Design et intégration : <a href="{{site.designerHandle}}" target="_blank">{{site.designerName}}</a></p>
<p>Illustrations : {{site.illustrators}}
</div>
<div class="">
<h3>Contact</h3>
<p>{{site.authorName}}</p>
<p>{{site.authorAddress}}<br>{{site.authorCity}}</p>
<ul>
<a href="{{site.authorSocial.mastodon}}" class="social">Mastodon</a>
<a href="{{site.authorSocial.twitter}}" class="social">Twitter</a>
<a href="{{site.authorSocial.linkedin}}" class="social">Linkedin</a>
</ul>
</div>
</div>
</footer>

View File

@ -0,0 +1,13 @@
<a class="skip-link" href="#main-content">Skip to content</a>
<header role="banner" class="[ site-head ]">
<div class="wrapper">
<div class="[ site-head__inner ] [ md:box-flex space-between align-center ]">
<a href="{{ url }}" class="[ site-head__site-name ] [ leading-tight ]">
<span class="visually-hidden">{{ site.name }} - Home</span>
{% include "icons/astrolabe_logo.svg" %}
</a>
{% set ariaLabel = 'navigation' %}
{% include "partials/components/nav.njk" %}
</div>
</div>
</header>

View File

@ -0,0 +1,7 @@
<!-- ADD YOUR THIRD PARTY COMMENTS CODE HERE -->
<!-- COMMENTO EXAMPLE
<div id="commento"></div>
<script defer
src="https://cdn.commento.io/js/commento.js">
</script>
-->

4
src/archive.md Normal file
View File

@ -0,0 +1,4 @@
---
title: 'Posts Archive'
layout: 'layouts/archive.njk'
---

30
src/feed.njk Normal file
View File

@ -0,0 +1,30 @@
---
permalink: '/feed.xml'
---
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ site.name }}</title>
<subtitle></subtitle>
<link href="{{ site.url }}{{ permalink }}" rel="self"/>
<link href="{{ site.url }}/"/>
{% if collections.posts|length %}
<updated>{{ collections.posts | rssLastUpdatedDate }}</updated>
{% endif %}
<id>{{ site.url }}</id>
<author>
<name>{{ site.authorName }}</name>
<email>{{ site.authorEmail }}</email>
</author>
{% for post in collections.posts %}
{% set absolutePostUrl %}{{ site.url }}{{ post.url | url }}{% endset %}
<entry>
<title>{{ post.data.title }}</title>
<link href="{{ absolutePostUrl }}"/>
<updated>{{ post.date | rssDate }}</updated>
<id>{{ absolutePostUrl }}</id>
<content type="html"><![CDATA[
{{ post.templateContent | safe }}
]]></content>
</entry>
{% endfor %}
</feed>

View File

@ -0,0 +1,17 @@
// Stolen from https://stackoverflow.com/a/31615643
const appendSuffix = n => {
var s = ['th', 'st', 'nd', 'rd'],
v = n % 100;
return n + (s[(v - 20) % 10] || s[v] || s[0]);
};
module.exports = function dateFilter(value) {
const dateObject = new Date(value);
// const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
const months = ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juill.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'];
const dayWithSuffix = appendSuffix(dateObject.getDate());
// return `${dayWithSuffix} ${months[dateObject.getMonth()]} ${dateObject.getFullYear()}`;
return `${dateObject.getDate()} ${months[dateObject.getMonth()]} ${dateObject.getFullYear()}`;
};

View File

@ -0,0 +1,9 @@
const markdownIt = require('markdown-it')({
html: true,
breaks: true,
linkify: true
});
module.exports = function markdown(value) {
return markdownIt.render(value);
};

View File

@ -0,0 +1,5 @@
module.exports = function w3cDate(value) {
const dateObject = new Date(value);
return dateObject.toISOString();
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/images/demo-image-1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
src/images/demo-image-2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

BIN
src/images/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

1
src/images/gitlab.svg Normal file
View File

@ -0,0 +1 @@
<svg width="110" height="101" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M109.052 56.536l-5.704-17.493a2.415 2.415 0 00-.138-.47L91.766 3.412a4.54 4.54 0 00-1.669-2.251 4.555 4.555 0 00-2.674-.846 4.478 4.478 0 00-2.661.856 4.464 4.464 0 00-1.632 2.266L72.222 36.942H37.795L26.871 3.438a4.465 4.465 0 00-1.624-2.26 4.478 4.478 0 00-2.65-.862h-.025a4.555 4.555 0 00-4.331 3.125L6.788 38.643c0 .032-.026.057-.035.09L.946 56.538a6.485 6.485 0 002.364 7.272l50.17 36.386a2.57 2.57 0 003.032-.016l50.179-36.37a6.493 6.493 0 002.361-7.275zM34.061 42.085l13.984 42.96-33.57-42.96H34.06zm27.911 42.97l13.41-41.187.578-1.783h19.602L65.19 80.92l-3.218 4.133zM87.467 6.735l9.827 30.206h-19.67l9.844-30.206zm-16.91 35.33l-9.743 29.927L55 89.816l-15.534-47.75h31.09zM22.55 6.736l9.846 30.206H12.739l9.81-30.206zM6.33 59.668a1.38 1.38 0 01-.501-1.547l4.311-13.225 31.624 40.466L6.329 59.668zm97.345 0L68.238 85.352l.118-.154 31.505-40.302 4.312 13.219a1.383 1.383 0 01-.498 1.55" fill="#111"/></svg>

After

Width:  |  Height:  |  Size: 998 B

BIN
src/images/social-share.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

40
src/index.md Normal file
View File

@ -0,0 +1,40 @@
---
layout: home
title: Accueil
brandHeading: La Coopérative d'Activité et d'Emploi spécialisée en informatique !
newsHeading: Actualité & Évenements
metaDesc: 'Hylia is a lightweight Eleventy starter kit to help you to create your own blog or personal website.'
---
<article>
<div class="content">
## Qui sommes-nous ?
Astrolabe CAE est une scop spécialisée dans la prestation de **services** autour des métiers du **numérique**.
Notre objectif est de favoriser l**autonomie** et l**émancipation** de nos membres sur un modèle déconomie sociale et **solidaire**.
</div>
![logo Gitlab](/images/gitlab.svg)
</article>
<article>
<div class="content">
## Communs numérique
Chez Astrolabe nous aimons et faisons la promotion du **logiciel libre**. Nos sommes membres d[Alliance Libre](http://www.alliance-libre.org/) et nous mettons nos documents et projets internes à disposition sur notre [gitlab]().
</div>
![logo Gitlab](/images/gitlab.svg "test")
</article>
<article>
<div class="content">
## Des profils variés
Nos coopérateurs possèdent des compétences propres allant de développement linux embarqué au web design et créent ainsi la **pluralité** de nos prestations.
<br><br>
Nous sommes également **distributeurs** de la solution logicielle [Naega](https://www.crealead.com/naega#bootstrap-fieldgroup-nav-item--prsentation).
</div>
![logo Gitlab](/images/gitlab.svg)
</article>

View File

@ -0,0 +1,98 @@
// For syntax highlighting only
const html = String.raw;
class ThemeToggle extends HTMLElement {
constructor() {
super();
this.STORAGE_KEY = 'user-color-scheme';
this.COLOR_MODE_KEY = '--color-mode';
}
connectedCallback() {
this.render();
}
getCSSCustomProp(propKey) {
let response = getComputedStyle(document.documentElement).getPropertyValue(propKey);
// Tidy up the string if theres something to work with
if (response.length) {
response = response.replace(/\'|"/g, '').trim();
}
// Return the string response by default
return response;
}
applySetting(passedSetting) {
let currentSetting = passedSetting || localStorage.getItem(this.STORAGE_KEY);
if (currentSetting) {
document.documentElement.setAttribute('data-user-color-scheme', currentSetting);
this.setButtonLabelAndStatus(currentSetting);
} else {
this.setButtonLabelAndStatus(this.getCSSCustomProp(this.COLOR_MODE_KEY));
}
}
toggleSetting() {
let currentSetting = localStorage.getItem(this.STORAGE_KEY);
switch (currentSetting) {
case null:
currentSetting =
this.getCSSCustomProp(this.COLOR_MODE_KEY) === 'dark' ? 'light' : 'dark';
break;
case 'light':
currentSetting = 'dark';
break;
case 'dark':
currentSetting = 'light';
break;
}
localStorage.setItem(this.STORAGE_KEY, currentSetting);
return currentSetting;
}
setButtonLabelAndStatus(currentSetting) {
this.modeToggleButton.innerText = `${
currentSetting === 'dark' ? 'Light' : 'Dark'
} theme`;
this.modeStatusElement.innerText = `Color mode is now "${currentSetting}"`;
}
render() {
this.innerHTML = html`
<div class="[ theme-toggle ] [ md:ta-right gap-top-500 ]">
<div role="status" class="[ visually-hidden ][ js-mode-status ]"></div>
<button class="[ button ] [ font-base text-base weight-bold ] [ js-mode-toggle ]">
Dark theme
</button>
</div>
`;
this.afterRender();
}
afterRender() {
this.modeToggleButton = document.querySelector('.js-mode-toggle');
this.modeStatusElement = document.querySelector('.js-mode-status');
this.modeToggleButton.addEventListener('click', evt => {
evt.preventDefault();
this.applySetting(this.toggleSetting());
});
this.applySetting();
}
}
if ('customElements' in window) {
customElements.define('theme-toggle', ThemeToggle);
}
export default ThemeToggle;

9
src/pages/contact.md Normal file
View File

@ -0,0 +1,9 @@
---
title: 'Contact'
permalink: '/contact/index.html'
layout: 'layouts/contact.njk'
---
You can have a contact page which uses a basic form. The [code with the form fields lives here](https://github.com/hankchizljaw/hylia/blob/master/src/_includes/layouts/contact.njk).
To delete the contact form for this site, delete this page in the CMS or at `src/pages/contact.md`. You probably will also want to delete `src/pages/thank-you.md`.

3
src/pages/pages.json Normal file
View File

@ -0,0 +1,3 @@
{
"layout": "layouts/page.njk"
}

6
src/pages/thank-you.md Normal file
View File

@ -0,0 +1,6 @@
---
title: 'Thank you'
permalink: '/thank-you/index.html'
---
This is your thank you page where if someone fills in your contact form, they will be directed to. Make sure you add a nice message 🙂

View File

@ -0,0 +1,64 @@
---
title: A post with code samples
date: '2019-12-18'
tags:
- demo-content
- code
- blog
---
The best way to demo a code post is to display a real life post, so check out this one from [andy-bell.design](https://andy-bell.design/wrote/creating-a-full-bleed-css-utility/) about a full bleed CSS utility.
- - -
Sometimes you want to break your components out of the constraints that they find themselves in. A common situation where this occurs is when you dont have much control of the container that it exists in, such as a CMS main content area.
This is even more the case with editing tools such as the [WordPress Gutenberg editor](https://wordpress.org/gutenberg/), where in theory, you could pull in a component from a design system and utilise it in the main content of your web page. In these situations, it can be pretty darn handy to have a little utility that makes the element 100% of the viewports width _and_ still maintain its flow within its parent container.
This is when I normally pull the `.full-bleed` utility class out of my back pocket.
## The `.full-bleed` utility
Its small, but hella mighty:
```css
.full-bleed {
width: 100vw;
margin-left: 50%;
transform: translateX(-50%);
}
```
Here it is in a context where it makes a fancy `<aside>` and a `<figure>` element bleed out of their parent container.
<iframe height="300" style="width: 100%;" scrolling="no" title="Piccalilli CSS Utility — Issue #2 — Full bleed utility" src="//codepen.io/andybelldesign/embed/Nmxrwv/?height=300&theme-id=dark&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true">
See the Pen <a href='https://codepen.io/andybelldesign/pen/Nmxrwv/'>Piccalilli CSS Utility — Issue #2 — Full bleed utility</a> by Andy Bell
(<a href='https://codepen.io/andybelldesign'>@andybelldesign</a>) on <a href='https://codepen.io'>CodePen</a>.
</iframe>
The `.full-bleed` utility gives those elements prominence and _importantly_ keeps their semantic place in the page. Just how I like it.
- - -
🔥 **Pro tip**: When working with a utility like `.full-bleed`, its a good idea to add an inner container that has a max-width and auto horizontal margin. For this, I normal create a shared `.wrapper` component like this: