diff options
Diffstat (limited to 'src')
74 files changed, 2608 insertions, 0 deletions
diff --git a/src/fonts/Inter/Inter.woff2 b/src/fonts/Inter/Inter.woff2 Binary files differnew file mode 100644 index 0000000..365eedc --- /dev/null +++ b/src/fonts/Inter/Inter.woff2 diff --git a/src/fonts/Inter/LICENSE.txt b/src/fonts/Inter/LICENSE.txt new file mode 100644 index 0000000..ff80f8c --- /dev/null +++ b/src/fonts/Inter/LICENSE.txt @@ -0,0 +1,94 @@ +Copyright (c) 2016-2020 The Inter Project Authors. +"Inter" is trademark of Rasmus Andersson. +https://github.com/rsms/inter + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION AND CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/fonts/Kanit/Kanit-Bold.woff b/src/fonts/Kanit/Kanit-Bold.woff Binary files differnew file mode 100644 index 0000000..7602cee --- /dev/null +++ b/src/fonts/Kanit/Kanit-Bold.woff diff --git a/src/fonts/Kanit/Kanit-Bold.woff2 b/src/fonts/Kanit/Kanit-Bold.woff2 Binary files differnew file mode 100644 index 0000000..8494234 --- /dev/null +++ b/src/fonts/Kanit/Kanit-Bold.woff2 diff --git a/src/fonts/Kanit/Kanit-BoldItalic.woff b/src/fonts/Kanit/Kanit-BoldItalic.woff Binary files differnew file mode 100644 index 0000000..af36319 --- /dev/null +++ b/src/fonts/Kanit/Kanit-BoldItalic.woff diff --git a/src/fonts/Kanit/Kanit-BoldItalic.woff2 b/src/fonts/Kanit/Kanit-BoldItalic.woff2 Binary files differnew file mode 100644 index 0000000..61f04ef --- /dev/null +++ b/src/fonts/Kanit/Kanit-BoldItalic.woff2 diff --git a/src/fonts/Kanit/Kanit-Italic.woff b/src/fonts/Kanit/Kanit-Italic.woff Binary files differnew file mode 100644 index 0000000..462f295 --- /dev/null +++ b/src/fonts/Kanit/Kanit-Italic.woff diff --git a/src/fonts/Kanit/Kanit-Italic.woff2 b/src/fonts/Kanit/Kanit-Italic.woff2 Binary files differnew file mode 100644 index 0000000..1723709 --- /dev/null +++ b/src/fonts/Kanit/Kanit-Italic.woff2 diff --git a/src/fonts/Kanit/Kanit-Light.woff b/src/fonts/Kanit/Kanit-Light.woff Binary files differnew file mode 100644 index 0000000..872ce1b --- /dev/null +++ b/src/fonts/Kanit/Kanit-Light.woff diff --git a/src/fonts/Kanit/Kanit-Light.woff2 b/src/fonts/Kanit/Kanit-Light.woff2 Binary files differnew file mode 100644 index 0000000..6b35eda --- /dev/null +++ b/src/fonts/Kanit/Kanit-Light.woff2 diff --git a/src/fonts/Kanit/Kanit-LightItalic.woff b/src/fonts/Kanit/Kanit-LightItalic.woff Binary files differnew file mode 100644 index 0000000..b81b7b3 --- /dev/null +++ b/src/fonts/Kanit/Kanit-LightItalic.woff diff --git a/src/fonts/Kanit/Kanit-LightItalic.woff2 b/src/fonts/Kanit/Kanit-LightItalic.woff2 Binary files differnew file mode 100644 index 0000000..f933a2c --- /dev/null +++ b/src/fonts/Kanit/Kanit-LightItalic.woff2 diff --git a/src/fonts/Kanit/Kanit-Medium.woff b/src/fonts/Kanit/Kanit-Medium.woff Binary files differnew file mode 100644 index 0000000..d5b3510 --- /dev/null +++ b/src/fonts/Kanit/Kanit-Medium.woff diff --git a/src/fonts/Kanit/Kanit-Medium.woff2 b/src/fonts/Kanit/Kanit-Medium.woff2 Binary files differnew file mode 100644 index 0000000..a012e98 --- /dev/null +++ b/src/fonts/Kanit/Kanit-Medium.woff2 diff --git a/src/fonts/Kanit/Kanit-MediumItalic.woff b/src/fonts/Kanit/Kanit-MediumItalic.woff Binary files differnew file mode 100644 index 0000000..6859f58 --- /dev/null +++ b/src/fonts/Kanit/Kanit-MediumItalic.woff diff --git a/src/fonts/Kanit/Kanit-MediumItalic.woff2 b/src/fonts/Kanit/Kanit-MediumItalic.woff2 Binary files differnew file mode 100644 index 0000000..8af9298 --- /dev/null +++ b/src/fonts/Kanit/Kanit-MediumItalic.woff2 diff --git a/src/fonts/Kanit/Kanit-Regular.woff b/src/fonts/Kanit/Kanit-Regular.woff Binary files differnew file mode 100644 index 0000000..eec0b42 --- /dev/null +++ b/src/fonts/Kanit/Kanit-Regular.woff diff --git a/src/fonts/Kanit/Kanit-Regular.woff2 b/src/fonts/Kanit/Kanit-Regular.woff2 Binary files differnew file mode 100644 index 0000000..9b925bf --- /dev/null +++ b/src/fonts/Kanit/Kanit-Regular.woff2 diff --git a/src/fonts/Kanit/Kanit-SemiBold.woff b/src/fonts/Kanit/Kanit-SemiBold.woff Binary files differnew file mode 100644 index 0000000..dacdb5b --- /dev/null +++ b/src/fonts/Kanit/Kanit-SemiBold.woff diff --git a/src/fonts/Kanit/Kanit-SemiBold.woff2 b/src/fonts/Kanit/Kanit-SemiBold.woff2 Binary files differnew file mode 100644 index 0000000..52d4527 --- /dev/null +++ b/src/fonts/Kanit/Kanit-SemiBold.woff2 diff --git a/src/fonts/Kanit/Kanit-SemiBoldItalic.woff b/src/fonts/Kanit/Kanit-SemiBoldItalic.woff Binary files differnew file mode 100644 index 0000000..ebf0137 --- /dev/null +++ b/src/fonts/Kanit/Kanit-SemiBoldItalic.woff diff --git a/src/fonts/Kanit/Kanit-SemiBoldItalic.woff2 b/src/fonts/Kanit/Kanit-SemiBoldItalic.woff2 Binary files differnew file mode 100644 index 0000000..300d77a --- /dev/null +++ b/src/fonts/Kanit/Kanit-SemiBoldItalic.woff2 diff --git a/src/fonts/Kanit/OFL.txt b/src/fonts/Kanit/OFL.txt new file mode 100644 index 0000000..0f48ea4 --- /dev/null +++ b/src/fonts/Kanit/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2020 The Kanit Project Authors (https://github.com/cadsondemak/kanit)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/images/armand-philippot-logo.svg b/src/images/armand-philippot-logo.svg new file mode 100644 index 0000000..17a245e --- /dev/null +++ b/src/images/armand-philippot-logo.svg @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="92.604164mm" + height="92.604164mm" + viewBox="0 0 92.604164 92.604164" + version="1.1" + id="svg8" + inkscape:version="1.0.2 (e86c870879, 2021-01-15)" + sodipodi:docname="armand-philippot-logo.svg"> + <defs + id="defs2"> + <rect + x="50.243404" + y="24.854818" + width="80.992653" + height="65.698357" + id="rect1471-2" /> + <rect + x="50.243404" + y="24.854818" + width="80.992653" + height="65.698357" + id="rect1666" /> + <rect + x="50.243404" + y="24.854818" + width="80.992653" + height="65.698357" + id="rect1471-2-3" /> + <rect + x="50.243404" + y="24.854818" + width="80.992653" + height="65.698357" + id="rect869" /> + <rect + x="50.243404" + y="24.854818" + width="80.992653" + height="65.698357" + id="rect1471-2-3-6" /> + <rect + x="50.243404" + y="24.854818" + width="80.992653" + height="65.698357" + id="rect928" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.979899" + inkscape:cx="62.374309" + inkscape:cy="220.65882" + inkscape:document-units="mm" + inkscape:current-layer="layer6" + inkscape:document-rotation="0" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1920" + inkscape:window-height="1019" + inkscape:window-x="0" + inkscape:window-y="33" + inkscape:window-maximized="1" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:groupmode="layer" + id="layer6" + inkscape:label="BG" + style="display:inline" + transform="translate(-38.78392,-94.321098)"> + <rect + style="fill:#386394;fill-opacity:1;stroke-width:0.767807" + id="rect1078" + width="92.604164" + height="92.604164" + x="38.78392" + y="94.321098" /> + </g> + <g + inkscape:label="PrimaryColor" + inkscape:groupmode="layer" + id="layer1" + style="display:inline" + transform="translate(-38.78392,-94.321098)"> + <path + id="rect1424-4-2" + style="fill:#194776;fill-opacity:1;stroke:none;stroke-width:2.28419;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="M 131.38808,95.225357 39.688622,186.92526 h 91.699458 z" + sodipodi:nodetypes="cccc" /> + </g> + <g + inkscape:groupmode="layer" + id="layer3" + inkscape:label="PrimaryColor-Dark" + style="display:inline" + transform="translate(-38.78392,-94.321098)"> + <path + id="rect1424-0" + style="display:inline;fill:#113d69;fill-opacity:1;stroke:none;stroke-width:2.2842;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 38.78392,94.321098 h 92.60403 L 38.78392,186.92514 Z" + sodipodi:nodetypes="cccc" /> + </g> + <g + inkscape:groupmode="layer" + id="layer7" + inkscape:label="Shadow" + transform="translate(-38.78392,-94.321098)"> + <g + aria-label="AP" + transform="matrix(1.0764391,0,0,1.0764391,-5.5904334,83.891018)" + id="text1469-5-2" + style="font-style:normal;font-weight:normal;font-size:50.8px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect1471-2-3);display:inline;fill:#1a2f47;fill-opacity:1;stroke:none"> + <path + d="m 51.514141,69.801562 12.547599,-32.7152 h 10.1092 l 12.5476,32.7152 h -9.9568 l -2.7432,-6.9596 h -9.8552 l -2.6924,6.9596 z m 13.919199,-13.8176 h 7.3152 l -3.6576,-9.6012 z" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Kanit;-inkscape-font-specification:'Kanit Bold';fill:#1a2f47;fill-opacity:1" + id="path957-9" /> + <path + d="m 90.274445,69.801562 v -32.7152 h 16.865595 q 4.0132,0 6.604,1.6256 2.6416,1.5748 3.9116,4.318 1.27,2.7432 1.27,6.096 0,3.4544 -1.4732,6.1468 -1.4732,2.6924 -4.1656,4.2164 -2.6924,1.524 -6.35,1.524 h -7.111995 v 8.7884 z m 9.5504,-16.1036 h 4.927605 q 2.23519,0 3.30199,-1.27 1.1176,-1.27 1.1176,-3.302 0,-2.1844 -1.016,-3.4544 -1.016,-1.27 -3.14959,-1.27 h -5.181605 z" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Kanit;-inkscape-font-specification:'Kanit Bold';fill:#1a2f47;fill-opacity:1" + id="path959-1" /> + </g> + </g> + <g + inkscape:groupmode="layer" + id="layer2" + inkscape:label="AP" + style="display:inline" + transform="translate(-38.78392,-94.321098)"> + <g + aria-label="AP" + transform="matrix(1.0764391,0,0,1.0764391,-7.7056069,82.297001)" + id="text1469-5" + style="font-style:normal;font-weight:normal;font-size:50.8px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;white-space:pre;shape-inside:url(#rect1471-2-3);fill:#f3f7fc;fill-opacity:1;stroke:none"> + <path + d="m 51.514141,69.801562 12.547599,-32.7152 h 10.1092 l 12.5476,32.7152 h -9.9568 l -2.7432,-6.9596 h -9.8552 l -2.6924,6.9596 z m 13.919199,-13.8176 h 7.3152 l -3.6576,-9.6012 z" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Kanit;-inkscape-font-specification:'Kanit Bold';fill:#f3f7fc;fill-opacity:1" + id="path957" /> + <path + d="m 90.274445,69.801562 v -32.7152 h 16.865595 q 4.0132,0 6.604,1.6256 2.6416,1.5748 3.9116,4.318 1.27,2.7432 1.27,6.096 0,3.4544 -1.4732,6.1468 -1.4732,2.6924 -4.1656,4.2164 -2.6924,1.524 -6.35,1.524 h -7.111995 v 8.7884 z m 9.5504,-16.1036 h 4.927605 q 2.23519,0 3.30199,-1.27 1.1176,-1.27 1.1176,-3.302 0,-2.1844 -1.016,-3.4544 -1.016,-1.27 -3.14959,-1.27 h -5.181605 z" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Kanit;-inkscape-font-specification:'Kanit Bold';fill:#f3f7fc;fill-opacity:1" + id="path959" /> + </g> + </g> +</svg> diff --git a/src/images/armand-philippot.jpg b/src/images/armand-philippot.jpg Binary files differnew file mode 100644 index 0000000..2c8ef50 --- /dev/null +++ b/src/images/armand-philippot.jpg diff --git a/src/images/cc-by-sa.svg b/src/images/cc-by-sa.svg new file mode 100644 index 0000000..b1fc892 --- /dev/null +++ b/src/images/cc-by-sa.svg @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="211.99811" + height="63.999996" + viewBox="0 0 211.99811 63.999996" + version="1.1" + id="svg8" + inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)" + sodipodi:docname="cc-by-sa.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4" + inkscape:cx="62.142857" + inkscape:cy="78.571429" + inkscape:document-units="px" + inkscape:current-layer="svg8" + inkscape:document-rotation="0" + showgrid="false" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:window-width="1920" + inkscape:window-height="1019" + inkscape:window-x="0" + inkscape:window-y="33" + inkscape:window-maximized="1" + inkscape:pagecheckerboard="0" + units="px" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <path + d="m 175.53911,15.829498 c 0,-3.008 1.485,-4.514 4.458,-4.514 2.973,0 4.457,1.504 4.457,4.514 0,2.971 -1.486,4.457 -4.457,4.457 -2.971,0 -4.458,-1.486 -4.458,-4.457 z" + id="path839" /> + <path + d="m 188.62611,24.057498 v 13.085 h -3.656 v 15.542 h -9.944 v -15.541 h -3.656 v -13.086 c 0,-0.572 0.2,-1.057 0.599,-1.457 0.401,-0.399 0.887,-0.6 1.457,-0.6 h 13.144 c 0.533,0 1.01,0.2 1.428,0.6 0.417,0.4 0.628,0.886 0.628,1.457 z" + id="path837" /> + <path + id="path4-3" + d="m 179.94147,-1.9073486e-6 c -8.839,0 -16.34167,3.0848125073486 -22.51367,9.2578125073486 -6.285,6.4000004 -9.42969,13.9811874 -9.42969,22.7421874 0,8.762 3.14469,16.284312 9.42969,22.570312 6.361,6.286 13.86467,9.429688 22.51367,9.429688 8.799,0 16.43611,-3.181922 22.91211,-9.544922 6.096,-5.98 9.14453,-13.464078 9.14453,-22.455078 0,-8.952 -3.10646,-16.532188 -9.31446,-22.7421874 -6.172,-6.172 -13.75418,-9.2578125073486 -22.74218,-9.2578125073486 z M 180.05475,5.7714825 c 7.238,0 13.40967,2.55225 18.51367,7.6562495 5.103,5.106 7.65625,11.294313 7.65625,18.570313 0,7.391 -2.51397,13.50575 -7.54297,18.34375 -5.295,5.221 -11.50591,7.828125 -18.6289,7.828125 -7.162,0 -13.33268,-2.589484 -18.51368,-7.771484 -5.18,-5.178001 -7.76953,-11.310485 -7.76953,-18.396485 0,-7.047 2.60813,-13.238266 7.82813,-18.572265 5.029,-5.1040004 11.18103,-7.6582035 18.45703,-7.6582035 z" /> + <path + d="m 91.998554,27.114498 c 0.609,-3.924 2.189,-6.962 4.742,-9.114 2.552,-2.152 5.655996,-3.228 9.313996,-3.228 5.027,0 9.029,1.62 12,4.856 2.971,3.238 4.457,7.391 4.457,12.457 0,4.915 -1.543,9 -4.627,12.256 -3.088,3.256 -7.086,4.886 -12.002,4.886 -3.619,0 -6.742996,-1.085 -9.370996,-3.257 -2.629,-2.172 -4.209,-5.257 -4.743,-9.257 h 8.059 c 0.189996,3.886 2.532996,5.829 7.028996,5.829 2.246,0 4.057,-0.972 5.428,-2.914 1.373,-1.942 2.059,-4.534 2.059,-7.771 0,-3.391 -0.629,-5.971 -1.885,-7.743 -1.258,-1.771 -3.066,-2.657 -5.43,-2.657 -4.268,0 -6.667,1.885 -7.199996,5.656 h 2.342996 l -6.341996,6.343 -6.343,-6.343 z" + id="path837-7" /> + <path + id="path4-5" + d="m 105.94241,-1.8610229e-6 c -8.799996,0 -16.304676,3.1054062610229 -22.513666,9.3164061610229 -6.285,6.3999997 -9.42969,13.9625467 -9.42969,22.6855467 0,8.763 3.14469,16.28336 9.42969,22.568359 6.361,6.286001 13.86467,9.429688 22.513666,9.429688 8.836,0 16.47511,-3.162328 22.91211,-9.486328 6.096,-6.057 9.14453,-13.559672 9.14453,-22.513672 0,-8.952 -3.10646,-16.513547 -9.31446,-22.6855468 -6.211,-6.21 -13.79118,-9.3144530610229 -22.74218,-9.3144530610229 z M 106.05569,5.7714825 c 7.275,0 13.44667,2.5698437 18.51367,7.7148435 5.103,5.028 7.65625,11.200672 7.65625,18.513672 0,7.353 -2.51397,13.46775 -7.54297,18.34375 -5.295,5.219 -11.50591,7.828125 -18.6289,7.828125 -7.161996,0 -13.332676,-2.589484 -18.513676,-7.771484 -5.18,-5.143 -7.76953,-11.275391 -7.76953,-18.400391 0,-7.046 2.60813,-13.217672 7.82813,-18.513672 5.029,-5.1429998 11.18103,-7.7148435 18.457026,-7.7148435 z" /> + <path + id="path4" + d="M 31.942383,5.9265138e-7 C 23.066111,5.9265138e-7 15.579851,3.1065496 9.484666,9.3147376 6.399571,12.400832 4.046856,15.896269 2.427808,19.801386 0.80876,23.706506 0,27.771846 0,32.000976 c 0,4.26713 0.800415,8.32413 2.400463,12.17225 1.600051,3.84811 3.933123,7.30532 7.000216,10.37141 3.067093,3.06609 6.534587,5.40951 10.400708,7.02756 3.867116,1.62105 7.914819,2.4278 12.142946,2.4278 4.22813,0 8.32441,-0.8171 12.28553,-2.45515 3.96313,-1.63805 7.50614,-4.00301 10.62923,-7.0881 3.0081,-2.93309 5.28529,-6.31477 6.82834,-10.14289 1.54104,-3.82712 2.31257,-7.93174 2.31257,-12.31288 0,-4.34313 -0.78277,-8.44771 -2.34382,-12.31483 C 60.094133,15.82003 57.808593,12.380471 54.800503,9.3713796 48.515313,3.1241896 40.893653,5.9265136e-7 31.942383,5.9265138e-7 Z M 32.057623,5.7716626 c 7.23822,0 13.42863,2.571923 18.57478,7.7150794 2.47408,2.478074 4.35948,5.297144 5.65252,8.459244 1.29504,3.16209 1.94342,6.51384 1.94342,10.05694 0,7.35423 -2.49445,13.46816 -7.4846,18.34432 -2.59208,2.51407 -5.49406,4.43661 -8.71316,5.77166 -3.2231,1.33404 -6.54486,1.9981 -9.97296,1.9981 -3.467107,0 -6.782568,-0.65672 -9.943661,-1.97076 -3.164098,-1.31604 -5.999858,-3.21894 -8.513933,-5.71502 -2.515077,-2.49507 -4.447918,-5.33279 -5.800959,-8.51588 -1.354042,-3.1791 -2.029358,-6.48331 -2.029358,-9.91242 0,-3.4671 0.675316,-6.79186 2.029358,-9.97295 1.352043,-3.1811 3.285882,-6.046798 5.800959,-8.599875 4.991151,-5.1041594 11.14337,-7.6584384 18.457594,-7.6584384 z" /> + <path + d="m 50.114533,26.687816 -4.22913,2.22907 c -0.45702,-0.95103 -1.02003,-1.61905 -1.68605,-2.00006 -0.66802,-0.38001 -1.30704,-0.57102 -1.91406,-0.57102 -2.85709,0 -4.28713,1.88506 -4.28713,5.65717 0,1.71406 0.363,3.0841 1.08603,4.11313 0.72302,1.02903 1.78906,1.54405 3.2011,1.54405 1.86506,0 3.1801,-0.91503 3.94112,-2.74309 l 4.00012,2.00007 c -0.87502,1.56304 -2.05706,2.79108 -3.54111,3.68611 -1.48604,0.89602 -3.10509,1.34304 -4.85715,1.34304 -2.89608,0 -5.20915,-0.87503 -6.94121,-2.62908 -1.73605,-1.75205 -2.60207,-4.19013 -2.60207,-7.31323 0,-3.04809 0.88502,-5.46616 2.65808,-7.25722 1.77005,-1.79005 4.00812,-2.68608 6.7132,-2.68608 3.96212,-0.002 6.78321,1.54105 8.45826,4.62714 z" + id="path846" /> + <path + d="m 31.656963,26.687816 -4.287128,2.22907 c -0.458013,-0.95103 -1.019029,-1.61905 -1.685048,-2.00006 -0.667024,-0.38001 -1.286042,-0.57102 -1.858057,-0.57102 -2.856087,0 -4.28613,1.88506 -4.28613,5.65717 0,1.71406 0.362014,3.0841 1.085029,4.11313 0.724025,1.02903 1.791056,1.54405 3.201101,1.54405 1.867057,0 3.181095,-0.91503 3.944118,-2.74309 l 3.942125,2.00007 c -0.83803,1.56304 -2.000065,2.79108 -3.486111,3.68611 -1.484043,0.89602 -3.123093,1.34304 -4.914149,1.34304 -2.857088,0 -5.163158,-0.87503 -6.915212,-2.62908 -1.752053,-1.75205 -2.62808,-4.19013 -2.62808,-7.31323 0,-3.04809 0.886028,-5.46616 2.657081,-7.25722 1.771054,-1.79005 4.009125,-2.68608 6.715205,-2.68608 3.963122,-0.002 6.800209,1.54105 8.515256,4.62714 z" + id="path844" /> +</svg> diff --git a/src/images/favicon/android-chrome-192x192.png b/src/images/favicon/android-chrome-192x192.png Binary files differnew file mode 100644 index 0000000..2def6f5 --- /dev/null +++ b/src/images/favicon/android-chrome-192x192.png diff --git a/src/images/favicon/android-chrome-512x512.png b/src/images/favicon/android-chrome-512x512.png Binary files differnew file mode 100644 index 0000000..514e060 --- /dev/null +++ b/src/images/favicon/android-chrome-512x512.png diff --git a/src/images/favicon/apple-touch-icon.png b/src/images/favicon/apple-touch-icon.png Binary files differnew file mode 100644 index 0000000..e4b7ae0 --- /dev/null +++ b/src/images/favicon/apple-touch-icon.png diff --git a/src/images/favicon/browserconfig.xml b/src/images/favicon/browserconfig.xml new file mode 100644 index 0000000..f9c2e67 --- /dev/null +++ b/src/images/favicon/browserconfig.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<browserconfig> + <msapplication> + <tile> + <square150x150logo src="/mstile-150x150.png"/> + <TileColor>#2b5797</TileColor> + </tile> + </msapplication> +</browserconfig> diff --git a/src/images/favicon/favicon-16x16.png b/src/images/favicon/favicon-16x16.png Binary files differnew file mode 100644 index 0000000..525a1b3 --- /dev/null +++ b/src/images/favicon/favicon-16x16.png diff --git a/src/images/favicon/favicon-32x32.png b/src/images/favicon/favicon-32x32.png Binary files differnew file mode 100644 index 0000000..c4b80ad --- /dev/null +++ b/src/images/favicon/favicon-32x32.png diff --git a/src/images/favicon/favicon.ico b/src/images/favicon/favicon.ico Binary files differnew file mode 100644 index 0000000..d1d41a8 --- /dev/null +++ b/src/images/favicon/favicon.ico diff --git a/src/images/favicon/mstile-144x144.png b/src/images/favicon/mstile-144x144.png Binary files differnew file mode 100644 index 0000000..f68a989 --- /dev/null +++ b/src/images/favicon/mstile-144x144.png diff --git a/src/images/favicon/mstile-150x150.png b/src/images/favicon/mstile-150x150.png Binary files differnew file mode 100644 index 0000000..b36424a --- /dev/null +++ b/src/images/favicon/mstile-150x150.png diff --git a/src/images/favicon/mstile-310x150.png b/src/images/favicon/mstile-310x150.png Binary files differnew file mode 100644 index 0000000..f395692 --- /dev/null +++ b/src/images/favicon/mstile-310x150.png diff --git a/src/images/favicon/mstile-310x310.png b/src/images/favicon/mstile-310x310.png Binary files differnew file mode 100644 index 0000000..3c7fd66 --- /dev/null +++ b/src/images/favicon/mstile-310x310.png diff --git a/src/images/favicon/mstile-70x70.png b/src/images/favicon/mstile-70x70.png Binary files differnew file mode 100644 index 0000000..12d226b --- /dev/null +++ b/src/images/favicon/mstile-70x70.png diff --git a/src/images/favicon/safari-pinned-tab.svg b/src/images/favicon/safari-pinned-tab.svg new file mode 100644 index 0000000..2354f78 --- /dev/null +++ b/src/images/favicon/safari-pinned-tab.svg @@ -0,0 +1,25 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg version="1.0" xmlns="http://www.w3.org/2000/svg" + width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000" + preserveAspectRatio="xMidYMid meet"> +<metadata> +Created by potrace 1.11, written by Peter Selinger 2001-2013 +</metadata> +<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)" +fill="#000000" stroke="none"> +<path d="M0 3500 l0 -3500 3500 0 3500 0 0 3500 0 3500 -3500 0 -3500 0 0 +-3500z m3032 60 c279 -729 508 -1326 508 -1327 0 -2 -182 -3 -404 -3 l-405 0 +-112 285 -113 285 -400 -2 -399 -3 -72 -185 c-40 -102 -89 -229 -109 -282 +l-38 -98 -405 0 c-320 0 -404 3 -400 13 24 64 993 2590 1003 2615 l13 32 412 +-2 413 -3 508 -1325z m2468 1298 c123 -34 193 -65 285 -129 178 -123 285 -288 +347 -536 19 -75 22 -115 22 -278 0 -174 -2 -198 -26 -287 -78 -287 -279 -514 +-543 -614 -153 -58 -219 -65 -612 -71 l-363 -6 0 -353 0 -354 -390 0 -390 0 0 +1330 0 1331 788 -3 787 -4 95 -26z"/> +<path d="M1960 3748 c-80 -209 -146 -384 -148 -389 -2 -5 124 -9 293 -9 285 0 +297 1 292 19 -7 29 -280 745 -286 753 -3 4 -71 -164 -151 -374z"/> +<path d="M4610 3919 l0 -381 253 4 c296 5 321 11 403 93 74 73 97 140 98 275 +1 226 -85 351 -264 379 -36 6 -161 11 -277 11 l-213 0 0 -381z"/> +</g> +</svg> diff --git a/src/images/favicon/site.webmanifest b/src/images/favicon/site.webmanifest new file mode 100644 index 0000000..31df508 --- /dev/null +++ b/src/images/favicon/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Armand Philippot", + "short_name": "AP", + "icons": [ + { + "src": "/wp-content/themes/apcom/assets/images/favicon/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/wp-content/themes/apcom/assets/images/favicon/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#194476", + "background_color": "#194476", + "display": "standalone" +} diff --git a/src/images/github.svg b/src/images/github.svg new file mode 100644 index 0000000..a39f6d2 --- /dev/null +++ b/src/images/github.svg @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="100" + height="100" + viewBox="0 0 100 100" + version="1.1" + id="svg8" + inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" + sodipodi:docname="github.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="4.6360027" + inkscape:cx="58.239828" + inkscape:cy="63.632405" + inkscape:document-units="px" + inkscape:current-layer="svg8" + inkscape:document-rotation="0" + showgrid="false" + units="px" + inkscape:window-width="1920" + inkscape:window-height="1019" + inkscape:window-x="0" + inkscape:window-y="33" + inkscape:window-maximized="1" + inkscape:pagecheckerboard="0" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <rect + style="fill: #1b1817; + fill-opacity: 1; + opacity: 1; + stroke-width: 6.55748;" + id="rect832" + width="100" + height="100" + x="0" + y="0" /> + <path + d="M 50.003222,15.863891 C 69.330089,15.863891 85,31.533801 85,50.864965 85,66.328607 74.972373,79.445952 61.064334,84.076237 c -1.751127,0.32014 -2.389268,-0.76061 -2.389268,-1.68882 0,-0.829368 0.03008,-3.031707 0.04727,-5.951686 9.735412,2.114245 11.789496,-4.692594 11.789496,-4.692594 1.59213,-4.043709 3.88686,-5.120169 3.88686,-5.120169 3.177814,-2.17011 -0.240646,-2.127137 -0.240646,-2.127137 -3.512998,0.247092 -5.360815,3.607538 -5.360815,3.607538 -3.12195,5.347924 -8.192701,3.803064 -10.186623,2.907088 -0.317995,-2.260352 -1.220417,-3.803063 -2.221677,-4.677553 7.771571,-0.883084 15.942786,-3.88686 15.942786,-17.298566 0,-3.820253 -1.364376,-6.944351 -3.603241,-9.391633 0.360969,-0.885233 1.562049,-4.443353 -0.341632,-9.262715 0,0 -2.939317,-0.941097 -9.625832,3.588201 -2.791062,-0.777802 -5.786243,-1.164554 -8.762086,-1.177446 -2.971546,0.01289 -5.966727,0.399644 -8.762085,1.177446 -6.68222,-4.529298 -9.615089,-3.588201 -9.615089,-3.588201 -1.910127,4.819362 -0.709046,8.377482 -0.348078,9.262715 -2.243163,2.447282 -3.598944,5.57138 -3.598944,9.391633 0,13.446084 8.184106,16.404739 15.98146,17.270634 -1.256945,1.080757 -2.376378,3.216489 -2.376378,6.482396 0,4.677553 0.04297,8.452684 0.04297,9.600049 0,0.9368 -0.629547,2.02615 -2.406458,1.68452 C 25.01903,79.43306 15,66.324309 15,50.864965 15,31.533801 30.672057,15.863891 50.003221,15.863891" + style="fill: #fff; + fill-opacity: 1; + fill-rule: evenodd; + stroke: none; + stroke-width: 0.999999;" + id="path198" /> +</svg> diff --git a/src/images/gitlab.svg b/src/images/gitlab.svg new file mode 100644 index 0000000..5a0ce62 --- /dev/null +++ b/src/images/gitlab.svg @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="100" + height="100" + viewBox="0 0 100 100" + version="1.1" + id="svg8" + inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" + sodipodi:docname="gitlab.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.8308202" + inkscape:cx="-61.174768" + inkscape:cy="22.940538" + inkscape:document-units="px" + inkscape:current-layer="svg8" + inkscape:document-rotation="0" + showgrid="false" + units="px" + inkscape:window-width="1920" + inkscape:window-height="1019" + inkscape:window-x="0" + inkscape:window-y="33" + inkscape:window-maximized="1" + inkscape:pagecheckerboard="0" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <rect + style="opacity:1;fill:#cccccc;fill-opacity:1;stroke-width:7.26231" + id="rect838" + width="100" + height="100" + x="0" + y="0" /> + <path + id="path50_2_" + class="st3" + d="m 49.997513,82.236501 v 0 L 62.893305,42.569483 H 37.120587 Z" + style="fill:#e24329;stroke-width:1" /> + <path + id="path66_6_" + class="st4" + d="m 19.057894,42.56969 v 0 l -3.92706,12.051333 c -0.355366,1.094294 0.0284,2.302206 0.966371,2.984325 L 49.99772,82.236501 Z" + style="fill:#fca326;stroke-width:1" /> + <path + id="path74_2_" + class="st3" + d="M 19.057894,42.56969 H 37.120587 L 29.346912,18.680161 c -0.397869,-1.222217 -2.13178,-1.222217 -2.543954,0 z" + style="fill:#e24329;stroke-width:1" /> + <path + id="path82_6_" + class="st4" + d="m 80.956206,42.56969 v 0 l 3.912962,12.051333 c 0.355365,1.094294 -0.02841,2.302206 -0.966371,2.984325 L 49.997513,82.236501 Z" + style="fill:#fca326;stroke-width:1" /> + <path + id="path86_2_" + class="st3" + d="M 80.956206,42.56969 H 62.893513 l 7.75937,-23.889529 c 0.397868,-1.222217 2.131779,-1.222217 2.543953,0 z" + style="fill:#e24329;stroke-width:1" /> + <path + id="polygon11-6" + style="fill:#fc6d26;stroke-width:4.82321" + class="st5" + d="M 50.016587,82.236502 80.956206,42.56969 H 62.893513 Z" /> + <path + id="polygon11-6-7" + style="fill:#fc6d26;stroke-width:4.82321" + class="st5" + d="M 49.997513,82.236502 19.057894,42.56969 h 18.062693 z" /> +</svg> diff --git a/src/js/app.js b/src/js/app.js new file mode 100644 index 0000000..38aee0e --- /dev/null +++ b/src/js/app.js @@ -0,0 +1,382 @@ +import projects from './config/projects'; +import { + translate, + setLocale, + currentLocale, + supportedLanguages, +} from './i18n/i18n'; +import { + hideToBottom, + hideToLeft, + showFromBottom, + showFromLeft, +} from './utilities/animations'; +import { isSmallVw, isStyleJsExists } from './utilities/helpers'; + +/** + * Show/hide header and footer with slide animation (left). + */ +function toggleHeaderFooter() { + const header = document.querySelector('header'); + const footer = document.querySelector('footer'); + const elements = [header, footer]; + + elements.forEach((el) => { + if (el.classList.contains('hide')) { + showFromLeft(el); + } else { + hideToLeft(el); + } + }); +} + +/** + * Show/hide project details with slide animation (bottom). + */ +function toggleProjectDetails() { + const details = document.querySelector('.project-details'); + + if (details.classList.contains('hide')) { + showFromBottom(details); + } else { + hideToBottom(details); + } +} + +/** + * Add an event listener to show or hide header and footer. + */ +function listenMenuBtn() { + const menuBtn = document.querySelector('.btn--menu'); + menuBtn.addEventListener('click', toggleHeaderFooter); +} + +/** + * Show or hide the project details button depending on current location. + */ +function toggleProjectDetailsBtn() { + const button = document.querySelector('.btn--details'); + const currentPath = window.location.hash; + + if (currentPath) { + button.style.display = ''; + } else { + button.style.display = 'none'; + } +} + +/** + * Update the visibility of some DOM elements depending on viewport. + */ +function updateView() { + const header = document.querySelector('header'); + const footer = document.querySelector('footer'); + const toolbar = document.querySelector('.toolbar'); + const details = document.querySelector('.project-details'); + + if (isSmallVw()) { + header.classList.add('hide'); + footer.classList.add('hide'); + toolbar.classList.remove('hide'); + details?.classList.add('hide'); + details?.classList.remove('fade-in'); + } else { + showFromLeft(header); + showFromLeft(footer); + toolbar.classList.add('hide'); + details?.classList.remove('hide'); + details?.classList.add('fade-in'); + } + + toggleProjectDetailsBtn(); +} + +/** + * Update view when the window size changes. + */ +function listenWindowSize() { + window.addEventListener('resize', updateView); +} + +/** + * Retrieve a project by id. + * @param {Integer} id - The project id. + * @returns {Object} The current project. + */ +function getCurrentProject(id) { + return projects.find((project) => project.id === id); +} + +/** + * Get a list item for the given repo. + * @param {String} name - The repository name. + * @param {String} url - The repository URL. + * @returns {HTMLElement} A list item. + */ +function getRepoItem(name, url) { + const item = document.createElement('li'); + const link = document.createElement('a'); + const span = document.createElement('span'); + span.classList.add('screen-reader-text'); + span.textContent = name; + link.classList.add('list__link', `list__link--${name.toLocaleLowerCase()}`); + link.href = url; + link.appendChild(span); + item.classList.add('list__item'); + item.appendChild(link); + return item; +} + +/** + * Get the repos list wrapped inside ul element and the title. + * @param {Object[]} repos - An array of repo with name and URL. + * @returns {[title, list]} An array of HTMLElements for title and list. + */ +function getRepos(repos) { + if (repos.length === 0) return []; + + const wrapper = document.createElement('div'); + const title = document.createElement('h3'); + const list = document.createElement('ul'); + const items = repos.map((repo) => getRepoItem(repo.name, repo.url)); + title.classList.add('project-details__title'); + title.textContent = translate('main.project.details.repo', { + count: repos.length, + }); + list.classList.add('list', 'list--repos'); + list.append(...items); + wrapper.append(title, list); + return [title, list]; +} + +/** + * Get the technologies list wrapped inside ul element and the title. + * @param {String[]} technologies - An array of technology names. + * @returns {[title, list]} An array of HTMLElements for title and list. + */ +function getTechs(technologies) { + if (technologies.length === 0) return []; + + const title = document.createElement('h3'); + title.classList.add('project-details__title'); + title.textContent = translate('main.project.details.tech', { + count: technologies.length, + }); + const list = document.createElement('ul'); + const items = technologies.map((technology) => { + const item = document.createElement('li'); + item.textContent = technology; + return item; + }); + list.classList.add('list', 'list--tech'); + list.append(...items); + return [title, list]; +} + +/** + * Retrieve the project details. + * @param {Object} project - The project. + * @returns {HTMLElement} The project details wrapped in a div. + */ +function getProjectDetails(project) { + const details = document.createElement('div'); + const title = document.createElement('h2'); + const techList = project?.technologies ? getTechs(project.technologies) : []; + const reposList = getRepos(project.repo); + const locale = currentLocale(); + let description; + + if (project.description) { + description = document.createElement('div'); + description.classList.add('project-details__description'); + description.textContent = project.description[locale] || ''; + } else { + description = ''; + } + + title.classList.add('project-details__title'); + title.textContent = translate('main.project.details.about', { + name: project.name, + }); + details.classList.add('project-details'); + if (!isSmallVw()) details.classList.add('fade-in'); + details.replaceChildren(title, description, ...techList, ...reposList); + + return details; +} + +/** + * Get an iframe for the given path/url. + * @param {String} src - The path/url to use as source. + * @returns {HTMLElement} The iframe. + */ +function getIframe(src) { + const iframe = document.createElement('iframe'); + iframe.src = src; + return iframe; +} + +/** + * Retrieve the project preview. + * @param {String} projectPath - The project path. + * @returns {HTMLElement} The project preview wrapped in a div. + */ +function getProjectPreview(projectPath) { + const preview = document.createElement('div'); + const iframe = getIframe(projectPath); + preview.classList.add('project-preview', 'fade-in'); + preview.replaceChildren(iframe); + return preview; +} + +/** + * Display the targeted project. + * @param {String} id - The project id. + */ +function showProject(id) { + const currentProject = getCurrentProject(id); + const main = document.querySelector('.main'); + const details = getProjectDetails(currentProject); + const preview = getProjectPreview(currentProject.path); + const detailsBtn = document.querySelector('.btn--details'); + + if (isSmallVw()) details.classList.add('hide'); + + detailsBtn.textContent = translate('main.project.details.about', { + name: currentProject.name, + }); + detailsBtn.addEventListener('click', toggleProjectDetails); + window.history.pushState({}, currentProject.name, `/#${id}`); + document.title = `${currentProject.name} | Demo | Armand Philippot`; + main.replaceChildren(preview, details); +} + +/** + * Add a CSS class to the current project in projects nav. + * @param {String} id - The project id. + */ +function setSelectedProject(id) { + const links = document.querySelectorAll('.nav__link'); + links.forEach((link) => { + if (link.id === id) { + link.classList.add('nav__link--selected'); + } else { + link.classList.remove('nav__link--selected'); + } + }); +} + +/** + * Create a list item for a project. + * @param {String} id - The project id. + * @param {String} name - The project name. + * @returns {HTMLElement} The list item. + */ +function getProjectsNavItem(id, name) { + const item = document.createElement('li'); + const link = document.createElement('a'); + link.classList.add('nav__link'); + link.href = `/#${id}`; + link.id = id; + link.textContent = name; + link.addEventListener('click', (e) => { + e.preventDefault(); + showProject(id); + setSelectedProject(id); + toggleProjectDetailsBtn(); + if (isSmallVw()) toggleHeaderFooter(); + }); + item.classList.add('nav__item'); + item.appendChild(link); + return item; +} + +/** + * Print the list of available projects. + */ +function printProjectsNav() { + const ul = document.querySelector('.nav .nav__list'); + + projects.forEach((project) => { + const item = getProjectsNavItem(project.id, project.name); + ul.appendChild(item); + }); +} + +/** + * Add style.js script for development purposes. + */ +function loadWebpackStyles() { + if (isStyleJsExists()) { + const head = document.querySelector('head'); + const script = document.createElement('script'); + script.src = 'assets/js/style.js'; + head.appendChild(script); + } +} + +/** + * Load corresponding project if the requested page contains a hash. + */ +function printRequestedPage() { + const currentPath = window.location.hash; + + if (currentPath) { + const id = currentPath.replace('#', ''); + showProject(id); + setSelectedProject(id); + } +} + +/** + * Replace the legal notice link and text. + */ +function replaceLegalNoticeLink() { + const link = document.querySelector('.nav__link--legal'); + link.href = translate('footer.legalNotice.link'); + link.textContent = translate('footer.legalNotice.txt'); +} + +/** + * Translate all text available in HTML templates. + */ +function translateHTMLContent() { + const brandingDesc = document.querySelector('.branding__description'); + const navLabel = document.querySelector('.nav__label'); + const license = document.querySelector('.copyright__license'); + const instructions = document.querySelector('.instructions'); + brandingDesc.textContent = translate('branding.description'); + navLabel.textContent = translate('nav.title'); + license.title = translate('footer.license'); + if (instructions) instructions.textContent = translate('main.instructions'); +} + +/** + * Translate the website according to the user preferred language. + */ +function setAppLocale() { + const preferredLanguage = navigator.language; + const supportedLanguage = supportedLanguages.find( + (lang) => preferredLanguage.startsWith(lang.code) + // eslint-disable-next-line function-paren-newline -- Conflict with Prettier + ); + const locale = supportedLanguage?.code || 'en'; + setLocale(locale); +} + +/** + * Initialize the website with the projects list. + */ +function init() { + setAppLocale(); + translateHTMLContent(); + replaceLegalNoticeLink(); + loadWebpackStyles(); + printProjectsNav(); + updateView(); + listenWindowSize(); + listenMenuBtn(); + printRequestedPage(); +} + +init(); diff --git a/src/js/config/projects.js b/src/js/config/projects.js new file mode 100644 index 0000000..53f1af8 --- /dev/null +++ b/src/js/config/projects.js @@ -0,0 +1,224 @@ +const projects = [ + { + id: 'bin2dec', + name: 'Bin2Dec', + description: { + en: 'Convert a binary string to a decimal number.', + fr: 'Convertit un nombre binaire en un nombre décimal.', + }, + path: './projects/js-small-apps/bin2dec/index.html', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/bin2dec', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/bin2dec', + }, + ], + technologies: ['Vanilla Javascript'], + }, + { + id: 'budget-app', + name: 'Budget App', + description: { + en: 'By selecting a language in the initialization form, only the currency is converted (the app is not translated). Also, no data is saved on page reload.', + fr: "En sélectionnant une langue dans le formulaire d'initialisation, seul le format des nombres change (l'application n'est pas traduite). Aucune donnée n'est conservée après rechargement de la page.", + }, + path: './projects/js-small-apps/budget-app/index.html', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/budget-app', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/budget-app', + }, + ], + technologies: ['Vanilla Javascript'], + }, + { + id: 'calculator', + name: 'Calculator', + description: { + en: 'A basic calculator. Decimal part is limited to 3 digits. The first part is limited to 8 digits. If the result does not respect these limits, you will see an error.', + fr: 'Une simple calculette. La partie décimale est limitée à 3 chiffres. La première partie est limitée à 8 chiffres. Si le résultat ne respecte pas ces limites, vous verrez une erreur.', + }, + path: './projects/js-small-apps/calculator/index.html', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/calculator', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/calculator', + }, + ], + technologies: ['Vanilla Javascript'], + }, + { + id: 'clock', + name: 'Clock', + description: { + en: 'What time is it? You can have the current hour in three formats: an analogic clock, a numeric display or a text.', + fr: "Quelle heure est-il ? Vous pouvez voir l'heure actuelle dans trois formats différents : une horloge analogique, un affichage numérique et sous forme de texte.", + }, + path: './projects/js-small-apps/clock/index.html', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/clock', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/clock', + }, + ], + technologies: ['Vanilla Javascript', 'SVG'], + }, + { + id: 'color-cycle', + name: 'Color cycle', + description: { + en: 'Play with hexadecimal colors. Set a color, then choose one or more increment values and start the preview.', + fr: "Jouez avec les couleurs hexadécimales. Définissez une couleur, puis choisissez une ou plusieurs valeurs d'incrémentation et démarrez l'aperçu.", + }, + path: './projects/js-small-apps/color-cycle/index.html', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/color-cycle', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/color-cycle', + }, + ], + technologies: ['Vanilla Javascript'], + }, + { + id: 'css-border-previewer', + name: 'CSS Border Previewer', + description: { + en: 'Play with CSS borders (style, width, radius). Then, you can copy the generated code if the preview suits you.', + fr: "Jouez avec les bordures CSS (style, largeur, radius). Ensuite, vous pouvez copier le code généré si l'aperçu vous satisfait.", + }, + path: './projects/js-small-apps/css-border-previewer/index.html', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/css-border-previewer', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/css-border-previewer', + }, + ], + technologies: ['Vanilla Javascript'], + }, + { + id: 'meme-generator', + name: 'Meme Generator', + description: { + en: 'Choose a random image, set one or more texts then position them. Your meme is ready!', + fr: 'Choisissez une image aléatoire, définissez un ou plusieurs textes et positionnez-les. Votre meme est prêt !', + }, + path: './projects/react-small-apps/meme-generator/build/index.html', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/react-small-apps/tree/main/meme-generator', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/react-small-apps/-/tree/main/meme-generator', + }, + ], + technologies: ['React', 'Fetch'], + }, + { + id: 'notebook', + name: 'Notebook', + description: { + en: 'Create as many pages as you want and fill them. You can define a title and a body. Then you can easily navigate between your pages with the nav.', + fr: 'Créez autant de pages que vous le souhaitez et remplissez-les. Vous pouvez définir un titre et un corps de texte. Ensuite, vous pouvez facilement naviguer entre vos pages grâce à la navigation.', + }, + path: './projects/react-small-apps/notebook/build/', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/react-small-apps/tree/main/notebook', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/react-small-apps/-/tree/main/notebook', + }, + ], + technologies: ['React', 'React router'], + }, + { + id: 'rps-game', + name: 'Rock Paper Scissors', + description: { + en: 'A basic implementation of the game. Try to beat your friend or the computer.', + fr: "Une implémentation du jeu. Essayez de battre votre ami ou l'ordinateur.", + }, + path: './projects/js-small-apps/rock-paper-scissors/index.html', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/rock-paper-scissors', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/rock-paper-scissors', + }, + ], + technologies: ['Vanilla Javascript'], + }, + { + id: 'todos', + name: 'Todos', + description: { + en: 'You can add, remove or mark as done your todos. For each todos, you can add some details in addition to the title.\n\nLogin: demo@email.com\nPassword: demo', + fr: 'Vous pouvez ajouter, supprimer ou marquer comme fait vos "todo". Pour chaque "todo", vous pouvez ajouter des détails en plus du titre.\n\nLogin : demo@email.com\nMot de passe : demo', + }, + path: './projects/react-small-apps/todos/build/', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/react-small-apps/tree/main/todos', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/react-small-apps/-/tree/main/todos', + }, + ], + technologies: ['React', 'React router', 'Redux'], + }, + { + id: 'users-list', + name: 'Users list', + description: { + en: 'You can see a list of username. By clicking on it, the next column display information about the selected user.', + fr: "Vous pouvez voir une liste de noms d'utilisateur. En cliquant sur l'un d'eux, la colonne suivante affiche les informations à propos de cet utilisateur.", + }, + path: './projects/js-small-apps/users-list/index.html', + repo: [ + { + name: 'Github', + url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/users-list', + }, + { + name: 'Gitlab', + url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/users-list', + }, + ], + technologies: ['Vanilla Javascript', 'Fetch'], + }, +]; + +export default projects; diff --git a/src/js/i18n/i18n.js b/src/js/i18n/i18n.js new file mode 100644 index 0000000..6bdc7cd --- /dev/null +++ b/src/js/i18n/i18n.js @@ -0,0 +1,42 @@ +import I18n from 'i18n-js'; +import en from './locales/en'; +import fr from './locales/fr'; + +const supportedLanguages = [ + { + code: 'en', + label: 'English', + translations: en, + }, + { + code: 'fr', + label: 'Français', + translations: fr, + }, +]; + +supportedLanguages.forEach((locale) => { + I18n.translations[locale.code] = locale.translations; +}); + +function setLocale(locale) { + I18n.locale = locale; +} + +function currentLocale() { + return I18n.currentLocale(); +} + +function translate(name, params = {}) { + return I18n.t(name, params); +} + +const { defaultLocale } = I18n; + +export { + supportedLanguages, + setLocale, + translate, + defaultLocale, + currentLocale, +}; diff --git a/src/js/i18n/locales/en.js b/src/js/i18n/locales/en.js new file mode 100644 index 0000000..9717528 --- /dev/null +++ b/src/js/i18n/locales/en.js @@ -0,0 +1,36 @@ +const en = { + branding: { + description: 'Front-end developer', + }, + nav: { + title: 'Apps list:', + }, + main: { + instructions: + 'Select an app inside menu to see a live preview and app details (description, technologies, repositories).', + project: { + details: { + about: 'About {{name}}', + repo: { + one: 'Repository:', + other: 'Repositories:', + zero: 'Repositories:', + }, + tech: { + one: 'Technology:', + other: 'Technologies:', + zero: 'Technologies:', + }, + }, + }, + }, + footer: { + legalNotice: { + txt: 'Legal notice', + link: 'legal-notice.html', + }, + license: 'License MIT', + }, +}; + +export default en; diff --git a/src/js/i18n/locales/fr.js b/src/js/i18n/locales/fr.js new file mode 100644 index 0000000..9c93012 --- /dev/null +++ b/src/js/i18n/locales/fr.js @@ -0,0 +1,36 @@ +const fr = { + branding: { + description: 'Intégrateur web', + }, + nav: { + title: 'Liste des applications :', + }, + main: { + instructions: + "Sélectionnez une application dans le menu pour afficher un aperçu en direct et les informations sur l'application (description, technologies, dépôts).", + project: { + details: { + about: 'À propos de {{name}}', + repo: { + one: 'Dépôt :', + other: 'Dépôts :', + zero: 'Dépôt :', + }, + tech: { + one: 'Technologie :', + other: 'Technologies :', + zero: 'Technologie :', + }, + }, + }, + }, + footer: { + legalNotice: { + txt: 'Mentions légales', + link: 'mentions-legales.html', + }, + license: 'Licence MIT', + }, +}; + +export default fr; diff --git a/src/js/utilities/animations.js b/src/js/utilities/animations.js new file mode 100644 index 0000000..9a30685 --- /dev/null +++ b/src/js/utilities/animations.js @@ -0,0 +1,45 @@ +/** + * Change the element classes to hide it with a slide out left animation. + * @param {HTMLElement} el - The HTMLElement to hide. + */ +function hideToLeft(el) { + el?.classList.remove('slide-in--left'); + el?.classList.add('slide-out--left'); + setTimeout(() => { + el?.classList.add('hide'); + }, 800); +} + +/** + * Change the element classes to show it with a slide in left animation. + * @param {HTMLElement} el - The HTMLElement to show. + */ +function showFromLeft(el) { + el?.classList.remove('slide-out--left'); + el?.classList.remove('hide'); + el?.classList.add('slide-in--left'); +} + +/** + * Change the element classes to hide it with a slide out bottom animation. + * @param {HTMLElement} el - The HTMLElement to hide. + */ +function hideToBottom(el) { + el?.classList.remove('slide-in--up'); + el?.classList.add('slide-out--bottom'); + setTimeout(() => { + el?.classList.add('hide'); + }, 800); +} + +/** + * Change the element classes to show it with a slide in up animation. + * @param {HTMLElement} el - The HTMLElement to show. + */ +function showFromBottom(el) { + el?.classList.remove('slide-out--bottom'); + el?.classList.remove('hide'); + el?.classList.add('slide-in--up'); +} + +export { hideToLeft, showFromLeft, hideToBottom, showFromBottom }; diff --git a/src/js/utilities/helpers.js b/src/js/utilities/helpers.js new file mode 100644 index 0000000..470c49c --- /dev/null +++ b/src/js/utilities/helpers.js @@ -0,0 +1,19 @@ +/** + * Check the size of the current viewport. + * @returns {Boolean} True if viewport lower than 1200px; false otherwise. + */ +function isSmallVw() { + return window.innerWidth < 1200; +} + +/** + * Check if /assets/styles.js exists (Webpack dev mode). + * @returns {Boolean} True if style.js exists ; false otherwise. + */ +async function isStyleJsExists() { + const filePath = 'assets/js/style.js'; + const response = await fetch(filePath); + return response.status === 200; +} + +export { isSmallVw, isStyleJsExists }; diff --git a/src/scss/abstracts/_functions.scss b/src/scss/abstracts/_functions.scss new file mode 100644 index 0000000..672e5e7 --- /dev/null +++ b/src/scss/abstracts/_functions.scss @@ -0,0 +1,4 @@ +@forward "./functions/convert"; +@forward "./functions/css-vars"; +@forward "./functions/str-replace"; +@forward "./functions/encode"; diff --git a/src/scss/abstracts/_mixins.scss b/src/scss/abstracts/_mixins.scss new file mode 100644 index 0000000..fd28631 --- /dev/null +++ b/src/scss/abstracts/_mixins.scss @@ -0,0 +1,2 @@ +@forward "./mixins/css-vars"; +@forward "./mixins/media-queries"; diff --git a/src/scss/abstracts/_placeholders.scss b/src/scss/abstracts/_placeholders.scss new file mode 100644 index 0000000..079cae7 --- /dev/null +++ b/src/scss/abstracts/_placeholders.scss @@ -0,0 +1,32 @@ +/// List Reset +%reset-list { + list-style-type: none; + margin: 0; + padding: 0; + + li { + margin-bottom: 0; + } +} + +/// Ordered List Reset +%reset-ordered-list { + @extend %reset-list; + + li { + counter-increment: none; + display: list-item; + + &::before { + display: none; + } + } +} + +/// Display an inline list with flexbox +%flex-list { + @extend %reset-list; + + display: flex; + flex-flow: row wrap; +} diff --git a/src/scss/abstracts/_variables.scss b/src/scss/abstracts/_variables.scss new file mode 100644 index 0000000..a8a22a8 --- /dev/null +++ b/src/scss/abstracts/_variables.scss @@ -0,0 +1,103 @@ +@use "sass:math"; +@use "../abstracts/functions" as fun; + +//=========================================================================== +// Ratios +//=========================================================================== + +/// Ratios map +/// @prop {String} keys - Keys are identifiers mapped to a given ratio +/// @prop {Map} value - Value is actual ratio +$ratios: ( + "minor-second": 1.067, + "major-second": 1.125, + "minor-third": 1.2, + "major-third": 1.25, + "perfect-fourth": 1.333, + "augmented-fourth": 1.414, + "perfect-fifth": 1.5, + "golden-number": 1.618, +); + +// Cannot declare the following function in partials due to module loop. +// Also, it will only be used in this file so it is not a problem. + +/// Get ratio +/// @param {String} $name - Ratio name. +/// @return {Integer} The ratio value. +@function get-ratio($name) { + @return map-get($ratios, $name); +} + +//=========================================================================== +// Layout +//=========================================================================== + +/// Breakpoints map +/// @prop {String} keys - Keys are identifiers mapped to a given length +/// @prop {Map} values - Values are actual breakpoints expressed in pixels +$breakpoints: ( + "xs": fun.convert-px(568, "em"), + "sm": fun.convert-px(768, "em"), + "md": fun.convert-px(1024, "em"), + "lg": fun.convert-px(1200, "em"), + "xl": fun.convert-px(1600, "em"), + "2xl": fun.convert-px(1920, "em"), +); + +//=========================================================================== +// Fonts +//=========================================================================== + +/* stylelint-disable -- Fonts name are not keywords, lowercase is not needed. */ +/// Regular font family +/// @type List +$font-family_primary: ("Inter", "Liberation Sans", Arial, sans-serif); + +/// Alternative regular font family +/// @type List +$font-family_secondary: ("Kanit", "Liberation Sans", Arial, sans-serif); + +$line-height: get-ratio("golden-number"); + +$font-size_base: 16px; +$font-size_base-rem: fun.convert-px(16); // font-size_base without unit +$font-size_ratio: get-ratio("minor-third"); +$font-size_sm: $font-size_base-rem * math.pow($font-size_ratio, -1); +$font-size_md: $font-size_base-rem * math.pow($font-size_ratio, 0); +$font-size_lg: $font-size_base-rem * math.pow($font-size_ratio, 1); +$font-size_xl: $font-size_base-rem * math.pow($font-size_ratio, 2); +$font-size_2xl: $font-size_base-rem * math.pow($font-size_ratio, 3); +$font-size_3xl: $font-size_base-rem * math.pow($font-size_ratio, 4); + +//============================================================================ +// Spacings +//============================================================================ + +$spacing_ratio: get-ratio("golden-number"); +$spacing_base: $spacing_ratio * 1rem; + +$spacing_3xs: math.div($spacing_base, 4); +$spacing_2xs: math.div($spacing_base, 3); +$spacing_xs: math.div($spacing_base, 2); +$spacing_sm: math.div($spacing_base, 1.5); +$spacing_md: $spacing_base; +$spacing_lg: $spacing_base * 1.5; + +//============================================================================ +// Colors +//============================================================================ + +$color_black-squeeze: hsl(212, 55%, 97%); +$color_catskill-white: hsl(212, 53%, 92%); +$color_link-water: hsl(212, 51%, 87%); +$color_geyser: hsl(212, 27%, 83%); +$color_gull-gray: hsl(212, 15%, 66%); +$color_pale-sky: hsl(212, 13%, 46%); +$color_nile-blue: hsl(212, 47%, 19%); +$color_firefly: hsl(212, 45%, 11%); +$color_chambray: hsl(212, 45%, 40%); +$color_chathams-blue: hsl(212, 65%, 28%); +$color_chathams-blue-light: hsl(212, 90%, 30%); +$color_chathams-blue-light-opacity-25: hsla(212, 90%, 30%, 0.25); +$color_chathams-blue-dark: hsl(212, 70%, 25%); diff --git a/src/scss/abstracts/functions/_convert.scss b/src/scss/abstracts/functions/_convert.scss new file mode 100644 index 0000000..9f51dc7 --- /dev/null +++ b/src/scss/abstracts/functions/_convert.scss @@ -0,0 +1,16 @@ +@use "sass:math"; + +/// Convert px to rem or em. +/// @param {Number} $px Value in px +/// @param {String} $to Unit. Either "rem" or "em" +/// @param {Number} $standard 1rem (or 1em) = 16px +/// @return {Number} Value in rem or em +@function convert-px($px, $to: "rem", $standard: 16) { + @if $to == "rem" { + @return math.div($px, $standard) + 0rem; // stylelint-disable-line + } @else if $to == "em" { + @return math.div($px, $standard) + 0em; // stylelint-disable-line + } @else { + @error "`$to` must be either `rem` or `em`."; + } +} diff --git a/src/scss/abstracts/functions/_css-vars.scss b/src/scss/abstracts/functions/_css-vars.scss new file mode 100644 index 0000000..89e1a15 --- /dev/null +++ b/src/scss/abstracts/functions/_css-vars.scss @@ -0,0 +1,8 @@ +/// Retrieve a CSS variable value with prefix +/// @see https://dev.to/felipperegazio/css-custom-properties-vars-with-sass-scss-a-practical-architecture-strategy-1m88 +/// @param {String} $name Variable name +/// @param {String} $prefix Variable prefix +/// @return {String} Variable in CSS format +@function get-var($name, $prefix: dap) { + @return var(--#{$prefix}-#{$name}); +} diff --git a/src/scss/abstracts/functions/_encode.scss b/src/scss/abstracts/functions/_encode.scss new file mode 100644 index 0000000..4350185 --- /dev/null +++ b/src/scss/abstracts/functions/_encode.scss @@ -0,0 +1,14 @@ +@use "str-replace" as fun; + +/// Encode a SVG. +/// @param {String} $svg A complete svg (`<svg>...</svg>`). +/// @return The encoded svg, ready to use for background-image. +@function encode-svg($svg) { + $svg-encoding: (("<", "%3C"), (">", "%3E"), ("#", "%23")); + + @each $char, $encoded in $svg-encoding { + $svg: fun.str-replace($svg, $char, $encoded); + } + + @return "data:image/svg+xml;utf8," + $svg; +} diff --git a/src/scss/abstracts/functions/_str-replace.scss b/src/scss/abstracts/functions/_str-replace.scss new file mode 100644 index 0000000..624bf33 --- /dev/null +++ b/src/scss/abstracts/functions/_str-replace.scss @@ -0,0 +1,20 @@ +/// Replace `$search` with `$replace` in `$string` +/// @author Hugo Giraudel +/// @param {String} $string - Initial string +/// @param {String} $search - Substring to replace +/// @param {String} $replace ('') - New value +/// @return {String} - Updated string +@function str-replace($string, $search, $replace: "") { + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + + str-replace( + str-slice($string, $index + str-length($search)), + $search, + $replace + ); + } + + @return $string; +} diff --git a/src/scss/abstracts/mixins/_css-vars.scss b/src/scss/abstracts/mixins/_css-vars.scss new file mode 100644 index 0000000..8e31c96 --- /dev/null +++ b/src/scss/abstracts/mixins/_css-vars.scss @@ -0,0 +1,20 @@ +/// Declare a set of CSS variables properly prefixed. +/// +/// @see https://dev.to/felipperegazio/css-custom-properties-vars-with-sass-scss-a-practical-architecture-strategy-1m88 +/// +/// @param {List} $variables - A list of variable name and value. +/// @param {Bool} $root - Set vars at root. +/// @param {String} $prefix - The variables prefix. +@mixin set-vars($variables, $root: true, $prefix: "dap") { + @if $root { + :root { + @each $name, $value in $variables { + --#{$prefix}-#{$name}: #{$value}; + } + } + } @else { + @each $name, $value in $variables { + --#{$prefix}-#{$name}: #{$value}; + } + } +} diff --git a/src/scss/abstracts/mixins/_media-queries.scss b/src/scss/abstracts/mixins/_media-queries.scss new file mode 100644 index 0000000..fcaea4b --- /dev/null +++ b/src/scss/abstracts/mixins/_media-queries.scss @@ -0,0 +1,81 @@ +@use "../variables" as var; + +/// Media query: media type +/// @param {String} $type - Media type: all, screen, print, retina. +/// @example scss - `@media only screen` equivalent is: +/// @include media("screen"); +@mixin media($type) { + @if $type == "retina" { + $type: "(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)"; + } @else if $type == "screen" or $type == "print" { + $type: "only #{$type}"; + } + + @media #{$type} { + @content; + } +} + +/// Media query: min-width / max-width +/// @param {String} $from - min-width breakpoint. +/// @param {String} $until - max-width breakpoint. +/// @example scss - `@media (min-width: "md")` equivalent is: +/// @include dimensions("md"); +@mixin dimensions($from: null, $until: null) { + $query: ""; + + @if $from { + @if type-of($from) == "string" { + $size: map-get(var.$breakpoints, $from); + $query: "(min-width: #{$size})"; + } @else { + @error "`$from` must be a string."; + } + } + + @if $from and $until { + $query: $query + " and "; + } + + @if $until { + @if type-of($until) == "string" { + $size: map-get(var.$breakpoints, $until); + $size: calc(#{$size} - 1px); + $query: $query + "(max-width: #{$size})"; + } @else { + @error "`$until` must be a string."; + } + } + + @media #{$query} { + @content; + } +} + +/// Media query: prefers-reduced-motion +/// @param {String} $value - Media query value: `no-preference` or `reduce`. +/// @example scss - @media (prefers-reduced-motion: "reduce") equivalent is: +/// @include motion("reduce"); +@mixin motion($value) { + @if $value == "no-preference" or $value == "reduce" { + @media (prefers-reduced-motion: #{$value}) { + @content; + } + } @else { + @error "Allowed values are `no-preference` and `reduce`."; + } +} + +/// Media query: any-pointer +/// @param {String} $value - Media query value: `fine`, `coarse` or `none`. +/// @example scss - @media (any-pointer: "fine") equivalent is: +/// @include pointer("fine"); +@mixin pointer($value) { + @if $value == "fine" or $value == "coarse" or $value == "none" { + @media (any-pointer: #{$value}) { + @content; + } + } @else { + @error "Allowed values are `fine`, `coarse` and `none`."; + } +} diff --git a/src/scss/base/_animations.scss b/src/scss/base/_animations.scss new file mode 100644 index 0000000..a2df8ab --- /dev/null +++ b/src/scss/base/_animations.scss @@ -0,0 +1,89 @@ +@keyframes fadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + visibility: visible; + } +} + +@keyframes fadeOut { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + visibility: hidden; + } +} + +@keyframes slideInLeft { + 0% { + margin-left: -100%; + } + + 100% { + margin-left: 0; + visibility: visible; + } +} + +@keyframes slideOutLeft { + 0% { + margin-left: 0; + } + + 100% { + margin-left: -100%; + visibility: hidden; + } +} + +@keyframes slideInUp { + 0% { + margin-bottom: -100vh; + } + + 100% { + margin-bottom: 0; + visibility: visible; + } +} + +@keyframes slideOutBottom { + 0% { + margin-bottom: 0; + } + + 100% { + margin-bottom: -100vh; + visibility: hidden; + } +} + +.fade-in { + animation: fadeIn 1s; +} + +.fade-out { + animation: fadeOut 1s; +} + +.slide-in--left { + animation: slideInLeft 0.8s; +} + +.slide-out--left { + animation: slideOutLeft 0.8s; +} + +.slide-in--up { + animation: slideInUp 1s; +} + +.slide-out--bottom { + animation: slideOutBottom 1s; +} diff --git a/src/scss/base/_base.scss b/src/scss/base/_base.scss new file mode 100644 index 0000000..a157a50 --- /dev/null +++ b/src/scss/base/_base.scss @@ -0,0 +1,3 @@ +html { + overflow: hidden; +} diff --git a/src/scss/base/_colors.scss b/src/scss/base/_colors.scss new file mode 100644 index 0000000..6251b2e --- /dev/null +++ b/src/scss/base/_colors.scss @@ -0,0 +1,21 @@ +@use "../abstracts/mixins" as mix; +@use "../abstracts/variables" as var; +@include mix.set-vars( + ( + color-bg: #{var.$color_black-squeeze}, + color-bg-secondary: #{var.$color_catskill-white}, + color-bg-tertiary: #{var.$color_link-water}, + color-fg: #{var.$color_firefly}, + color-fg-inverted: #{var.$color_black-squeeze}, + color-border: #{var.$color_chathams-blue}, + color-border-light: #{var.$color_geyser}, + color-shadow-darker: #{var.$color_nile-blue}, + color-shadow-dark: #{var.$color_pale-sky}, + color-shadow: #{var.$color_chambray}, + color-shadow-light: #{var.$color_gull-gray}, + color-primary: #{var.$color_chathams-blue}, + color-primary-light: #{var.$color_chathams-blue-light}, + color-primary-light-opacity: #{var.$color_chathams-blue-light-opacity-25}, + color-primary-dark: #{var.$color_chathams-blue-dark}, + ) +); diff --git a/src/scss/base/_fonts.scss b/src/scss/base/_fonts.scss new file mode 100644 index 0000000..192f6b8 --- /dev/null +++ b/src/scss/base/_fonts.scss @@ -0,0 +1,115 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; +@use "../abstracts/variables" as var; + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 700; + src: url("../fonts/Kanit/Kanit-Bold.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Bold.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 700; + src: url("../fonts/Kanit/Kanit-BoldItalic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-BoldItalic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 600; + src: url("../fonts/Kanit/Kanit-SemiBold.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-SemiBold.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 600; + src: url("../fonts/Kanit/Kanit-SemiBoldItalic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-SemiBoldItalic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 500; + src: url("../fonts/Kanit/Kanit-Medium.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Medium.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 500; + src: url("../fonts/Kanit/Kanit-MediumItalic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-MediumItalic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 400; + src: url("../fonts/Kanit/Kanit-Regular.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Regular.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 400; + src: url("../fonts/Kanit/Kanit-Italic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Italic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: normal; + font-weight: 300; + src: url("../fonts/Kanit/Kanit-Light.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-Light.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Kanit; + font-style: italic; + font-weight: 300; + src: url("../fonts/Kanit/Kanit-LightItalic.woff2") format("woff2"), + url("../fonts/Kanit/Kanit-LightItalic.woff") format("woff"); +} + +@font-face { + font-display: swap; + font-family: Inter; + font-style: oblique 0deg 10deg; + font-weight: 100 900; + src: url("../fonts/Inter/Inter.woff2?v=3.18") format("woff2"); +} + +@include mix.set-vars( + ( + font-family-primary: #{var.$font-family_primary}, + font-family-secondary: #{var.$font-family_secondary}, + font-size-sm: #{var.$font-size_sm}, + font-size-md: #{var.$font-size_md}, + font-size-lg: #{var.$font-size_lg}, + font-size-xl: #{var.$font-size_xl}, + font-size-2xl: #{var.$font-size_2xl}, + font-size-3xl: #{var.$font-size_3xl}, + line-height: #{var.$line-height}, + ) +); diff --git a/src/scss/base/_helpers.scss b/src/scss/base/_helpers.scss new file mode 100644 index 0000000..d6a9233 --- /dev/null +++ b/src/scss/base/_helpers.scss @@ -0,0 +1,44 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; + +.hide { + display: none !important; +} + +/* Text meant only for screen readers. */ +.screen-reader-text { + border: 0; + clip: rect(1px, 1px, 1px, 1px); + height: fun.convert-px(1); + overflow: hidden; + padding: 0; + position: absolute !important; + width: fun.convert-px(1); + word-break: normal; + word-wrap: normal !important; /* Many screen reader and browser combinations announce broken words as they would appear visually. */ + + &:focus { + background: fun.get-var(color-bg); + border: fun.convert-px(3) solid fun.get-var(color-border); + box-shadow: 0 0 fun.convert-px(2) fun.convert-px(2) + fun.get-var(color-shadow-light); + clip: auto !important; + color: fun.get-var(color-primary); + display: block; + font-size: fun.get-var(font-size-md); + font-weight: 600; + height: auto; + left: 0; + padding: fun.get-var(spacing-sm) fun.get-var(spacing-md); + top: 0; + width: auto; + z-index: 100000; + } +} + +@include mix.motion("reduce") { + * { + animation: none !important; + transition: none !important; + } +} diff --git a/src/scss/base/_spacings.scss b/src/scss/base/_spacings.scss new file mode 100644 index 0000000..e908caf --- /dev/null +++ b/src/scss/base/_spacings.scss @@ -0,0 +1,24 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; +@use "../abstracts/variables" as var; +@include mix.set-vars( + ( + spacing-3xs: var.$spacing_3xs, + spacing-2xs: var.$spacing_2xs, + spacing-xs: var.$spacing_xs, + spacing-sm: var.$spacing_sm, + spacing-md: var.$spacing_md, + spacing-lg: var.$spacing_lg, + toolbar-height: fun.convert-px(60), + ) +); + +@include mix.media("screen") { + @include mix.dimensions("lg") { + @include mix.set-vars( + ( + toolbar-height: fun.convert-px(0), + ) + ); + } +} diff --git a/src/scss/base/_typography.scss b/src/scss/base/_typography.scss new file mode 100644 index 0000000..b0504b7 --- /dev/null +++ b/src/scss/base/_typography.scss @@ -0,0 +1,48 @@ +@use "../abstracts/functions" as fun; + +*::selection { + background: fun.get-var(color-primary-light-opacity); +} + +body { + background: fun.get-var(color-bg); + color: fun.get-var(color-fg); + font-size: fun.get-var(font-size-md); + line-height: fun.get-var(line-height); +} + +h1, +h2, +h3, +h4, +h5, +h6, +p, +ul { + margin: 0 0 fun.get-var(spacing-sm); +} + +a { + color: fun.get-var(color-primary); + text-decoration-thickness: fun.convert-px(2); + text-underline-offset: fun.convert-px(3); + transition: all 0.3s ease-in-out 0s; + + &:hover, + &:focus { + color: fun.get-var(color-primary-light); + text-decoration-color: fun.get-var(color-primary-light); + text-decoration-thickness: fun.convert-px(4); + } + + &:focus { + outline: fun.get-var(color-primary) dotted fun.convert-px(1); + } + + &:active { + color: fun.get-var(color-primary-dark); + outline: none; + text-decoration-color: fun.get-var(color-primary-dark); + text-decoration-thickness: fun.convert-px(2); + } +} diff --git a/src/scss/components/_buttons.scss b/src/scss/components/_buttons.scss new file mode 100644 index 0000000..bc7959e --- /dev/null +++ b/src/scss/components/_buttons.scss @@ -0,0 +1,21 @@ +@use "../abstracts/functions" as fun; + +.btn { + background: fun.get-var(color-bg); + border: 0; + color: fun.get-var(color-primary); + cursor: pointer; + display: block; + font-weight: 600; + + &:hover, + &:focus { + background: fun.get-var(color-primary); + color: fun.get-var(color-fg-inverted); + } + + &:active { + background: fun.get-var(color-bg); + color: fun.get-var(color-primary); + } +} diff --git a/src/scss/layout/_footer.scss b/src/scss/layout/_footer.scss new file mode 100644 index 0000000..7dce0dc --- /dev/null +++ b/src/scss/layout/_footer.scss @@ -0,0 +1,40 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; + +.footer { + align-items: center; + background: fun.get-var(color-bg-secondary); + border-top: fun.convert-px(1) solid fun.get-var(color-border-light); + display: flex; + flex-flow: row wrap; + font-family: fun.get-var(font-family-secondary); + font-size: fun.get-var(font-size-md); + gap: fun.get-var(spacing-3xs); + justify-content: center; + padding: fun.get-var(spacing-sm) fun.get-var(spacing-md) + calc(#{fun.get-var(toolbar-height)} + #{fun.get-var(spacing-sm)}); + + @include mix.media("screen") { + @include mix.dimensions("lg") { + box-shadow: 0 -1px 2px 0 fun.get-var(color-shadow); + padding: fun.get-var(spacing-sm) fun.get-var(spacing-md); + } + } + + .nav { + display: inline-flex; + gap: fun.get-var(spacing-3xs); + + &::after { + content: "/"; + } + } +} + +.copyright { + align-items: center; + display: flex; + flex-flow: row wrap; + gap: fun.get-var(spacing-3xs); + justify-content: center; +} diff --git a/src/scss/layout/_grid.scss b/src/scss/layout/_grid.scss new file mode 100644 index 0000000..3749678 --- /dev/null +++ b/src/scss/layout/_grid.scss @@ -0,0 +1,43 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; + +.body { + display: grid; + grid-template-columns: minmax(0, 1fr); + grid-template-rows: minmax(0, 1fr) max-content; + height: 100vh; + position: relative; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + grid-template-columns: 1.5fr 4fr; + } + + @include mix.dimensions("xl") { + grid-template-columns: 1fr 4fr; + } + } +} + +.header { + grid-column: 1; + grid-row: 1; + width: 100%; +} + +.main { + grid-column: 1; + grid-row: 1 / -1; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + grid-column: 2; + } + } +} + +.footer { + grid-column: 1; + grid-row: 2; + width: 100%; +} diff --git a/src/scss/layout/_header.scss b/src/scss/layout/_header.scss new file mode 100644 index 0000000..cbc1693 --- /dev/null +++ b/src/scss/layout/_header.scss @@ -0,0 +1,143 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; + +.header { + background: fun.get-var(color-bg-secondary); + overflow-y: auto; + padding: fun.get-var(spacing-md) + clamp(#{fun.get-var(spacing-md)}, 3vw, #{fun.get-var(spacing-lg)}); + scrollbar-color: fun.get-var(color-primary-light-opacity) + fun.get-var(color-bg-tertiary); + z-index: 5; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + box-shadow: 0 -1px 2px 0 fun.get-var(color-shadow); + } + } +} + +.branding { + margin-bottom: clamp( + #{fun.get-var(spacing-sm)}, + 3vw, + #{fun.get-var(spacing-md)} + ); + text-align: center; + + &__title { + font-family: fun.get-var(font-family-secondary); + font-size: clamp( + #{fun.get-var(font-size-2xl)}, + 5vw, + #{fun.get-var(font-size-3xl)} + ); + font-weight: 500; + margin: fun.get-var(spacing-xs) 0 fun.get-var(spacing-3xs); + } + + &__link { + background: linear-gradient( + to top, + fun.get-var(color-primary-light) fun.convert-px(5), + transparent fun.convert-px(5) + ) + center / 0 100% no-repeat; + text-decoration: none; + transition: all 0.5s ease-in-out 0s; + + &:hover, + &:focus { + background-size: 100% 100%; + } + + &:active { + background-size: 0 100%; + } + } + + &__description { + font-family: fun.get-var(font-family-secondary); + font-size: clamp( + #{fun.get-var(font-size-md)}, + 3vw, + #{fun.get-var(font-size-lg)} + ); + font-weight: 400; + letter-spacing: fun.convert-px(1); + margin: 0; + text-transform: uppercase; + } +} + +.logo { + margin: auto; + position: relative; + width: max-content; + + &__image { + backface-visibility: hidden; + border: fun.convert-px(3) solid fun.get-var(color-border-light); + border-radius: 50%; + box-shadow: 0 0 fun.convert-px(6) fun.convert-px(1) + fun.get-var(color-shadow-darker); + left: 0; + position: absolute; + top: 0; + width: 100%; + + &--back { + transform: rotateY(180deg); + } + } + + &__link { + display: block; + height: clamp(#{fun.convert-px(75)}, 15vmin, #{fun.convert-px(90)}); + transform-style: preserve-3d; + transition: all 0.6s linear 0s; + width: clamp(#{fun.convert-px(75)}, 15vmin, #{fun.convert-px(90)}); + + &:hover, + &:focus { + outline: none; + transform: rotateY(180deg); + } + + &:hover &, + &:focus & { + &__image { + &--front { + transform: none; + } + + &--back { + transform: rotateY(180deg); + } + } + } + + &:focus & { + &__image { + box-shadow: 0 0 fun.convert-px(6) fun.convert-px(1) + fun.get-var(color-shadow-dark), + 0 0 0 fun.convert-px(5) fun.get-var(color-primary-light-opacity); + outline: none; + } + } + + &:active & { + &__image { + box-shadow: 0 0 fun.convert-px(6) fun.convert-px(1) + fun.get-var(color-shadow-dark), + 0 0 0 fun.convert-px(7) fun.get-var(color-primary-light-opacity); + } + } + } + + &:hover & { + &__link { + transform: rotateY(180deg); + } + } +} diff --git a/src/scss/layout/_main.scss b/src/scss/layout/_main.scss new file mode 100644 index 0000000..8ab842b --- /dev/null +++ b/src/scss/layout/_main.scss @@ -0,0 +1,138 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/mixins" as mix; +@use "../abstracts/placeholders"; + +.main { + display: flex; + flex-flow: column nowrap; + height: calc(100% - #{fun.get-var(toolbar-height)}); + + @include mix.media("screen") { + @include mix.dimensions("lg") { + display: grid; + grid-template-columns: 5fr 2fr; + } + + @include mix.dimensions("xl") { + grid-template-columns: 4fr 1fr; + } + } +} + +// NoScript extension seems to replace noscript tag with a span. +.main > span, +.instructions, +noscript { + background: fun.get-var(color-bg); + padding: fun.get-var(spacing-md); + text-align: center; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + grid-column: 1 / -1; + } + } +} + +.instructions { + align-items: center; + display: flex; + justify-content: center; +} + +.legal-notice { + height: 100%; + overflow-y: auto; + padding: clamp(#{fun.get-var(spacing-md)}, 3vw, #{fun.get-var(spacing-lg)}); + scrollbar-color: fun.get-var(color-primary-light-opacity) + fun.get-var(color-bg-tertiary); + width: 100%; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + grid-column: 1 / -1; + } + } +} + +.project-preview { + background: fun.get-var(color-bg); + flex: 0 1 100%; + min-height: 0; + width: 100%; + + @include mix.media("screen") { + @include mix.dimensions("lg") { + height: 100%; + } + } + + iframe { + border: 0; + height: 100%; + width: 100%; + } +} + +.project-details { + background: fun.get-var(color-bg-secondary); + box-shadow: 0 -1px 2px 0 fun.get-var(color-shadow); + flex: 1 0 100%; + overflow-y: auto; + padding: fun.get-var(spacing-md); + scrollbar-color: fun.get-var(color-primary-light-opacity) + fun.get-var(color-bg-tertiary); + + @include mix.media("screen") { + @include mix.dimensions("lg") { + font-size: fun.get-var(font-size-md); + } + } + + &__description { + margin-bottom: fun.get-var(spacing-md); + white-space: pre-wrap; + } + + .list { + &--tech { + padding-left: fun.get-var(spacing-sm); + } + + &--repos { + @extend %flex-list; + + gap: fun.get-var(spacing-xs); + } + + &__link { + background-repeat: no-repeat; + background-size: contain; + box-shadow: 0 0 0 0 fun.get-var(color-shadow); + display: block; + height: fun.convert-px(50); + transition: transform 0.3s ease-in-out 0s, + box-shadow 0.15s ease-in-out 0.15s; + width: fun.convert-px(50); + + &--github { + background: url(#{fun.encode-svg('<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path style="fill:#1b1817;fill-opacity:1;opacity:1;stroke-width:6.55748" d="M0 0h100v100H0z"/><path d="M50.003 15.864C69.33 15.864 85 31.534 85 50.865c0 15.464-10.028 28.581-23.936 33.211-1.75.32-2.389-.76-2.389-1.689 0-.829.03-3.031.047-5.951 9.736 2.114 11.79-4.693 11.79-4.693 1.592-4.044 3.887-5.12 3.887-5.12 3.178-2.17-.241-2.127-.241-2.127-3.513.247-5.36 3.607-5.36 3.607-3.123 5.348-8.193 3.803-10.187 2.907-.318-2.26-1.22-3.803-2.222-4.677 7.772-.883 15.943-3.887 15.943-17.299 0-3.82-1.365-6.944-3.604-9.391.361-.886 1.563-4.444-.341-9.263 0 0-2.94-.941-9.626 3.588-2.791-.778-5.786-1.164-8.762-1.177-2.972.013-5.967.4-8.762 1.177-6.682-4.53-9.615-3.588-9.615-3.588-1.91 4.82-.71 8.377-.348 9.263-2.243 2.447-3.6 5.571-3.6 9.391 0 13.446 8.185 16.405 15.982 17.271-1.257 1.08-2.376 3.216-2.376 6.482 0 4.678.043 8.453.043 9.6 0 .937-.63 2.027-2.407 1.685C25.02 79.433 15 66.324 15 50.865c0-19.331 15.672-35.001 35.003-35.001" style="fill:#fff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:.999999"/></svg>')}); + } + + &--gitlab { + background: url(#{fun.encode-svg('<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path style="opacity:1;fill:#ccc;fill-opacity:1;stroke-width:7.26231" d="M0 0h100v100H0z"/><path class="st3" d="m49.998 82.237 12.895-39.668H37.121Z" style="fill:#e24329;stroke-width:1"/><path class="st4" d="M19.058 42.57 15.13 54.62a2.67 2.67 0 0 0 .966 2.984l33.9 24.632Z" style="fill:#fca326;stroke-width:1"/><path class="st3" d="M19.058 42.57H37.12l-7.774-23.89c-.398-1.222-2.132-1.222-2.544 0z" style="fill:#e24329;stroke-width:1"/><path class="st4" d="m80.956 42.57 3.914 12.05a2.67 2.67 0 0 1-.966 2.984L49.998 82.237Z" style="fill:#fca326;stroke-width:1"/><path class="st3" d="M80.956 42.57H62.894l7.759-23.89c.398-1.222 2.132-1.222 2.544 0z" style="fill:#e24329;stroke-width:1"/><path style="fill:#fc6d26;stroke-width:4.82321" class="st5" d="m50.017 82.237 30.94-39.667H62.893Zm-.019 0L19.058 42.57H37.12z"/></svg>')}); + } + + &:hover, + &:focus { + box-shadow: fun.convert-px(-1) fun.convert-px(1) fun.convert-px(4) + fun.convert-px(2) fun.get-var(color-shadow-light); + transform: scale(1.15); + } + + &:active { + opacity: 1; + } + } + } +} diff --git a/src/scss/layout/_nav.scss b/src/scss/layout/_nav.scss new file mode 100644 index 0000000..98e4cb5 --- /dev/null +++ b/src/scss/layout/_nav.scss @@ -0,0 +1,70 @@ +@use "../abstracts/functions" as fun; +@use "../abstracts/placeholders"; + +.nav { + text-align: center; + + &__label { + font-weight: 600; + } + + &__list { + @extend %reset-list; + + .btn { + width: 100%; + } + } + + &:not(&--footer) &__item { + margin: fun.get-var(spacing-2xs) 0; + } + + &:not(&--footer) &__link { + background-image: linear-gradient( + to left, + #{fun.get-var(color-bg)} 0, + #{fun.get-var(color-bg)} 50%, + #{fun.get-var(color-primary)} 50% + ); + background-position: 100% 0; + background-size: 200% 100%; + border: fun.convert-px(3) solid fun.get-var(color-border); + border-radius: fun.convert-px(50); + display: block; + font-weight: 600; + margin: auto; + padding: fun.get-var(spacing-3xs); + position: relative; + text-decoration: none; + transition: all 0.4s ease-in-out 0s; + width: 75%; + + &:hover, + &:focus { + background-position: 0 0; + color: fun.get-var(color-fg-inverted); + } + + &:active { + background-position: 100% 0; + color: fun.get-var(color-primary-dark); + text-decoration: fun.convert-px(1) solid underline; + } + + &--selected { + background: fun.get-var(color-primary-dark); + box-shadow: inset 0 0 0 4px fun.get-var(color-bg); + color: fun.get-var(color-fg-inverted); + + &:hover, + &:focus { + background: fun.get-var(color-primary-light); + } + } + } + + .btn { + margin: auto; + } +} diff --git a/src/scss/layout/_toolbar.scss b/src/scss/layout/_toolbar.scss new file mode 100644 index 0000000..00e2bd7 --- /dev/null +++ b/src/scss/layout/_toolbar.scss @@ -0,0 +1,34 @@ +@use "../abstracts/functions" as fun; + +.toolbar { + align-items: center; + background: fun.get-var(color-primary); + bottom: 0; + box-shadow: 0 -1px 2px 0 fun.get-var(color-shadow-dark); + color: fun.get-var(color-fg-inverted); + display: flex; + flex-flow: row nowrap; + gap: fun.get-var(spacing-xs); + height: fun.get-var(toolbar-height); + justify-content: center; + left: 0; + padding: 0 fun.get-var(spacing-sm); + position: absolute; + right: 0; + z-index: 2; + + & > &__options { + background: fun.get-var(color-primary); + color: fun.get-var(color-fg-inverted); + font-size: fun.get-var(font-size-sm); + height: 85%; + line-height: inherit; + padding: 0 fun.get-var(spacing-xs); + + &:hover, + &:focus { + background: fun.get-var(color-bg); + color: fun.get-var(color-primary); + } + } +} diff --git a/src/scss/style.scss b/src/scss/style.scss new file mode 100644 index 0000000..96c8fe5 --- /dev/null +++ b/src/scss/style.scss @@ -0,0 +1,40 @@ +@charset 'utf-8'; + +/** + * 1.0 Vendors + * + * Import each files separately to define vendors styles order. + */ +@use "modern-normalize"; + +/** + * 2.0 Base + * + * Define some standard styles and CSS variables (colors, fonts...). + */ +@use "base/base"; +@use "base/animations"; +@use "base/colors"; +@use "base/fonts"; +@use "base/helpers"; +@use "base/spacings"; +@use "base/typography"; + +/** + * 3.0 Layout + * + * Define website layout. + */ +@use "layout/grid"; +@use "layout/header"; +@use "layout/main"; +@use "layout/footer"; +@use "layout/toolbar"; +@use "layout/nav"; + +/** +* 4.0 Components +* +* Define styles for all kind of specific modules like buttons, widgets... +*/ +@use "components/buttons"; |
