[{"data":1,"prerenderedAt":1264},["ShallowReactive",2],{"blog-list":3},[4,299,863,977],{"id":5,"title":6,"ancienne_url":7,"body":8,"date":287,"description":288,"extension":289,"meta":290,"navigation":291,"path":292,"seo":293,"stem":294,"tags":295,"__hash__":298},"blog\u002Fblog\u002Fscreencast-wayland-sway.md","Screencast \u002F partage d'écran avec Wayland et Sway","\u002Fdivers\u002Fscreencast-avec-wayland-et-sway\u002F",{"type":9,"value":10,"toc":276},"minimark",[11,23,32,41,55,60,71,76,79,86,127,131,134,153,157,166,185,191,195,204,211,215,223,227,253,257,260,269,272],[12,13,14,15,22],"p",{},"En ces temps de confinement, les besoins et envies de partage d'écran sous\nWayland sont d'actualité, et c'est l'occasion de s'y re-pencher. Je tourne avec\nGentoo et ",[16,17,21],"a",{"href":18,"rel":19},"https:\u002F\u002Fswaywm.org\u002F",[20],"nofollow","Sway"," (et c'est génial, rapide et super\nefficace). Bref, j'ai besoin de partager une appli Python \u002F wxPython pour une\ndémo \u002F réunion dans deux semaines.",[12,24,25,26,31],{},"Pour savoir où vous en êtes, il y a une page de test pour le partage d'écran avec\nvotre navigateur : ",[16,27,30],{"href":28,"rel":29},"https:\u002F\u002Fmozilla.github.io\u002Fwebrtc-landing\u002Fgum_test.html",[20],"gum_test.html",".",[12,33,34,35,40],{},"Le navigateur est mon choix par défaut pour la visio sous Linux, parce que j'ai\nrarement envie d'installer les applis dédiées. Si ça marche avec le lien\nci-dessus, ça devrait marcher avec ",[16,36,39],{"href":37,"rel":38},"https:\u002F\u002Fjitsi.org\u002F",[20],"Jitsi"," ou Zoom (dont je\nne souhaite vraiment pas installer l'appli !). Hélas, la réunion sera sous\nGoToMeeting, donc il y a un facteur surprise, mais ça doit être aussi du WebRTC,\nn'est-ce pas :)",[12,42,43,44,49,50,54],{},"La marche à suivre est à peu près tracée\n",[16,45,48],{"href":46,"rel":47},"https:\u002F\u002Fwww.reddit.com\u002Fr\u002Fswaywm\u002Fcomments\u002Ffq1qoe\u002Fhow_to_use_xdgdesktopportalwlr_to_share_the_screen\u002F",[20],"ici",".\nEt d'après l'auteur, ça marche, ô joie ! Après cette lueur de joie, quelques\nheures de sueurs, de la réussite et un peu de désillusion, j'ai conclu avec un\ncompromis puisque je n'aurai besoin de la fonctionnalité que quelques instants…\n(Divulgâchage : ça implique ",[51,52,53],"code",{},"Xwayland",".)",[56,57,59],"h2",{"id":58},"le-fond","Le fond",[12,61,62,63,66,67,70],{},"Attention : j'ai eu quelques crashs plus ou moins violents sur la route, dont\n",[51,64,65],{},"sway","… Les instructions ne fonctionneront probablement pas en les copiant\ndirectement car il manque quelques ",[51,68,69],{},"cd"," ou autres.",[72,73,75],"h3",{"id":74},"pipewire-03-git","Pipewire 0.3 (git)",[12,77,78],{},"« PipeWire is a server and user space API to deal with multimedia pipelines. »",[12,80,81,82,85],{},"C'est lui qui va transmettre le flux vidéo entre la capture au niveau Wayland et\nle navigateur… Right ? Gentoo n'a que la version 0.2 dans les repos, et ça ne\nsuffit pas pour compiler ",[51,83,84],{},"xdg-desktop-portal-wlr"," !",[87,88,93],"pre",{"className":89,"code":90,"language":91,"meta":92,"style":92},"language-zsh shiki shiki-themes github-light github-dark-default","git clone https:\u002F\u002Fgithub.com\u002FPipeWire\u002Fpipewire.git\n# [...]\nmeson build -Djack=false -Dvulkan=false -Dpipewire-jack=false --prefix=\u002Fusr\u002F --libdir=\u002Fusr\u002Flib\u002F\nsudo ninja -C build install\nsystemctl --user start pipewire.service\n","zsh","",[51,94,95,103,109,115,121],{"__ignoreMap":92},[96,97,100],"span",{"class":98,"line":99},"line",1,[96,101,102],{},"git clone https:\u002F\u002Fgithub.com\u002FPipeWire\u002Fpipewire.git\n",[96,104,106],{"class":98,"line":105},2,[96,107,108],{},"# [...]\n",[96,110,112],{"class":98,"line":111},3,[96,113,114],{},"meson build -Djack=false -Dvulkan=false -Dpipewire-jack=false --prefix=\u002Fusr\u002F --libdir=\u002Fusr\u002Flib\u002F\n",[96,116,118],{"class":98,"line":117},4,[96,119,120],{},"sudo ninja -C build install\n",[96,122,124],{"class":98,"line":123},5,[96,125,126],{},"systemctl --user start pipewire.service\n",[72,128,130],{"id":129},"xdg-desktop-portal-git","xdg-desktop-portal (git)",[12,132,133],{},"« Desktop integration portal » — vous ouvre les portes du « bureau » par le biais\nde requêtes D-Bus.",[87,135,137],{"className":89,"code":136,"language":91,"meta":92,"style":92},"git clone https:\u002F\u002Fgithub.com\u002Fflatpak\u002Fxdg-desktop-portal.git\n# [...]\nsystemctl --user start xdg-desktop-portal.service\n",[51,138,139,144,148],{"__ignoreMap":92},[96,140,141],{"class":98,"line":99},[96,142,143],{},"git clone https:\u002F\u002Fgithub.com\u002Fflatpak\u002Fxdg-desktop-portal.git\n",[96,145,146],{"class":98,"line":105},[96,147,108],{},[96,149,150],{"class":98,"line":111},[96,151,152],{},"systemctl --user start xdg-desktop-portal.service\n",[72,154,156],{"id":155},"xdg-desktop-portal-wlr-git","xdg-desktop-portal-wlr (git)",[12,158,159,160,163,164,31],{},"« xdg-desktop-portal backend for wlroots » — implémente le portail pour\n",[51,161,162],{},"wlroots",", le compositeur Wayland de ",[51,165,65],{},[87,167,169],{"className":89,"code":168,"language":91,"meta":92,"style":92},"git clone https:\u002F\u002Fgithub.com\u002Femersion\u002Fxdg-desktop-portal-wlr.git\n# [...]\nxdg-desktop-portal-wlr -lTRACE -p BGRx\n",[51,170,171,176,180],{"__ignoreMap":92},[96,172,173],{"class":98,"line":99},[96,174,175],{},"git clone https:\u002F\u002Fgithub.com\u002Femersion\u002Fxdg-desktop-portal-wlr.git\n",[96,177,178],{"class":98,"line":105},[96,179,108],{},[96,181,182],{"class":98,"line":111},[96,183,184],{},"xdg-desktop-portal-wlr -lTRACE -p BGRx\n",[12,186,187,190],{},[51,188,189],{},"-lTRACE"," pour le debug.",[72,192,194],{"id":193},"etcenvironment","\u002Fetc\u002Fenvironment",[87,196,198],{"className":89,"code":197,"language":91,"meta":92,"style":92},"XDG_CURRENT_DESKTOP=sway\n",[51,199,200],{"__ignoreMap":92},[96,201,202],{"class":98,"line":99},[96,203,197],{},[12,205,206,207,210],{},"Est nécessaire pour le lancement du portail. Attention, ça casse potentiellement\nla barre d'icônes ",[51,208,209],{},"libappindicator"," dans Waybar.",[72,212,214],{"id":213},"tester-avec-castpy","Tester avec cast.py",[12,216,217,218,222],{},"Le script est ici (Python) : ",[16,219,220],{"href":220,"rel":221},"https:\u002F\u002Fgitlab.gnome.org\u002Fsnippets\u002F19",[20],". Et là,\nmiracle, si tout va bien, on voit son écran. Il faudra peut-être redémarrer avant\nque ça fonctionne. Pour moi, ça ne marche pas !",[56,224,226],{"id":225},"la-forme","La forme",[12,228,229,230,233,234,237,238,241,242,245,246,249,250,252],{},"Si vous pensiez vous en être tiré, eh bien soit c'est le cas et vous pouvez\ncaster un de vos écrans, soit vous êtes comme moi et maintenant, il faut un\nnavigateur (ou une application tierce) natif Wayland et qui utilise ",[51,231,232],{},"pipewire",".\nEt là, misère. Ce n'est pas le cas de mon fidèle ",[51,235,236],{},"qutebrowser",". Ni de\n",[51,239,240],{},"firefox-bin"," (Wayland mais pas pipewire) ou ",[51,243,244],{},"google-chrome-stable"," (pipewire\nmais Xwayland). En fait il faut un Firefox patché à la Fedora ou un ",[51,247,248],{},"chromium","\ncompilé avec Wayland et pipewire. Comme mon temps de compilation est déjà\nabusivement long pour ",[51,251,236],{}," (3 h pour le qtwebengine), je n'ai pas du tout\nenvie de compiler chromium ou firefox en plus !",[56,254,256],{"id":255},"la-solution-qui-nen-est-pas-vraiment-une","La solution qui n'en est pas vraiment une…",[12,258,259],{},"Parmi tous les tests effectués, je me suis retrouvé à un moment à pouvoir\nsélectionner une fenêtre à caster : celle de Google Chrome. Celui-ci est un des\nrares énergumènes qui tourne sous Xwayland. Du coup, j'essaie : si je lance mon\nappli en mode de compatibilité Xwayland, sera-t-elle elle aussi visible dans ce\nchoix de fenêtres ? Eh oui !",[87,261,263],{"className":89,"code":262,"language":91,"meta":92,"style":92},"GDK_BACKEND=x11 python __main__.py\n",[51,264,265],{"__ignoreMap":92},[96,266,267],{"class":98,"line":99},[96,268,262],{},[12,270,271],{},"Ça marche même avec Firefox pourtant lancé en mode Wayland. Et bien ça ira pour\ncette fois : on peut choisir une application Xwayland dans le protocole WebRTC.\nPeut-être qu'en regardant comment fonctionne le VNC sous Wayland (wayvnc, article\nà suivre ?), je trouverai quelque chose de sympa :)",[273,274,275],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":92,"searchDepth":105,"depth":105,"links":277},[278,285,286],{"id":58,"depth":105,"text":59,"children":279},[280,281,282,283,284],{"id":74,"depth":111,"text":75},{"id":129,"depth":111,"text":130},{"id":155,"depth":111,"text":156},{"id":193,"depth":111,"text":194},{"id":213,"depth":111,"text":214},{"id":225,"depth":105,"text":226},{"id":255,"depth":105,"text":256},"2020-04-12","Partager son écran sous Wayland et Sway pour une visio dans le navigateur : pipewire, xdg-desktop-portal-wlr, et un compromis via Xwayland.","md",{},true,"\u002Fblog\u002Fscreencast-wayland-sway",{"title":6,"description":288},"blog\u002Fscreencast-wayland-sway",[65,296,297],"wayland","linux","RV_fBUzApEUe8_31K1Wi9mM6OwQc3uc1TXnh8FcjgXg",{"id":300,"title":301,"ancienne_url":302,"body":303,"date":854,"description":855,"extension":289,"meta":856,"navigation":291,"path":857,"seo":858,"stem":859,"tags":860,"__hash__":862},"blog\u002Fblog\u002Ftheme-sombre-scss.md","Avoir le choix d'un thème sombre sur son site (SCSS et JavaScript)","\u002Fdivers\u002Ftheme_sombre_scss\u002F",{"type":9,"value":304,"toc":850},[305,311,314,321,347,370,374,377,386,445,453,621,626,740,751,829,833,847],[306,307,308],"blockquote",{},[12,309,310],{},"Billet d'archive (2020), rédigé à l'époque du site sous Hugo. Le principe reste\nvalable ; le site actuel (Nuxt) utilise la même mécanique de variables CSS et\nde préférence système.",[12,312,313],{},"Étonnamment, je préfère les thèmes sombres, sûrement une dérive des journées\npassées sur une flotte de terminaux (et des soirées ?). Du coup, mon site web\nétait aussi en sombre. Mais tout le monde n'est pas fan, et le noir peut être mal\nperçu. Alors, pourquoi ne pas donner le choix au visiteur ?",[12,315,316],{},[317,318],"img",{"alt":319,"src":320},"Le site avec un thème sombre ou clair","\u002Fimgs\u002Ftheme_sombre_example.png",[12,322,323,324,329,330,334,335,338,339,342,343,346],{},"Sur cette piste, il existe plusieurs voies. J'ai choisi de combiner le SCSS déjà\ninclus dans le ",[16,325,328],{"href":326,"rel":327},"https:\u002F\u002Fthemes.gohugo.io\u002Fhermit\u002F",[20],"thème Hugo",", des ",[331,332,333],"strong",{},"variables\nCSS"," et des ",[331,336,337],{},"attributs de page"," pour une mise à jour instantanée, du\n",[331,340,341],{},"JavaScript"," et la requête de média CSS ",[51,344,345],{},"prefers-color-scheme",". On obtient une\nsolution dont le thème :",[348,349,350,364,367],"ul",{},[351,352,353,354,357,358,363],"li",{},"est adapté aux préférences générales ",[51,355,356],{},"clair\u002Fsombre"," de l'utilisateur, si c'est\n",[16,359,362],{"href":360,"rel":361},"https:\u002F\u002Fcaniuse.com\u002F#feat=prefers-color-scheme",[20],"supporté par le navigateur"," ;",[351,365,366],{},"est modifiable localement par l'utilisateur avec un bouton ;",[351,368,369],{},"dont le choix est stocké pour les visites suivantes.",[72,371,373],{"id":372},"concrètement","Concrètement",[12,375,376],{},"En gardant la structure de mon site en Hugo, cela donnait :",[348,378,379],{},[351,380,381,382,385],{},"dans ",[51,383,384],{},"\u002Fassets\u002Fscss\u002F_predefined.scss",", on définit les couleurs :",[87,387,391],{"className":388,"code":389,"language":390,"meta":92,"style":92},"language-scss shiki shiki-themes github-light github-dark-default","$text: #000000;\n$background: #ffffff;\n$darkmode-text: #ffffff;\n$darkmode-background: #000000;\n","scss",[51,392,393,411,423,434],{"__ignoreMap":92},[96,394,395,399,403,407],{"class":98,"line":99},[96,396,398],{"class":397},"sjlk-","$text",[96,400,402],{"class":401},"sfpNf",": ",[96,404,406],{"class":405},"sPgVT","#000000",[96,408,410],{"class":409},"szmH1",";\n",[96,412,413,416,418,421],{"class":98,"line":105},[96,414,415],{"class":397},"$background",[96,417,402],{"class":401},[96,419,420],{"class":405},"#ffffff",[96,422,410],{"class":409},[96,424,425,428,430,432],{"class":98,"line":111},[96,426,427],{"class":397},"$darkmode-text",[96,429,402],{"class":401},[96,431,420],{"class":405},[96,433,410],{"class":409},[96,435,436,439,441,443],{"class":98,"line":117},[96,437,438],{"class":397},"$darkmode-background",[96,440,402],{"class":401},[96,442,406],{"class":405},[96,444,410],{"class":409},[348,446,447],{},[351,448,381,449,452],{},[51,450,451],{},"\u002Fassets\u002Fscss\u002Fstyle.scss",", on définit les variables CSS et on les\napplique là où il faut :",[87,454,456],{"className":388,"code":455,"language":390,"meta":92,"style":92},"[data-theme=\"light\"] {\n  --background: #{$background};\n  --text: #{$text};\n}\n\n[data-theme=\"dark\"] {\n  --background: #{$darkmode-background};\n  --text: #{$darkmode-text};\n}\n\nbody {\n  color: var(--text);\n  background: var(--background);\n}\n",[51,457,458,483,495,507,512,517,535,547,559,564,569,579,599,616],{"__ignoreMap":92},[96,459,460,463,467,471,475,478,480],{"class":98,"line":99},[96,461,462],{"class":409},"[",[96,464,466],{"class":465},"syv4q","data-theme",[96,468,470],{"class":469},"sDgYj","=",[96,472,474],{"class":473},"sNbzA","\"",[96,476,477],{"class":409},"light",[96,479,474],{"class":473},[96,481,482],{"class":409},"] {\n",[96,484,485,488,490,493],{"class":98,"line":105},[96,486,487],{"class":397},"  --background",[96,489,402],{"class":409},[96,491,492],{"class":397},"#{$background}",[96,494,410],{"class":409},[96,496,497,500,502,505],{"class":98,"line":111},[96,498,499],{"class":397},"  --text",[96,501,402],{"class":409},[96,503,504],{"class":397},"#{$text}",[96,506,410],{"class":409},[96,508,509],{"class":98,"line":117},[96,510,511],{"class":409},"}\n",[96,513,514],{"class":98,"line":123},[96,515,516],{"emptyLinePlaceholder":291},"\n",[96,518,520,522,524,526,528,531,533],{"class":98,"line":519},6,[96,521,462],{"class":409},[96,523,466],{"class":465},[96,525,470],{"class":469},[96,527,474],{"class":473},[96,529,530],{"class":409},"dark",[96,532,474],{"class":473},[96,534,482],{"class":409},[96,536,538,540,542,545],{"class":98,"line":537},7,[96,539,487],{"class":397},[96,541,402],{"class":409},[96,543,544],{"class":397},"#{$darkmode-background}",[96,546,410],{"class":409},[96,548,550,552,554,557],{"class":98,"line":549},8,[96,551,499],{"class":397},[96,553,402],{"class":409},[96,555,556],{"class":397},"#{$darkmode-text}",[96,558,410],{"class":409},[96,560,562],{"class":98,"line":561},9,[96,563,511],{"class":409},[96,565,567],{"class":98,"line":566},10,[96,568,516],{"emptyLinePlaceholder":291},[96,570,572,576],{"class":98,"line":571},11,[96,573,575],{"class":574},"sXQ1o","body",[96,577,578],{"class":409}," {\n",[96,580,582,585,587,590,593,596],{"class":98,"line":581},12,[96,583,584],{"class":405},"  color",[96,586,402],{"class":409},[96,588,589],{"class":405},"var",[96,591,592],{"class":409},"(",[96,594,595],{"class":397},"--text",[96,597,598],{"class":409},");\n",[96,600,602,605,607,609,611,614],{"class":98,"line":601},13,[96,603,604],{"class":405},"  background",[96,606,402],{"class":409},[96,608,589],{"class":405},[96,610,592],{"class":409},[96,612,613],{"class":397},"--background",[96,615,598],{"class":409},[96,617,619],{"class":98,"line":618},14,[96,620,511],{"class":409},[348,622,623],{},[351,624,625],{},"la checkbox à insérer où l'on veut :",[87,627,631],{"className":628,"code":629,"language":630,"meta":92,"style":92},"language-html shiki shiki-themes github-light github-dark-default","\u003Cdiv class=\"theme-switch-wrapper\">\n  \u003Clabel class=\"theme-switch\" for=\"checkbox\">\n    \u003Cinput type=\"checkbox\" id=\"checkbox\" \u002F>\n    \u003Cdiv class=\"slider round\">\u003C\u002Fdiv>\n  \u003C\u002Flabel>\n\u003C\u002Fdiv>\n","html",[51,632,633,652,677,702,722,731],{"__ignoreMap":92},[96,634,635,638,641,644,646,649],{"class":98,"line":99},[96,636,637],{"class":409},"\u003C",[96,639,640],{"class":574},"div",[96,642,643],{"class":465}," class",[96,645,470],{"class":409},[96,647,648],{"class":473},"\"theme-switch-wrapper\"",[96,650,651],{"class":409},">\n",[96,653,654,657,660,662,664,667,670,672,675],{"class":98,"line":105},[96,655,656],{"class":409},"  \u003C",[96,658,659],{"class":574},"label",[96,661,643],{"class":465},[96,663,470],{"class":409},[96,665,666],{"class":473},"\"theme-switch\"",[96,668,669],{"class":465}," for",[96,671,470],{"class":409},[96,673,674],{"class":473},"\"checkbox\"",[96,676,651],{"class":409},[96,678,679,682,685,688,690,692,695,697,699],{"class":98,"line":111},[96,680,681],{"class":409},"    \u003C",[96,683,684],{"class":574},"input",[96,686,687],{"class":465}," type",[96,689,470],{"class":409},[96,691,674],{"class":473},[96,693,694],{"class":465}," id",[96,696,470],{"class":409},[96,698,674],{"class":473},[96,700,701],{"class":409}," \u002F>\n",[96,703,704,706,708,710,712,715,718,720],{"class":98,"line":117},[96,705,681],{"class":409},[96,707,640],{"class":574},[96,709,643],{"class":465},[96,711,470],{"class":409},[96,713,714],{"class":473},"\"slider round\"",[96,716,717],{"class":409},">\u003C\u002F",[96,719,640],{"class":574},[96,721,651],{"class":409},[96,723,724,727,729],{"class":98,"line":123},[96,725,726],{"class":409},"  \u003C\u002F",[96,728,659],{"class":574},[96,730,651],{"class":409},[96,732,733,736,738],{"class":98,"line":519},[96,734,735],{"class":409},"\u003C\u002F",[96,737,640],{"class":574},[96,739,651],{"class":409},[348,741,742],{},[351,743,744,745,747,748,750],{},"côté JavaScript, on change le curseur et l'attribut de page ",[51,746,466],{},",\net on écoute ",[51,749,345],{}," :",[87,752,756],{"className":753,"code":754,"language":755,"meta":92,"style":92},"language-javascript shiki shiki-themes github-light github-dark-default","const toggleSwitch = document.querySelector('.theme-switch input[type=\"checkbox\"]');\nconst currentTheme = localStorage.getItem('theme');\n\nif (currentTheme) {\n  document.documentElement.setAttribute('data-theme', currentTheme);\n  toggleSwitch.checked = currentTheme === 'dark';\n}\n\nfunction switchTheme(e) {\n  const theme = e.target.checked ? 'dark' : 'light';\n  document.documentElement.setAttribute('data-theme', theme);\n  localStorage.setItem('theme', theme);\n}\n\ntoggleSwitch.addEventListener('change', switchTheme, false);\n","javascript",[51,757,758,763,768,772,777,782,787,791,795,800,805,810,815,819,823],{"__ignoreMap":92},[96,759,760],{"class":98,"line":99},[96,761,762],{},"const toggleSwitch = document.querySelector('.theme-switch input[type=\"checkbox\"]');\n",[96,764,765],{"class":98,"line":105},[96,766,767],{},"const currentTheme = localStorage.getItem('theme');\n",[96,769,770],{"class":98,"line":111},[96,771,516],{"emptyLinePlaceholder":291},[96,773,774],{"class":98,"line":117},[96,775,776],{},"if (currentTheme) {\n",[96,778,779],{"class":98,"line":123},[96,780,781],{},"  document.documentElement.setAttribute('data-theme', currentTheme);\n",[96,783,784],{"class":98,"line":519},[96,785,786],{},"  toggleSwitch.checked = currentTheme === 'dark';\n",[96,788,789],{"class":98,"line":537},[96,790,511],{},[96,792,793],{"class":98,"line":549},[96,794,516],{"emptyLinePlaceholder":291},[96,796,797],{"class":98,"line":561},[96,798,799],{},"function switchTheme(e) {\n",[96,801,802],{"class":98,"line":566},[96,803,804],{},"  const theme = e.target.checked ? 'dark' : 'light';\n",[96,806,807],{"class":98,"line":571},[96,808,809],{},"  document.documentElement.setAttribute('data-theme', theme);\n",[96,811,812],{"class":98,"line":581},[96,813,814],{},"  localStorage.setItem('theme', theme);\n",[96,816,817],{"class":98,"line":601},[96,818,511],{},[96,820,821],{"class":98,"line":618},[96,822,516],{"emptyLinePlaceholder":291},[96,824,826],{"class":98,"line":825},15,[96,827,828],{},"toggleSwitch.addEventListener('change', switchTheme, false);\n",[72,830,832],{"id":831},"références","Références",[348,834,835,841],{},[351,836,837],{},[16,838,839],{"href":839,"rel":840},"https:\u002F\u002Fdev.to\u002Fananyaneogi\u002Fcreate-a-dark-light-mode-switch-with-css-variables-34l8",[20],[351,842,843],{},[16,844,845],{"href":845,"rel":846},"https:\u002F\u002Fmedium.com\u002F@jonas_duri\u002Fenable-dark-mode-with-css-variables-and-javascript-today-66cedd3d7845",[20],[273,848,849],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sjlk-, html code.shiki .sjlk-{--shiki-default:#E36209;--shiki-dark:#FFA657}html pre.shiki code .sfpNf, html code.shiki .sfpNf{--shiki-default:#24292E;--shiki-dark:#FFA657}html pre.shiki code .sPgVT, html code.shiki .sPgVT{--shiki-default:#005CC5;--shiki-dark:#79C0FF}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}html pre.shiki code .syv4q, html code.shiki .syv4q{--shiki-default:#6F42C1;--shiki-dark:#79C0FF}html pre.shiki code .sDgYj, html code.shiki .sDgYj{--shiki-default:#D73A49;--shiki-dark:#FF7B72}html pre.shiki code .sNbzA, html code.shiki .sNbzA{--shiki-default:#032F62;--shiki-dark:#A5D6FF}html pre.shiki code .sXQ1o, html code.shiki .sXQ1o{--shiki-default:#22863A;--shiki-dark:#7EE787}",{"title":92,"searchDepth":105,"depth":105,"links":851},[852,853],{"id":372,"depth":111,"text":373},{"id":831,"depth":111,"text":832},"2020-01-08","Donner au visiteur le choix entre thème clair et sombre : variables CSS, prefers-color-scheme, un peu de JavaScript et un choix mémorisé.",{},"\u002Fblog\u002Ftheme-sombre-scss",{"title":301,"description":855},"blog\u002Ftheme-sombre-scss",[51,861],"hugo","km71SYYT8YL0D68Q-ccP02j9OuShdQgvf3d_YX-lLcc",{"id":864,"title":865,"ancienne_url":866,"body":867,"date":969,"description":970,"extension":289,"meta":971,"navigation":291,"path":972,"seo":973,"stem":974,"tags":975,"__hash__":976},"blog\u002Fblog\u002Fmaj-hugo.md","Mise à jour Hugo > 0.60 et HTML brut","\u002Fdivers\u002Fmaj_hugo\u002F",{"type":9,"value":868,"toc":967},[869,874,897,900,927,938,954,957,964],[306,870,871],{},[12,872,873],{},"Billet d'archive (2020), rédigé à l'époque du site sous Hugo. Le site tourne\ndésormais sous Nuxt.",[12,875,876,877,882,883,886,887,892,893,896],{},"Gentoo venait de passer à ",[16,878,881],{"href":879,"rel":880},"https:\u002F\u002Fpackages.gentoo.org\u002Fpackages\u002Fwww-apps\u002Fhugo",[20],"Hugo 0.62",",\nla première version supérieure à ",[331,884,885],{},"0.60"," il me semble. Du coup, des parties du\nsite n'apparaissaient plus. Depuis 0.60, le HTML brut est\n",[16,888,891],{"href":889,"rel":890},"https:\u002F\u002Fgohugo.io\u002Fnews\u002F0.60.0-relnotes",[20],"désactivé par défaut",", suite à un\nchangement du moteur de traitement du Markdown. On retrouvait donc de petits\n",[51,894,895],{},"\u003C!-- raw HTML omitted -->"," dans la source de la page, à la place du contenu.",[12,898,899],{},"La solution proposée est d'annuler cette mesure de sécurité, si on a beaucoup de\nHTML brut dans son site. On peut rajouter dans le fichier de configuration :",[87,901,905],{"className":902,"code":903,"language":904,"meta":92,"style":92},"language-toml shiki shiki-themes github-light github-dark-default","[markup]\n  [markup.goldmark]\n    [markup.goldmark.renderer]\n      unsafe = true\n","toml",[51,906,907,912,917,922],{"__ignoreMap":92},[96,908,909],{"class":98,"line":99},[96,910,911],{},"[markup]\n",[96,913,914],{"class":98,"line":105},[96,915,916],{},"  [markup.goldmark]\n",[96,918,919],{"class":98,"line":111},[96,920,921],{},"    [markup.goldmark.renderer]\n",[96,923,924],{"class":98,"line":117},[96,925,926],{},"      unsafe = true\n",[12,928,929,930,934,935,750],{},"Pour ma part, n'ayant alors que très peu de HTML brut, c'était l'occasion de\ntester la création d'un ",[931,932,933],"em",{},"shortcode",". Dans un fichier ",[51,936,937],{},"layout\u002Fshortcodes\u002Frawhtml.html",[87,939,941],{"className":628,"code":940,"language":630,"meta":92,"style":92},"\u003C!-- raw html -->\n{{ .Inner }}\n",[51,942,943,949],{"__ignoreMap":92},[96,944,945],{"class":98,"line":99},[96,946,948],{"class":947},"sPyeA","\u003C!-- raw html -->\n",[96,950,951],{"class":98,"line":105},[96,952,953],{"class":409},"{{ .Inner }}\n",[12,955,956],{},"On peut alors insérer du HTML au besoin, par exemple pour un e-mail encodé.",[12,958,959,960,31],{},"Avec le recul, cette astuce d'obfuscation JavaScript de l'adresse e-mail n'a plus\nlieu d'être : le site est aujourd'hui en Nuxt et l'adresse est simplement\n",[16,961,963],{"href":962},"mailto:jeremy@tezoi.com","jeremy@tezoi.com",[273,965,966],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sPyeA, html code.shiki .sPyeA{--shiki-default:#6A737D;--shiki-dark:#8B949E}html pre.shiki code .szmH1, html code.shiki .szmH1{--shiki-default:#24292E;--shiki-dark:#E6EDF3}",{"title":92,"searchDepth":105,"depth":105,"links":968},[],"2020-01-07","Depuis Hugo 0.60, le HTML brut est désactivé par défaut dans le Markdown. Des morceaux de page disparaissaient, remplacés par des « raw HTML omitted ».",{},"\u002Fblog\u002Fmaj-hugo",{"title":865,"description":970},"blog\u002Fmaj-hugo",[51,861],"zE8dzVE8yxlbfU2LVLOY5ys2UvAPfD5JOYqIz0Z_4Ic",{"id":978,"title":979,"ancienne_url":980,"body":981,"date":1254,"description":1255,"extension":289,"meta":1256,"navigation":291,"path":1257,"seo":1258,"stem":1259,"tags":1260,"__hash__":1263},"blog\u002Fblog\u002Fpain-au-levain.md","Pain au levain en moule","\u002Fdivers\u002Fpain\u002F",{"type":9,"value":982,"toc":1239},[983,991,994,1002,1008,1011,1015,1018,1021,1024,1028,1031,1045,1048,1051,1055,1061,1067,1069,1073,1076,1080,1083,1094,1098,1101,1115,1118,1136,1143,1147,1150,1154,1157,1163,1167,1170,1173,1187,1190,1196,1200,1203,1209,1211,1215,1236],[12,984,985],{},[317,986],{"alt":987,"height":988,"src":989,"width":990},"Pain au levain",3024,"\u002Fpain\u002Fimgs\u002Ftitre.jpg",4032,[12,992,993],{},"La recette de base pour faire un pain au levain cuit en moule n'est ni complexe,\nni trop gourmande en temps : un volume de levain, deux volumes d'eau, trois\nvolumes de farine, mélanger, faire lever, mettre en moule, faire lever, cuire,\ndéguster. Même s'il y a beaucoup d'explications et de variations, c'est un\nprocessus simple, demandant uniquement un peu d'observation et d'attention.",[348,995,996,999],{},[351,997,998],{},"Temps d'action : 20 minutes",[351,1000,1001],{},"Temps total : 6 h → plusieurs jours",[12,1003,1004],{},[16,1005,1007],{"href":1006},"\u002Fpain\u002Fpain.pdf","Télécharger le PDF",[1009,1010],"hr",{},[56,1012,1014],{"id":1013},"le-levain","Le levain",[12,1016,1017],{},"On peut récupérer un peu de levain déjà en forme ou le créer en une semaine, à\npartir de farine et d'eau. Un bocal en verre avec couvercle qui se visse ou avec\nun joint fera l'affaire de contenant.",[12,1019,1020],{},"Le levain se nourrit de farine et d'eau. Les bactéries transforment la farine et\nproduisent des saveurs et du gaz. Le levain va monter, gonfler sous l'effet de la\nfermentation. Après un certain délai, il existe un moment pour lequel l'activité\ndes bactéries est maximale et la hauteur du levain dans le bocal est maximale.",[12,1022,1023],{},"Il est possible de marquer le niveau initial sur le bocal lors du nourrissage. On\nobserve alors bien l'augmentation de volume. Un levain qui arrive au maximum\n6-12 h après avoir été nourri est en forme : c'est le moment idéal pour\nl'utiliser. Passé ce délai, les bactéries ont faim, les bulles s'échappent et le\nlevain retombe et s'acidifie.",[72,1025,1027],{"id":1026},"genèse","Genèse",[12,1029,1030],{},"Cette étape de création du levain n'est à faire qu'une seule fois, ensuite on n'a\nqu'à l'entretenir. Il faut :",[348,1032,1033,1036,1039,1042],{},[351,1034,1035],{},"de la farine et de l'eau en quantités égales (environ 2 cuillères à soupe de\nfarine, le même poids en eau) ;",[351,1037,1038],{},"laisser au minimum 3-4 jours dans le bocal ouvert : des bulles se forment,\nl'odeur s'acidifie ;",[351,1040,1041],{},"le processus peut être plus rapide s'il fait chaud, plus long s'il fait froid ;",[351,1043,1044],{},"lorsque des bulles se sont formées, on peut nourrir le levain (1 volume de\nlevain : 1 volume de farine, 1 volume d'eau).",[12,1046,1047],{},"Garder le bocal fermé désormais. Après 12-24 h, des bulles se sont formées, le\nlevain est mousseux : nourrir de nouveau, il est prêt à l'utilisation.",[12,1049,1050],{},"Il est de tradition et de bon augure de donner un nom à son levain nouvellement\ncréé ou adopté.",[72,1052,1054],{"id":1053},"entretien","Entretien",[12,1056,1057,1060],{},[331,1058,1059],{},"À température ambiante :"," le nourrir (1:1:1, par exemple 50 g de levain, 50 g\nde farine, 50 g d'eau) ; après 8-12 h, le levain a doublé de volume, odeur acide\nagréable ; utiliser quasiment tout pour faire le pain ; nourrir et mettre au frigo\nsi pas de pain dans les 2 jours.",[12,1062,1063,1066],{},[331,1064,1065],{},"À la sortie du frigo (moins de 10 jours) :"," le laisser réchauffer 1 à 12 h,\npuis suivre les instructions ci-dessus. Si tout va bien, le levain aura doublé\naprès 6-12 h.",[1009,1068],{},[56,1070,1072],{"id":1071},"le-pain","Le pain",[12,1074,1075],{},"La recette la plus facile pour commencer est un pain au levain cuit et levé dans\nun moule. C'est également la méthode la plus raisonnable pour les farines pauvres\nen gluten. Pour un moule à cake classique, partir sur environ 125 g de levain ;\n200 g permettent d'obtenir deux pains moulés.",[72,1077,1079],{"id":1078},"les-farines","Les farines",[12,1081,1082],{},"Tout est possible : blé T80-T110-T150, petit épeautre, sarrasin, riz (ajouter des\ngraines de lin mixées pour la structure). Mélanges à hauteur de 10 à 20 % du poids\nde farine :",[348,1084,1085,1088,1091],{},[351,1086,1087],{},"seigle (pain « tradition ») ;",[351,1089,1090],{},"lentilles mixées ;",[351,1092,1093],{},"graines (éventuellement trempées 12-24 h) : chia, pignons de pin, flocons\nd'avoine, noix, noisettes, sésame, quinoa, lin, raisins secs, figues.",[72,1095,1097],{"id":1096},"le-mélange","Le mélange",[12,1099,1100],{},"La recette de base pour un pain moulé (la pâte est assez liquide) :",[348,1102,1103,1106,1109,1112],{},[351,1104,1105],{},"1 volume de levain ;",[351,1107,1108],{},"2 volumes d'eau (2× le poids du levain) ;",[351,1110,1111],{},"2,5 volumes de farine (2,5× le poids du levain) ;",[351,1113,1114],{},"moins de 1 % de sel (moins de 18 g par kg de farine).",[12,1116,1117],{},"Pour un poids de levain X = 200 g :",[1119,1120,1121,1124,1127,1130,1133],"ol",{},[351,1122,1123],{},"Peser le levain : 200 g.",[351,1125,1126],{},"Ajouter un peu d'eau et mélanger pour diluer, puis compléter jusqu'à 400 g\nd'eau.",[351,1128,1129],{},"Ajouter 500 g de farine.",[351,1131,1132],{},"Ajouter 10 g de sel.",[351,1134,1135],{},"Mélanger sans déchirer la pâte, de 1 à 10 min. La consistance doit être ni\ntrop dure, ni trop liquide.",[12,1137,1138],{},[317,1139],{"alt":1140,"height":1141,"src":1142,"width":1141},"Préparation : le levain, avec un peu d'eau, avec toute l'eau, ajout de farine et sel, mélange, levée",2896,"\u002Fpain\u002Fimgs\u002Fcollage_prep.jpg",[72,1144,1146],{"id":1145},"première-levée","Première levée",[12,1148,1149],{},"La pâte est en boule dans un saladier, couverte d'un torchon humide. Selon la\nmétéo, laisser reposer : 3 h dans le four avec la lumière, 5 h dans la cuisine\n(≈ 20 °C), la nuit entière en extérieur au printemps ou automne, ou 1 h dans la\ncuisine puis 12-24 h au frigo. À la fin, la pâte a quasiment doublé de volume mais\ngarde de la puissance pour la levée suivante.",[72,1151,1153],{"id":1152},"deuxième-levée","Deuxième levée",[12,1155,1156],{},"Verser délicatement la pâte dans le moule (légèrement huilé ou papier sulfurisé),\nsans remplir à plus de la moitié. Saupoudrer éventuellement (sésame, chia, flocons\nd'avoine). Couvrir d'un torchon humide et laisser lever jusqu'à ce que la pâte ait\ndoublé, de 30 min à 1 h à 25-28 °C.",[12,1158,1159],{},[317,1160],{"alt":1161,"height":1141,"src":1162,"width":1141},"Mise en moule et levée avec la lumière du four","\u002Fpain\u002Fimgs\u002Fcollage_moule.jpg",[72,1164,1166],{"id":1165},"la-cuisson","La cuisson",[12,1168,1169],{},"Préchauffer le four à 250 °C, avec une lèchefrite en bas, mode haut\u002Fbas, sans\nchaleur tournante. Préparer une lame et un verre d'eau chaude. Entailler le pain,\nl'enfourner, verser le verre d'eau dans la lèchefrite, refermer (ne plus ouvrir).",[12,1171,1172],{},"Minuterie t = 0 :",[348,1174,1175,1178,1181,1184],{},[351,1176,1177],{},"baisser le four à 230 °C ;",[351,1179,1180],{},"t = 15 min : 200 °C ;",[351,1182,1183],{},"t = 35 min : démouler et réenfourner ;",[351,1185,1186],{},"vérifier la cuisson à 40 min.",[12,1188,1189],{},"Le pain est cuit quand il sonne creux en dessous, doré et croustillant (40 à\n50 min).",[12,1191,1192],{},[317,1193],{"alt":1194,"height":1141,"src":1195,"width":1141},"Cuisson : pâte levée, mise au four, fin de cuisson sans le moule","\u002Fpain\u002Fimgs\u002Fcollage_four.jpg",[72,1197,1199],{"id":1198},"le-refroidissement","Le refroidissement",[12,1201,1202],{},"Placer le pain sur une grille, laisser refroidir au moins 1 h. Les saveurs se\ndéveloppent avec le temps ; le pain se conserve plusieurs jours, ou plusieurs\nsemaines congelé en tranches.",[12,1204,1205],{},[317,1206],{"alt":1207,"height":1141,"src":1208,"width":1141},"Pain cuit et mie","\u002Fpain\u002Fimgs\u002Fcollage_cuit.jpg",[1009,1210],{},[56,1212,1214],{"id":1213},"inspirations-et-techniques","Inspirations et techniques",[348,1216,1217,1223,1229],{},[351,1218,1219],{},[16,1220,1221],{"href":1221,"rel":1222},"https:\u002F\u002Fmakanaibio.com\u002F2008\u002F10\u002F123-pain-au-levain-une-formule-qui.html",[20],[351,1224,1225],{},[16,1226,1227],{"href":1227,"rel":1228},"https:\u002F\u002Fnicrunicuit.com\u002Ffaire\u002Ffermenter\u002Fvotre-premier-pain-au-levain\u002F",[20],[351,1230,1231,1232],{},"En vidéo : ",[16,1233,1234],{"href":1234,"rel":1235},"https:\u002F\u002Fyoutu.be\u002F8tmaHkwk3P0",[20],[12,1237,1238],{},"Il y a énormément de combinaisons de proportions, de force du levain, de temps et\nde température. La cuisson en moule est assez tolérante, mais il ne faut pas\nhésiter à prendre des notes pour ajuster ensuite un paramètre.",{"title":92,"searchDepth":105,"depth":105,"links":1240},[1241,1245,1253],{"id":1013,"depth":105,"text":1014,"children":1242},[1243,1244],{"id":1026,"depth":111,"text":1027},{"id":1053,"depth":111,"text":1054},{"id":1071,"depth":105,"text":1072,"children":1246},[1247,1248,1249,1250,1251,1252],{"id":1078,"depth":111,"text":1079},{"id":1096,"depth":111,"text":1097},{"id":1145,"depth":111,"text":1146},{"id":1152,"depth":111,"text":1153},{"id":1165,"depth":111,"text":1166},{"id":1198,"depth":111,"text":1199},{"id":1213,"depth":105,"text":1214},"2019-12-22","Une recette simple de pain au levain cuit en moule : entretien du levain, mélange, levées, cuisson, refroidissement.",{},"\u002Fblog\u002Fpain-au-levain",{"title":979,"description":1255},"blog\u002Fpain-au-levain",[1261,1262],"pain","recettes","BCw6RnmcfbqmrkTgKY_p_IWbkrSH9TF_MTF3dTVPK7I",1783955629856]