@@ -3,33 +3,37 @@
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width,initial-scale=1.0" >
< title > Физика 8 — учебник< / title >
< link href = "https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&family=Inter:wght@400;500;600;700&display=swap" rel = "stylesheet" >
< title > Физика 8 класс — учебник< / title >
< link href = "https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&family=Inter:wght@400;500;600;700&family=Unbounded:wght@400;700;800;900& display=swap" rel = "stylesheet" >
< script src = "/js/api.js" defer > < / script >
< script src = "/js/xp.js" defer > < / script >
< script src = "/js/textbook-xp-widget.js" defer > < / script >
< style >
: root {
--bg : #eff6ff ; --card : #fff ;
--text : #1e293b ; --muted : #64748b ;
--border : #dbea fe ;
--pri : #2563eb ; --pri-d : #1d4ed8 ;
--amber : #d97706 ; --amber-d : #b45309 ; --amber-bg : #fef3c7 ;
--blue : #2563eb ; --blue-d : #1d4ed8 ; --blue-bg : #dbeafe ;
--violet : #7c3aed ; --violet-d : #6d28d9 ; --violet-bg : #ede9fe ;
--sh : 0 4 px 16 px rgba ( 37 , 99 , 235 , .10 ) ;
--sh-h : 0 12 px 36 px rgba ( 37 , 99 , 235 , .18 ) ;
--text : #1a1a2e ; --muted : #5b6b7d ;
--border : #bf dbfe ;
--pri : #1d4ed8 ; --pri-d : #1e40af ;
--pri-soft : #dbeafe ;
--acc : #06b6d4 ; --acc-d : #0891b2 ;
--ch1 : #f97316 ; --ch1-d : #ea580c ;
--ch2 : #2563eb ; --ch2-d : #1d4ed8 ;
--ch3 : #9333ea ; --ch3-d : #7c3aed ;
--sh : 0 4 px 16 px rgba ( 29 , 78 , 216 , .09 ) ;
--sh-h : 0 12 px 36 px rgba ( 29 , 78 , 216 , .18 ) ;
}
html . dark {
--bg : #0b1220 ; --card : #152033 ;
--text : #e2e8f0 ; --muted : #94a3b8 ;
--border : #1e293b ;
--amber-bg : rgba ( 217 , 119 , 6 , .16 ) ;
--blue-bg : rgba ( 37 , 99 , 235 , .18 ) ;
--violet-bg : rgba ( 124 , 58 , 237 , .18 ) ;
--bg : #0b1220 ; --card : #111c2d ;
--text : #e2e8f0 ; --muted : #80 94aa ;
--border : #1e3a5a ;
--pri-soft : rgba ( 29 , 78 , 216 , .16 ) ;
}
* { margin : 0 ; padding : 0 ; box-sizing : border-box }
html , body { min-height : 100 vh }
body { font-family : 'Inter' , system-ui , sans-serif ; background : var ( - - bg ) ; color : var ( - - text ) ; line-height : 1.55 ; transition : background .25 s , color .25 s }
. hdr { position : relative ; background : linear-gradient ( 120 deg , #1e3a8a 0 % , #2563eb 55 % , #3b82f6 100 % ) ; color : #fff ; padding : 32 px 24 px 28 px ; overflow : hidden ; border-bottom : 2 px solid rgba ( 255 , 255 , 255 , .08 ) }
/* HEADER */
. hdr { position : relative ; background : linear-gradient ( 110 deg , #1e3a8a 0 % , #1d4ed8 55 % , #06b6d4 100 % ) ; color : #fff ; padding : 32 px 24 px 28 px ; overflow : hidden ; border-bottom : 2 px solid rgba ( 255 , 255 , 255 , .08 ) }
. hdr :: before { content : 'ФИЗИКА' ; position : absolute ; right : -14 px ; top : -18 % ; font-family : 'Outfit' , sans-serif ; font-size : clamp ( 5 rem , 16 vw , 13 rem ) ; font-weight : 900 ; letter-spacing : -.04 em ; color : transparent ; -webkit- text-stroke : 1.5 px rgba ( 255 , 255 , 255 , .10 ) ; line-height : 1 ; pointer-events : none ; user-select : none }
. hdr-inner { position : relative ; z-index : 1 ; max-width : 1100 px ; margin : 0 auto ; display : flex ; align-items : center ; gap : 18 px ; flex-wrap : wrap }
. hdr-back { display : inline-flex ; align-items : center ; gap : 8 px ; padding : 8 px 14 px ; background : rgba ( 255 , 255 , 255 , .14 ) ; border-radius : 9 px ; color : #fff ; text-decoration : none ; font-size : .85 rem ; font-weight : 600 ; transition : background .15 s }
@@ -37,29 +41,21 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--t
. hdr h1 { font-family : 'Outfit' , sans-serif ; font-size : 1.85 rem ; font-weight : 900 ; letter-spacing : -.01 em }
. hdr-sub { font-size : .92 rem ; opacity : .85 ; margin-top : 4 px }
. hdr-side { margin-left : auto ; display : flex ; gap : 8 px }
. hdr-btn { padding : 8 px 12 px ; background : rgba ( 255 , 255 , 255 , .14 ) ; border : none ; color : #fff ; border-radius : 9 px ; cursor : pointer ; font-weight : 600 ; font-size : .82 rem ; display : inline-flex ; align-items : center ; gap : 6 px ; transition : background .15 s }
. hdr-btn { padding : 8 px 12 px ; background : rgba ( 255 , 255 , 255 , .14 ) ; border : none ; color : #fff ; border-radius : 9 px ; cursor : pointer ; font-weight : 600 ; font-size : .82 rem ; display : inline-flex ; align-items : center ; gap : 6 px ; transition : background .15 s ; font-family : inherit }
. hdr-btn : hover { background : rgba ( 255 , 255 , 255 , .24 ) }
. ic { width : 16 px ; height : 16 px ; stroke : currentColor ; fill : none ; stroke-width : 2 ; stroke-linecap : round ; stroke-linejoin : round }
main { max-width : 1100 px ; margin : 0 auto ; padding : 32 px 24 px 60 px }
/* INTRO */
. intro { background : var ( - - card ) ; border : 1 px solid var ( - - border ) ; border-radius : 18 px ; padding : 24 px 26 px ; margin-bottom : 30 px ; box-shadow : var ( - - sh ) ; position : relative ; overflow : hidden }
. intro :: before { content : '⚡' ; position : absolute ; right : -10 px ; top : -30 px ; font-size : 11 rem ; opacity : .05 ; line-height : 1 ; pointer-events : none }
. intro h2 { font-family : 'Outfit' , sans-serif ; font-size : 1.45 rem ; font-weight : 800 ; color : var ( - - pri - d ) ; margin-bottom : 10 px ; letter-spacing : -.01 em }
. intro p { font-size : 1.02 rem ; color : var ( - - text ) ; opacity : .9 ; max-width : 720 px ; margin-bottom : 8 px }
. intro . meta { margin-top : 14 px ; display : flex ; gap : 18 px ; flex-wrap : wrap ; font-size : .86 rem ; color : var ( - - muted ) }
. intro . meta b { color : var ( - - pri - d ) }
/* OVERALL PROGRESS */
. prog-overall { background : linear-gradient ( 135 deg , var ( - - blue - bg ) , var ( - - violet - bg ) ) ; border : 1 px solid var ( - - border ) ; border-radius : 14 px ; padding : 14 px 18 px ; margin-bottom : 28 px ; display : flex ; gap : 14 px ; align-items : center ; flex-wrap : wrap }
. po-icon { width : 46 px ; height : 46 px ; border-radius : 12 px ; background : linear-gradient ( 135 deg , #3b82f6 , #7c3aed ) ; color : #fff ; display : flex ; align-items : center ; justify-content : center ; flex-shrink : 0 ; font-family : 'Outfit' , sans-serif ; font-size : 1.4 rem ; font-weight : 900 }
. prog-overall { background : linear-gradient ( 135 deg , var ( - - pri - soft ) , rgba ( 6 , 182 , 212 , .12 ) ) ; border : 1 px solid var ( - - border ) ; border-radius : 14 px ; padding : 14 px 18 px ; margin-bottom : 28 px ; display : flex ; gap : 14 px ; align-items : center ; flex-wrap : wrap }
. po-icon { width : 46 px ; height : 46 px ; border-radius : 12 px ; background : linear-gradient ( 135 deg , #1d4ed8 , #06b6d4 ) ; color : #fff ; display : flex ; align-items : center ; justify-content : center ; flex-shrink : 0 ; font-family : 'Outfit' , sans-serif ; font-size : 1.4 rem ; font-weight : 900 }
. po-text { flex : 1 ; min-width : 160 px }
. po-label { font-size : .78 rem ; font-weight : 700 ; color : var ( - - muted ) ; text-transform : uppercase ; letter-spacing : .06 em ; margin-bottom : 4 px }
. po-bar { height : 8 px ; background : rgba ( 37 , 99 , 235 , .18 ) ; border-radius : 5 px ; overflow : hidden ; margin-top : 6 px }
. po-fill { height : 100 % ; background : linear-gradient ( 90 deg , var ( - - blue ) , var ( - - violet ) ) ; border-radius : 5 px ; transition : width .5 s }
. po-bar { height : 8 px ; background : rgba ( 29 , 78 , 216 , .12 ) ; border-radius : 5 px ; overflow : hidden ; margin-top : 6 px }
. po-fill { height : 100 % ; background : linear-gradient ( 90 deg , #1d4ed8 , #06b6d4 ) ; border-radius : 5 px ; transition : width .5 s }
/* CHAPTERS */
/* CHAPTER GRID */
. ch-grid { display : grid ; grid-template-columns : 1 fr ; gap : 18 px ; margin-bottom : 30 px }
@ media ( min-width : 760px ) { . ch-grid { grid-template-columns : 1 fr 1 fr 1 fr } }
@@ -67,42 +63,42 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 60px}
. ch-card : hover { transform : translateY ( -4 px ) ; box-shadow : var ( - - sh - h ) }
. ch-cover { padding : 22 px 22 px 18 px ; color : #fff ; position : relative ; overflow : hidden }
. ch-cover-wm { position : absolute ; right : -10 px ; top : -30 px ; font-size : 8 rem ; font-weight : 900 ; font-family : 'Outfit' , sans-serif ; line-height : 1 ; letter-spacing : -.04 em ; color : rgba ( 255 , 255 , 255 , .13 ) ; pointer-events : none }
. ch-num { display : inline-block ; padding : 4 px 10 px ; background : rgba ( 255 , 255 , 255 , .20 ) ; border-radius : 99 px ; font-size : .7 rem ; font-weight : 700 ; text-transform : uppercase ; letter-spacing : .08 em ; margin-bottom : 8 px ; position : relative ; z-index : 1 }
. ch-title { font-family : 'Outfit' , sans-serif ; font-size : 1.25 rem ; font-weight : 800 ; letter-spacing : -.01 em ; position : relative ; z-index : 1 }
. ch-num { display : inline-block ; padding : 4 px 10 px ; background : rgba ( 255 , 255 , 255 , .22 ) ; border-radius : 99 px ; font-size : .7 rem ; font-weight : 700 ; text-transform : uppercase ; letter-spacing : .08 em ; margin-bottom : 8 px ; position : relative ; z-index : 1 }
. ch-title { font-family : 'Outfit' , sans-serif ; font-size : 1.2 rem ; font-weight : 800 ; letter-spacing : -.01 em ; position : relative ; z-index : 1 ; line-height : 1.3 }
. ch-range { font-size : .86 rem ; opacity : .85 ; margin-top : 4 px ; position : relative ; z-index : 1 ; font-weight : 500 }
. ch-cover . thermal { background : linear-gradient ( 135 deg , #9 2400e , #d 9770 6 60 % , #f59e0b ) }
. ch-cover . electro { background : linear-gradient ( 135 deg , #1e40af , #2563eb 60 % , #3b82f6 ) }
. ch-cover . optics { background : linear-gradient ( 135 deg , #5 b21b6 , #7c3aed 60 % , #a855f7 ) }
. ch-cover . ch1 { background : linear-gradient ( 135 deg , #c 2410c , #f 9731 6 60 % , #fb923c ) }
. ch-cover . ch2 { background : linear-gradient ( 135 deg , #1e3a8a , #2563eb 60 % , #3b82f6 ) }
. ch-cover . ch3 { background : linear-gradient ( 135 deg , #6 b21a8 , #9333ea 60 % , #a855f7 ) }
. ch-body { padding : 18 px 22 px 20 px ; display : flex ; flex-direction : column ; flex : 1 }
. ch-desc { font-size : .92 rem ; color : var ( - - text ) ; opacity : .85 ; flex : 1 ; margin-bottom : 14 px ; line-height : 1.55 }
. ch-topics { display : flex ; flex-wrap : wrap ; gap : 5 px ; margin-bottom : 14 px }
. ch-topic { padding : 3 px 9 px ; background : var ( - - blue - bg ) ; color : var ( - - blue - d ) ; border-radius : 6 px ; font-size : .72 rem ; font-weight : 600 }
. ch-card . ch-topic . amber { background : var ( - - amber - bg ) ; color : var ( - - amber - d ) }
. ch-card . ch-topic . violet { background : var ( - - violet - bg ) ; color : var ( - - violet - d ) }
. ch-desc { font-size : .9 rem ; color : var ( - - text ) ; opacity : .82 ; flex : 1 ; margin-bottom : 14 px ; line-height : 1.55 }
. ch-prog { margin-bottom : 14 px }
. ch-prog-label { display : flex ; justify-content : space-between ; font-size : .74 rem ; color : var ( - - muted ) ; font-weight : 600 ; margin-bottom : 4 px }
. ch-prog-bar { height : 6 px ; background : rgba ( 37 , 99 , 235 , .12 ) ; border-radius : 4 px ; overflow : hidden }
. ch-prog-bar { height : 6 px ; background : rgba ( 29 , 78 , 216 , .10 ) ; border-radius : 4 px ; overflow : hidden }
. ch-prog-fill { height : 100 % ; border-radius : 4 px ; transition : width .5 s }
. ch-card . thermal . ch-prog-fill { background : linear-gradient ( 90 deg , #d97706 , #f59e0b ) }
. ch-card . electro . ch-prog-fill { background : linear-gradient ( 90 deg , #2563eb , #3b82f6 ) }
. ch-card . optics . ch-prog-fill { background : linear-gradient ( 90 deg , #7c3aed , #a855f7 ) }
. ch-card . ch1-card . ch-prog-fill { background : linear-gradient ( 90 deg , var ( - - ch1 ) , var ( - - ch1 - d ) ) }
. ch-card . ch2-card . ch-prog-fill { background : linear-gradient ( 90 deg , var ( - - ch2 ) , var ( - - ch2 - d ) ) }
. ch-card . ch3-card . ch-prog-fill { background : linear-gradient ( 90 deg , var ( - - ch3 ) , var ( - - ch3 - d ) ) }
. ch-action { display : flex ; align-items : center ; justify-content : space-between ; padding : 10 px 14 px ; border-radius : 11 px ; font-weight : 700 ; font-size : .92 rem ; color : #fff ; transition : filter .15 s }
. ch-action : hover { filter : brightness ( 1.08 ) }
. ch-card . thermal . ch-action { background : linear-gradient ( 135 deg , #d97706 , #f59e0b ) }
. ch-card . electro . ch-action { background : linear-gradient ( 135 deg , #2563eb , #3b82f6 ) }
. ch-card . optics . ch-action { background : linear-gradient ( 135 deg , #7c3aed , #a855f7 ) }
. ch-card . ch1-card . ch-action { background : linear-gradient ( 135 deg , var ( - - ch1 ) , #fb923c ) }
. ch-card . ch2-card . ch-action { background : linear-gradient ( 135 deg , var ( - - ch2 ) , #3b82f6 ) }
. ch-card . ch3-card . ch-action { background : linear-gradient ( 135 deg , var ( - - ch3 ) , #a855f7 ) }
/* INFO BLOCKS */
. info-grid { display : grid ; grid-template-columns : repeat ( auto - fit , minmax ( 220 px , 1 fr ) ) ; gap : 14 px ; margin-bottom : 30 px }
. info-card { background : var ( - - card ) ; border : 1 px solid var ( - - border ) ; border-radius : 13 px ; padding : 16 px 18 px ; display : flex ; gap : 12 px ; align-items : flex-start }
. info-card-ic { width : 38 px ; height : 38 px ; border-radius : 10 px ; background : var ( - - blue - bg ) ; color : var ( - - blue - d ) ; display : flex ; align-items : center ; justify-content : center ; flex-shrink : 0 }
. info-card-ic . ic { width : 20 px ; height : 20 px ; stroke-width : 2.2 }
. info-card-title { font-weight : 700 ; color : var ( - - pri - d ) ; margin-bottom : 3 px }
. info-card-text { font-size : .85 rem ; color : var ( - - muted ) ; line-height : 1.5 }
/* ACHIEVEMENT STRIP */
. ach-strip { background : var ( - - card ) ; border : 1.5 px solid var ( - - border ) ; border-radius : 16 px ; padding : 18 px 22 px ; margin-bottom : 28 px ; display : flex ; align-items : center ; gap : 16 px ; transition : border-color .4 s , box-shadow .4 s }
. ach-strip . lit { border-color : #f59e0b ; box-shadow : 0 0 0 3 px rgba ( 245 , 158 , 11 , .18 ) }
. ach-icon { width : 52 px ; height : 52 px ; border-radius : 14 px ; background : rgba ( 0 , 0 , 0 , .06 ) ; display : flex ; align-items : center ; justify-content : center ; flex-shrink : 0 ; transition : background .4 s }
. ach-strip . lit . ach-icon { background : linear-gradient ( 135 deg , #fbbf24 , #f59e0b ) }
. ach-icon svg { width : 28 px ; height : 28 px ; stroke : var ( - - muted ) }
. ach-strip . lit . ach-icon svg { stroke : #fff }
. ach-text { flex : 1 }
. ach-title { font-weight : 800 ; font-size : 1.02 rem ; color : var ( - - text ) }
. ach-sub { font-size : .85 rem ; color : var ( - - muted ) ; margin-top : 2 px }
. ach-strip . lit . ach-title { color : #92400e }
. foot { text-align : center ; padding : 24 px 16 px ; color : var ( - - muted ) ; font-size : .78 rem ; border-top : 1 px solid var ( - - border ) }
< / style >
@@ -118,8 +114,8 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 60px}
< / a >
< / div >
< div >
< h1 > Физика 8 класс< / h1 >
< div class = "hdr-sub" > Интерактивный учебник · 40 параграфов · 3 раздела < / div >
< h1 > Физика — 8 класс< / h1 >
< div class = "hdr-sub" > Три раздела: тепловые, электрические и световые явления < / div >
< / div >
< div class = "hdr-side" >
< button id = "theme-btn" class = "hdr-btn" title = "Сменить тему" >
@@ -133,89 +129,73 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 60px}
< main >
< section class = "prog-overall" >
< div class = "po-icon" > Σ < / div >
< div class = "po-icon" >
< svg width = "22" height = "22" viewBox = "0 0 24 24" fill = "none" stroke = "#fff" stroke-width = "2.2" stroke-linecap = "round" stroke-linejoin = "round" > < polygon points = "13 2 3 14 12 14 11 22 21 10 12 10 13 2" / > < / svg >
< / div >
< div class = "po-text" >
< div class = "po-label" > Общий прогресс по курсу< / div >
< div id = "overall-text" style = "font-size:1.05rem;font-weight:700" > — параграфов < / div >
< div id = "overall-text" style = "font-size:1.05rem;font-weight:700" > Загрузка... < / div >
< div class = "po-bar" > < div id = "overall-fill" class = "po-fill" style = "width:0%" > < / div > < / div >
< / div >
< / section >
< div class = "ch-grid" >
< a href = "/textbooks /physics8_ thermal.html " class = "ch-card thermal " id = "ch-thermal " >
< div class = "ch-cover thermal " >
< div class = "ch-cover-wm" > I < / div >
< div class = "ch-num" > Раздел I · §1–§1 1< / div >
< a href = "/textbook/physics-8- thermal" class = "ch-card ch1-card " id = "ch-1 " >
< div class = "ch-cover ch1 " >
< div class = "ch-cover-wm" > T < / div >
< div class = "ch-num" > Раздел 1< / div >
< div class = "ch-title" > Тепловые явления< / div >
< div class = "ch-range" > 11 параграфов < / div >
< div class = "ch-range" > §1–§11 < / div >
< / div >
< div class = "ch-body" >
< div class = "ch-desc" > Внутренняя энергия, теплопередача , удельная теплоёмкость, фазовые переходы, плавление и парообразование, тепловые двигатели.< / div >
< div class = "ch-topics" >
< span class = "ch-topic amber" > Температура< / span >
< span class = "ch-topic amber" > Теплоёмкость< / span >
< span class = "ch-topic amber" > Кипение< / span >
< span class = "ch-topic amber" > КПД< / span >
< / div >
< div class = "ch-desc" > Внутренняя энергия и её изменение, виды теплопередачи , удельная теплоёмкость, фазовые переходы, тепловые двигатели и их КПД .< / div >
< div class = "ch-prog" >
< div class = "ch-prog-label" > < span > Прогресс< / span > < span id = "prog-thermal " > 0%< / span > < / div >
< div class = "ch-prog-bar" > < div class = "ch-prog-fill" id = "fill-thermal " style = "width:0%" > < / div > < / div >
< div class = "ch-prog-label" > < span > Прогресс< / span > < span id = "prog-1 " > 0%< / span > < / div >
< div class = "ch-prog-bar" > < div class = "ch-prog-fill" id = "fill-1 " style = "width:0%" > < / div > < / div >
< / div >
< div class = "ch-action" >
< span id = "btn-thermal " > Открыть раздел< / span >
< span id = "btn-1 " > Открыть раздел< / span >
< svg class = "ic" viewBox = "0 0 24 24" > < polyline points = "9 18 15 12 9 6" / > < / svg >
< / div >
< / div >
< / a >
< a href = "/textbooks /physics8_ electro.html " class = "ch-card electro " id = "ch-electro " >
< div class = "ch-cover electro " >
< div class = "ch-cover-wm" > II < / div >
< div class = "ch-num" > Раздел II · §12–§31 < / div >
< a href = "/textbook/physics-8- electro" class = "ch-card ch2-card " id = "ch-2 " >
< div class = "ch-cover ch2 " >
< div class = "ch-cover-wm" > Φ < / div >
< div class = "ch-num" > Раздел 2 < / div >
< div class = "ch-title" > Электрические явления< / div >
< div class = "ch-range" > 20 параграфов < / div >
< div class = "ch-range" > §12–§31 < / div >
< / div >
< div class = "ch-body" >
< div class = "ch-desc" > Электризация , закон Кулона, электрически й ток, закон Ома, работа и мощность тока, электромагнитные явления, генератор и трансформатор .< / div >
< div class = "ch-topics" >
< span class = "ch-topic" > Электричество< / span >
< span class = "ch-topic" > Сопротивление< / span >
< span class = "ch-topic" > Закон Ома< / span >
< span class = "ch-topic" > Магнетизм< / span >
< / div >
< div class = "ch-desc" > Электростатика , закон Кулона, постоянны й ток, закон Ома, последовательные и параллельные цепи, работа и мощность тока.< / div >
< div class = "ch-prog" >
< div class = "ch-prog-label" > < span > Прогресс< / span > < span id = "prog-electro " > 0%< / span > < / div >
< div class = "ch-prog-bar" > < div class = "ch-prog-fill" id = "fill-electro " style = "width:0%" > < / div > < / div >
< div class = "ch-prog-label" > < span > Прогресс< / span > < span id = "prog-2 " > 0%< / span > < / div >
< div class = "ch-prog-bar" > < div class = "ch-prog-fill" id = "fill-2 " style = "width:0%" > < / div > < / div >
< / div >
< div class = "ch-action" >
< span id = "btn-electro " > Открыть раздел< / span >
< span id = "btn-2 " > Открыть раздел< / span >
< svg class = "ic" viewBox = "0 0 24 24" > < polyline points = "9 18 15 12 9 6" / > < / svg >
< / div >
< / div >
< / a >
< a href = "/textbooks /physics8_ optics.html " class = "ch-card optics " id = "ch-optics " >
< div class = "ch-cover optics " >
< div class = "ch-cover-wm" > III < / div >
< div class = "ch-num" > Раздел III · §32–§40 < / div >
< a href = "/textbook/physics-8- optics" class = "ch-card ch3-card " id = "ch-3 " >
< div class = "ch-cover ch3 " >
< div class = "ch-cover-wm" > λ < / div >
< div class = "ch-num" > Раздел 3 < / div >
< div class = "ch-title" > Световые явления< / div >
< div class = "ch-range" > 9 параграфов < / div >
< div class = "ch-range" > §32–§40 < / div >
< / div >
< div class = "ch-body" >
< div class = "ch-desc" > Источники света, прямолинейное распространение, отражение и преломление, плоское зеркало , линзы, оптические приборы, цвет и спектр.< / div >
< div class = "ch-topics" >
< span class = "ch-topic violet" > Свет< / span >
< span class = "ch-topic violet" > Линзы< / span >
< span class = "ch-topic violet" > Зеркала< / span >
< span class = "ch-topic violet" > Спектр< / span >
< / div >
< div class = "ch-desc" > Источники и распространение света , отражение и преломление, полное внутреннее отражение , линзы, оптические приборы, цвет и спектр.< / div >
< div class = "ch-prog" >
< div class = "ch-prog-label" > < span > Прогресс< / span > < span id = "prog-optics " > 0%< / span > < / div >
< div class = "ch-prog-bar" > < div class = "ch-prog-fill" id = "fill-optics " style = "width:0%" > < / div > < / div >
< div class = "ch-prog-label" > < span > Прогресс< / span > < span id = "prog-3 " > 0%< / span > < / div >
< div class = "ch-prog-bar" > < div class = "ch-prog-fill" id = "fill-3 " style = "width:0%" > < / div > < / div >
< / div >
< div class = "ch-action" >
< span id = "btn-optics " > Открыть раздел< / span >
< span id = "btn-3 " > Открыть раздел< / span >
< svg class = "ic" viewBox = "0 0 24 24" > < polyline points = "9 18 15 12 9 6" / > < / svg >
< / div >
< / div >
@@ -223,6 +203,17 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 60px}
< / div >
< div class = "ach-strip" id = "ach-strip" >
< div class = "ach-icon" >
< svg viewBox = "0 0 24 24" fill = "none" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< circle cx = "12" cy = "8" r = "6" / > < path d = "M15.477 12.89L17 22l-5-3-5 3 1.523-9.11" / >
< / svg >
< / div >
< div class = "ach-text" >
< div class = "ach-title" > Эксперт физики 8< / div >
< div class = "ach-sub" id = "ach-sub" > Прочитайте все 40 параграфов трёх разделов, чтобы получить достижение< / div >
< / div >
< / div >
< / main >
@@ -233,81 +224,90 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 60px}
< script >
'use strict' ;
/* THEME (sync with chapter files: they likely also use localStorage 'theme' or similar) */
/* THEME */
( function ( ) {
const t = localStorage . getItem ( 'physics8_theme' ) || localStorage . getItem ( 'theme' ) || 'light' ;
if ( t === 'dark' ) document . documentElement . classList . add ( 'dark' ) ;
const lab = document . getElementById ( 'theme-lab' ) ;
if ( lab ) lab . textContent = t === 'dark' ? 'Светлая' : 'Тёмная' ;
document . getElementById ( 'theme-btn' ) . addEventListener ( 'click' , ( ) => {
var saved = localStorage . getItem ( 'physics8_theme' ) || localStorage . getItem ( 'theme' ) || 'light' ;
if ( saved === 'dark' ) document . documentElement . classList . add ( 'dark' ) ;
var lab = document . getElementById ( 'theme-lab' ) ;
if ( lab ) lab . textContent = saved === 'dark' ? 'Светлая' : 'Тёмная' ;
document . getElementById ( 'theme-btn' ) . addEventListener ( 'click' , function ( ) {
document . documentElement . classList . toggle ( 'dark' ) ;
const dark = document . documentElement . classList . contains ( 'dark' ) ;
var dark = document . documentElement . classList . contains ( 'dark' ) ;
localStorage . setItem ( 'physics8_theme' , dark ? 'dark' : 'light' ) ;
localStorage . setItem ( 'theme' , dark ? 'dark' : 'light' ) ;
if ( lab ) lab . textContent = dark ? 'Светлая' : 'Тёмная' ;
if ( lab ) lab . textContent = dark ? 'Светлая' : 'Тёмная' ;
} ) ;
} ) ( ) ;
/* PROGRESS — читаем из LocalStorage главных файлов
(каждая глава физики 8 хранит свой прогресс, попробуем найти ключи) */
function readChapterProgress ( prefix , totalParas ) {
// Поищем ключи в localStorage: физика 8 главы хранят что-то типа "p1_done", "thermal_p3" и т.д.
// Применим эвристику: ищем ключи, содержащие prefix
let count = 0 ;
for ( let i = 0 ; i < localStorage . length ; i ++ ) {
const k = localStorage . key ( i ) ;
if ( ! k ) continue ;
const v = localStorage . getItem ( k ) ;
if ( k . toLowerCase ( ) . includes ( prefix ) && ( v === 'true' || v === '1' || v === 'done' ) ) {
count ++ ;
}
/* PROGRESS
Overall progress = weighted average by para_count across the 3 children.
Weight = child.para_count / 40 (total).
This gives each paragraph equal weight regardless of section size. */
var TOTAL = 40 ;
var CH _PARA = { 'physics-8-thermal' : 11 , 'physics-8-electro' : 20 , 'physics-8-optics' : 9 } ;
var CH _IDX = { 'physics-8-thermal' : 1 , 'physics-8-electro' : 2 , 'physics-8-optics' : 3 } ;
function setChProg ( idx , readCount , total ) {
var pct = total ? Math . round ( readCount * 100 / total ) : 0 ;
var labelEl = document . getElementById ( 'prog-' + idx ) ;
var fillEl = document . getElementById ( 'fill-' + idx ) ;
var btnEl = document . getElementById ( 'btn-' + idx ) ;
if ( labelEl ) labelEl . textContent = pct + '%' ;
if ( fillEl ) fillEl . style . width = pct + '%' ;
if ( btnEl ) {
if ( readCount > 0 && readCount < total ) btnEl . textContent = 'Продолжить' ;
else if ( readCount >= total ) btnEl . textContent = 'Открыть снова' ;
else btnEl . textContent = 'Открыть раздел' ;
}
// Fallback: попробуем разные форматы — JSON-массив пройденных
const candidates = [ ` physics8_ ${ prefix } _done ` , ` ${ prefix } _progress ` , ` physics8_ ${ prefix } _read ` ] ;
for ( const key of candidates ) {
const v = localStorage . getItem ( key ) ;
if ( v ) {
try {
const arr = JSON . parse ( v ) ;
if ( Array . isArray ( arr ) ) return Math . min ( arr . length , totalParas ) ;
} catch { }
}
}
return Math . min ( count , totalParas ) ;
return pct ;
}
function updateProgress ( ) {
const tBy = readChapterProgress ( 'thermal' , 11 ) ;
const eBy = readChapterProgress ( 'electro' , 20 ) ;
const oBy = readChapterProgress ( 'optics' , 9 ) ;
function set ( id , fillId , n , total ) {
const pct = total ? Math . round ( n * 100 / total ) : 0 ;
const el = document . getElementById ( id ) ;
const fl = document . getElementById ( fillId ) ;
if ( el ) el . textContent = pct + '% · ' + n + '/' + total ;
if ( fl ) fl . style . width = pct + '%' ;
function renderProgress ( children ) {
var totalRead = 0 ;
for ( var i = 0 ; i < children . length ; i ++ ) {
var ch = children [ i ] ;
var idx = CH _IDX [ ch . slug ] ;
if ( ! idx ) continue ;
var read = ch . progress ? ( Array . isArray ( ch . progress . read ) ? ch . progress . read . length : 0 ) : 0 ;
var total = ch . para _count || CH _PARA [ ch . slug ] || 1 ;
totalRead += read ;
setChProg ( idx , read , total ) ;
}
var pct = Math . round ( totalRead * 100 / TOTAL ) ;
var overallEl = document . getElementById ( 'overall-text' ) ;
var fillEl = document . getElementById ( 'overall-fill' ) ;
if ( overallEl ) overallEl . textContent = totalRead + ' из ' + TOTAL + ' параграфов · ' + pct + '%' ;
if ( fillEl ) fillEl . style . width = pct + '%' ;
if ( totalRead >= TOTAL ) {
var strip = document . getElementById ( 'ach-strip' ) ;
var sub = document . getElementById ( 'ach-sub' ) ;
if ( strip ) strip . classList . add ( 'lit' ) ;
if ( sub ) sub . textContent = 'Выполнено! Вы прочитали весь курс физики 8 класса.' ;
}
set ( 'prog-thermal' , 'fill-thermal' , tBy , 11 ) ;
set ( 'prog-electro' , 'fill-electro' , eBy , 20 ) ;
set ( 'prog-optics' , 'fill-optics' , oBy , 9 ) ;
const total = tBy + eBy + oBy ;
const totalPct = Math . round ( total * 100 / 40 ) ;
document . getElementById ( 'overall-text' ) . textContent = total + ' из 40 параграфов · ' + totalPct + '%' ;
document . getElementById ( 'overall-fill' ) . style . width = totalPct + '%' ;
// Buttons text
[ 'thermal' , 'electro' , 'optics' ] . forEach ( k => {
const elBtn = document . getElementById ( 'btn-' + k ) ;
if ( elBtn ) {
const n = k === 'thermal' ? tBy : k === 'electro' ? eBy : oBy ;
const total = k === 'thermal' ? 11 : k === 'electro' ? 20 : 9 ;
if ( n > 0 && n < total ) elBtn . textContent = 'Продолжить' ;
else if ( n >= total ) elBtn . textContent = 'Открыть снова' ;
else elBtn . textContent = 'Открыть раздел' ;
}
} ) ;
}
updateProgress ( ) ;
window . addEventListener ( 'focus' , updateProgress ) ;
function loadProgress ( ) {
if ( typeof window . LS === 'undefined' || typeof window . LS . api !== 'function' ) {
renderProgress ( [ ] ) ;
return ;
}
window . LS . api ( '/api/textbooks/physics-8/children' )
. then ( function ( data ) {
if ( data && data . children ) renderProgress ( data . children ) ;
else renderProgress ( [ ] ) ;
} )
. catch ( function ( ) { renderProgress ( [ ] ) ; } ) ;
}
if ( document . readyState === 'loading' ) {
document . addEventListener ( 'DOMContentLoaded' , loadProgress ) ;
} else {
loadProgress ( ) ;
}
window . addEventListener ( 'focus' , loadProgress ) ;
< / script >
< / body >