first commit:
- we have a static astro website under /website. It has the implementation docs of the homepage/gaufre templates, and it handles the few API endpoints (the gaufre js, backgrounds, logos) - we have a vite app under /packages/integration. It has the react components generating the homepage and the gaufre button, and their css. Its used to generate an npm package
BIN
website/src/assets/backgrounds/0.avif
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
website/src/assets/backgrounds/0.jpg
Normal file
|
After Width: | Height: | Size: 289 KiB |
BIN
website/src/assets/backgrounds/1.avif
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
website/src/assets/backgrounds/1.jpg
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
website/src/assets/backgrounds/10.avif
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
website/src/assets/backgrounds/10.jpg
Normal file
|
After Width: | Height: | Size: 256 KiB |
BIN
website/src/assets/backgrounds/11.avif
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
website/src/assets/backgrounds/11.jpg
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
website/src/assets/backgrounds/12.avif
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
website/src/assets/backgrounds/12.jpg
Normal file
|
After Width: | Height: | Size: 281 KiB |
BIN
website/src/assets/backgrounds/13.avif
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
website/src/assets/backgrounds/13.jpg
Normal file
|
After Width: | Height: | Size: 332 KiB |
BIN
website/src/assets/backgrounds/14.avif
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
website/src/assets/backgrounds/14.jpg
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
website/src/assets/backgrounds/15.avif
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
website/src/assets/backgrounds/15.jpg
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
website/src/assets/backgrounds/16.avif
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
website/src/assets/backgrounds/16.jpg
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
website/src/assets/backgrounds/17.avif
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
website/src/assets/backgrounds/17.jpg
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
website/src/assets/backgrounds/18.avif
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
website/src/assets/backgrounds/18.jpg
Normal file
|
After Width: | Height: | Size: 278 KiB |
BIN
website/src/assets/backgrounds/19.avif
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
website/src/assets/backgrounds/19.jpg
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
website/src/assets/backgrounds/2.avif
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
website/src/assets/backgrounds/2.jpg
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
website/src/assets/backgrounds/20.avif
Normal file
|
After Width: | Height: | Size: 243 KiB |
BIN
website/src/assets/backgrounds/20.jpg
Normal file
|
After Width: | Height: | Size: 444 KiB |
BIN
website/src/assets/backgrounds/21.avif
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
website/src/assets/backgrounds/21.jpg
Normal file
|
After Width: | Height: | Size: 423 KiB |
BIN
website/src/assets/backgrounds/3.avif
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
website/src/assets/backgrounds/3.jpg
Normal file
|
After Width: | Height: | Size: 295 KiB |
BIN
website/src/assets/backgrounds/4.avif
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
website/src/assets/backgrounds/4.jpg
Normal file
|
After Width: | Height: | Size: 263 KiB |
BIN
website/src/assets/backgrounds/5.avif
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
website/src/assets/backgrounds/5.jpg
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
website/src/assets/backgrounds/6.avif
Normal file
|
After Width: | Height: | Size: 229 KiB |
BIN
website/src/assets/backgrounds/6.jpg
Normal file
|
After Width: | Height: | Size: 475 KiB |
BIN
website/src/assets/backgrounds/7.avif
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
website/src/assets/backgrounds/7.jpg
Normal file
|
After Width: | Height: | Size: 297 KiB |
BIN
website/src/assets/backgrounds/8.avif
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
website/src/assets/backgrounds/8.jpg
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
website/src/assets/backgrounds/9.avif
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
website/src/assets/backgrounds/9.jpg
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
website/src/assets/fonts/Marianne-Bold.woff2
Executable file
BIN
website/src/assets/fonts/Marianne-Medium.woff2
Executable file
BIN
website/src/assets/fonts/Marianne-Regular.woff2
Executable file
15
website/src/assets/lasuite-logo.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<svg width="479.815" height="127.447" viewBox="0 0 479.815 127.447" fill="none" version="1.1" id="svg31" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M41.6279 84.5078c0 23.5822 15.9791 41.4232 37.3945 41.4232.9652 0 1.918-.037 2.8521-.112V98.6872c-6.7939-1.2143-11.5453-6.8998-11.5453-14.1794 0-7.2797 4.7514-12.9713 11.5453-14.1856V43.1964c-.9341-.0809-1.8869-.1183-2.8521-.1183-21.4154 0-37.3945 17.8472-37.3945 41.4297z" fill="#000091" id="path1"/>
|
||||
<path d="M296.15 45.9783h-27.929v79.1297h27.929Z" fill="#e1000f" id="path2"/>
|
||||
<path d="M119.531 43.0781H91.6016v82.0289h27.9294z" fill="#000091" id="path3"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="m27.8544 12.3591.0748 111.7099H0V12.3591Z" fill="#000091" id="path4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M164.459 61.6758c7.292 0 13.339 2.6404 19.703 6.2086l11.95-17.0689c-7.759-5.1187-18.003-10.0819-32.743-10.0819-2.341 0-4.627.1308-6.837.3924v23.2213c.685-1.918 4.047-2.6715 7.927-2.6715z" fill="#e1000f" id="path5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M167.019 72.5548c-5.96-1.1334-10.313-2.1547-11.022-4.4525v24.6846c.635.1308 1.264.2616 1.874.3862 6.825 1.3949 11.477 2.4846 11.477 5.4301 0 .4297-.131.8094-.318 1.1706.193.3612.318.7412.318 1.1772 0 2.634-3.724 4.035-9.466 4.035-1.338 0-2.621-.106-3.885-.249v20.986c1.606.131 3.256.205 4.975.205 20.17 0 35.838-9.465 35.838-27.6175 0-19.5472-17.686-23.4268-29.791-25.7557z" fill="#e1000f" id="path6"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M157.871 93.173c-.61-.1245-1.239-.2554-1.874-.3861v2.3414c.635.137 1.264.2679 1.874.3924 5.822 1.1894 10.038 2.167 11.159 4.2531.187-.3612.318-.741.318-1.1707 0-2.9454-4.652-4.0352-11.477-5.4301z" fill="#e1000f" id="path7"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M440.715 102.34c-5.512 0-9.952-2.13-12.872-5.8474V124.44c3.823.941 7.859 1.482 12.093 1.482 14.117 0 26.534-5.43 35.066-14.272l-18.308-16.1351c-2.946 3.1011-8.687 6.8251-15.979 6.8251z" fill="#e1000f" id="path8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M437.919 44.5889c-3.5 0-6.857.4109-10.076 1.1146v27.406c2.428-3.1136 5.785-4.9382 9.764-4.9382 5.586 0 10.4 3.5682 12.417 9.7767h-22.181v15.9791h51.35c.467-2.0114.622-5.1188.622-7.2921 0-24.3546-18.003-42.0461-41.896-42.0461z" fill="#e1000f" id="path9"/>
|
||||
<path d="M342.946 45.9783h-27.929v79.1297h27.929z" fill="#e1000f" id="path10"/>
|
||||
<path d="M342.946 0h-27.929v27.8369h27.929z" fill="#e1000f" id="path11"/>
|
||||
<path d="M390.218 27.8362h-27.929v18.6193h-.162V71.9h.162v25.2887c0 17.2243 8.999 30.2583 30.414 30.2583 6.209 0 11.172-1.09 15.979-3.575V97.8115c-2.796 1.3949-6.202 2.6345-9.932 2.6345-5.891 0-8.532-3.2572-8.532-7.9152V71.9h18.464V46.4555h-18.464z" fill="#e1000f" id="path12"/>
|
||||
<path d="M251.305 98.9288c-6.203 0-10.393-4.1909-10.393-10.5489V44.9387h-27.93v47.3207c0 20.3256 15.207 33.6706 38.323 33.6706 2.721 0 5.324-.206 7.815-.56V95.6782c-1.831 2.0487-4.527 3.2506-7.815 3.2506z" fill="#e1000f" id="path13"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
0
website/src/assets/logos/.gitkeep
Normal file
8
website/src/components/Aside.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
export default function Aside({ type = "note", title = "", children }) {
|
||||
return (
|
||||
<div className={`starlight-aside starlight-aside--${type}`}>
|
||||
<p className="starlight-aside__title">{title}</p>
|
||||
<section className="starlight-aside__content">{children}</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
24
website/src/components/Code.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { useEffect } from "react"
|
||||
import * as Prism from "prismjs"
|
||||
import "prismjs/components/prism-jsx"
|
||||
import "@/styles/prism.css"
|
||||
|
||||
export default function Code({ children, language, fixedHeight = false }) {
|
||||
useEffect(() => {
|
||||
Prism.highlightAll()
|
||||
}, [children, language])
|
||||
return (
|
||||
<div className={fixedHeight ? "language-fixedheight react-code" : "react-code"}>
|
||||
<pre>
|
||||
<code className={`language-${language}`}>{children}</code>
|
||||
</pre>
|
||||
<button
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(children)
|
||||
}}
|
||||
>
|
||||
Copier
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
237
website/src/components/HomepageGenerator.tsx
Normal file
@@ -0,0 +1,237 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import { renderToStaticMarkup } from "react-dom/server"
|
||||
import services from "@/data/services.json"
|
||||
import Code from "./Code"
|
||||
import {
|
||||
Homepage,
|
||||
HomepageEmail,
|
||||
HomepageEmailOrProconnect,
|
||||
HomepageProconnect,
|
||||
} from "@gouvfr-lasuite/integration"
|
||||
import * as prettier from "prettier/standalone"
|
||||
import prettierHtml from "prettier/plugins/html"
|
||||
|
||||
const defaultFormData = {
|
||||
serviceId: "",
|
||||
serviceName: "Service",
|
||||
tagline: "**Service**, un outil sécurisé <br>pour les agents de l'État",
|
||||
entity: "Gouvernement",
|
||||
homepageType: "proconnect",
|
||||
}
|
||||
|
||||
const homepageTypes = {
|
||||
proconnect: {
|
||||
label: "ProConnect uniquement",
|
||||
importCode: "HomepageProconnect",
|
||||
componentCode: `<HomepageProconnect url="~~replace~~" />`,
|
||||
Component: <HomepageProconnect url="~~replace~~" />,
|
||||
},
|
||||
"email-or-proconnect": {
|
||||
label: "E-mail + ProConnect",
|
||||
importCode: "HomepageEmailOrProconnect",
|
||||
componentCode: `<HomepageEmailOrProconnect proconnectUrl="~~replace~~" emailForm={{ action: "~~replace~~" }} />`,
|
||||
Component: (
|
||||
<HomepageEmailOrProconnect
|
||||
proconnectUrl="~~replace~~"
|
||||
emailForm={{ action: "~~replace~~" }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
email: {
|
||||
label: "E-mail uniquement",
|
||||
importCode: "HomepageEmail",
|
||||
componentCode: `<HomepageEmail action="~~replace~~" />`,
|
||||
Component: <HomepageEmail action="~~replace~~" />,
|
||||
},
|
||||
custom: {
|
||||
label: "Autre",
|
||||
importCode: null,
|
||||
componentCode: `~~replace~~`,
|
||||
Component: null,
|
||||
},
|
||||
}
|
||||
|
||||
export default function HomepageGenerator() {
|
||||
const [codeData, setCodeData] = useState<any>(defaultFormData)
|
||||
const [htmlMarkup, setHtmlMarkup] = useState<string>("")
|
||||
useEffect(() => {
|
||||
getHTMLMarkup(codeData).then((html) => {
|
||||
setHtmlMarkup(html)
|
||||
})
|
||||
}, [codeData])
|
||||
|
||||
return (
|
||||
<div style={{ margin: "1.5rem 0" }}>
|
||||
<form
|
||||
className="react-form not-content"
|
||||
onChange={(e) => {
|
||||
const formData = new FormData(e.currentTarget)
|
||||
setCodeData({
|
||||
...Object.fromEntries(formData),
|
||||
serviceId:
|
||||
formData.get("serviceId") && formData.get("serviceId") !== "other"
|
||||
? formData.get("serviceId")
|
||||
: undefined,
|
||||
})
|
||||
}}
|
||||
>
|
||||
<div className="react-form-input">
|
||||
<label htmlFor="serviceId">Service</label>
|
||||
<select
|
||||
name="serviceId"
|
||||
id="serviceId"
|
||||
defaultValue={defaultFormData.serviceId}
|
||||
onChange={(e) => {
|
||||
const serviceId = e.currentTarget.value
|
||||
const service = services.find((service) => service.id === serviceId)
|
||||
;(document.querySelector("#tagline") as HTMLInputElement).value = (
|
||||
service || defaultFormData
|
||||
).tagline
|
||||
;(document.querySelector("#entity") as HTMLInputElement).value = (
|
||||
service || defaultFormData
|
||||
).entity
|
||||
;(document.querySelector("#serviceName") as HTMLInputElement).value = service
|
||||
? service.name
|
||||
: defaultFormData.serviceName
|
||||
;(document.querySelector("#homepageType") as HTMLInputElement).value = (
|
||||
service || defaultFormData
|
||||
).homepageType
|
||||
}}
|
||||
>
|
||||
<option value="">Choisir votre service pour pré-remplir les champs</option>
|
||||
{services.map((service) => (
|
||||
<option key={service.id} value={service.id}>
|
||||
{service.name}
|
||||
</option>
|
||||
))}
|
||||
<option value="other">Autre…</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="react-form-input">
|
||||
<label htmlFor="serviceName">Nom du service</label>
|
||||
<input
|
||||
type="text"
|
||||
name="serviceName"
|
||||
id="serviceName"
|
||||
defaultValue={defaultFormData.serviceName}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="entity" id="entity" defaultValue={defaultFormData.entity} />
|
||||
|
||||
<div className="react-form-input">
|
||||
<label htmlFor="tagline">
|
||||
Phrase d'accroche
|
||||
<span>
|
||||
Mettre le texte entre ** pour l'écrire en gras, usage de <code><br></code>{" "}
|
||||
possible
|
||||
</span>
|
||||
</label>
|
||||
<input type="text" name="tagline" id="tagline" defaultValue={defaultFormData.tagline} />
|
||||
</div>
|
||||
|
||||
<div className="react-form-input">
|
||||
<label htmlFor="homepageType">Type de connexion</label>
|
||||
<select name="homepageType" id="homepageType">
|
||||
<option value="">Choisir…</option>
|
||||
{Object.keys(homepageTypes).map((key) => (
|
||||
<option key={key} value={key}>
|
||||
{homepageTypes[key].label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{!!codeData && (
|
||||
<>
|
||||
<div>
|
||||
<h2 style={{ marginTop: "1.5em" }}>Code React correspondant</h2>
|
||||
<Code language="jsx">{getReactMarkup(codeData)}</Code>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 style={{ marginTop: "1.5em" }}>Code HTML correspondant</h2>
|
||||
<Code language="html" fixedHeight>
|
||||
{htmlMarkup}
|
||||
</Code>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const getReactMarkup = (codeData) => {
|
||||
return `import { Homepage${
|
||||
codeData.homepageType && homepageTypes[codeData.homepageType].importCode
|
||||
? `, ${homepageTypes[codeData.homepageType].importCode}`
|
||||
: ""
|
||||
} } from "@gouvfr-lasuite/integration"
|
||||
|
||||
export default function MyHomepage() {
|
||||
return (
|
||||
<Homepage
|
||||
lasuiteApiUrl="${import.meta.env.PUBLIC_LASUITE_API_URL}"
|
||||
entity="${codeData.entity}"
|
||||
tagline="${codeData.tagline}"
|
||||
serviceName="${codeData.serviceName}" ${
|
||||
!!codeData.serviceId
|
||||
? `
|
||||
serviceId="${codeData.serviceId}"`
|
||||
: ""
|
||||
}
|
||||
logo="~~replace~~"
|
||||
homepageUrl="/"
|
||||
footerOptions={{
|
||||
description: "Un service de la Direction interministérielle du numérique",
|
||||
sitemapUrl: "~~replace~~",
|
||||
a11yUrl: "~~replace~~",
|
||||
a11yLevel: "~~replace~~",
|
||||
termsUrl: "~~replace~~",
|
||||
privacyUrl: "~~replace~~",
|
||||
}}
|
||||
>
|
||||
${codeData.homepageType ? homepageTypes[codeData.homepageType].componentCode : ""}
|
||||
</Homepage>
|
||||
)
|
||||
}`
|
||||
}
|
||||
|
||||
const getHTMLMarkup = (codeData) => {
|
||||
const Component = (
|
||||
<Homepage
|
||||
lasuiteApiUrl={import.meta.env.PUBLIC_LASUITE_API_URL}
|
||||
entity={codeData.entity}
|
||||
tagline={codeData.tagline}
|
||||
serviceName={codeData.serviceName}
|
||||
serviceId={codeData.serviceId}
|
||||
logo={
|
||||
codeData.serviceId
|
||||
? `${import.meta.env.PUBLIC_LASUITE_API_URL}/api/logos/v1/${codeData.serviceId}.svg`
|
||||
: "~~replace~~"
|
||||
}
|
||||
homepageUrl="/"
|
||||
footerOptions={{
|
||||
description: "Un service de la Direction interministérielle du numérique",
|
||||
sitemapUrl: "~~replace~~",
|
||||
a11yUrl: "~~replace~~",
|
||||
a11yLevel: "~~replace~~" as "non compliant",
|
||||
termsUrl: "~~replace~~",
|
||||
privacyUrl: "~~replace~~",
|
||||
}}
|
||||
>
|
||||
{codeData.homepageType ? homepageTypes[codeData.homepageType].Component : ""}
|
||||
</Homepage>
|
||||
)
|
||||
const markup = renderToStaticMarkup(Component)
|
||||
return prettier.format(markup, {
|
||||
parser: "html",
|
||||
plugins: [prettierHtml],
|
||||
printWidth: 100,
|
||||
tabWidth: 4,
|
||||
bracketSameLine: false,
|
||||
htmlWhitespaceSensitivity: "ignore",
|
||||
})
|
||||
}
|
||||
6
website/src/content/config.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { defineCollection } from "astro:content"
|
||||
import { docsSchema } from "@astrojs/starlight/schema"
|
||||
|
||||
export const collections = {
|
||||
docs: defineCollection({ schema: docsSchema() }),
|
||||
}
|
||||
103
website/src/content/docs/guides/gaufre.mdx
Normal file
@@ -0,0 +1,103 @@
|
||||
---
|
||||
title: La Gaufre
|
||||
sidebar:
|
||||
order: 30
|
||||
---
|
||||
|
||||
import { Aside } from "@astrojs/starlight/components"
|
||||
import assetGaufre from "./gaufre.png"
|
||||
import { Code } from "@astrojs/starlight/components"
|
||||
import gaufreHtml from "@gouvfr-lasuite/integration/dist/html/gaufre.html?raw"
|
||||
|
||||

|
||||
|
||||
Le bouton "Gaufre" est un élément d'interface commun à tous les services de La Suite numérique. Il
|
||||
permet aux internautes de facilement passer d'un service de La Suite à un autre.
|
||||
|
||||
Pour intégrer la Gaufre, il y a trois étapes :
|
||||
|
||||
- intégrer le HTML du bouton
|
||||
- ajouter le fichier CSS nécessaire
|
||||
- ajouter le fichier JS chargeant le widget au clic du bouton
|
||||
|
||||
:::note
|
||||
|
||||
Ce guide est à suivre pour intégrer la Gaufre sur toute page autre que
|
||||
[votre page d'accueil](../homepage). Le gabarit de page d'accueil inclut déjà le bouton.
|
||||
|
||||
:::
|
||||
|
||||
## Règles d'utilisation
|
||||
|
||||
Le bouton Gaufre est destiné à être présent dans le coin supérieur droit de la page de votre page
|
||||
web afin d'être toujours placé au même endroit quelque soit le service.
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. HTML
|
||||
|
||||
#### Avec React
|
||||
|
||||
Si vous utilisez React, utilisez le composant `Gaufre` fourni par le paquet :
|
||||
|
||||
```jsx
|
||||
import { Gaufre } from "@gouvfr-lasuite/integration"
|
||||
|
||||
function MonComposant() {
|
||||
return <Gaufre />
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
Même en utilisant React, vous devrez charger le CSS et le JS manuellement. Ce petit travail
|
||||
supplémentaire est fait pour vous donner plus de contrôle sur le chargement des assets suivant votre
|
||||
stack technique.
|
||||
|
||||
:::
|
||||
|
||||
#### Sans React
|
||||
|
||||
Si vous n'utilisez pas React, utilisez le HTML présent dans le paquet :
|
||||
|
||||
<Code code={gaufreHtml} lang="html" title="@gouvfr-lasuite/integration/dist/html/gaufre.html" />
|
||||
|
||||
### 2. CSS
|
||||
|
||||
Le CSS nécessaire est présent dans `@gouvfr-lasuite/integration/dist/css/gaufre.css`. Il est à
|
||||
inclure dans votre projet comme n'importe quel fichier CSS.
|
||||
|
||||
Suivant votre stack technique, vous pouvez peut-être inclure directement le CSS depuis les
|
||||
dépendances. Par exemple avec _vite_ :
|
||||
|
||||
<Code
|
||||
code={`@import "@gouvfr-lasuite/integration/dist/css/gaufre.css";`}
|
||||
lang="css"
|
||||
title="vos/styles/globaux/app.css"
|
||||
/>
|
||||
|
||||
Si vous n'utilisez pas de _bundler_ particulier et que avez plutôt décidé à l'installation de
|
||||
[copier les assets](/guides/getting-started/#gestion-des-assets), vous pouvez inclure le CSS
|
||||
directement via une balise `link` comme tout fichier CSS.
|
||||
|
||||
### 3. JS
|
||||
|
||||
Après avoir ajouté le bouton, il est nécessaire de le faire fonctionner. Pour ça, chargez ce fichier
|
||||
JS externe qui s'occupe d'afficher le widget au clic du bouton. Vous pouvez ajouter ce code dans
|
||||
votre `<head>` :
|
||||
|
||||
<Code
|
||||
code={`<script id="lasuite-gaufre-script" async defer src="${import.meta.env.PUBLIC_LASUITE_API_URL}/api/v1/gaufre.js"></script>`}
|
||||
lang="html"
|
||||
/>
|
||||
|
||||
:::note
|
||||
|
||||
Pour que le script fonctionne il est nécessaire qu'il ait un id `lasuite-gaufre-script`. Ne
|
||||
l'enlevez pas en copiant l'exemple !
|
||||
|
||||
:::
|
||||
|
||||
## Exemple
|
||||
|
||||
[La Gaufre : exemple HTML](/examples/gaufre/html).
|
||||
BIN
website/src/content/docs/guides/gaufre.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
103
website/src/content/docs/guides/getting-started.mdx
Normal file
@@ -0,0 +1,103 @@
|
||||
---
|
||||
title: Démarrer
|
||||
sidebar:
|
||||
order: 0
|
||||
---
|
||||
|
||||
import { Tabs, TabItem } from "@astrojs/starlight/components"
|
||||
|
||||
Utilisez les composants d'interface prêt-à-l'emploi pour votre service de La Suite numérique.
|
||||
|
||||
## Présentation
|
||||
|
||||
Nous mettons à disposition plusieurs composants.
|
||||
|
||||
### Gabarit de page d'accueil
|
||||
|
||||

|
||||
|
||||
Le gabarit de page d'accueil permet de rapidement intégrer dans le code de votre service une page
|
||||
d'accueil suivant un visuel commun avec tous les autres services de La Suite.
|
||||
|
||||
### _La Gaufre_, le bouton des services
|
||||
|
||||

|
||||
|
||||
Le bouton de La Suite numérique permet aux internautes de facilement passer d'un service de La Suite
|
||||
à un autre.
|
||||
|
||||
Tous ces éléments sont disponibles via :
|
||||
|
||||
- des gabarits HTML, utilisables au choix via des **composants React** ou directement via des
|
||||
**fichiers .html**,
|
||||
- **du CSS** nécessaire à afficher correctement les gabarits HTML,
|
||||
- et une **API web** exposant plusieurs _endpoints_.
|
||||
|
||||
## Installation
|
||||
|
||||
### Via NPM
|
||||
|
||||
Le plus simple pour accéder au code est d'installer le paquet npm avec votre gestionnaire de paquets
|
||||
préféré :
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="npm">
|
||||
|
||||
```sh
|
||||
npm install @gouvfr-lasuite/integration
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Yarn">
|
||||
|
||||
```sh
|
||||
yarn add @gouvfr-lasuite/integration
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="pnpm">
|
||||
|
||||
```sh
|
||||
pnpm add @gouvfr-lasuite/integration
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Manuellement
|
||||
|
||||
À la place d'utiliser npm, vous pouvez télécharger directement les fichiers depuis le dépôt sur
|
||||
GitHub :
|
||||
|
||||
@TODO
|
||||
|
||||
### Gestion des assets
|
||||
|
||||
Quand vous voudrez utiliser les assets fournis par le paquet, vous aurez peut-être besoin de copier
|
||||
les assets dans un dossier accessible par votre serveur web, suivant votre stack technique.
|
||||
|
||||
Tous les fichiers exposés par le paquet npm sont dans son dossier `dist/`.
|
||||
|
||||
Si vous utilisez déjà _webpack_, _vite_ ou alternative, vous pourrez importer les fichiers CSS
|
||||
directement depuis votre code comme tout autre CSS venant des dépendances. Par exemple avec _vite_ :
|
||||
|
||||
```js
|
||||
// dans un fichier JS :
|
||||
import '@gouvfr-lasuite/integration/dist/gaufre.css';
|
||||
// ou dans un fichier CSS :
|
||||
@import "@gouvfr-lasuite/integration/dist/gaufre.css";
|
||||
```
|
||||
|
||||
Si vous n'utilisez pas de bundler, une façon simple de rendre accessible le code du paquet est
|
||||
d'avoir un script qui copie pour vous les fichiers nécessaires dans un dossier accessible par votre
|
||||
serveur web. Par exemple, rajouter ceci dans votre `package.json` copiera les fichiers du paquet
|
||||
dans un dossier `public/@gouvfr-lasuite/integration` après chaque installation :
|
||||
|
||||
```diff lang="json"
|
||||
"scripts": {
|
||||
+ "copy-lasuite-assets": "cp -r node_modules/@gouvfr-lasuite/integration/dist/ public/@gouvfr-lasuite/integration",
|
||||
+ "postinstall": "npm run copy-lasuite-assets"
|
||||
}
|
||||
```
|
||||
|
||||
Une fois les fichiers installés, vous êtes prêt à utiliser les composants fournis par le paquet !
|
||||
29
website/src/content/docs/guides/homepage-generator.mdx
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Générateur de page d'accueil
|
||||
sidebar:
|
||||
order: 20
|
||||
---
|
||||
|
||||
import HomepageGenerator from "@/components/HomepageGenerator.tsx"
|
||||
|
||||
Après avoir [installé le JS et le CSS nécessaires de la page d'accueil](../homepage), vous pouvez
|
||||
utiliser ce formulaire pour générer facilement la partie HTML.
|
||||
|
||||
Séléctionnez votre service dans la liste pour automatiquement générer le template prévu. Vous pouvez
|
||||
aussi générer un template sans service pré-défini si besoin.
|
||||
|
||||
:::caution
|
||||
|
||||
Dans les exemples fournis, toutes les parties marquées <code>\~\~replace\~\~</code> sont à remplacer
|
||||
avec vos données !
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Le logo à afficher en entête peut être récupéré dans le dossier `dist/logos` du paquet npm si
|
||||
besoin.
|
||||
|
||||
:::
|
||||
|
||||
<HomepageGenerator client:load />
|
||||
159
website/src/content/docs/guides/homepage.mdx
Normal file
@@ -0,0 +1,159 @@
|
||||
---
|
||||
title: Gabarit de page d'accueil
|
||||
sidebar:
|
||||
order: 10
|
||||
---
|
||||
|
||||
import { Image } from "astro:assets"
|
||||
import { Code, Tabs, TabItem } from "@astrojs/starlight/components"
|
||||
import assetHomepage from "./homepage.png"
|
||||
import homepageHtml from "@gouvfr-lasuite/integration/dist/html/homepage.html?raw"
|
||||
|
||||
<p>
|
||||
<a href={assetHomepage.src} target="_blank">
|
||||
<Image
|
||||
src={assetHomepage}
|
||||
alt="Voir le gabarit de page d'accueil en grand (nouvelle fenêtre)"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
Le gabarit de page d'accueil vous permet de rapidement intégrer dans le code de votre service une
|
||||
page d'accueil suivant un visuel commun avec tous les autres services de La Suite.
|
||||
|
||||
## Règles d'utilisation
|
||||
|
||||
Le gabarit de page d'accueil est un guide à utiliser pour intégrer votre page d'accueil de service.
|
||||
Si pour des raisons techniques quelconques vous ne pouvez pas reprendre les templates proposés à la
|
||||
lettre, voici les points importants à retenir :
|
||||
|
||||
- la page d'accueil doit contenir [le bouton Gaufre](../gaufre) dans son coin supérieur droit,
|
||||
- elle doit présenter le nom de votre service à travers une phrase d'accroche suivant un minimum le
|
||||
visuel proposé,
|
||||
- elle doit permettre à l'utilisateur de se connecter à votre application,
|
||||
- elle doit afficher en fond de page
|
||||
[une des photos communes de La Suite](/reference/api#background)
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. CSS
|
||||
|
||||
Le gabarit se base sur une partie du [DSFR](https://www.systeme-de-design.gouv.fr/). Suivant que
|
||||
vous l'utilisiez déjà ou non dans votre projet, un fichier CSS différent est à charger.
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Vous n'utilisez pas le DSFR">
|
||||
Le fichier CSS à utiliser est :
|
||||
|
||||
```
|
||||
@gouvfr-lasuite/integration/dist/css/homepage-gaufre-dsfr.css
|
||||
```
|
||||
|
||||
Si durant l'installation vous avez décidé de
|
||||
[copier les assets](../getting-started/#gestion-des-assets), assurez-vous que la police de
|
||||
caractères Marianne a bien été copiée en suivant le chemin noté dans le CSS.
|
||||
|
||||
</TabItem>
|
||||
<TabItem label="Vous utilisez déjà le DSFR">
|
||||
Le fichier CSS à utiliser est :
|
||||
|
||||
```
|
||||
@gouvfr-lasuite/integration/dist/css/homepage-gaufre.css
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### 2. JS
|
||||
|
||||
Pour faire fonctionner le bouton Gaufre présent en haut à droite de la page, il est nécessaire de
|
||||
charger un fichier JS externe qui s'occupe d'afficher le widget au clic du bouton.
|
||||
|
||||
Vous pouvez ajouter ce code dans le `<head>` de votre page d'accueil uniquement, ou dans le `<head>`
|
||||
commun à toutes vos pages si vous décidez d'intégrer [La Gaufre](../gaufre) de façon globale sur
|
||||
votre site :
|
||||
|
||||
<Code
|
||||
code={`<script id="lasuite-gaufre-script" async defer src="${import.meta.env.PUBLIC_LASUITE_API_URL}/api/v1/gaufre.js"></script>`}
|
||||
lang="html"
|
||||
/>
|
||||
|
||||
:::note
|
||||
|
||||
Pour que le script fonctionne il est nécessaire qu'il ait un id `lasuite-gaufre-script`, ne
|
||||
l'enlevez pas !
|
||||
|
||||
:::
|
||||
|
||||
### 3. HTML
|
||||
|
||||
:::tip
|
||||
|
||||
Pour facilement générer le code nécessaire, utilisez
|
||||
[le générateur de gabarit de page d'accueil](../homepage-generator).
|
||||
|
||||
Sinon, suivez les conseils ci-dessous.
|
||||
|
||||
:::
|
||||
|
||||
#### Avec React
|
||||
|
||||
Si vous utilisez React, utilisez le composant `Homepage` fourni par le paquet. Il faut lui passer
|
||||
plusieurs _props_ pour adapter le contenu à votre service. Et lui passer en enfant le contenu à
|
||||
afficher dans la partie droite de la page d'accueil.
|
||||
|
||||
Plusieurs composants prêt-à-l'emploi sont disponibles pour vous aider à construire rapidement ce
|
||||
contenu :
|
||||
|
||||
- `HomepageEmail` affiche un bloc contenant un formulaire de connexion par e-mail,
|
||||
- `HomepageEmailOrProconnect` affiche un bloc contenant un formulaire de connexion par e-mail et un
|
||||
bouton Proconnect,
|
||||
- `HomepageProconnect` affiche un bloc contenant un bouton de connexion par Proconnect,
|
||||
|
||||
Tous les composants sont typés avec TypeScript avec des props commentées. En attendant une
|
||||
documentation plus complète, vous pouvez vous aider de l'autocomplétion de votre éditeur pour en
|
||||
savoir plus sur chaque composant.
|
||||
|
||||
##### Traduction
|
||||
|
||||
Si vous utilisez les composants React et que vous avez besoin de traduire votre page d'accueil,
|
||||
vous pouvez envelopper les composants avec le provider `LaSuiteTranslationsProvider` provenant du
|
||||
paquet, et lui passer en props vos `translations`. Les traductions françaises sont exportées en
|
||||
tant que `frTranslations`.
|
||||
|
||||
#### Sans React
|
||||
|
||||
Si vous n'utilisez pas React, utilisez le HTML présent dans
|
||||
`@gouvfr-lasuite/integration/dist/html/homepage.html` :
|
||||
|
||||
<details>
|
||||
<summary>Voir le code HTML</summary>
|
||||
<Code
|
||||
code={homepageHtml}
|
||||
lang="html"
|
||||
title="@gouvfr-lasuite/integration/dist/html/homepage.html"
|
||||
/>
|
||||
</details>
|
||||
|
||||
Remplacez le contenu de la div `.lasuite-homepage__form-inner` par le contenu propre à votre page
|
||||
d'accueil. Vous pouvez utiliser du HTML prêt à l'emploi pour construire rapidement ce contenu :
|
||||
|
||||
- `@gouvfr-lasuite/integration/dist/html/email.html` affiche un bloc contenant un formulaire de
|
||||
connexion par e-mail,
|
||||
- `@gouvfr-lasuite/integration/dist/html/email-or-proconnect.html` affiche un bloc contenant un
|
||||
formulaire de connexion par e-mail et un bouton Proconnect,
|
||||
- `@gouvfr-lasuite/integration/dist/html/proconnect.html` affiche un bloc contenant un bouton de
|
||||
connexion par Proconnect.
|
||||
|
||||
:::caution
|
||||
|
||||
Dans les gabarits HTML fournis, toutes les parties `~~replace~~` sont à remplacer avec vos données !
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Vous pouvez récupérer le logo de votre service au format svg dans le paquet npm :
|
||||
`@gouvfr-lasuite/integration/dist/logos`.
|
||||
|
||||
:::
|
||||
BIN
website/src/content/docs/guides/homepage.png
Normal file
|
After Width: | Height: | Size: 220 KiB |
18
website/src/content/docs/index.mdx
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
title: Intégrations de La Suite numérique
|
||||
description:
|
||||
Intégrez facilement les interfaces utilisateurs communes des services de La Suite numérique.
|
||||
template: splash
|
||||
hero:
|
||||
tagline:
|
||||
Intégrez facilement les interfaces utilisateurs communes des services de <a style="color:
|
||||
var(--sl-color-text-accent)" href="https://lasuite.numerique.gouv.fr">La Suite numérique</a>.
|
||||
image:
|
||||
file: ../../assets/lasuite-logo.svg
|
||||
alt: ""
|
||||
actions:
|
||||
- text: Commencer
|
||||
link: /guides/getting-started
|
||||
icon: right-arrow
|
||||
variant: primary
|
||||
---
|
||||
90
website/src/content/docs/reference/api.md
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
title: Endpoints de l'API web
|
||||
---
|
||||
|
||||
L'API d'intégration de La Suite expose plusieurs endpoints facilitant l'usage des UI communes.
|
||||
|
||||
## URL de l'API
|
||||
|
||||
```
|
||||
https://integration.lasuite.numerique.gouv.fr
|
||||
```
|
||||
|
||||
C'est par exemple l'URL à passer comme `lasuiteApiUrl` aux composants React.
|
||||
|
||||
## Fond d'écran de page d'accueil
|
||||
|
||||
```text "{id}" "{avif,jpg}"
|
||||
https://integration.lasuite.numerique.gouv.fr/api/backgrounds/v1/{id}.avif
|
||||
https://integration.lasuite.numerique.gouv.fr/api/backgrounds/v1/{id}.jpg
|
||||
```
|
||||
|
||||
- Méthode : GET
|
||||
- Retourne : une image en AVIF ou JPG en 1920x1080
|
||||
- Passer l'[id d'un service](#liste-des-services-de-la-suite) à la place de `{id}`.
|
||||
💡 Si votre service n'est pas (encore) supporté, vous pouvez utiliser l'id `default`.
|
||||
|
||||
Les photos d'arrière-plan de chaque page d'accueil de service changent plusieurs fois par mois à
|
||||
travers tous les services.
|
||||
|
||||
Pour que ce changement se fasse sans avoir à mettre à jour le code des pages d'accueil
|
||||
régulièrement, un service peut requêter une photo d'arrière-plan avec son identifiant. L'image
|
||||
exposée sur cette URL change régulièrement.
|
||||
|
||||
Les photos sont disponibles à la fois en avif et en jpeg.
|
||||
|
||||
### Exemple d'usage
|
||||
|
||||
Avec le service Resana :
|
||||
|
||||
```html
|
||||
<picture>
|
||||
<source
|
||||
srcset="https://integration.lasuite.numerique.gouv.fr/api/backgrounds/v1/resana.avif"
|
||||
type="image/avif"
|
||||
/>
|
||||
<img
|
||||
src="https://integration.lasuite.numerique.gouv.fr/api/backgrounds/v1/resana.jpg"
|
||||
alt=""
|
||||
width="1920"
|
||||
height="1080"
|
||||
/>
|
||||
</picture>
|
||||
```
|
||||
|
||||
<picture>
|
||||
<source
|
||||
srcset="https://integration.lasuite.numerique.gouv.fr/api/backgrounds/v1/resana.avif"
|
||||
type="image/avif"
|
||||
/>
|
||||
<img
|
||||
src="https://integration.lasuite.numerique.gouv.fr/api/backgrounds/v1/resana.jpg"
|
||||
alt=""
|
||||
width="1920"
|
||||
height="1080"
|
||||
/>
|
||||
</picture>
|
||||
|
||||
## Widget La Gaufre
|
||||
|
||||
```
|
||||
https://integration.lasuite.numerique.gouv.fr/api/v1/gaufre.js
|
||||
```
|
||||
|
||||
- Méthode : GET
|
||||
- Retourne : le JavaScript s'occupant d'afficher la popup listant les services de La Suite au clic
|
||||
sur le bouton [Gaufre](/guides/gaufre)
|
||||
|
||||
## Liste des services de La Suite
|
||||
|
||||
`https://integration.lasuite.numerique.gouv.fr/api/v1/services.json`
|
||||
|
||||
Retourne un tableau JSON listant les services de La Suite numérique. Chaque service a cette
|
||||
structure :
|
||||
|
||||
- `id` l'identifiant du service, utilisé par d'autres APIs,
|
||||
- `name` le nom du service,
|
||||
- `url` l'url de la page d'accueil du service.
|
||||
|
||||
Ce endpoint sert principalement à retrouver l'`id` correspondant à un service et est là plutôt à
|
||||
titre informatif.
|
||||
42
website/src/data/services.json
Normal file
@@ -0,0 +1,42 @@
|
||||
[
|
||||
{
|
||||
"id": "equipes",
|
||||
"name": "Equipes",
|
||||
"url": "https://desk-staging.beta.numerique.gouv.fr/",
|
||||
"tagline": "**Equipes**, la gestion de groupes <br>centralisée pour tous vos projets",
|
||||
"homepageType": "proconnect",
|
||||
"entity": "Gouvernement"
|
||||
},
|
||||
{
|
||||
"id": "france-transfert",
|
||||
"name": "France Transfert",
|
||||
"url": "https://francetransfert.numerique.gouv.fr/upload",
|
||||
"tagline": "**France Transfert** permet d’envoyer des fichiers <br>volumineux non sensibles de manière sécurisée <br>à un agent de l’Etat ou entre agents",
|
||||
"homepageType": "custom",
|
||||
"entity": "Gouvernement"
|
||||
},
|
||||
{
|
||||
"id": "messagerie",
|
||||
"name": "Messagerie",
|
||||
"url": "https://webmail.numerique.gouv.fr/appsuite/",
|
||||
"tagline": "**Messagerie** de l'État <br>le mail simple, centralisé et sécurisé",
|
||||
"homepageType": "email",
|
||||
"entity": "Gouvernement"
|
||||
},
|
||||
{
|
||||
"id": "resana",
|
||||
"name": "Resana",
|
||||
"url": "https://resana.numerique.gouv.fr/public/",
|
||||
"tagline": "**Resana** <br>groupes de travail <br>et suite collaborative en ligne",
|
||||
"homepageType": "email-or-proconnect",
|
||||
"entity": "Gouvernement"
|
||||
},
|
||||
{
|
||||
"id": "tchap",
|
||||
"name": "Tchap",
|
||||
"url": "https://www.tchap.gouv.fr/",
|
||||
"tagline": "**Tchap** <br>la messagerie <br>instantanée du Secteur Public",
|
||||
"homepageType": "email",
|
||||
"entity": "Gouvernement"
|
||||
}
|
||||
]
|
||||
9
website/src/env.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
||||
interface ImportMetaEnv {
|
||||
readonly PUBLIC_LASUITE_API_URL: string
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
218
website/src/pages/api/v1/gaufre.astro
Normal file
@@ -0,0 +1,218 @@
|
||||
---
|
||||
import services from "@/data/services.json"
|
||||
import { Image } from "astro:assets"
|
||||
const logos = import.meta.glob<{ default: ImageMetadata }>("/src/assets/logos/*.svg")
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Services de La Suite numérique</title>
|
||||
<style is:inline>
|
||||
@font-face {
|
||||
font-family: Marianne;
|
||||
src: url("/fonts/Marianne-Regular-subset.woff2") format("woff2");
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Marianne fallback";
|
||||
src: local("Arial");
|
||||
ascent-override: 103.16%;
|
||||
descent-override: 23.35%;
|
||||
line-gap-override: 0%;
|
||||
size-adjust: 109.64%;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
.lasuite-Services {
|
||||
height: 100vh;
|
||||
max-height: 22rem;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 100%;
|
||||
font-family: Marianne, "Marianne fallback", BlinkMacSystemFont, "Segoe UI", "Noto Sans",
|
||||
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0 0 0.5rem;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.fr-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap; /* added line */
|
||||
border: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.fr-enlarge-link {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fr-enlarge-link a {
|
||||
background-image: none;
|
||||
outline-width: 0;
|
||||
}
|
||||
|
||||
.fr-enlarge-link a::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
outline-offset: 2px;
|
||||
outline-style: inherit;
|
||||
outline-color: inherit;
|
||||
outline-width: 2px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.lasuite-Services {
|
||||
background-color: #01018fcc;
|
||||
padding: 3px;
|
||||
width: 19rem;
|
||||
border-radius: 8px;
|
||||
filter: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.lasuite-Services-outer {
|
||||
height: 100%;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.lasuite-Services-inner {
|
||||
border-radius: 2px;
|
||||
background-color: white;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.lasuite-Service {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1rem 2rem;
|
||||
border-top: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
.lasuite-Service:hover,
|
||||
.lasuite-Service:focus-within {
|
||||
background-color: #f0f0fa;
|
||||
border-top: 1px solid #8989cd;
|
||||
border-bottom: 1px solid #8989cd;
|
||||
}
|
||||
|
||||
.lasuite-Service-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.lasuite-Service-name {
|
||||
margin-left: 1.5rem;
|
||||
text-decoration: none;
|
||||
color: #161616;
|
||||
}
|
||||
|
||||
.lasuite-Service-name:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.scrollbars {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #aaa transparent;
|
||||
}
|
||||
.scrollbars::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
.scrollbars::-webkit-scrollbar-track {
|
||||
background: 0 0;
|
||||
}
|
||||
.scrollbars::-webkit-scrollbar-thumb {
|
||||
background-color: #ddd;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.scrollbars:not(:hover, :focus) {
|
||||
scrollbar-color: transparent transparent;
|
||||
}
|
||||
.scrollbars:not(:hover, :focus):-webkit-scrollbar-thumb {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#lasuite-service-suite-numerique {
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="lasuite-Services">
|
||||
<div class="lasuite-Services-outer">
|
||||
<h1 class="fr-sr-only">Liste des services de La Suite numérique</h1>
|
||||
<ul class="lasuite-Services-inner scrollbars">
|
||||
{
|
||||
services.map(({ id, name, url }, i) => (
|
||||
<li>
|
||||
<div class="lasuite-Services-item lasuite-Service fr-enlarge-link">
|
||||
<div class="lasuite-Service-icon">
|
||||
<Image
|
||||
src={logos[`/src/assets/logos/${id}.svg`]()}
|
||||
width="40"
|
||||
height="40"
|
||||
alt=""
|
||||
loading="eager"
|
||||
/>
|
||||
</div>
|
||||
<a
|
||||
target="_parent"
|
||||
class="lasuite-Service-name"
|
||||
href={url}
|
||||
id={`lasuite-service-${id}`}
|
||||
{...((i === 0 && { autofocus: true }) || {})}
|
||||
>
|
||||
{name}
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener("keyup", (event) => {
|
||||
if (event.key === "Escape") {
|
||||
window.parent.postMessage("lasuite-close-services-iframe", "*")
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
16
website/src/pages/api/v1/services.json.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { APIContext } from "astro"
|
||||
import services from "@/data/services.json"
|
||||
|
||||
export async function GET({ url }: APIContext) {
|
||||
const response = new Response(
|
||||
JSON.stringify(
|
||||
services.map((service) => ({
|
||||
id: service.id,
|
||||
name: service.name,
|
||||
url: new URL(`/services/${service.id}`, url).toString(),
|
||||
})),
|
||||
),
|
||||
)
|
||||
response.headers.set("Content-Type", "application/json")
|
||||
return response
|
||||
}
|
||||
94
website/src/pages/examples/gaufre/html.astro
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
import gaufreCssUrl from "@gouvfr-lasuite/integration/dist/css/gaufre.css?url"
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Exemple intégration bouton La Gaufre - La Suite numérique</title>
|
||||
<style is:inline>
|
||||
.wrapper {
|
||||
margin: 2rem auto;
|
||||
font-family: sans-serif;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
}
|
||||
.example {
|
||||
margin: 2rem auto;
|
||||
border: 1px solid #999;
|
||||
padding: 2rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
.example > div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.example > div > h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
.example > p {
|
||||
margin-top: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- code à ajouter pour faire marcher le bouton Gaufre -->
|
||||
<!-- ce fichier buildé correspond à @gouvfr-lasuite/integration/dist/css/gaufre.css -->
|
||||
<link rel="stylesheet" href={gaufreCssUrl} />
|
||||
<script
|
||||
is:inline
|
||||
id="lasuite-gaufre-script"
|
||||
async
|
||||
defer
|
||||
src={`${import.meta.env.PUBLIC_LASUITE_API_URL}/api/v1/gaufre.js`}></script>
|
||||
<!-- fin du code à ajouter -->
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<p><a href="/guides/gaufre">Retour à la documentation</a></p>
|
||||
<div class="example">
|
||||
<div>
|
||||
<h1>Test de la Gaufre</h1>
|
||||
|
||||
<!-- code à copier pour faire marcher le bouton Gaufre -->
|
||||
<button
|
||||
type="button"
|
||||
class="lasuite-gaufre-btn lasuite-gaufre-btn--vanilla js-lasuite-gaufre-btn"
|
||||
title="Les services de La Suite numérique"
|
||||
>
|
||||
Les services de La Suite numérique
|
||||
</button>
|
||||
<!-- fin du code à copier -->
|
||||
</div>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac diam a libero posuere
|
||||
ornare facilisis in mi. Nullam eu vulputate augue, in auctor nibh. Praesent ac tempus dui.
|
||||
Integer vel enim non purus facilisis mattis et vel dolor. Aliquam lacinia elit et massa
|
||||
faucibus, at dictum risus ornare. Vivamus ultricies magna et gravida consequat. Donec ac
|
||||
odio finibus, lobortis purus vel, consequat purus. Maecenas convallis vel enim eu
|
||||
malesuada. Vestibulum elementum maximus massa, a porta erat congue quis. Nunc neque quam,
|
||||
euismod et malesuada in, bibendum ac ex. Phasellus felis elit, egestas a convallis nec,
|
||||
malesuada a est. Donec ac urna venenatis lorem aliquet rhoncus in accumsan ipsum.
|
||||
</p>
|
||||
<p>
|
||||
Interdum et malesuada fames ac ante ipsum primis in faucibus. Morbi sed augue elementum,
|
||||
tempus diam in, euismod purus. Fusce interdum, leo nec blandit eleifend, sapien ligula
|
||||
egestas quam, quis aliquam ex turpis ut augue. Nullam a neque consectetur, feugiat eros a,
|
||||
lacinia tortor. Proin imperdiet vehicula justo, eget bibendum tortor gravida a.
|
||||
Pellentesque sit amet fermentum urna. Ut rutrum eros a ligula dapibus pharetra. In
|
||||
porttitor arcu in euismod dictum. Aenean vestibulum mi et dignissim rutrum. Phasellus
|
||||
ultrices ex justo, eu tincidunt metus efficitur non. Curabitur ac lorem ornare, aliquet
|
||||
neque et, tristique elit. Donec quis turpis sodales, interdum massa fermentum, dictum
|
||||
magna.
|
||||
</p>
|
||||
<p>
|
||||
Mauris elit risus, facilisis at magna quis, interdum tempor nulla. Ut ac erat eget tellus
|
||||
ultricies semper. Ut at dictum ante. Lorem ipsum dolor sit amet, consectetur adipiscing
|
||||
elit. Nam placerat lacinia eros ac convallis. Sed ultricies lectus et pharetra aliquet.
|
||||
Vestibulum feugiat pulvinar fermentum. Vivamus imperdiet dapibus ornare. Donec venenatis,
|
||||
lectus id faucibus tempus, sapien urna molestie augue, at egestas enim lectus quis nisi.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
129
website/src/styles/global.css
Normal file
@@ -0,0 +1,129 @@
|
||||
@import "./prism.css";
|
||||
|
||||
@font-face {
|
||||
font-family: Marianne;
|
||||
src: url(../assets/fonts/Marianne-Regular.woff2) format("woff2");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Marianne;
|
||||
src: url(../assets/fonts/Marianne-Medium.woff2) format("woff2");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Marianne;
|
||||
src: url(../assets/fonts/Marianne-Bold.woff2) format("woff2");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Marianne_cls_fallback;
|
||||
src: local("Arial");
|
||||
ascent-override: 103.16%;
|
||||
descent-override: 23.35%;
|
||||
line-gap-override: 0%;
|
||||
size-adjust: 109.64%;
|
||||
}
|
||||
|
||||
:root {
|
||||
--sl-font: "Marianne", "Marianne_cls_fallback", ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--sl-text-code-sm: var(--sl-text-code);
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
/* Light mode colors. */
|
||||
:root[data-theme="light"] {
|
||||
--sl-color-accent-low: #e3e3fd;
|
||||
--sl-color-accent: #000091;
|
||||
--sl-color-accent-high: #8585f6;
|
||||
--sl-color-white: #17181c;
|
||||
--sl-color-gray-1: #24272f;
|
||||
--sl-color-gray-2: #353841;
|
||||
--sl-color-gray-3: #545861;
|
||||
--sl-color-gray-4: #888b96;
|
||||
--sl-color-gray-5: #c0c2c7;
|
||||
--sl-color-gray-6: #edeef3;
|
||||
--sl-color-gray-7: #f5f6f8;
|
||||
--sl-color-black: #ffffff;
|
||||
--sl-color-blue-low: #ececfe;
|
||||
--sl-color-blue-middle: #cacafb;
|
||||
--sl-color-blue: #000091;
|
||||
--sl-color-bg-inline-code: var(--sl-color-blue-low);
|
||||
}
|
||||
|
||||
.action {
|
||||
border-radius: 0;
|
||||
font-weight: 500;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
.sl-markdown-content :is(h1, h2, h3, h4, h5, h6) > a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sl-markdown-content :is(h1, h2, h3, h4, h5, h6) > a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.starlight-aside--note {
|
||||
border-top: 1px solid var(--sl-color-blue-middle, var(--sl-color-blue));
|
||||
border-bottom: 1px solid var(--sl-color-blue-middle, var(--sl-color-blue));
|
||||
border-right: 1px solid var(--sl-color-blue-middle, var(--sl-color-blue));
|
||||
}
|
||||
|
||||
.sl-markdown-content p img {
|
||||
display: block;
|
||||
margin: auto;
|
||||
box-shadow: var(--sl-shadow-sm);
|
||||
border: 1px solid var(--sl-color-gray-5);
|
||||
}
|
||||
|
||||
.react-form label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.react-form label span {
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.75;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.react-form-input {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.react-form :is(input, select) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sl-markdown-content :is(h1, h2, h3, h4, h5, h6):target {
|
||||
background-color: #fef7da;
|
||||
}
|
||||
|
||||
.react-code {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.react-code button {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
background-color: var(--sl-color-bg);
|
||||
color: var(--sl-color-text);
|
||||
margin: 0 !important;
|
||||
right: 20px;
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
158
website/src/styles/prism.css
Normal file
@@ -0,0 +1,158 @@
|
||||
:root {
|
||||
--prism-color: #c9d1d9;
|
||||
--prism-bg: #24292e;
|
||||
--prism-inline-bg: #343942;
|
||||
--prism-selection: #234879;
|
||||
--prism-highlight-bg: #2f2a1e;
|
||||
--prism-highlight-shadow: #674c16;
|
||||
--prism-token-comment: #8b949e;
|
||||
--prism-token-punctuation: #c9d1d9;
|
||||
--prism-token-tag: #79c0ff;
|
||||
--prism-token-string: #a5d6ff;
|
||||
--prism-token-operator: #a5d6ff;
|
||||
--prism-token-keyword: #a5d6ff;
|
||||
--prism-token-function: #d2a8ff;
|
||||
--prism-token-regex: #a8daff;
|
||||
}
|
||||
|
||||
:root[data-theme="light"] {
|
||||
--prism-selection: #9fc6e9;
|
||||
--prism-color: #24292f;
|
||||
--prism-bg: #f5f5fe;
|
||||
--prism-inline-bg: #eff1f3;
|
||||
--prism-highlight-bg: #fff8c5;
|
||||
--prism-highlight-shadow: #eed888;
|
||||
--prism-token-comment: #6e7781;
|
||||
--prism-token-punctuation: #24292f;
|
||||
--prism-token-tag: #0550ae;
|
||||
--prism-token-string: #0a3069;
|
||||
--prism-token-operator: #0550ae;
|
||||
--prism-token-keyword: #cf222e;
|
||||
--prism-token-function: #8250df;
|
||||
--prism-token-regex: #0a3069;
|
||||
}
|
||||
|
||||
.expressive-code .frame pre {
|
||||
background-color: var(--prism-bg) !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Github Light/Dark theme for Prism.js
|
||||
* Based on Github: https://github.com
|
||||
* @author Katorly
|
||||
*/
|
||||
pre[class*="language-"],
|
||||
code[class*="language-"] {
|
||||
color: var(--prism-color);
|
||||
box-shadow: rgba(0, 0, 0, 0.157) 1.8px 1.8px 3.6px 0px;
|
||||
border: 1px solid rgb(225, 228, 232);
|
||||
}
|
||||
pre[class*="language-"]::selection,
|
||||
code[class*="language-"]::selection,
|
||||
pre[class*="language-"]::mozselection,
|
||||
code[class*="language-"]::mozselection {
|
||||
text-shadow: none;
|
||||
background: var(--prism-selection);
|
||||
}
|
||||
@media print {
|
||||
pre[class*="language-"],
|
||||
code[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
overflow: auto;
|
||||
background: var(--prism-bg);
|
||||
}
|
||||
.language-fixedheight pre[class*="language-"] {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: 0.1em 0.3em;
|
||||
border-radius: 0.3em;
|
||||
color: #24292f;
|
||||
background: var(--prism-inline-bg);
|
||||
}
|
||||
/* Line highlighting */
|
||||
pre[data-line] {
|
||||
position: relative;
|
||||
}
|
||||
pre[class*="language-"] > code[class*="language-"] {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.line-highlight {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: inherit 0;
|
||||
margin-top: 1em;
|
||||
background: var(--prism-highlight-bg);
|
||||
box-shadow: inset 5px 0 0 var(--prism-highlight-shadow);
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
line-height: inherit;
|
||||
white-space: pre;
|
||||
}
|
||||
/* Tokens */
|
||||
.namespace {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: var(--prism-token-comment);
|
||||
}
|
||||
.token.punctuation {
|
||||
color: var(--prism-token-punctuation);
|
||||
}
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: var(--prism-token-tag);
|
||||
}
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: var(--prism-token-string);
|
||||
}
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: var(--prism-token-operator);
|
||||
}
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: var(--prism-token-keyword);
|
||||
}
|
||||
.token.function {
|
||||
color: var(--prism-token-function);
|
||||
}
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: var(--prism-token-regex);
|
||||
}
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||