new: add offline fallback support for WebView

This commit is contained in:
Antoine Jaury committed 2026-07-08 17:08:02 +02:00
1 parent b063dfaff6
commit f6a12ad84a
14 files changed
+747 -20

No files matched your search

@@ -0,0 +1,310 @@
<!doctype html>
<html lang="fr-FR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5, viewport-fit=cover">
<link rel="profile" href="https://gmpg.org/xfn/11">
<title>App Chom Bev &#8211; À propos &#8211; Kerlenn Sten Kidna</title>
<meta name='robots' content='max-image-preview:large' />
<link rel="alternate" type="application/rss+xml" title="Kerlenn Sten Kidna &raquo; Flux" href="https://ksk.bzh/fr/feed/" />
<link rel="alternate" type="application/rss+xml" title="Kerlenn Sten Kidna &raquo; Flux des commentaires" href="https://ksk.bzh/fr/comments/feed/" />
<link rel="alternate" title="oEmbed (JSON)" type="application/json+oembed" href="https://ksk.bzh/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fksk.bzh%2Ffr%2Fchom-bev-a-propos%2F&#038;lang=fr" />
<link rel="alternate" title="oEmbed (XML)" type="text/xml+oembed" href="https://ksk.bzh/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fksk.bzh%2Ffr%2Fchom-bev-a-propos%2F&#038;format=xml&#038;lang=fr" />
<style id="wp-img-auto-sizes-contain-inline-css">
img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px}
/*# sourceURL=wp-img-auto-sizes-contain-inline-css */
</style>
<link rel='stylesheet' id='blocksy-dynamic-global-css' href='https://ksk.bzh/wp-content/uploads/blocksy/css/global.css?ver=64854' media='all' />
<link rel='stylesheet' id='ugb-style-css-css' href='https://ksk.bzh/wp-content/plugins/stackable-ultimate-gutenberg-blocks/dist/frontend_blocks.css?ver=3.19.9' media='all' />
<style id="ugb-style-css-inline-css">
:root {--stk-block-width-default-detected: 1290px;}
#start-resizable-editor-section{display:none}@media only screen and (min-width:1000px){:where(.has-text-align-left) .stk-block-divider{--stk-dots-margin-left:0;--stk-dots-margin-right:auto}:where(.has-text-align-right) .stk-block-divider{--stk-dots-margin-right:0;--stk-dots-margin-left:auto}:where(.has-text-align-center) .stk-block-divider{--stk-dots-margin-right:auto;--stk-dots-margin-left:auto}.stk-block.stk-block-divider.has-text-align-center{--stk-dots-margin-right:auto;--stk-dots-margin-left:auto}.stk-block.stk-block-divider.has-text-align-right{--stk-dots-margin-right:0;--stk-dots-margin-left:auto}.stk-block.stk-block-divider.has-text-align-left{--stk-dots-margin-left:0;--stk-dots-margin-right:auto}.stk-block-feature>*>.stk-row{flex-wrap:var(--stk-feature-flex-wrap,nowrap)}.stk-row{flex-wrap:nowrap}.stk--hide-desktop,.stk--hide-desktop.stk-block{display:none!important}}@media only screen and (min-width:690px){:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(2)){flex:1 1 calc(50% - var(--stk-column-gap, 0px)*1/2)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):last-child){flex:1 1 calc(50% - var(--stk-column-gap, 0px)*1/2)!important}:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(3)){flex:1 1 calc(33.33333% - var(--stk-column-gap, 0px)*2/3)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):nth-last-child(2)){flex:1 1 calc(33.33333% - var(--stk-column-gap, 0px)*2/3)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(3):last-child){flex:1 1 calc(33.33333% - var(--stk-column-gap, 0px)*2/3)!important}:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(4)){flex:1 1 calc(25% - var(--stk-column-gap, 0px)*3/4)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):nth-last-child(3)){flex:1 1 calc(25% - var(--stk-column-gap, 0px)*3/4)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(3):nth-last-child(2)){flex:1 1 calc(25% - var(--stk-column-gap, 0px)*3/4)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(4):last-child){flex:1 1 calc(25% - var(--stk-column-gap, 0px)*3/4)!important}:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(5)){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):nth-last-child(4)){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(3):nth-last-child(3)){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(4):nth-last-child(2)){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(5):last-child){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(6)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):nth-last-child(5)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(3):nth-last-child(4)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(4):nth-last-child(3)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(5):nth-last-child(2)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(6):last-child){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical{grid-template-columns:auto 1fr auto}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical>.stk-block-tab-labels:first-child{grid-column:1/2}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical>.stk-block-tab-content:last-child{grid-column:2/4}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical>.stk-block-tab-content:first-child{grid-column:1/3}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical>.stk-block-tab-labels:last-child{grid-column:3/4}.stk-block .stk-block.aligncenter,.stk-block-carousel:is(.aligncenter,.alignwide,.alignfull)>:where(.stk-block-carousel__content-wrapper)>.stk-content-align:not(.alignwide):not(.alignfull),.stk-block:is(.aligncenter,.alignwide,.alignfull)>.stk-content-align:not(.alignwide):not(.alignfull){margin-left:auto;margin-right:auto;max-width:var(--stk-block-default-width,var(--stk-block-width-default-detected,900px));width:100%}.stk-block .stk-block.alignwide,.stk-block-carousel:is(.aligncenter,.alignwide,.alignfull)>:where(.stk-block-carousel__content-wrapper)>.stk-content-align.alignwide,.stk-block:is(.aligncenter,.alignwide,.alignfull)>.stk-content-align.alignwide{margin-left:auto;margin-right:auto;max-width:var(--stk-block-wide-widtLine truncated
/*# sourceURL=ugb-style-css-inline-css */
</style>
<style id="ugb-block-style-inheritance-nodep-inline-css">
/* Block style inheritance */
:root{--stk-button-column-gap:var(--theme-content-spacing);--stk-button-row-gap:var(--theme-content-spacing);}
/*# sourceURL=ugb-block-style-inheritance-nodep-inline-css */
</style>
<style id="ugb-style-css-nodep-inline-css">
/* Global Color Schemes (background-scheme-default-3) */
.stk--background-scheme--scheme-default-3{--stk-block-background-color:#0f0e17;--stk-heading-color:#fffffe;--stk-text-color:#fffffe;--stk-link-color:#f00069;--stk-accent-color:#f00069;--stk-subtitle-color:#f00069;--stk-button-background-color:#f00069;--stk-button-text-color:#fffffe;--stk-button-outline-color:#fffffe;}
/* Global Color Schemes (container-scheme-default-3) */
.stk--container-scheme--scheme-default-3{--stk-container-background-color:#0f0e17;--stk-heading-color:#fffffe;--stk-text-color:#fffffe;--stk-link-color:#f00069;--stk-accent-color:#f00069;--stk-subtitle-color:#f00069;--stk-button-background-color:#f00069;--stk-button-text-color:#fffffe;--stk-button-outline-color:#fffffe;}
/* Global Preset Controls */
:root{--stk--preset--font-size--small:var(--wp--preset--font-size--small);--stk--preset--font-size--medium:var(--wp--preset--font-size--medium);--stk--preset--font-size--large:var(--wp--preset--font-size--large);--stk--preset--font-size--x-large:var(--wp--preset--font-size--x-large);--stk--preset--font-size--xx-large:var(--wp--preset--font-size--xx-large);--stk--preset--spacing--20:var(--wp--preset--spacing--20);--stk--preset--spacing--30:var(--wp--preset--spacing--30);--stk--preset--spacing--40:var(--wp--preset--spacing--40);--stk--preset--spacing--50:var(--wp--preset--spacing--50);--stk--preset--spacing--60:var(--wp--preset--spacing--60);--stk--preset--spacing--70:var(--wp--preset--spacing--70);--stk--preset--spacing--80:var(--wp--preset--spacing--80);}
/*# sourceURL=ugb-style-css-nodep-inline-css */
</style>
<style id="wp-block-library-inline-css">
:root{--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122,0,223;--wp-bound-block-color:var(--wp-block-synced-color);--wp-editor-canvas-background:#ddd;--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0,124,186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0,107,160.5;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0,90,135;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}.wp-element-button{cursor:pointer}:root .has-very-light-gray-background-color{background-color:#eee}:root .has-very-dark-gray-background-color{background-color:#313131}:root .has-very-light-gray-color{color:#eee}:root .has-very-dark-gray-color{color:#313131}:root .has-vivid-green-cyan-to-vivid-cyan-blue-gradient-background{background:linear-gradient(135deg,#00d084,#0693e3)}:root .has-purple-crush-gradient-background{background:linear-gradient(135deg,#34e2e4,#4721fb 50%,#ab1dfe)}:root .has-hazy-dawn-gradient-background{background:linear-gradient(135deg,#faaca8,#dad0ec)}:root .has-subdued-olive-gradient-background{background:linear-gradient(135deg,#fafae1,#67a671)}:root .has-atomic-cream-gradient-background{background:linear-gradient(135deg,#fdd79a,#004a59)}:root .has-nightshade-gradient-background{background:linear-gradient(135deg,#330968,#31cdcf)}:root .has-midnight-gradient-background{background:linear-gradient(135deg,#020381,#2874fc)}:root{--wp--preset--font-size--normal:16px;--wp--preset--font-size--huge:42px}.has-regular-font-size{font-size:1em}.has-larger-font-size{font-size:2.625em}.has-normal-font-size{font-size:var(--wp--preset--font-size--normal)}.has-huge-font-size{font-size:var(--wp--preset--font-size--huge)}:root .has-text-align-center{text-align:center}:root .has-text-align-left{text-align:left}:root .has-text-align-right{text-align:right}.has-fit-text{white-space:nowrap!important}#end-resizable-editor-section{display:none}.aligncenter{clear:both}.items-justified-left{justify-content:flex-start}.items-justified-center{justify-content:center}.items-justified-right{justify-content:flex-end}.items-justified-space-between{justify-content:space-between}.screen-reader-text{word-wrap:normal!important;border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.screen-reader-text:focus{background-color:#ddd;clip-path:none;color:#444;display:block;font-size:1em;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}html :where(.has-border-color){border-style:solid}html :where([style*=border-color]){border-style:solid}html :where([style*=border-top-color]){border-top-style:solid}html :where([style*=border-right-color]){border-right-style:solid}html :where([style*=border-bottom-color]){border-bottom-style:solid}html :where([style*=border-left-color]){border-left-style:solid}html :where([style*=border-width]){border-style:solid}html :where([style*=border-top-width]){border-top-style:solid}html :where([style*=border-right-width]){border-right-style:solid}html :where([style*=border-bottom-width]){border-bottom-style:solid}html :where([style*=border-left-width]){border-left-style:solid}html :where(img[class*=wp-image-]){height:auto;max-width:100%}:where(figure){margin:0 0 1em}html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:var(--wp-admin--admin-bar--height,0px)}@media screen and (max-width:600px){html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:0px}}
/*# sourceURL=/wp-includes/css/dist/block-library/common.min.css */
</style>
<style id="wp-block-heading-inline-css">
h1:where(.wp-block-heading).has-background,h2:where(.wp-block-heading).has-background,h3:where(.wp-block-heading).has-background,h4:where(.wp-block-heading).has-background,h5:where(.wp-block-heading).has-background,h6:where(.wp-block-heading).has-background{padding:1.25em 2.375em}h1.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h1.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h2.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h2.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h3.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h3.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h4.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h4.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h5.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h5.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h6.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h6.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]){rotate:180deg}
/*# sourceURL=https://ksk.bzh/wp-includes/blocks/heading/style.min.css */
</style>
<style id="wp-block-list-inline-css">
ol,ul{box-sizing:border-box}:root :where(.wp-block-list.has-background){padding:1.25em 2.375em}
/*# sourceURL=https://ksk.bzh/wp-includes/blocks/list/style.min.css */
</style>
<style id="wp-block-paragraph-inline-css">
.is-small-text{font-size:.875em}.is-regular-text{font-size:1em}.is-large-text{font-size:2.25em}.is-larger-text{font-size:3em}.has-drop-cap:not(:focus):first-letter{float:left;font-size:8.4em;font-style:normal;font-weight:100;line-height:.68;margin:.05em .1em 0 0;text-transform:uppercase}body.rtl .has-drop-cap:not(:focus):first-letter{float:none;margin-left:.1em}p.has-drop-cap.has-background{overflow:hidden}:root :where(p.has-background){padding:1.25em 2.375em}:where(p.has-text-color:not(.has-link-color)) a{color:inherit}p.has-text-align-left[style*="writing-mode:vertical-lr"],p.has-text-align-right[style*="writing-mode:vertical-rl"]{rotate:180deg}
/*# sourceURL=https://ksk.bzh/wp-includes/blocks/paragraph/style.min.css */
</style>
<style id="wp-block-preformatted-inline-css">
.wp-block-preformatted{box-sizing:border-box;white-space:pre-wrap}:where(.wp-block-preformatted.has-background){padding:1.25em 2.375em}
/*# sourceURL=https://ksk.bzh/wp-includes/blocks/preformatted/style.min.css */
</style>
<style id="global-styles-inline-css">
:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--color--palette-color-1: var(--theme-palette-color-1, #ff9201);--wp--preset--color--palette-color-2: var(--theme-palette-color-2, #ff9201);--wp--preset--color--palette-color-3: var(--theme-palette-color-3, #1a242b);--wp--preset--color--palette-color-4: var(--theme-palette-color-4, #334654);--wp--preset--color--palette-color-5: var(--theme-palette-color-5, #ffebd1);--wp--preset--color--palette-color-6: var(--theme-palette-color-6, #fff7ec);--wp--preset--color--palette-color-7: var(--theme-palette-color-7, #ffffff);--wp--preset--color--palette-color-8: var(--theme-palette-color-8, #ffffff);--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,0) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--gradient--juicy-peach: linear-gradient(to right, #ffecd2 0%, #fcb69f 100%);--wp--preset--gradient--young-passion: linear-gradient(to right, #ff8177 0%, #ff867a 0%, #ff8c7f 21%, #f99185 52%, #cf556c 78%, #b12a5b 100%);--wp--preset--gradient--true-sunset: linear-gradient(to right, #fa709a 0%, #fee140 100%);--wp--preset--gradient--morpheus-den: linear-gradient(to top, #30cfd0 0%, #330867 100%);--wp--preset--gradient--plum-plate: linear-gradient(135deg, #667eea 0%, #764ba2 100%);--wp--preset--gradient--aqua-splash: linear-gradient(15deg, #13547a 0%, #80d0c7 100%);--wp--preset--gradient--love-kiss: linear-gradient(to top, #ff0844 0%, #ffb199 100%);--wp--preset--gradient--new-retrowave: linear-gradient(to top, #3b41c5 0%, #a981bb 49%, #ffc8a9 100%);--wp--preset--gradient--plum-bath: linear-gradient(to top, #cc208e 0%, #6713d2 100%);--wp--preset--gradient--high-flight: linear-gradient(to right, #0acffe 0%, #495aff 100%);--wp--preset--gradient--teen-party: linear-gradient(135deg, #FF057C 0%, #8D0B93 50%, #321575 100%);--wp--preset--gradient--fabled-sunset: linear-gradient(135deg, #231557 0%, #44107A 29%, #FF1361 67%, #FFF800 100%);--wp--preset--gradient--arielle-smile: radial-gradient(circle 248px at center, #16d9e3 0%, #30c7ec 47%, #46aef7 100%);--wp--preset--gradient--itmeo-branding: linear-gradient(180deg, #2af598 0%, #009efd 100%);--wp--preset--gradient--deep-blue: linear-gradient(to right, #6a11cb 0%, #2575fc 100%);--wp--preset--gradient--strong-bliss: linear-gradient(to right, #f78ca0 0%, #f9748f 19%, #fd868c 60%, #fe9a8b 100%);--wp--preset--gradient--sweet-period: linear-gradient(to top, #3f51b1 0%, #5a55ae 13%, #7b5fac 25%, #8f6aae 38%, #a86aa4 50%, #cc6b8e 62%, #f18271 75%, #f3a469 87%, #f7c978 100%);--wp--preset--gradient--purple-division: linear-gradient(to top, #7028e4 0%, #e5b2ca 100%);--wp--preset--gradient--cold-evening: linear-gradient(to top, #0c3483 0%, #a2b6df 100%, #6b8cce 100%, #a2b6df 100%);--wp--preset--gradient--mountain-rock: linear-gradient(to right, #868f96 0%, #596164 100%);--wp--preset--gradient--desert-hump: lineaLine truncated
/*# sourceURL=global-styles-inline-css */
</style>
<link rel='stylesheet' id='ct-main-styles-css' href='https://ksk.bzh/wp-content/themes/blocksy/static/bundle/main.min.css?ver=2.1.48' media='all' />
<link rel='stylesheet' id='ct-stackable-styles-css' href='https://ksk.bzh/wp-content/themes/blocksy/static/bundle/stackable.min.css?ver=2.1.48' media='all' />
<link rel="https://api.w.org/" href="https://ksk.bzh/wp-json/" /><link rel="alternate" title="JSON" type="application/json" href="https://ksk.bzh/wp-json/wp/v2/pages/1413" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://ksk.bzh/xmlrpc.php?rsd" />
<meta name="generator" content="WordPress 7.0" />
<link rel="canonical" href="https://ksk.bzh/fr/chom-bev-a-propos/" />
<link rel='shortlink' href='https://ksk.bzh/?p=1413' />
<noscript><link rel='stylesheet' href='https://ksk.bzh/wp-content/themes/blocksy/static/bundle/no-scripts.min.css' type='text/css'></noscript>
<link rel="icon" href="https://ksk.bzh/wp-content/uploads/2025/10/cropped-logo_round-32x32.png" sizes="32x32" />
<link rel="icon" href="https://ksk.bzh/wp-content/uploads/2025/10/cropped-logo_round-192x192.png" sizes="192x192" />
<link rel="apple-touch-icon" href="https://ksk.bzh/wp-content/uploads/2025/10/cropped-logo_round-180x180.png" />
<meta name="msapplication-TileImage" content="https://ksk.bzh/wp-content/uploads/2025/10/cropped-logo_round-270x270.png" />
<style id="wp-custom-css">
/* Fonts */
@font-face {
font-family: 'Roboto';
src: url('/wp-content/themes/blocksy/static/fonts/Roboto-VariableFont_wdth%2Cwght.woff2') format('woff2');
font-weight: 400 700;
font-style: normal;
font-display: swap;
}
/* forms */
.ct-appointment-form .wpforms-submit {
width: 100%;
}
.ct-subscribe-wpforms {
--form-field-border-width: 0;
--theme-button-background-initial-color: var(--theme-palette-color-4);
--theme-button-text-hover-color: var(--theme-palette-color-4);
--theme-button-background-hover-color: #fff;
}
/* slider */
.blockslider-pagination.blockslider-pagination-square span {
width: 45px !important;
margin: 5px 8px !important;
}
/* Polylang - lang. picker */
.pll-parent-menu-item .sub-menu {
min-width: 80px !important;
width: 50px !important;
background-color: #FFFFFF !important;
position: absolute !important;
top: 100% !important;
z-index: 10;
}
@media (max-width: 690px) {
.hide-on-mobile {
display: none !important;
}
}
/* Cacher sur desktop */
.mobile-only {
display: none;
}
/* Afficher uniquement sur les petits écrans */
@media (max-width: 690px) {
.mobile-only {
display: block;
}
}
</style>
</head>
<body class="wp-singular page-template-default page page-id-1413 wp-custom-logo wp-embed-responsive wp-theme-blocksy stk--is-blocksy-theme stk-has-block-style-inheritance" data-link="type-2" data-prefix="single_page" itemscope="itemscope" itemtype="https://schema.org/WebPage">
<a class="skip-link screen-reader-text" href="#main">Passer au contenu</a>
<div id="main-container">
<main id="main" class="site-main hfeed" tabindex="-1">
<div
class="ct-container-full"
data-content="normal" >
<article
id="post-1413"
class="post-1413 page type-page status-publish hentry">
<div class="entry-content is-layout-constrained">
<div class="wp-block-stackable-heading stk-block-heading stk-block-heading--v2 stk-block stk-70cd5d3" id="ℹ️-a-propos" data-block-id="70cd5d3"><h2 class="stk-block-heading__text">ℹ️ À propos</h2></div>
<pre class="wp-block-preformatted">"<strong>Chom Bev e Brezhoneg</strong>" est une application qui vous est proposée gratuitement par l'association <strong>Kerlenn Sten Kidna</strong> dans le but de vous aider à vous initier au Breton, et particulièrement aux sonorités et tournures typiques du <strong>Breton Vannetais</strong>.</pre>
<h2 class="wp-block-heading has-large-font-size">🎙️ Contributeurs</h2>
<h3 class="wp-block-heading" style="font-size:clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.234), 17px);">Contenu</h3>
<p class="wp-block-paragraph">Cette application vous est proposée par l&rsquo;association <a href="https://ksk.bzh" target="_blank" rel="noreferrer noopener">Kerlenn Sten Kidna (KSK)</a>. « Chom Bev e Brezhoneg » est une oeuvre créée par KSK, initialement sous la forme d&rsquo;un livret imprimé et accompagné d&rsquo;un CD audio. Il est adapté ici au format numérique. L&rsquo;association KSK a notamment pour mission de faire vivre le patrimoine culturel breton en pays d&rsquo;Auray. Elle propose un ensemble de ressources (collectages audio, vidéo, écrits, &#8230;) mais aussi des rencontres (stages, soirées jeux, cafés pain-beurre, club lecteur &#8230;) et des cours hebdomadaires de breton (en journée &amp; en soirée, en présentiel &amp; à distance). </p>
<p class="wp-block-paragraph">Le contenu, les textes et enregistrements ont été réalisés par l&rsquo;association, et restent la propriété de l&rsquo;association. Pour une réutilisation en dehors de l&rsquo;application, merci de vous rapprocher de l&rsquo;association.</p>
<p class="wp-block-paragraph">Sur les enregistrement, nous retrouvons deux voix :</p>
<ul class="wp-block-list">
<li>Patrig Dréan, actuel président de Kerlenn Sten Kidna, formateur et auteur de nombreuses œuvres en breton.</li>
<li>?</li>
</ul>
<h3 class="wp-block-heading" style="font-size:clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.234), 17px);">Conception de l&rsquo;app, pilotage &amp; développement</h3>
<p class="wp-block-paragraph">La conception et le développement de l&rsquo;application sont pilotés et réalisés par <a href="https://antoinejaury.github.io/">Antoine Jaury</a>, développeur professionnel d&rsquo;applications mobiles. Le code source de l&rsquo;application est ouvert (Open Source), et utilise Kotlin Multi-Platform (KMP) avec Compose Multi-Platform (CMP) afin de proposer une application fonctionnant sur Android, iOS, navigateur Web, mais aussi en application bureau.</p>
<p class="wp-block-paragraph">Le code source de l&rsquo;application est disponible sur : <a href="https://.../chombev">https://&#8230;/chombev</a></p>
<h2 class="wp-block-heading has-large-font-size">💬 C&rsquo;est quoi le Breton Vannetais (Gwenedeg) ?</h2>
<p class="wp-block-paragraph">Le breton Vannetais regroupe une variété de bretons parlée dans la quasi-totalité de la partie bretonnante du Morbihan, et un peu au-delà. C&rsquo;est le cas notamment du Pays d&rsquo;Auray actuel.</p>
<p class="wp-block-paragraph">+ ajout d&rsquo;une carte ? </p>
<h2 class="wp-block-heading has-large-font-size">🤙🏼 Contact</h2>
<p class="wp-block-paragraph">Vous souhaitez contacter l&rsquo;association Kerlenn Sten Kidna : <a href="mailto:ksk@ksk.bzh">ksk@ksk.bzh</a></p>
<p class="wp-block-paragraph">Vous avez une question, une suggestion concernant l&rsquo;application : <a href="mailto:antoine@jaury.eu">antoine@jaury.eu</a></p>
<h2 class="wp-block-heading has-large-font-size">🔒 Politique de confidentialité</h2>
<p class="wp-block-paragraph">Cette application ne demande ni ne collecte de données personnelles telles que votre nom, votre adresse électronique ou votre position géographique.</p>
<p class="wp-block-paragraph">Les contenus audio sont intégrés à l&rsquo;application et restent accessibles hors connexion.</p>
<p class="wp-block-paragraph">Les sections <strong>« Approfondir »</strong> et <strong>« À propos »</strong> affichent des pages web hébergées sous WordPress. Lors de leur consultation, des données techniques nécessaires au fonctionnement du serveur web peuvent être traitées (par exemple l&rsquo;adresse IP, les informations du navigateur ou les journaux de connexion).</p>
<p class="wp-block-paragraph">Afin d&rsquo;améliorer la stabilité de l&rsquo;application, un service de collecte des erreurs (GlitchTip) est utilisé. En cas de plantage ou d&rsquo;erreur inattendue, des informations techniques (telles que la version de l&rsquo;application, le modèle de l&rsquo;appareil, la version du système d&rsquo;exploitation et la trace de l&rsquo;erreur) peuvent être transmises. Ces informations sont utilisées uniquement pour diagnostiquer et corriger les problèmes techniques. </p>
<p class="wp-block-paragraph">L&rsquo;ensemble de ces données sont stockées sur des serveurs hébergés en Europe :</p>
<ul class="wp-block-list">
<li>En France pour les pages web, hébergées chez l’Association LA KAZ,</li>
<li>En Allemagne pour les données de stabilité avec GlitchTip Europe.</li>
</ul>
<p class="wp-block-paragraph">Pour plus de détails, veuillez consulter notre : <a href="https://ksk.bzh/fr/app-chom-bev-politique-de-confidentialite/">politique de confidentialité</a>.</p>
<h2 class="wp-block-heading has-large-font-size">🧑🏽‍⚖️ Mentions légales</h2>
<p class="wp-block-paragraph">Les mentions légales de l&rsquo;application sont disponibles via <a href="https://ksk.bzh/fr/app-chom-bev-mentions-legales/">ce lien</a>.</p>
<div class="wp-block-stackable-spacer stk-block-spacer stk--no-padding stk-block stk-adc34e5" data-block-id="adc34e5"></div>
</div>
</article>
</div>
</main>
</div>
<script type="speculationrules">
{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/blocksy/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]}
</script>
<script id="ct-scripts-js-extra">
var ct_localizations = {"ajax_url":"https://ksk.bzh/wp-admin/admin-ajax.php","public_url":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/","rest_url":"https://ksk.bzh/wp-json/","search_url":"https://ksk.bzh/fr/search/QUERY_STRING/","show_more_text":"Afficher plus","more_text":"Plus","search_live_results":"R\u00e9sultats de recherche","search_live_no_results":"Aucun r\u00e9sultat","search_live_results_closed":"R\u00e9sultats de recherche ferm\u00e9s.","search_live_no_result":"Aucun r\u00e9sultat","search_live_one_result":"Vous avez %s r\u00e9sultat. Veuillez appuyer sur Tab pour le s\u00e9lectionner.","search_live_many_results":"Vous avez %s r\u00e9sultats. Veuillez appuyer sur Tab pour en s\u00e9lectionner un.","search_live_stock_status_texts":{"instock":"En stock","outofstock":"En rupture de stock"},"clipboard_copied":"Copi\u00e9\u00a0!","clipboard_failed":"\u00c9chec de la copie","expand_submenu":"D\u00e9plier le menu d\u00e9roulant","collapse_submenu":"Replier le menu d\u00e9roulant","dynamic_js_chunks":[{"id":"blocksy_sticky_header","selector":"header [data-sticky]","url":"https://ksk.bzh/wp-content/plugins/blocksy-companion/static/bundle/sticky.js?ver=2.1.48","version":"2.1.48"}],"dynamic_styles":{"lazy_load":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/non-critical-styles.min.css?ver=2.1.48","search_lazy":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/non-critical-search-styles.min.css?ver=2.1.48","back_to_top":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/back-to-top.min.css?ver=2.1.48"},"dynamic_styles_selectors":[{"selector":".ct-header-cart, #woo-cart-panel","url":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/cart-header-element-lazy.min.css?ver=2.1.48"},{"selector":".flexy","url":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/flexy.min.css?ver=2.1.48"},{"selector":".ct-pagination","url":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/pagination.min.css?ver=2.1.48"},{"selector":"#account-modal","url":"https://ksk.bzh/wp-content/plugins/blocksy-companion/static/bundle/header-account-modal-lazy.min.css?ver=2.1.48"},{"selector":".ct-header-account","url":"https://ksk.bzh/wp-content/plugins/blocksy-companion/static/bundle/header-account-dropdown-lazy.min.css?ver=2.1.48"}],"login_generic_error_msg":"Une erreur inattendue s\u2019est produite. Veuillez r\u00e9essayer ult\u00e9rieurement.","lang":"fr"};
//# sourceURL=ct-scripts-js-extra
</script>
<script id="ct-scripts-js" src="https://ksk.bzh/wp-content/themes/blocksy/static/bundle/main.js?ver=2.1.48"></script>
</body>
</html>
@@ -0,0 +1,277 @@
<!doctype html>
<html lang="fr-FR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5, viewport-fit=cover">
<link rel="profile" href="https://gmpg.org/xfn/11">
<title>App Chom Bev -​ Approfondir &#8211; Kerlenn Sten Kidna</title>
<meta name='robots' content='max-image-preview:large' />
<link rel="alternate" type="application/rss+xml" title="Kerlenn Sten Kidna &raquo; Flux" href="https://ksk.bzh/fr/feed/" />
<link rel="alternate" type="application/rss+xml" title="Kerlenn Sten Kidna &raquo; Flux des commentaires" href="https://ksk.bzh/fr/comments/feed/" />
<link rel="alternate" title="oEmbed (JSON)" type="application/json+oembed" href="https://ksk.bzh/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fksk.bzh%2Ffr%2Fchom-bev-approfondir%2F&#038;lang=fr" />
<link rel="alternate" title="oEmbed (XML)" type="text/xml+oembed" href="https://ksk.bzh/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fksk.bzh%2Ffr%2Fchom-bev-approfondir%2F&#038;format=xml&#038;lang=fr" />
<style id="wp-img-auto-sizes-contain-inline-css">
img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px}
/*# sourceURL=wp-img-auto-sizes-contain-inline-css */
</style>
<link rel='stylesheet' id='blocksy-dynamic-global-css' href='https://ksk.bzh/wp-content/uploads/blocksy/css/global.css?ver=64854' media='all' />
<link rel='stylesheet' id='ugb-style-css-css' href='https://ksk.bzh/wp-content/plugins/stackable-ultimate-gutenberg-blocks/dist/frontend_blocks.css?ver=3.19.9' media='all' />
<style id="ugb-style-css-inline-css">
:root {--stk-block-width-default-detected: 1290px;}
#start-resizable-editor-section{display:none}@media only screen and (min-width:1000px){:where(.has-text-align-left) .stk-block-divider{--stk-dots-margin-left:0;--stk-dots-margin-right:auto}:where(.has-text-align-right) .stk-block-divider{--stk-dots-margin-right:0;--stk-dots-margin-left:auto}:where(.has-text-align-center) .stk-block-divider{--stk-dots-margin-right:auto;--stk-dots-margin-left:auto}.stk-block.stk-block-divider.has-text-align-center{--stk-dots-margin-right:auto;--stk-dots-margin-left:auto}.stk-block.stk-block-divider.has-text-align-right{--stk-dots-margin-right:0;--stk-dots-margin-left:auto}.stk-block.stk-block-divider.has-text-align-left{--stk-dots-margin-left:0;--stk-dots-margin-right:auto}.stk-block-feature>*>.stk-row{flex-wrap:var(--stk-feature-flex-wrap,nowrap)}.stk-row{flex-wrap:nowrap}.stk--hide-desktop,.stk--hide-desktop.stk-block{display:none!important}}@media only screen and (min-width:690px){:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(2)){flex:1 1 calc(50% - var(--stk-column-gap, 0px)*1/2)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):last-child){flex:1 1 calc(50% - var(--stk-column-gap, 0px)*1/2)!important}:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(3)){flex:1 1 calc(33.33333% - var(--stk-column-gap, 0px)*2/3)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):nth-last-child(2)){flex:1 1 calc(33.33333% - var(--stk-column-gap, 0px)*2/3)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(3):last-child){flex:1 1 calc(33.33333% - var(--stk-column-gap, 0px)*2/3)!important}:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(4)){flex:1 1 calc(25% - var(--stk-column-gap, 0px)*3/4)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):nth-last-child(3)){flex:1 1 calc(25% - var(--stk-column-gap, 0px)*3/4)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(3):nth-last-child(2)){flex:1 1 calc(25% - var(--stk-column-gap, 0px)*3/4)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(4):last-child){flex:1 1 calc(25% - var(--stk-column-gap, 0px)*3/4)!important}:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(5)){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):nth-last-child(4)){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(3):nth-last-child(3)){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(4):nth-last-child(2)){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(5):last-child){flex:1 1 calc(20% - var(--stk-column-gap, 0px)*4/5)!important}:where(body:not(.wp-admin) .stk-block-column:first-child:nth-last-child(6)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(2):nth-last-child(5)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(3):nth-last-child(4)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(4):nth-last-child(3)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(5):nth-last-child(2)){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}:where(body:not(.wp-admin) .stk-block-column:nth-child(6):last-child){flex:1 1 calc(16.66667% - var(--stk-column-gap, 0px)*5/6)!important}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical{grid-template-columns:auto 1fr auto}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical>.stk-block-tab-labels:first-child{grid-column:1/2}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical>.stk-block-tab-content:last-child{grid-column:2/4}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical>.stk-block-tab-content:first-child{grid-column:1/3}.stk-block-tabs>.stk-inner-blocks.stk-block-tabs--vertical>.stk-block-tab-labels:last-child{grid-column:3/4}.stk-block .stk-block.aligncenter,.stk-block-carousel:is(.aligncenter,.alignwide,.alignfull)>:where(.stk-block-carousel__content-wrapper)>.stk-content-align:not(.alignwide):not(.alignfull),.stk-block:is(.aligncenter,.alignwide,.alignfull)>.stk-content-align:not(.alignwide):not(.alignfull){margin-left:auto;margin-right:auto;max-width:var(--stk-block-default-width,var(--stk-block-width-default-detected,900px));width:100%}.stk-block .stk-block.alignwide,.stk-block-carousel:is(.aligncenter,.alignwide,.alignfull)>:where(.stk-block-carousel__content-wrapper)>.stk-content-align.alignwide,.stk-block:is(.aligncenter,.alignwide,.alignfull)>.stk-content-align.alignwide{margin-left:auto;margin-right:auto;max-width:var(--stk-block-wide-widtLine truncated
/*# sourceURL=ugb-style-css-inline-css */
</style>
<style id="ugb-block-style-inheritance-nodep-inline-css">
/* Block style inheritance */
:root{--stk-button-column-gap:var(--theme-content-spacing);--stk-button-row-gap:var(--theme-content-spacing);}
/*# sourceURL=ugb-block-style-inheritance-nodep-inline-css */
</style>
<style id="ugb-style-css-nodep-inline-css">
/* Global Color Schemes (background-scheme-default-3) */
.stk--background-scheme--scheme-default-3{--stk-block-background-color:#0f0e17;--stk-heading-color:#fffffe;--stk-text-color:#fffffe;--stk-link-color:#f00069;--stk-accent-color:#f00069;--stk-subtitle-color:#f00069;--stk-button-background-color:#f00069;--stk-button-text-color:#fffffe;--stk-button-outline-color:#fffffe;}
/* Global Color Schemes (container-scheme-default-3) */
.stk--container-scheme--scheme-default-3{--stk-container-background-color:#0f0e17;--stk-heading-color:#fffffe;--stk-text-color:#fffffe;--stk-link-color:#f00069;--stk-accent-color:#f00069;--stk-subtitle-color:#f00069;--stk-button-background-color:#f00069;--stk-button-text-color:#fffffe;--stk-button-outline-color:#fffffe;}
/* Global Preset Controls */
:root{--stk--preset--font-size--small:var(--wp--preset--font-size--small);--stk--preset--font-size--medium:var(--wp--preset--font-size--medium);--stk--preset--font-size--large:var(--wp--preset--font-size--large);--stk--preset--font-size--x-large:var(--wp--preset--font-size--x-large);--stk--preset--font-size--xx-large:var(--wp--preset--font-size--xx-large);--stk--preset--spacing--20:var(--wp--preset--spacing--20);--stk--preset--spacing--30:var(--wp--preset--spacing--30);--stk--preset--spacing--40:var(--wp--preset--spacing--40);--stk--preset--spacing--50:var(--wp--preset--spacing--50);--stk--preset--spacing--60:var(--wp--preset--spacing--60);--stk--preset--spacing--70:var(--wp--preset--spacing--70);--stk--preset--spacing--80:var(--wp--preset--spacing--80);}
/*# sourceURL=ugb-style-css-nodep-inline-css */
</style>
<style id="wp-block-library-inline-css">
:root{--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122,0,223;--wp-bound-block-color:var(--wp-block-synced-color);--wp-editor-canvas-background:#ddd;--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0,124,186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0,107,160.5;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0,90,135;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}.wp-element-button{cursor:pointer}:root .has-very-light-gray-background-color{background-color:#eee}:root .has-very-dark-gray-background-color{background-color:#313131}:root .has-very-light-gray-color{color:#eee}:root .has-very-dark-gray-color{color:#313131}:root .has-vivid-green-cyan-to-vivid-cyan-blue-gradient-background{background:linear-gradient(135deg,#00d084,#0693e3)}:root .has-purple-crush-gradient-background{background:linear-gradient(135deg,#34e2e4,#4721fb 50%,#ab1dfe)}:root .has-hazy-dawn-gradient-background{background:linear-gradient(135deg,#faaca8,#dad0ec)}:root .has-subdued-olive-gradient-background{background:linear-gradient(135deg,#fafae1,#67a671)}:root .has-atomic-cream-gradient-background{background:linear-gradient(135deg,#fdd79a,#004a59)}:root .has-nightshade-gradient-background{background:linear-gradient(135deg,#330968,#31cdcf)}:root .has-midnight-gradient-background{background:linear-gradient(135deg,#020381,#2874fc)}:root{--wp--preset--font-size--normal:16px;--wp--preset--font-size--huge:42px}.has-regular-font-size{font-size:1em}.has-larger-font-size{font-size:2.625em}.has-normal-font-size{font-size:var(--wp--preset--font-size--normal)}.has-huge-font-size{font-size:var(--wp--preset--font-size--huge)}:root .has-text-align-center{text-align:center}:root .has-text-align-left{text-align:left}:root .has-text-align-right{text-align:right}.has-fit-text{white-space:nowrap!important}#end-resizable-editor-section{display:none}.aligncenter{clear:both}.items-justified-left{justify-content:flex-start}.items-justified-center{justify-content:center}.items-justified-right{justify-content:flex-end}.items-justified-space-between{justify-content:space-between}.screen-reader-text{word-wrap:normal!important;border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.screen-reader-text:focus{background-color:#ddd;clip-path:none;color:#444;display:block;font-size:1em;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}html :where(.has-border-color){border-style:solid}html :where([style*=border-color]){border-style:solid}html :where([style*=border-top-color]){border-top-style:solid}html :where([style*=border-right-color]){border-right-style:solid}html :where([style*=border-bottom-color]){border-bottom-style:solid}html :where([style*=border-left-color]){border-left-style:solid}html :where([style*=border-width]){border-style:solid}html :where([style*=border-top-width]){border-top-style:solid}html :where([style*=border-right-width]){border-right-style:solid}html :where([style*=border-bottom-width]){border-bottom-style:solid}html :where([style*=border-left-width]){border-left-style:solid}html :where(img[class*=wp-image-]){height:auto;max-width:100%}:where(figure){margin:0 0 1em}html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:var(--wp-admin--admin-bar--height,0px)}@media screen and (max-width:600px){html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:0px}}
/*# sourceURL=/wp-includes/css/dist/block-library/common.min.css */
</style>
<style id="wp-block-heading-inline-css">
h1:where(.wp-block-heading).has-background,h2:where(.wp-block-heading).has-background,h3:where(.wp-block-heading).has-background,h4:where(.wp-block-heading).has-background,h5:where(.wp-block-heading).has-background,h6:where(.wp-block-heading).has-background{padding:1.25em 2.375em}h1.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h1.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h2.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h2.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h3.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h3.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h4.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h4.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h5.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h5.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]),h6.has-text-align-left[style*=writing-mode]:where([style*=vertical-lr]),h6.has-text-align-right[style*=writing-mode]:where([style*=vertical-rl]){rotate:180deg}
/*# sourceURL=https://ksk.bzh/wp-includes/blocks/heading/style.min.css */
</style>
<style id="wp-block-paragraph-inline-css">
.is-small-text{font-size:.875em}.is-regular-text{font-size:1em}.is-large-text{font-size:2.25em}.is-larger-text{font-size:3em}.has-drop-cap:not(:focus):first-letter{float:left;font-size:8.4em;font-style:normal;font-weight:100;line-height:.68;margin:.05em .1em 0 0;text-transform:uppercase}body.rtl .has-drop-cap:not(:focus):first-letter{float:none;margin-left:.1em}p.has-drop-cap.has-background{overflow:hidden}:root :where(p.has-background){padding:1.25em 2.375em}:where(p.has-text-color:not(.has-link-color)) a{color:inherit}p.has-text-align-left[style*="writing-mode:vertical-lr"],p.has-text-align-right[style*="writing-mode:vertical-rl"]{rotate:180deg}
/*# sourceURL=https://ksk.bzh/wp-includes/blocks/paragraph/style.min.css */
</style>
<style id="wp-block-group-inline-css">
.wp-block-group{box-sizing:border-box}:where(.wp-block-group.wp-block-group-is-layout-constrained){position:relative}
/*# sourceURL=https://ksk.bzh/wp-includes/blocks/group/style.min.css */
</style>
<style id="wp-block-preformatted-inline-css">
.wp-block-preformatted{box-sizing:border-box;white-space:pre-wrap}:where(.wp-block-preformatted.has-background){padding:1.25em 2.375em}
/*# sourceURL=https://ksk.bzh/wp-includes/blocks/preformatted/style.min.css */
</style>
<style id="global-styles-inline-css">
:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--color--palette-color-1: var(--theme-palette-color-1, #ff9201);--wp--preset--color--palette-color-2: var(--theme-palette-color-2, #ff9201);--wp--preset--color--palette-color-3: var(--theme-palette-color-3, #1a242b);--wp--preset--color--palette-color-4: var(--theme-palette-color-4, #334654);--wp--preset--color--palette-color-5: var(--theme-palette-color-5, #ffebd1);--wp--preset--color--palette-color-6: var(--theme-palette-color-6, #fff7ec);--wp--preset--color--palette-color-7: var(--theme-palette-color-7, #ffffff);--wp--preset--color--palette-color-8: var(--theme-palette-color-8, #ffffff);--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,0) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--gradient--juicy-peach: linear-gradient(to right, #ffecd2 0%, #fcb69f 100%);--wp--preset--gradient--young-passion: linear-gradient(to right, #ff8177 0%, #ff867a 0%, #ff8c7f 21%, #f99185 52%, #cf556c 78%, #b12a5b 100%);--wp--preset--gradient--true-sunset: linear-gradient(to right, #fa709a 0%, #fee140 100%);--wp--preset--gradient--morpheus-den: linear-gradient(to top, #30cfd0 0%, #330867 100%);--wp--preset--gradient--plum-plate: linear-gradient(135deg, #667eea 0%, #764ba2 100%);--wp--preset--gradient--aqua-splash: linear-gradient(15deg, #13547a 0%, #80d0c7 100%);--wp--preset--gradient--love-kiss: linear-gradient(to top, #ff0844 0%, #ffb199 100%);--wp--preset--gradient--new-retrowave: linear-gradient(to top, #3b41c5 0%, #a981bb 49%, #ffc8a9 100%);--wp--preset--gradient--plum-bath: linear-gradient(to top, #cc208e 0%, #6713d2 100%);--wp--preset--gradient--high-flight: linear-gradient(to right, #0acffe 0%, #495aff 100%);--wp--preset--gradient--teen-party: linear-gradient(135deg, #FF057C 0%, #8D0B93 50%, #321575 100%);--wp--preset--gradient--fabled-sunset: linear-gradient(135deg, #231557 0%, #44107A 29%, #FF1361 67%, #FFF800 100%);--wp--preset--gradient--arielle-smile: radial-gradient(circle 248px at center, #16d9e3 0%, #30c7ec 47%, #46aef7 100%);--wp--preset--gradient--itmeo-branding: linear-gradient(180deg, #2af598 0%, #009efd 100%);--wp--preset--gradient--deep-blue: linear-gradient(to right, #6a11cb 0%, #2575fc 100%);--wp--preset--gradient--strong-bliss: linear-gradient(to right, #f78ca0 0%, #f9748f 19%, #fd868c 60%, #fe9a8b 100%);--wp--preset--gradient--sweet-period: linear-gradient(to top, #3f51b1 0%, #5a55ae 13%, #7b5fac 25%, #8f6aae 38%, #a86aa4 50%, #cc6b8e 62%, #f18271 75%, #f3a469 87%, #f7c978 100%);--wp--preset--gradient--purple-division: linear-gradient(to top, #7028e4 0%, #e5b2ca 100%);--wp--preset--gradient--cold-evening: linear-gradient(to top, #0c3483 0%, #a2b6df 100%, #6b8cce 100%, #a2b6df 100%);--wp--preset--gradient--mountain-rock: linear-gradient(to right, #868f96 0%, #596164 100%);--wp--preset--gradient--desert-hump: lineaLine truncated
/*# sourceURL=global-styles-inline-css */
</style>
<link rel='stylesheet' id='ct-main-styles-css' href='https://ksk.bzh/wp-content/themes/blocksy/static/bundle/main.min.css?ver=2.1.48' media='all' />
<link rel='stylesheet' id='ct-stackable-styles-css' href='https://ksk.bzh/wp-content/themes/blocksy/static/bundle/stackable.min.css?ver=2.1.48' media='all' />
<link rel="https://api.w.org/" href="https://ksk.bzh/wp-json/" /><link rel="alternate" title="JSON" type="application/json" href="https://ksk.bzh/wp-json/wp/v2/pages/1381" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://ksk.bzh/xmlrpc.php?rsd" />
<meta name="generator" content="WordPress 7.0" />
<link rel="canonical" href="https://ksk.bzh/fr/chom-bev-approfondir/" />
<link rel='shortlink' href='https://ksk.bzh/?p=1381' />
<noscript><link rel='stylesheet' href='https://ksk.bzh/wp-content/themes/blocksy/static/bundle/no-scripts.min.css' type='text/css'></noscript>
<link rel="icon" href="https://ksk.bzh/wp-content/uploads/2025/10/cropped-logo_round-32x32.png" sizes="32x32" />
<link rel="icon" href="https://ksk.bzh/wp-content/uploads/2025/10/cropped-logo_round-192x192.png" sizes="192x192" />
<link rel="apple-touch-icon" href="https://ksk.bzh/wp-content/uploads/2025/10/cropped-logo_round-180x180.png" />
<meta name="msapplication-TileImage" content="https://ksk.bzh/wp-content/uploads/2025/10/cropped-logo_round-270x270.png" />
<style id="wp-custom-css">
/* Fonts */
@font-face {
font-family: 'Roboto';
src: url('/wp-content/themes/blocksy/static/fonts/Roboto-VariableFont_wdth%2Cwght.woff2') format('woff2');
font-weight: 400 700;
font-style: normal;
font-display: swap;
}
/* forms */
.ct-appointment-form .wpforms-submit {
width: 100%;
}
.ct-subscribe-wpforms {
--form-field-border-width: 0;
--theme-button-background-initial-color: var(--theme-palette-color-4);
--theme-button-text-hover-color: var(--theme-palette-color-4);
--theme-button-background-hover-color: #fff;
}
/* slider */
.blockslider-pagination.blockslider-pagination-square span {
width: 45px !important;
margin: 5px 8px !important;
}
/* Polylang - lang. picker */
.pll-parent-menu-item .sub-menu {
min-width: 80px !important;
width: 50px !important;
background-color: #FFFFFF !important;
position: absolute !important;
top: 100% !important;
z-index: 10;
}
@media (max-width: 690px) {
.hide-on-mobile {
display: none !important;
}
}
/* Cacher sur desktop */
.mobile-only {
display: none;
}
/* Afficher uniquement sur les petits écrans */
@media (max-width: 690px) {
.mobile-only {
display: block;
}
}
</style>
<style id="core-block-supports-inline-css">
.wp-container-core-group-is-layout-995f960e{flex-wrap:nowrap;}
/*# sourceURL=core-block-supports-inline-css */
</style>
</head>
<body class="wp-singular page-template-default page page-id-1381 wp-custom-logo wp-embed-responsive wp-theme-blocksy stk--is-blocksy-theme stk-has-block-style-inheritance" data-link="type-2" data-prefix="single_page" itemscope="itemscope" itemtype="https://schema.org/WebPage">
<a class="skip-link screen-reader-text" href="#main">Passer au contenu</a>
<div id="main-container">
<main id="main" class="site-main hfeed" tabindex="-1">
<div
class="ct-container-full"
data-content="narrow" >
<article
id="post-1381"
class="post-1381 page type-page status-publish hentry">
<div class="entry-content is-layout-constrained">
<div class="wp-block-stackable-heading stk-block-heading stk-block-heading--v2 stk-block stk-e165ec5" id="📚-approfondir" data-block-id="e165ec5"><h2 class="stk-block-heading__text">📚 Approfondir</h2></div>
<pre class="wp-block-preformatted">Voici quelques propositions pour aller plus loin dans votre apprentissage du Breton, et particulièrement du Breton Vannetais.<br><br>Pour trouver des ressources concernant la culture et la langue bretonnes sur le Pays d'Auray, suivez les publications de <a href="https://www.tidouaralre.com/">Ti Douar Alre.</a></pre>
<h2 class="wp-block-heading has-large-font-size">🧑🏼‍🏫 Cours hebdo.</h2>
<h3 class="wp-block-heading" style="font-size:clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.234), 17px);">Sur le Pays d&rsquo;Auray</h3>
<p class="wp-block-paragraph"><a href="https://ksk.bzh" target="_blank" rel="noreferrer noopener">Kerlenn Sten Kidna (KSK)</a> propose des cours hebdomadaires : en journée, mais aussi en soirée ; en présentiel, mais aussi une ligne. Différents niveaux sont proposés, de quoi permettre à chacun·e de trouver un créneau qui lui convienne.</p>
<h3 class="wp-block-heading" style="font-size:clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.234), 17px);">Locoal-Mendon, Plouhinec</h3>
<p class="wp-block-paragraph">L&rsquo;association <a href="https://www.tidouaralre.com/ar-vammenn-member-15.html">Ar Vammenn</a> propose des cours du soir pour les débutant·e·s à Locoal-Mendon.</p>
<h2 class="wp-block-heading has-large-font-size">🍻 Les rencontres</h2>
<p class="wp-block-paragraph"><a href="https://bev.bzh">bev.bzh</a> permet aux personnes souhaitant parler Breton entre elles de se retrouver, quelque soit le lieu. Une carte vous permettra de voir les animations et rencontres autour de chez vous, et de proposer vos propres activités.</p>
<h2 class="wp-block-heading has-large-font-size">💻 L&rsquo;apprentissage en ligne</h2>
<p class="wp-block-paragraph"><a href="https://desketa.bzh">Desketa.bzh</a> est une application en ligne, proposée gratuitement par l&rsquo;<a href="https://www.fr.brezhoneg.bzh/">Office Public de la Langue Bretonne</a> afin d&rsquo;apprendre et perfectionner le Breton unifié (KLT). Si vous souhaitez apprendre le Breton du Pays d&rsquo;Auray, cette ressource pourra vous être d&rsquo;une bonne aide pour appréhender la construction des phrases, enrichir votre vocabulaire et pouvoir interagir facilement avec d&rsquo;autres bretonnant·e·s qui ne sont pas familiers avec le Vannetais. L&rsquo;écoute et les échanges en Vannetais vous permettront de compléter vos acquis et de pratiquer pleinement le Vannetais.</p>
<h2 class="wp-block-heading has-large-font-size">L&rsquo;écoute</h2>
<div class="wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-995f960e wp-block-group-is-layout-flex">
<h3 class="wp-block-heading" style="font-size:clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.234), 17px);">📻 Radio Bro Gwened</h3>
</div>
<p class="wp-block-paragraph">Sur le Pays de Vannes (<em>Bro-Gwened</em>), vous avez certainement déjà croisé les ondes de Radio Bro Gwened (<a href="https://rbg.bzh">RBG.bzh</a>). Si ce n&rsquo;est pas le cas, allez vite faire un tour sur la radio en ligne. Vous y trouverez une écoute en direct et en rediffusion d&rsquo;émissions en Breton et en français, ainsi qu&rsquo;un bouillon de culture bretonne. Pour le Vannetais, à vous de creuser pour trouver les bonnes émissions.<br></p>
<h3 class="wp-block-heading" style="font-size:clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.234), 17px);">🎧​ Kleweled</h3>
<p class="wp-block-paragraph"><a href="https://kleweled.bzh">Kleweled.bzh</a> est un portail qui référence un nombre important de ressources audiovisuelles en langue bretonne. Elle regroupe des podcasts des différentes radios bretonnantes, des films, des séries, des émissions, des documentaires, des dessins animés &#8230; et plus on creuse, plus on trouve de contenus !</p>
<h3 class="wp-block-heading" style="font-size:clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.234), 17px);">🎬 La chaîne Youtube KSK<sup> </sup></h3>
<p class="wp-block-paragraph"><a href="https://www.youtube.com/@kskanalre6535">La chaîne Youtube de Kerlenn Sten Kidna</a> diffuse un nombre important de collectage vidéos essentiellement réalisés sur le Pays d&rsquo;Auray. Vous y trouverez plus de 250 vidéos !</p>
<h2 class="wp-block-heading has-large-font-size">👋🏻 Votre voisin·e</h2>
<p class="wp-block-paragraph">Des fois, il ne faut pas aller bien loin ! Un « Demat » à l&rsquo;occasion de croiser une tête que l&rsquo;on connait crée parfois de belles surprises. Et quoi de mieux que de pratiquer le breton dans son quotidien pour progresser. Les meilleurs collectages de breton que l&rsquo;on puisse entendre sont ceux que l&rsquo;on vit !</p>
<div class="wp-block-stackable-spacer stk-block-spacer stk--no-padding stk-block stk-ef24a69" data-block-id="ef24a69"></div>
</div>
</article>
</div>
</main>
</div>
<script type="speculationrules">
{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/blocksy/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]}
</script>
<script id="ct-scripts-js-extra">
var ct_localizations = {"ajax_url":"https://ksk.bzh/wp-admin/admin-ajax.php","public_url":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/","rest_url":"https://ksk.bzh/wp-json/","search_url":"https://ksk.bzh/fr/search/QUERY_STRING/","show_more_text":"Afficher plus","more_text":"Plus","search_live_results":"R\u00e9sultats de recherche","search_live_no_results":"Aucun r\u00e9sultat","search_live_results_closed":"R\u00e9sultats de recherche ferm\u00e9s.","search_live_no_result":"Aucun r\u00e9sultat","search_live_one_result":"Vous avez %s r\u00e9sultat. Veuillez appuyer sur Tab pour le s\u00e9lectionner.","search_live_many_results":"Vous avez %s r\u00e9sultats. Veuillez appuyer sur Tab pour en s\u00e9lectionner un.","search_live_stock_status_texts":{"instock":"En stock","outofstock":"En rupture de stock"},"clipboard_copied":"Copi\u00e9\u00a0!","clipboard_failed":"\u00c9chec de la copie","expand_submenu":"D\u00e9plier le menu d\u00e9roulant","collapse_submenu":"Replier le menu d\u00e9roulant","dynamic_js_chunks":[{"id":"blocksy_sticky_header","selector":"header [data-sticky]","url":"https://ksk.bzh/wp-content/plugins/blocksy-companion/static/bundle/sticky.js?ver=2.1.48","version":"2.1.48"}],"dynamic_styles":{"lazy_load":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/non-critical-styles.min.css?ver=2.1.48","search_lazy":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/non-critical-search-styles.min.css?ver=2.1.48","back_to_top":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/back-to-top.min.css?ver=2.1.48"},"dynamic_styles_selectors":[{"selector":".ct-header-cart, #woo-cart-panel","url":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/cart-header-element-lazy.min.css?ver=2.1.48"},{"selector":".flexy","url":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/flexy.min.css?ver=2.1.48"},{"selector":".ct-pagination","url":"https://ksk.bzh/wp-content/themes/blocksy/static/bundle/pagination.min.css?ver=2.1.48"},{"selector":"#account-modal","url":"https://ksk.bzh/wp-content/plugins/blocksy-companion/static/bundle/header-account-modal-lazy.min.css?ver=2.1.48"},{"selector":".ct-header-account","url":"https://ksk.bzh/wp-content/plugins/blocksy-companion/static/bundle/header-account-dropdown-lazy.min.css?ver=2.1.48"}],"login_generic_error_msg":"Une erreur inattendue s\u2019est produite. Veuillez r\u00e9essayer ult\u00e9rieurement.","lang":"fr"};
//# sourceURL=ct-scripts-js-extra
</script>
<script id="ct-scripts-js" src="https://ksk.bzh/wp-content/themes/blocksy/static/bundle/main.js?ver=2.1.48"></script>
</body>
</html>
@@ -1,10 +1,7 @@
package bzh.ajaury.chombev.web.ui package bzh.ajaury.chombev.web.ui
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent
import android.webkit.WebResourceRequest
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
@@ -15,6 +12,7 @@ import androidx.webkit.WebViewFeature
@Composable @Composable
actual fun PlatformWebView( actual fun PlatformWebView(
url: String, url: String,
offlineHtml: String?,
darkTheme: Boolean, darkTheme: Boolean,
onLoadingStateChange: (Boolean) -> Unit, onLoadingStateChange: (Boolean) -> Unit,
modifier: Modifier, modifier: Modifier,
@@ -24,7 +22,15 @@ actual fun PlatformWebView(
factory = { context -> factory = { context ->
WebView(context).apply { WebView(context).apply {
// Keep navigation inside the embedded view instead of launching an external browser. // Keep navigation inside the embedded view instead of launching an external browser.
webViewClient = WebClientDelegatingExtLinks(onLoadingStateChange = onLoadingStateChange) webViewClient = WebClientDelegatingExtLinks(
onLoadingStateChange = onLoadingStateChange,
onMainFrameError = {
// Swap in the bundled offline copy, keeping the real URL as base so links resolve.
offlineHtml?.let { html ->
loadDataWithBaseURL(url, html, "text/html", "utf-8", null)
}
},
)
settings.javaScriptEnabled = false settings.javaScriptEnabled = false
settings.domStorageEnabled = true settings.domStorageEnabled = true
applyDarkTheme(darkTheme) applyDarkTheme(darkTheme)
@@ -10,9 +10,13 @@ import android.webkit.WebViewClient
/** /**
* Keeps the initial page inside the embedded web view but opens any link the user taps in the system * Keeps the initial page inside the embedded web view but opens any link the user taps in the system
* browser. Reports page load start/finish through [onLoadingStateChange] so the UI can show a loader. * browser. Reports page load start/finish through [onLoadingStateChange] so the UI can show a loader.
*
* [onMainFrameError] fires when the top-level page itself fails to load (not a sub-resource), so the
* caller can swap in an offline fallback.
*/ */
class WebClientDelegatingExtLinks( class WebClientDelegatingExtLinks(
private val onLoadingStateChange: (Boolean) -> Unit = {}, private val onLoadingStateChange: (Boolean) -> Unit = {},
private val onMainFrameError: () -> Unit = {},
) : WebViewClient() { ) : WebViewClient() {
override fun onPageStarted( override fun onPageStarted(
view: WebView?, view: WebView?,
@@ -34,6 +38,11 @@ class WebClientDelegatingExtLinks(
request: WebResourceRequest?, request: WebResourceRequest?,
error: WebResourceError?, error: WebResourceError?,
) { ) {
// Only fall back for the top-level page; a failed sub-resource (image, etc.) shouldn't
// replace the whole page.
if (request?.isForMainFrame == true) {
onMainFrameError()
}
// Stop the loader even if the page failed, so the user isn't stuck on the spinner. // Stop the loader even if the page failed, so the user isn't stuck on the spinner.
onLoadingStateChange(false) onLoadingStateChange(false)
} }
@@ -7,6 +7,7 @@ import bzh.ajaury.chombev.preferences.di.preferencesModule
import bzh.ajaury.chombev.records.di.recordsModule import bzh.ajaury.chombev.records.di.recordsModule
import bzh.ajaury.chombev.records.ui.viewmodel.RecordsViewModel import bzh.ajaury.chombev.records.ui.viewmodel.RecordsViewModel
import bzh.ajaury.chombev.resources.di.resourcesModule import bzh.ajaury.chombev.resources.di.resourcesModule
import bzh.ajaury.chombev.web.ui.viewmodel.WebViewModel
import org.koin.core.module.dsl.viewModelOf import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.module import org.koin.dsl.module
@@ -18,4 +19,5 @@ val sharedModule = module {
includes(resourcesModule) includes(resourcesModule)
viewModelOf(::RecordsViewModel) viewModelOf(::RecordsViewModel)
viewModelOf(::PlayerViewModel) viewModelOf(::PlayerViewModel)
viewModelOf(::WebViewModel)
} }
@@ -4,12 +4,21 @@ import kotlinx.serialization.Serializable
/** /**
* Web destinations reachable from the main bottom navigation bar and shown inside the app. * Web destinations reachable from the main bottom navigation bar and shown inside the app.
* Placeholder URLs for now. *
* [offlineAsset] is the resource path of a bundled HTML snapshot shown when the online [url] cannot
* be reached, so the page still has content offline.
*/ */
@Serializable @Serializable
enum class WebPage( enum class WebPage(
val url: String, val url: String,
val offlineAsset: String,
) { ) {
DEEPEN("https://ksk.bzh/fr/chom-bev-approfondir/"), DEEPEN(
ABOUT("https://ksk.bzh/fr/chom-bev-a-propos/"), url = "https://ksk.bzh/fr/chom-bev-approfondir/",
offlineAsset = "files/offline_deepen.html",
),
ABOUT(
url = "https://ksk.bzh/fr/chom-bev-a-propos/",
offlineAsset = "files/offline_about.html",
),
} }
@@ -8,12 +8,16 @@ import androidx.compose.ui.Modifier
* honouring [darkTheme] so the page matches the app's light/dark appearance; the others fall back to * honouring [darkTheme] so the page matches the app's light/dark appearance; the others fall back to
* [WebViewUnavailable], which offers to open the page in the system browser. * [WebViewUnavailable], which offers to open the page in the system browser.
* *
* When [url] cannot be reached, the native web views swap in [offlineHtml] — a bundled offline
* snapshot — so the page still shows content. When it is `null` no fallback is loaded.
*
* [onLoadingStateChange] reports whether a page is currently loading, so the caller can show a * [onLoadingStateChange] reports whether a page is currently loading, so the caller can show a
* loader. Fallback platforms report `false` immediately since there is nothing to load. * loader. Fallback platforms report `false` immediately since there is nothing to load.
*/ */
@Composable @Composable
expect fun PlatformWebView( expect fun PlatformWebView(
url: String, url: String,
offlineHtml: String?,
darkTheme: Boolean, darkTheme: Boolean,
onLoadingStateChange: (Boolean) -> Unit = {}, onLoadingStateChange: (Boolean) -> Unit = {},
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@@ -11,33 +11,62 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import bzh.ajaury.chombev.navigation.WebPage import bzh.ajaury.chombev.navigation.WebPage
import bzh.ajaury.chombev.web.ui.viewmodel.WebUiState
import bzh.ajaury.chombev.web.ui.viewmodel.WebViewModel
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.parameter.parametersOf
/** /**
* Displays a [WebPage] inside the app: the embedded page, matching the app's [darkTheme]. A * Displays a [WebPage] inside the app. Injects a [WebViewModel] keyed by the page so each page keeps
* [WebViewLoader] covers the page while it loads. The surrounding top and bottom bars are provided by * its own online URL and bundled offline snapshot.
* the app-level scaffold.
*/ */
@Composable @Composable
fun WebViewScreen( fun WebViewScreen(
page: WebPage, page: WebPage,
contentPadding: PaddingValues, contentPadding: PaddingValues,
darkTheme: Boolean = isSystemInDarkTheme(), darkTheme: Boolean = isSystemInDarkTheme(),
viewModel: WebViewModel = koinViewModel(key = page.name) { parametersOf(page) },
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
WebViewScreen(
uiState = uiState,
contentPadding = contentPadding,
darkTheme = darkTheme,
)
}
/**
* Renders the embedded page for [uiState], matching the app's [darkTheme]. A [WebViewLoader] covers
* the page while it loads; if the online page fails, the web view swaps in the offline snapshot. The
* surrounding top and bottom bars are provided by the app-level scaffold.
*/
@Composable
fun WebViewScreen(
uiState: WebUiState?,
contentPadding: PaddingValues,
darkTheme: Boolean = isSystemInDarkTheme(),
) { ) {
// Start in the loading state; each distinct page loads afresh. // Start in the loading state; each distinct page loads afresh.
var isLoading by remember(page) { mutableStateOf(true) } var isLoading by remember(uiState) { mutableStateOf(true) }
Box( Box(
modifier = Modifier modifier = Modifier
.padding(contentPadding) .padding(contentPadding)
.fillMaxSize(), .fillMaxSize(),
) { ) {
PlatformWebView( if (uiState != null) {
url = page.url, PlatformWebView(
darkTheme = darkTheme, url = uiState.url,
onLoadingStateChange = { isLoading = it }, offlineHtml = uiState.offlineHtml,
modifier = Modifier.fillMaxSize(), darkTheme = darkTheme,
) onLoadingStateChange = { isLoading = it },
modifier = Modifier.fillMaxSize(),
)
}
if (isLoading) { if (isLoading) {
WebViewLoader(modifier = Modifier.fillMaxSize()) WebViewLoader(modifier = Modifier.fillMaxSize())
} }
@@ -0,0 +1,16 @@
package bzh.ajaury.chombev.web.ui.viewmodel
import androidx.compose.runtime.Immutable
/**
* UI state for [bzh.ajaury.chombev.web.ui.WebViewScreen].
*
* [url] is the online page to display. [offlineHtml] is the bundled fallback shown when [url] fails
* to load; it is `null` until the snapshot has been read (or if reading it failed), in which case no
* offline fallback is available.
*/
@Immutable
data class WebUiState(
val url: String = "",
val offlineHtml: String? = null,
)
@@ -0,0 +1,42 @@
package bzh.ajaury.chombev.web.ui.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import bzh.ajaury.chombev.core.logging.domain.Logger
import bzh.ajaury.chombev.navigation.WebPage
import bzh.ajaury.chombev.resources.domain.ResourceReader
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
/**
* Owns the state for a single [page]: the online URL to display and its bundled offline snapshot,
* read from resources on init so it is ready as a fallback the moment the online page fails to load.
*/
class WebViewModel(
private val page: WebPage,
private val resourceReader: ResourceReader,
private val logger: Logger,
) : ViewModel() {
private val _uiState = MutableStateFlow<WebUiState?>(null)
val uiState: StateFlow<WebUiState?> = _uiState.asStateFlow()
init {
loadOfflineSnapshot()
}
private fun loadOfflineSnapshot() {
viewModelScope.launch {
val html = runCatching { resourceReader.read(page.offlineAsset) }
.onFailure {
logger.error(
"Failed to read offline snapshot ${page.offlineAsset}",
it,
)
}.getOrNull()
_uiState.update { WebUiState(url = page.url, offlineHtml = html) }
}
}
}
@@ -23,6 +23,7 @@ import platform.darwin.NSObject
@Composable @Composable
actual fun PlatformWebView( actual fun PlatformWebView(
url: String, url: String,
offlineHtml: String?,
darkTheme: Boolean, darkTheme: Boolean,
onLoadingStateChange: (Boolean) -> Unit, onLoadingStateChange: (Boolean) -> Unit,
modifier: Modifier, modifier: Modifier,
@@ -30,6 +31,8 @@ actual fun PlatformWebView(
// WKWebView holds its navigationDelegate weakly, so keep a strong reference across recompositions. // WKWebView holds its navigationDelegate weakly, so keep a strong reference across recompositions.
val navigationDelegate = remember { WebViewNavigationDelegate() } val navigationDelegate = remember { WebViewNavigationDelegate() }
navigationDelegate.onLoadingStateChange = onLoadingStateChange navigationDelegate.onLoadingStateChange = onLoadingStateChange
navigationDelegate.offlineHtml = offlineHtml
navigationDelegate.baseUrl = url
UIKitView( UIKitView(
modifier = modifier, modifier = modifier,
@@ -54,12 +57,19 @@ actual fun PlatformWebView(
/** /**
* Forwards WKWebView load lifecycle events to [onLoadingStateChange] so the UI can show a loader * Forwards WKWebView load lifecycle events to [onLoadingStateChange] so the UI can show a loader
* while a page is loading and hide it once loading finishes (or fails). * while a page is loading and hide it once loading finishes.
*
* When a navigation fails, it swaps in [offlineHtml] (loaded against [baseUrl] so links resolve) so
* the page still shows content offline. [showingOffline] guards against re-entering the fallback.
*/ */
private class WebViewNavigationDelegate : private class WebViewNavigationDelegate :
NSObject(), NSObject(),
WKNavigationDelegateProtocol { WKNavigationDelegateProtocol {
var onLoadingStateChange: (Boolean) -> Unit = {} var onLoadingStateChange: (Boolean) -> Unit = {}
var offlineHtml: String? = null
var baseUrl: String = ""
private var showingOffline = false
override fun webView( override fun webView(
webView: WKWebView, webView: WKWebView,
@@ -82,7 +92,7 @@ private class WebViewNavigationDelegate :
didFailNavigation: WKNavigation?, didFailNavigation: WKNavigation?,
withError: NSError, withError: NSError,
) { ) {
onLoadingStateChange(false) handleFailure(webView)
} }
// Shares the (WKWebView, WKNavigation?, NSError) Kotlin signature with didFailNavigation above. // Shares the (WKWebView, WKNavigation?, NSError) Kotlin signature with didFailNavigation above.
@@ -92,7 +102,17 @@ private class WebViewNavigationDelegate :
didFailProvisionalNavigation: WKNavigation?, didFailProvisionalNavigation: WKNavigation?,
withError: NSError, withError: NSError,
) { ) {
onLoadingStateChange(false) handleFailure(webView)
}
private fun handleFailure(webView: WKWebView) {
val html = offlineHtml
if (html != null && !showingOffline) {
showingOffline = true
webView.loadHTMLString(string = html, baseURL = NSURL.URLWithString(baseUrl))
} else {
onLoadingStateChange(false)
}
} }
} }
@@ -7,6 +7,7 @@ import androidx.compose.ui.Modifier
@Composable @Composable
actual fun PlatformWebView( actual fun PlatformWebView(
url: String, url: String,
offlineHtml: String?,
darkTheme: Boolean, darkTheme: Boolean,
onLoadingStateChange: (Boolean) -> Unit, onLoadingStateChange: (Boolean) -> Unit,
modifier: Modifier, modifier: Modifier,
@@ -7,6 +7,7 @@ import androidx.compose.ui.Modifier
@Composable @Composable
actual fun PlatformWebView( actual fun PlatformWebView(
url: String, url: String,
offlineHtml: String?,
darkTheme: Boolean, darkTheme: Boolean,
onLoadingStateChange: (Boolean) -> Unit, onLoadingStateChange: (Boolean) -> Unit,
modifier: Modifier, modifier: Modifier,
@@ -7,6 +7,7 @@ import androidx.compose.ui.Modifier
@Composable @Composable
actual fun PlatformWebView( actual fun PlatformWebView(
url: String, url: String,
offlineHtml: String?,
darkTheme: Boolean, darkTheme: Boolean,
onLoadingStateChange: (Boolean) -> Unit, onLoadingStateChange: (Boolean) -> Unit,
modifier: Modifier, modifier: Modifier,