+ Nous sommes aujourd'hui le +
+ +—
+—
+—
+ Année sextile ++ Équivalent grégorien : + — +
+diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ee7c078 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +npm-debug.log* +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9800329 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM node:20-alpine + +WORKDIR /app + +COPY package.json package-lock.json* ./ +RUN npm install --omit=dev + +COPY server.js ./ +COPY src ./src +COPY public ./public +COPY locales ./locales + +ENV PORT=3000 +EXPOSE 3000 + +CMD ["node", "server.js"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..eb77ad5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +services: + calendrier-republicain: + build: + context: . + dockerfile: Dockerfile + container_name: calendrier-republicain + ports: + - "3000:3000" + environment: + - PORT=3000 + restart: unless-stopped diff --git a/locales/en/about.json b/locales/en/about.json new file mode 100644 index 0000000..70579e8 --- /dev/null +++ b/locales/en/about.json @@ -0,0 +1,74 @@ +{ + "history": { + "title": "History of the Republican calendar", + "sections": [ + { + "heading": "A revolutionary creation", + "paragraphs": [ + "The French Republican calendar was created by the National Convention during the French Revolution. It came into force on 15 Vendémiaire, Year II (6 October 1793), with a retroactive start date of 1 Vendémiaire, Year I — 22 September 1792, the day after the abolition of the monarchy, proclaimed the first day of the \"era of the French\".", + "Like the metric system, the calendar grew out of the revolutionaries' wish to base the measurement of time on the decimal system and to replace the Gregorian calendar, associated with Christianity and the Ancien Régime.", + "The year was split into twelve thirty-day months, grouped into three ten-day décades, replacing the seven-day week and its Sunday with a ten-day rest cycle. Five complementary days (six in sextile years) closed out the year outside of any month." + ] + }, + { + "heading": "The Romme commission and Fabre d'Églantine", + "paragraphs": [ + "Tasked by the Convention with reforming the calendar, deputy Gilbert Romme worked with several members of the Academy of Sciences (Lagrange, Monge, Lalande, Pingré...). His report, presented on 20 September 1793, laid out the calendar's core principles: a year anchored to the autumnal equinox, a decimal division of time, and twelve thirty-day months.", + "The poetic month names — Vendémiaire, Brumaire, Frimaire, Nivôse, Pluviôse, Ventôse, Germinal, Floréal, Prairial, Messidor, Thermidor, Fructidor — were coined by the poet and deputy Fabre d'Églantine and approved by the Convention on 24 October 1793. Each day was further associated with an agricultural product or a farming tool." + ] + }, + { + "heading": "A short but memorable life", + "paragraphs": [ + "The Republican calendar remained in force for just over twelve years, until it was abolished by Napoleon I effective 1 January 1806, for practical as much as political and religious reasons.", + "It was briefly revived by the Paris Commune in 1871, and left a lasting mark on the French language through several given names (Nivôse, Floréal...) and the expression \"sans-culotte\"." + ] + } + ] + }, + "leapYears": { + "title": "Sextile years", + "sections": [ + { + "heading": "A contradiction in the founding decree", + "paragraphs": [ + "The decree of 4 Frimaire, Year II (24 November 1793) set two hard-to-reconcile rules: the year begins on the day of the true autumnal equinox at the Paris Observatory (Article III), and a sextile year — the Republican equivalent of a leap year — is inserted every four years (Article X).", + "In reality, the interval between two successive equinoxes is not perfectly constant. During the calendar's actual period of use (Year I to Year XIV), sextile years did fall every four years (Year III, Year VII, Year XI), but astronomers already knew this regularity would not hold indefinitely." + ] + }, + { + "heading": "Romme's reform proposal", + "paragraphs": [ + "On 19 Floréal, Year III (8 May 1795), Romme proposed to settle the contradiction by dropping the reference to the observed equinox in favour of a predictable, perpetual arithmetic rule: a sextile year every four years (the first being Year IV), except centennial years — which stay common unless their number is divisible by 400 — with the exception of the fortieth century, which remains common.", + "This rule closely mirrors the Gregorian leap-year rule, simply shifted by one year. Romme was arrested shortly afterwards and took his own life in prison, so his reform was never officially adopted — but it remains the reference for any perpetual Republican calendar, and it is the one used by this converter." + ] + }, + { + "heading": "The rule used here", + "paragraphs": [ + "A Republican year is therefore sextile (366 days) if its number is divisible by 4, unless it is divisible by 100 without being divisible by 400, and unless it is divisible by 4000. Every other year has 365 days, split into twelve thirty-day months plus five complementary days." + ] + } + ] + }, + "complementaryDays": { + "title": "The complementary days", + "sections": [ + { + "heading": "Closing out the year", + "paragraphs": [ + "Twelve thirty-day months only add up to 360 days: five more days are needed to complete a tropical year, six in sextile years. These days, first called \"épagomènes\" and then \"sans-culottides\" by the decree of 4 Frimaire, Year II, were renamed \"complementary days\" by the decree of 7 Fructidor, Year III (24 August 1795).", + "Sitting outside any month or décade, they carry no décadi name and were devoted to public rejoicing and festivities marking the end of the Republican year, roughly between 17 and 22 September on the Gregorian calendar." + ] + }, + { + "heading": "The five (or six) days", + "paragraphs": [ + "The Day of Virtue, the Day of Genius, the Day of Labour, the Day of Opinion and the Day of Rewards make up the five complementary days of every Republican year.", + "In sextile years — every four years under Romme's perpetual rule — a sixth day is added, the Day of the Revolution, devoted to national games in memory of the Republic's founding.", + "The four-year span between two sextile years is called a \"Franciade\", echoing the Olympiads of ancient Greece." + ] + } + ] + } +} diff --git a/locales/en/common.json b/locales/en/common.json new file mode 100644 index 0000000..233c805 --- /dev/null +++ b/locales/en/common.json @@ -0,0 +1,48 @@ +{ + "site": { + "title": "Republican Calendar", + "tagline": "Perpetual converter" + }, + "nav": { + "menuLabel": "Menu", + "home": "Home", + "about": "About", + "aboutHistory": "History of the calendar", + "aboutLeapYears": "Sextile years", + "aboutComplementaryDays": "The complementary days", + "language": "Language" + }, + "home": { + "todayHeading": "Today is", + "resultHeading": "Converted date", + "gregorianEquivalent": "Gregorian equivalent", + "sextileBadge": "Sextile year", + "decadeLabel": "Décade", + "dayOfYearLabel": "Day of the year", + "yearLabel": "Year" + }, + "form": { + "title": "Convert another date", + "dateLabel": "Gregorian date (DD/MM/YYYY)", + "submit": "Convert", + "todayButton": "Back to today", + "helpText": "Pick a day, month and year: the form checks automatically that the date actually exists.", + "errorInvalid": "This date does not exist in the Gregorian calendar.", + "errorBeforeEpoch": "The Republican calendar starts on 22 September 1792 (1 Vendémiaire, Year I). Please choose a later date.", + "errorGeneric": "Something went wrong while converting this date." + }, + "weekdays": { + "monday": "Monday", + "tuesday": "Tuesday", + "wednesday": "Wednesday", + "thursday": "Thursday", + "friday": "Friday", + "saturday": "Saturday", + "sunday": "Sunday" + }, + "footer": { + "text": "Dates computed with the perpetual arithmetic rule proposed by Gilbert Romme (19 Floréal, Year III / 8 May 1795).", + "sourceNote": "Historical content adapted from the \"French Republican calendar\" reference article." + }, + "loading": "Loading…" +} diff --git a/locales/en/months.json b/locales/en/months.json new file mode 100644 index 0000000..dd6d5af --- /dev/null +++ b/locales/en/months.json @@ -0,0 +1,135 @@ +{ + "seasonSuffix": { + "autumn": "Ending in \"-aire\" (from Latin -arius)", + "winter": "Ending in \"-ôse\" (from Latin -osus, \"endowed with\")", + "spring": "Ending in \"-al\" (from Latin -alis)", + "summer": "Ending in \"-idor\" (from Greek dôron, \"gift\")" + }, + "months": { + "vendemiaire": { + "name": "Vendémiaire", + "season": "autumn", + "period": "22/23/24 September – 21/22/23 October", + "etymology": "From Latin vindemia, \"grape harvest\".", + "description": "The first month of the Republican year opens autumn and starts on equinox day. Fabre d'Églantine named it after the grape harvest that closes the work of the vineyard." + }, + "brumaire": { + "name": "Brumaire", + "season": "autumn", + "period": "22/23/24 October – 20/21/22 November", + "etymology": "From Latin bruma, \"fog, mist\".", + "description": "The month of the mists and fog that blanket the countryside between October and November." + }, + "frimaire": { + "name": "Frimaire", + "season": "autumn", + "period": "21/22/23 November – 20/21/22 December", + "etymology": "From the French word \"frimas\", the damp cold of late autumn.", + "description": "The last month of autumn, marked by the first frosts, alternately dry and humid, heralding winter." + }, + "nivose": { + "name": "Nivôse", + "season": "winter", + "period": "21/22/23 December – 19/20/21 January", + "etymology": "From Latin nix, nivis, \"snow\".", + "description": "The first month of winter, named for the snow that whitens the ground between December and January." + }, + "pluviose": { + "name": "Pluviôse", + "season": "winter", + "period": "20/21/22 January – 18/19/20 February", + "etymology": "From Latin pluvia, \"rain\".", + "description": "The month of abundant rainfall typically falling between January and February." + }, + "ventose": { + "name": "Ventôse", + "season": "winter", + "period": "19/20/21 February – 20/21 March", + "etymology": "From Latin ventosus, \"windy\".", + "description": "The last month of winter, that of squalls and drying winds between February and March." + }, + "germinal": { + "name": "Germinal", + "season": "spring", + "period": "21/22 March – 19/20 April", + "etymology": "From Latin germen, \"sprout, germ\".", + "description": "The first month of spring, that of budding and rising sap between March and April." + }, + "floreal": { + "name": "Floréal", + "season": "spring", + "period": "20/21 April – 19/20 May", + "etymology": "From Latin flos, floris, \"flower\".", + "description": "The month when flowers bloom, between April and May." + }, + "prairial": { + "name": "Prairial", + "season": "spring", + "period": "20/21 May – 18/19 June", + "etymology": "From the French word \"prairie\", meadow.", + "description": "The last month of spring, that of cheerful abundance and the meadow harvest between May and June." + }, + "messidor": { + "name": "Messidor", + "season": "summer", + "period": "19/20 June – 18/19 July", + "etymology": "From Latin messis, \"harvest\", and Greek dôron, \"gift\".", + "description": "The first month of summer, that of rippling ears of wheat and golden harvests between June and July." + }, + "thermidor": { + "name": "Thermidor", + "season": "summer", + "period": "19/20 July – 17/18 August", + "etymology": "From Greek thermos, \"heat\", and dôron, \"gift\".", + "description": "The month of heat, both solar and terrestrial, that sets the air ablaze between July and August." + }, + "fructidor": { + "name": "Fructidor", + "season": "summer", + "period": "18/19 August – 16/17 September", + "etymology": "From Latin fructus, \"fruit\", and Greek dôron, \"gift\".", + "description": "The last month of the year, that of the fruit ripened golden by the sun between August and September." + } + }, + "decadeDays": { + "primidi": "Primidi", + "duodi": "Duodi", + "tridi": "Tridi", + "quartidi": "Quartidi", + "quintidi": "Quintidi", + "sextidi": "Sextidi", + "septidi": "Septidi", + "octidi": "Octidi", + "nonidi": "Nonidi", + "decadi": "Décadi" + }, + "complementaryDays": { + "title": "Complementary days (sans-culottides)", + "days": { + "virtue": { + "name": "Day of Virtue", + "description": "First complementary day, dedicated to civic virtue." + }, + "genius": { + "name": "Day of Genius", + "description": "Second complementary day, celebrating genius and inventiveness." + }, + "labour": { + "name": "Day of Labour", + "description": "Third complementary day, honouring work." + }, + "opinion": { + "name": "Day of Opinion", + "description": "Fourth complementary day, devoted to freedom of opinion." + }, + "rewards": { + "name": "Day of Rewards", + "description": "Fifth complementary day, dedicated to public rewards." + }, + "revolution": { + "name": "Day of the Revolution", + "description": "Sixth complementary day, added only in sextile years, commemorating the Revolution with national games." + } + } + } +} diff --git a/locales/fr/about.json b/locales/fr/about.json new file mode 100644 index 0000000..85cd31c --- /dev/null +++ b/locales/fr/about.json @@ -0,0 +1,74 @@ +{ + "history": { + "title": "Histoire du calendrier républicain", + "sections": [ + { + "heading": "Une création révolutionnaire", + "paragraphs": [ + "Le calendrier républicain, ou calendrier révolutionnaire français, est créé par la Convention nationale au cours de la Révolution française. Il entre en vigueur le 15 vendémiaire an II (6 octobre 1793), avec pour date initiale rétroactive le 1er vendémiaire an I, soit le 22 septembre 1792 — lendemain de l'abolition de la monarchie, proclamé premier jour de l'« ère des Français ».", + "Comme le système métrique, ce calendrier procède de la volonté des révolutionnaires de fonder la mesure du temps sur le système décimal et de remplacer le calendrier grégorien, associé au christianisme et à l'Ancien Régime.", + "L'année y est découpée en douze mois de trente jours, regroupés en trois décades de dix jours chacune, remplaçant ainsi la semaine de sept jours et son dimanche par un jour de repos décadaire. Cinq jours complémentaires (six les années sextiles) closent l'année en dehors des mois." + ] + }, + { + "heading": "La commission Romme et Fabre d'Églantine", + "paragraphs": [ + "Chargé par la Convention d'étudier la réforme du calendrier, le député Gilbert Romme s'entoure de plusieurs membres de l'Académie des sciences (Lagrange, Monge, Lalande, Pingré...). Son rapport, présenté le 20 septembre 1793, pose les grands principes du nouveau calendrier : une année calée sur l'équinoxe d'automne, une division décimale du temps et douze mois de trente jours.", + "Les noms poétiques des mois — Vendémiaire, Brumaire, Frimaire, Nivôse, Pluviôse, Ventôse, Germinal, Floréal, Prairial, Messidor, Thermidor, Fructidor — sont l'œuvre du poète et député Fabre d'Églantine, approuvés par la Convention le 24 octobre 1793. Chaque jour du calendrier y est en outre associé à une production agricole ou un outil rural." + ] + }, + { + "heading": "Un usage bref mais marquant", + "paragraphs": [ + "Le calendrier républicain reste en vigueur un peu plus de douze ans, jusqu'à son abrogation par Napoléon Ier à compter du 1er janvier 1806, pour des raisons pratiques autant que politiques et religieuses.", + "Il sera brièvement remis en usage par la Commune de Paris en 1871, et laissera une trace durable dans la langue française à travers plusieurs prénoms (Nivôse, Floréal...) et l'expression « sans-culotte »." + ] + } + ] + }, + "leapYears": { + "title": "Les années sextiles", + "sections": [ + { + "heading": "Une contradiction dans le décret fondateur", + "paragraphs": [ + "Le décret du 4 frimaire an II (24 novembre 1793) fixe deux règles difficilement compatibles : l'année commence le jour de l'équinoxe d'automne vrai à l'Observatoire de Paris (article III), et l'année sextile — l'équivalent républicain de l'année bissextile — est intercalée tous les quatre ans (article X).", + "Or l'intervalle réel entre deux équinoxes successifs n'est pas rigoureusement constant : durant la période d'usage effectif du calendrier (an I à an XIV), les années sextiles tombèrent bien tous les quatre ans (an III, an VII, an XI), mais les astronomes savaient déjà que cette régularité ne durerait pas indéfiniment." + ] + }, + { + "heading": "Le projet de réforme de Romme", + "paragraphs": [ + "Le 19 floréal an III (8 mai 1795), Romme propose de trancher la contradiction en abandonnant la référence à l'équinoxe observé, au profit d'une règle arithmétique et perpétuement prévisible : une année sextile tous les quatre ans (la première étant l'an IV), sauf les années séculaires — non sextiles sauf si leur millésime est divisible par 400 — à l'exception du quarantième siècle, qui reste commun.", + "Cette règle est directement calquée sur celle du calendrier grégorien, simplement décalée d'une unité. Romme est arrêté peu après et se suicide en prison ; sa réforme ne sera donc jamais adoptée officiellement, mais elle reste la référence pour tout calendrier républicain perpétuel — c'est celle utilisée par ce convertisseur." + ] + }, + { + "heading": "La règle appliquée ici", + "paragraphs": [ + "Une année républicaine est donc sextile (366 jours) si son millésime est divisible par 4, sauf s'il est divisible par 100 sans l'être par 400, et sauf s'il est divisible par 4000. Toutes les autres années comptent 365 jours, réparties en douze mois de trente jours et cinq jours complémentaires." + ] + } + ] + }, + "complementaryDays": { + "title": "Les jours complémentaires", + "sections": [ + { + "heading": "Le solde de l'année", + "paragraphs": [ + "Douze mois de trente jours ne totalisent que 360 jours : il manque cinq jours pour compléter une année tropique, six les années sextiles. Ces jours, d'abord appelés « épagomènes » puis « sans-culottides » par le décret du 4 frimaire an II, prennent le nom de « jours complémentaires » à partir du décret du 7 fructidor an III (24 août 1795).", + "Placés hors des mois et des décades, ils ne portent pas de nom de décadi et sont consacrés aux réjouissances et fêtes publiques marquant la fin de l'année républicaine, autour du 17 au 22 septembre du calendrier grégorien." + ] + }, + { + "heading": "Les cinq (ou six) journées", + "paragraphs": [ + "Le jour de la Vertu, le jour du Génie, le jour du Travail, le jour de l'Opinion et le jour des Récompenses composent les cinq jours complémentaires de toute année républicaine.", + "Les années sextiles — tous les quatre ans dans la règle perpétuelle de Romme — s'y ajoute un sixième jour, le jour de la Révolution, consacré aux jeux nationaux en mémoire de la fondation de la République.", + "La période de quatre ans séparant deux années sextiles porte le nom de « Franciade », en écho aux Olympiades de la Grèce antique." + ] + } + ] + } +} diff --git a/locales/fr/common.json b/locales/fr/common.json new file mode 100644 index 0000000..63c9925 --- /dev/null +++ b/locales/fr/common.json @@ -0,0 +1,48 @@ +{ + "site": { + "title": "Calendrier républicain", + "tagline": "Convertisseur perpétuel" + }, + "nav": { + "menuLabel": "Menu", + "home": "Accueil", + "about": "À propos", + "aboutHistory": "Histoire du calendrier", + "aboutLeapYears": "Les années sextiles", + "aboutComplementaryDays": "Les jours complémentaires", + "language": "Langue" + }, + "home": { + "todayHeading": "Nous sommes aujourd'hui le", + "resultHeading": "Date convertie", + "gregorianEquivalent": "Équivalent grégorien", + "sextileBadge": "Année sextile", + "decadeLabel": "Décade", + "dayOfYearLabel": "Quantième de l'année", + "yearLabel": "An" + }, + "form": { + "title": "Convertir une autre date", + "dateLabel": "Date grégorienne (JJ/MM/AAAA)", + "submit": "Convertir", + "todayButton": "Revenir à aujourd'hui", + "helpText": "Sélectionnez un jour, un mois et une année : le formulaire vérifie automatiquement que la date existe.", + "errorInvalid": "Cette date n'existe pas dans le calendrier grégorien.", + "errorBeforeEpoch": "Le calendrier républicain débute le 22 septembre 1792 (1er vendémiaire an I). Choisissez une date postérieure.", + "errorGeneric": "Une erreur est survenue pendant la conversion." + }, + "weekdays": { + "monday": "Lundi", + "tuesday": "Mardi", + "wednesday": "Mercredi", + "thursday": "Jeudi", + "friday": "Vendredi", + "saturday": "Samedi", + "sunday": "Dimanche" + }, + "footer": { + "text": "Dates calculées selon la règle arithmétique perpétuelle proposée par Gilbert Romme (19 floréal an III / 8 mai 1795).", + "sourceNote": "Contenu historique inspiré de l'article « Calendrier républicain »." + }, + "loading": "Chargement…" +} diff --git a/locales/fr/months.json b/locales/fr/months.json new file mode 100644 index 0000000..cb4a4c7 --- /dev/null +++ b/locales/fr/months.json @@ -0,0 +1,135 @@ +{ + "seasonSuffix": { + "autumn": "Terminaison en « -aire » (du latin -arius)", + "winter": "Terminaison en « -ôse » (du latin -osus, « doté de »)", + "spring": "Terminaison en « -al » (du latin -alis)", + "summer": "Terminaison en « -idor » (du grec dôron, « don »)" + }, + "months": { + "vendemiaire": { + "name": "Vendémiaire", + "season": "autumn", + "period": "22/23/24 septembre – 21/22/23 octobre", + "etymology": "Du latin vindemia, « vendange ».", + "description": "Premier mois de l'année républicaine, il ouvre l'automne et débute le jour de l'équinoxe. Fabre d'Églantine y voit le mois du raisin et des vendanges qui achèvent le travail de la vigne." + }, + "brumaire": { + "name": "Brumaire", + "season": "autumn", + "period": "22/23/24 octobre – 20/21/22 novembre", + "etymology": "Du latin bruma, « brouillard, brume ».", + "description": "Mois des brumes et des brouillards qui enveloppent la campagne, correspondant à la transsudation de la nature entre octobre et novembre." + }, + "frimaire": { + "name": "Frimaire", + "season": "autumn", + "period": "21/22/23 novembre – 20/21/22 décembre", + "etymology": "Du mot « frimas », froid humide de la fin d'automne.", + "description": "Dernier mois de l'automne, marqué par les premiers froids, tantôt secs, tantôt humides, qui annoncent l'hiver." + }, + "nivose": { + "name": "Nivôse", + "season": "winter", + "period": "21/22/23 décembre – 19/20/21 janvier", + "etymology": "Du latin nix, nivis, « neige ».", + "description": "Premier mois de l'hiver, celui de la neige qui blanchit la terre entre décembre et janvier." + }, + "pluviose": { + "name": "Pluviôse", + "season": "winter", + "period": "20/21/22 janvier – 18/19/20 février", + "etymology": "Du latin pluvia, « pluie ».", + "description": "Mois des pluies abondantes qui tombent généralement entre janvier et février." + }, + "ventose": { + "name": "Ventôse", + "season": "winter", + "period": "19/20/21 février – 20/21 mars", + "etymology": "Du latin ventosus, « venteux ».", + "description": "Dernier mois de l'hiver, celui des giboulées et des vents qui sèchent la terre entre février et mars." + }, + "germinal": { + "name": "Germinal", + "season": "spring", + "period": "21/22 mars – 19/20 avril", + "etymology": "Du latin germen, « germe ».", + "description": "Premier mois du printemps, celui de la fermentation et du développement de la sève entre mars et avril." + }, + "floreal": { + "name": "Floréal", + "season": "spring", + "period": "20/21 avril – 19/20 mai", + "etymology": "Du latin flos, floris, « fleur ».", + "description": "Mois de l'épanouissement des fleurs entre avril et mai." + }, + "prairial": { + "name": "Prairial", + "season": "spring", + "period": "20/21 mai – 18/19 juin", + "etymology": "Du mot « prairie ».", + "description": "Dernier mois du printemps, celui de la fécondité riante et de la récolte des prairies entre mai et juin." + }, + "messidor": { + "name": "Messidor", + "season": "summer", + "period": "19/20 juin – 18/19 juillet", + "etymology": "Du latin messis, « moisson », et du grec dôron, « don ».", + "description": "Premier mois de l'été, celui des épis ondoyants et des moissons dorées entre juin et juillet." + }, + "thermidor": { + "name": "Thermidor", + "season": "summer", + "period": "19/20 juillet – 17/18 août", + "etymology": "Du grec thermos, « chaleur », et dôron, « don ».", + "description": "Mois de la chaleur, à la fois solaire et terrestre, qui embrase l'air entre juillet et août." + }, + "fructidor": { + "name": "Fructidor", + "season": "summer", + "period": "18/19 août – 16/17 septembre", + "etymology": "Du latin fructus, « fruit », et du grec dôron, « don ».", + "description": "Dernier mois de l'année, celui des fruits que le soleil dore et mûrit entre août et septembre." + } + }, + "decadeDays": { + "primidi": "Primidi", + "duodi": "Duodi", + "tridi": "Tridi", + "quartidi": "Quartidi", + "quintidi": "Quintidi", + "sextidi": "Sextidi", + "septidi": "Septidi", + "octidi": "Octidi", + "nonidi": "Nonidi", + "decadi": "Décadi" + }, + "complementaryDays": { + "title": "Jours complémentaires (sans-culottides)", + "days": { + "virtue": { + "name": "Jour de la Vertu", + "description": "Premier jour complémentaire, dédié à la vertu civique." + }, + "genius": { + "name": "Jour du Génie", + "description": "Deuxième jour complémentaire, célébrant le génie et l'esprit d'invention." + }, + "labour": { + "name": "Jour du Travail", + "description": "Troisième jour complémentaire, en l'honneur du travail." + }, + "opinion": { + "name": "Jour de l'Opinion", + "description": "Quatrième jour complémentaire, consacré à la liberté d'opinion." + }, + "rewards": { + "name": "Jour des Récompenses", + "description": "Cinquième jour complémentaire, jour des récompenses publiques." + }, + "revolution": { + "name": "Jour de la Révolution", + "description": "Sixième jour complémentaire, ajouté uniquement les années sextiles, en mémoire de la Révolution et des jeux nationaux." + } + } + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..046116c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,832 @@ +{ + "name": "calendrier-republicain", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "calendrier-republicain", + "version": "1.0.0", + "dependencies": { + "express": "^4.19.2" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.8", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.8.tgz", + "integrity": "sha512-JNcyFQ64OiijEkPzUBTCe+hyPXUD/3LEldGQ6iF5LR1w00mx9o7xtDWHXBY2iItjdCFGoilOLNQbH943ut7pHA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.16.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.3.tgz", + "integrity": "sha512-Bdcs4+3qlpVlx2NRn6fgX2Ue2/gGRaPeawebgclM0ERSCqDpA+owF1fdPwjJUTAJWMTuAaxjDf+hzb0/4eKvvw==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.13", + "proxy-addr": "~2.0.7", + "qs": "~6.16.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.8.tgz", + "integrity": "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/qs": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..37b98f9 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "calendrier-republicain", + "version": "1.0.0", + "description": "Convertisseur perpetuel du calendrier gregorien vers le calendrier republicain francais", + "private": true, + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.19.2" + } +} diff --git a/public/assets/months/brumaire.svg b/public/assets/months/brumaire.svg new file mode 100644 index 0000000..e2d826d --- /dev/null +++ b/public/assets/months/brumaire.svg @@ -0,0 +1,9 @@ + diff --git a/public/assets/months/complementary.svg b/public/assets/months/complementary.svg new file mode 100644 index 0000000..b2d2f90 --- /dev/null +++ b/public/assets/months/complementary.svg @@ -0,0 +1,9 @@ + diff --git a/public/assets/months/floreal.svg b/public/assets/months/floreal.svg new file mode 100644 index 0000000..6645b54 --- /dev/null +++ b/public/assets/months/floreal.svg @@ -0,0 +1,14 @@ + diff --git a/public/assets/months/frimaire.svg b/public/assets/months/frimaire.svg new file mode 100644 index 0000000..17faade --- /dev/null +++ b/public/assets/months/frimaire.svg @@ -0,0 +1,13 @@ + diff --git a/public/assets/months/fructidor.svg b/public/assets/months/fructidor.svg new file mode 100644 index 0000000..5e3b4ba --- /dev/null +++ b/public/assets/months/fructidor.svg @@ -0,0 +1,8 @@ + diff --git a/public/assets/months/germinal.svg b/public/assets/months/germinal.svg new file mode 100644 index 0000000..e26d3e9 --- /dev/null +++ b/public/assets/months/germinal.svg @@ -0,0 +1,7 @@ + diff --git a/public/assets/months/messidor.svg b/public/assets/months/messidor.svg new file mode 100644 index 0000000..cea0607 --- /dev/null +++ b/public/assets/months/messidor.svg @@ -0,0 +1,16 @@ + diff --git a/public/assets/months/nivose.svg b/public/assets/months/nivose.svg new file mode 100644 index 0000000..4dc32f8 --- /dev/null +++ b/public/assets/months/nivose.svg @@ -0,0 +1,14 @@ + diff --git a/public/assets/months/pluviose.svg b/public/assets/months/pluviose.svg new file mode 100644 index 0000000..24188df --- /dev/null +++ b/public/assets/months/pluviose.svg @@ -0,0 +1,10 @@ + diff --git a/public/assets/months/prairial.svg b/public/assets/months/prairial.svg new file mode 100644 index 0000000..1d8c9f1 --- /dev/null +++ b/public/assets/months/prairial.svg @@ -0,0 +1,15 @@ + diff --git a/public/assets/months/thermidor.svg b/public/assets/months/thermidor.svg new file mode 100644 index 0000000..e22af25 --- /dev/null +++ b/public/assets/months/thermidor.svg @@ -0,0 +1,14 @@ + diff --git a/public/assets/months/vendemiaire.svg b/public/assets/months/vendemiaire.svg new file mode 100644 index 0000000..49965be --- /dev/null +++ b/public/assets/months/vendemiaire.svg @@ -0,0 +1,16 @@ + diff --git a/public/assets/months/ventose.svg b/public/assets/months/ventose.svg new file mode 100644 index 0000000..a136e81 --- /dev/null +++ b/public/assets/months/ventose.svg @@ -0,0 +1,8 @@ + diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000..5f98a24 --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,446 @@ +:root { + --cream-bg: #faf3e6; + --cream-panel: #f6efe0; + --cream-panel-alt: #efe4cc; + --ink: #3a2e22; + --ink-soft: #6b5a45; + --accent: #b5652b; + --accent-soft: #d99a5b; + --brass: #8a6b45; + --border: #d8c9a8; + --shadow: 0 6px 20px rgba(90, 66, 34, 0.12); + color-scheme: light; +} + +* { + box-sizing: border-box; +} + +[hidden] { + display: none !important; +} + +html, body { + margin: 0; + padding: 0; +} + +body { + background: var(--cream-bg); + background-image: radial-gradient(circle at 10% 10%, rgba(181, 101, 43, 0.05), transparent 40%), + radial-gradient(circle at 90% 20%, rgba(138, 107, 69, 0.06), transparent 45%); + color: var(--ink); + font-family: 'Inter', 'Segoe UI', sans-serif; + line-height: 1.55; + min-height: 100vh; + display: flex; + flex-direction: column; +} + +h1, h2, .brand-title, .republican-date, .republican-year { + font-family: 'Fraunces', 'Georgia', serif; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; +} + +/* Header */ +.site-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--border); + background: var(--cream-panel); + position: sticky; + top: 0; + z-index: 20; +} + +.brand { + display: flex; + align-items: center; + gap: 0.6rem; + text-decoration: none; + color: var(--ink); +} + +.brand-mark { + font-family: 'Fraunces', serif; + font-style: italic; + font-size: 0.9rem; + color: var(--accent); + border: 1px solid var(--accent); + border-radius: 999px; + padding: 0.1rem 0.6rem; +} + +.brand-title { + font-size: 1.15rem; + font-weight: 600; +} + +.header-actions { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.lang-switch { + border: 1px solid var(--brass); + background: transparent; + color: var(--ink); + border-radius: 999px; + padding: 0.35rem 0.75rem; + font-weight: 600; + font-size: 0.85rem; + cursor: pointer; +} + +.lang-switch:hover { + background: var(--cream-panel-alt); +} + +.menu-toggle { + display: flex; + flex-direction: column; + justify-content: center; + gap: 5px; + width: 40px; + height: 36px; + border: 1px solid var(--border); + border-radius: 8px; + background: var(--cream-bg); + cursor: pointer; + padding: 0 8px; +} + +.burger-bar { + display: block; + height: 2px; + background: var(--ink); + border-radius: 2px; +} + +/* Nav panel */ +.main-nav { + position: fixed; + top: 0; + right: 0; + height: 100%; + width: min(300px, 85vw); + background: var(--cream-panel); + border-left: 1px solid var(--border); + box-shadow: var(--shadow); + padding: calc(1.5rem + env(safe-area-inset-top, 0px)) 1.5rem 1.5rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + transform: translateX(100%); + transition: transform 0.25s ease; + z-index: 30; +} + +.main-nav.open { + transform: translateX(0); +} + +.nav-link { + color: var(--ink); + text-decoration: none; + padding: 0.6rem 0.5rem; + border-radius: 8px; + font-weight: 500; +} + +.nav-link:hover, .nav-link.active { + background: var(--cream-panel-alt); + color: var(--accent); +} + +.nav-section-label { + margin: 1rem 0 0.1rem; + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--ink-soft); +} + +.nav-backdrop { + position: fixed; + inset: 0; + background: rgba(58, 46, 34, 0.35); + z-index: 25; +} + +/* Main content */ +main#app { + flex: 1; + width: 100%; + max-width: 1080px; + margin: 0 auto; + padding: 2rem 1.25rem 3rem; +} + +.today-heading { + text-align: center; + font-weight: 400; + font-size: 1.4rem; + color: var(--ink-soft); + margin-bottom: 1.5rem; +} + +.calendar-card { + display: grid; + grid-template-columns: minmax(180px, 220px) 1fr minmax(220px, 320px); + gap: 1.5rem; + align-items: stretch; + background: var(--cream-panel); + border: 1px solid var(--border); + border-radius: 16px; + padding: 2rem; + box-shadow: var(--shadow); +} + +.month-illustration { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.75rem; + text-align: center; + border-right: 1px dashed var(--border); + padding-right: 1.5rem; +} + +.month-illustration img { + width: 100%; + max-width: 150px; + height: auto; +} + +.month-period { + font-size: 0.85rem; + color: var(--ink-soft); + font-style: italic; +} + +.date-display { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + gap: 0.3rem; +} + +.decade-day { + text-transform: uppercase; + letter-spacing: 0.12em; + font-size: 0.85rem; + color: var(--accent); + font-weight: 600; + margin: 0; +} + +.republican-date { + font-size: clamp(1.8rem, 4vw, 2.6rem); + margin: 0.1rem 0; + font-weight: 600; +} + +.republican-year { + font-size: 1.1rem; + color: var(--ink-soft); + margin: 0; +} + +.sextile-badge { + display: inline-block; + margin-top: 0.5rem; + background: var(--accent); + color: var(--cream-bg); + border-radius: 999px; + padding: 0.2rem 0.75rem; + font-size: 0.75rem; + font-weight: 600; + letter-spacing: 0.04em; +} + +.gregorian-equivalent { + margin-top: 0.75rem; + font-size: 0.85rem; + color: var(--ink-soft); +} + +.description-panel { + border-left: 1px dashed var(--border); + padding-left: 1.5rem; +} + +.month-name { + margin: 0 0 0.2rem; + font-size: 1.3rem; +} + +.month-season-suffix { + font-size: 0.8rem; + color: var(--brass); + margin: 0 0 0.6rem; +} + +.month-etymology { + font-style: italic; + color: var(--ink-soft); + margin: 0 0 0.6rem; +} + +.month-description { + margin: 0; +} + +/* Form */ +.convert-form { + margin-top: 2rem; + background: var(--cream-panel-alt); + border: 1px solid var(--border); + border-radius: 16px; + padding: 1.5rem; +} + +.convert-form h2 { + margin-top: 0; + font-size: 1.1rem; +} + +.convert-form label { + display: block; + font-size: 0.85rem; + margin-bottom: 0.4rem; + color: var(--ink-soft); +} + +.convert-form-row { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + align-items: center; +} + +.convert-form-row input[type="date"] { + font-family: inherit; + font-size: 1rem; + padding: 0.5rem 0.75rem; + border: 1px solid var(--border); + border-radius: 8px; + background: var(--cream-bg); + color: var(--ink); +} + +.convert-form-row button { + font-family: inherit; + font-size: 0.95rem; + font-weight: 600; + padding: 0.55rem 1.1rem; + border-radius: 8px; + border: 1px solid var(--accent); + background: var(--accent); + color: #fff; + cursor: pointer; +} + +.convert-form-row button.secondary { + background: transparent; + color: var(--accent); +} + +.convert-form-row button:hover { + filter: brightness(1.05); +} + +.form-help { + margin: 0.75rem 0 0; + font-size: 0.8rem; + color: var(--ink-soft); +} + +.form-error { + margin: 0.75rem 0 0; + font-size: 0.85rem; + color: #a13f2b; + font-weight: 600; +} + +/* About view */ +.about-view { + background: var(--cream-panel); + border: 1px solid var(--border); + border-radius: 16px; + padding: 2rem; + box-shadow: var(--shadow); +} + +.about-view h1 { + margin-top: 0; +} + +.about-content h2 { + font-size: 1.15rem; + color: var(--accent); + margin: 1.5rem 0 0.5rem; +} + +.about-content h2:first-child { + margin-top: 0; +} + +.about-content p { + margin: 0 0 0.75rem; +} + +/* Footer */ +.site-footer { + text-align: center; + padding: 1.5rem 1rem calc(1.5rem + env(safe-area-inset-bottom, 0px)); + font-size: 0.8rem; + color: var(--ink-soft); + border-top: 1px solid var(--border); +} + +/* Responsive */ +@media (max-width: 820px) { + .calendar-card { + grid-template-columns: 1fr; + text-align: center; + } + .month-illustration, + .description-panel { + border: none; + padding: 0; + } + .month-illustration { + padding-bottom: 1rem; + border-bottom: 1px dashed var(--border); + } + .description-panel { + padding-top: 1rem; + border-top: 1px dashed var(--border); + } +} + +@media (max-width: 480px) { + .site-header { + padding: 0.75rem 1rem; + } + main#app { + padding: 1.5rem 0.9rem 2rem; + } + .calendar-card, .convert-form, .about-view { + padding: 1.25rem; + } +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..8ed4131 --- /dev/null +++ b/public/index.html @@ -0,0 +1,96 @@ + + +
+ + +—
+—
+—
+ Année sextile ++ Équivalent grégorien : + — +
+