diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-14 21:34:49 -0800 |
|---|---|---|
| committer | Adam Mathes <adam@adammathes.com> | 2026-02-14 21:34:49 -0800 |
| commit | 6e28d1530aa08b878f5082bbcd85a95f84f830e8 (patch) | |
| tree | 7f6b1fb3a74166d97f2ba74f50d3cd787ec163dd /frontend/coverage/src/components | |
| parent | 5e2b1b2de36fc63cfa677705388f5701c62ee138 (diff) | |
| download | neko-6e28d1530aa08b878f5082bbcd85a95f84f830e8.tar.gz neko-6e28d1530aa08b878f5082bbcd85a95f84f830e8.tar.bz2 neko-6e28d1530aa08b878f5082bbcd85a95f84f830e8.zip | |
chore: update build artifacts and finalize test improvements
Diffstat (limited to 'frontend/coverage/src/components')
| -rw-r--r-- | frontend/coverage/src/components/FeedItem.css.html | 74 | ||||
| -rw-r--r-- | frontend/coverage/src/components/FeedItem.tsx.html | 18 | ||||
| -rw-r--r-- | frontend/coverage/src/components/FeedItems.css.html | 2 | ||||
| -rw-r--r-- | frontend/coverage/src/components/FeedItems.tsx.html | 254 | ||||
| -rw-r--r-- | frontend/coverage/src/components/FeedList.css.html | 150 | ||||
| -rw-r--r-- | frontend/coverage/src/components/FeedList.tsx.html | 215 | ||||
| -rw-r--r-- | frontend/coverage/src/components/Login.css.html | 2 | ||||
| -rw-r--r-- | frontend/coverage/src/components/Login.tsx.html | 55 | ||||
| -rw-r--r-- | frontend/coverage/src/components/Settings.css.html | 361 | ||||
| -rw-r--r-- | frontend/coverage/src/components/Settings.tsx.html | 316 | ||||
| -rw-r--r-- | frontend/coverage/src/components/index.html | 105 |
11 files changed, 1163 insertions, 389 deletions
diff --git a/frontend/coverage/src/components/FeedItem.css.html b/frontend/coverage/src/components/FeedItem.css.html index 213077f..192959f 100644 --- a/frontend/coverage/src/components/FeedItem.css.html +++ b/frontend/coverage/src/components/FeedItem.css.html @@ -188,7 +188,51 @@ <a name='L123'></a><a href='#L123'>123</a> <a name='L124'></a><a href='#L124'>124</a> <a name='L125'></a><a href='#L125'>125</a> -<a name='L126'></a><a href='#L126'>126</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<a name='L126'></a><a href='#L126'>126</a> +<a name='L127'></a><a href='#L127'>127</a> +<a name='L128'></a><a href='#L128'>128</a> +<a name='L129'></a><a href='#L129'>129</a> +<a name='L130'></a><a href='#L130'>130</a> +<a name='L131'></a><a href='#L131'>131</a> +<a name='L132'></a><a href='#L132'>132</a> +<a name='L133'></a><a href='#L133'>133</a> +<a name='L134'></a><a href='#L134'>134</a> +<a name='L135'></a><a href='#L135'>135</a> +<a name='L136'></a><a href='#L136'>136</a> +<a name='L137'></a><a href='#L137'>137</a> +<a name='L138'></a><a href='#L138'>138</a> +<a name='L139'></a><a href='#L139'>139</a> +<a name='L140'></a><a href='#L140'>140</a> +<a name='L141'></a><a href='#L141'>141</a> +<a name='L142'></a><a href='#L142'>142</a> +<a name='L143'></a><a href='#L143'>143</a> +<a name='L144'></a><a href='#L144'>144</a> +<a name='L145'></a><a href='#L145'>145</a> +<a name='L146'></a><a href='#L146'>146</a> +<a name='L147'></a><a href='#L147'>147</a> +<a name='L148'></a><a href='#L148'>148</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -330,7 +374,7 @@ } .item-title { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-family: var(--font-heading); font-size: 1.8rem; font-weight: bold; text-decoration: none; @@ -429,7 +473,7 @@ border: 1px solid var(--border-color, #ccc); color: blue; cursor: pointer; - font-family: 'Helvetica Neue'; + font-family: var(--font-heading); font-weight: bold; font-size: 0.8rem; padding: 2px 6px; @@ -438,6 +482,28 @@ .scrape-btn:hover { background: var(--sidebar-bg); +} + +@media (max-width: 768px) { + .feed-item { + margin-top: 2rem; + padding: 0.5rem; + } + + .item-title { + font-size: 1.4rem; + word-break: break-word; + } + + .item-header { + flex-direction: column; + gap: 0.5rem; + } + + .item-actions { + margin-left: 0; + margin-bottom: 0.5rem; + } }</pre></td></tr></table></pre> <div class='push'></div><!-- for sticky footer --> @@ -445,7 +511,7 @@ <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/FeedItem.tsx.html b/frontend/coverage/src/components/FeedItem.tsx.html index 6e76131..6df1fec 100644 --- a/frontend/coverage/src/components/FeedItem.tsx.html +++ b/frontend/coverage/src/components/FeedItem.tsx.html @@ -189,18 +189,18 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">33x</span> -<span class="cline-any cline-yes">33x</span> +<span class="cline-any cline-yes">56x</span> +<span class="cline-any cline-yes">56x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">33x</span> -<span class="cline-any cline-yes">16x</span> +<span class="cline-any cline-yes">56x</span> +<span class="cline-any cline-yes">22x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">33x</span> +<span class="cline-any cline-yes">56x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">33x</span> +<span class="cline-any cline-yes">56x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">1x</span> @@ -236,7 +236,7 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">33x</span> +<span class="cline-any cline-yes">56x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> @@ -254,7 +254,7 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">33x</span> +<span class="cline-any cline-yes">56x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -415,7 +415,7 @@ export default function FeedItem({ item: initialItem }: FeedItemProps) { <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/FeedItems.css.html b/frontend/coverage/src/components/FeedItems.css.html index 7a971c6..66a3307 100644 --- a/frontend/coverage/src/components/FeedItems.css.html +++ b/frontend/coverage/src/components/FeedItems.css.html @@ -136,7 +136,7 @@ <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/FeedItems.tsx.html b/frontend/coverage/src/components/FeedItems.tsx.html index f6b7493..9811743 100644 --- a/frontend/coverage/src/components/FeedItems.tsx.html +++ b/frontend/coverage/src/components/FeedItems.tsx.html @@ -23,30 +23,30 @@ <div class='clearfix'> <div class='fl pad1y space-right2'> - <span class="strong">88.97% </span> + <span class="strong">89.23% </span> <span class="quiet">Statements</span> - <span class='fraction'>113/127</span> + <span class='fraction'>116/130</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">75.3% </span> + <span class="strong">76.19% </span> <span class="quiet">Branches</span> - <span class='fraction'>61/81</span> + <span class='fraction'>64/84</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">86.2% </span> + <span class="strong">87.09% </span> <span class="quiet">Functions</span> - <span class='fraction'>25/29</span> + <span class='fraction'>27/31</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">88.69% </span> + <span class="strong">89.07% </span> <span class="quiet">Lines</span> - <span class='fraction'>102/115</span> + <span class='fraction'>106/119</span> </div> @@ -296,7 +296,25 @@ <a name='L231'></a><a href='#L231'>231</a> <a name='L232'></a><a href='#L232'>232</a> <a name='L233'></a><a href='#L233'>233</a> -<a name='L234'></a><a href='#L234'>234</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<a name='L234'></a><a href='#L234'>234</a> +<a name='L235'></a><a href='#L235'>235</a> +<a name='L236'></a><a href='#L236'>236</a> +<a name='L237'></a><a href='#L237'>237</a> +<a name='L238'></a><a href='#L238'>238</a> +<a name='L239'></a><a href='#L239'>239</a> +<a name='L240'></a><a href='#L240'>240</a> +<a name='L241'></a><a href='#L241'>241</a> +<a name='L242'></a><a href='#L242'>242</a> +<a name='L243'></a><a href='#L243'>243</a> +<a name='L244'></a><a href='#L244'>244</a> +<a name='L245'></a><a href='#L245'>245</a> +<a name='L246'></a><a href='#L246'>246</a> +<a name='L247'></a><a href='#L247'>247</a> +<a name='L248'></a><a href='#L248'>248</a> +<a name='L249'></a><a href='#L249'>249</a> +<a name='L250'></a><a href='#L250'>250</a> +<a name='L251'></a><a href='#L251'>251</a> +<a name='L252'></a><a href='#L252'>252</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -304,78 +322,78 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">27x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">36x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">27x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">36x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">8x</span> -<span class="cline-any cline-yes">1x</span> -<span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">7x</span> -<span class="cline-any cline-yes">7x</span> -<span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">8x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-yes">3x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">8x</span> <span class="cline-any cline-yes">8x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">8x</span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">11x</span> <span class="cline-any cline-yes">2x</span> -<span class="cline-any cline-yes">6x</span> +<span class="cline-any cline-yes">9x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">8x</span> -<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-yes">3x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">8x</span> -<span class="cline-any cline-yes">8x</span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-yes">11x</span> <span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">8x</span> +<span class="cline-any cline-yes">11x</span> <span class="cline-any cline-no"> </span> -<span class="cline-any cline-yes">8x</span> +<span class="cline-any cline-yes">11x</span> <span class="cline-any cline-no"> </span> <span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">8x</span> -<span class="cline-any cline-yes">8x</span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-yes">11x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">8x</span> -<span class="cline-any cline-yes">8x</span> -<span class="cline-any cline-yes">8x</span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-yes">11x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">8x</span> +<span class="cline-any cline-yes">11x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">7x</span> +<span class="cline-any cline-yes">10x</span> <span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">7x</span> -<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">10x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">6x</span> -<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-yes">9x</span> +<span class="cline-any cline-yes">3x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">6x</span> -<span class="cline-any cline-yes">6x</span> -<span class="cline-any cline-yes">6x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">9x</span> +<span class="cline-any cline-yes">9x</span> +<span class="cline-any cline-yes">9x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">1x</span> @@ -384,20 +402,21 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">7x</span> -<span class="cline-any cline-yes">7x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">8x</span> +<span class="cline-any cline-yes">8x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">2x</span> -<span class="cline-any cline-yes">2x</span> -<span class="cline-any cline-yes">2x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-yes">5x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">36x</span> <span class="cline-any cline-yes">2x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">3x</span> @@ -409,7 +428,7 @@ <span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> +<span class="cline-any cline-yes">36x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">2x</span> @@ -421,22 +440,29 @@ <span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">23x</span> -<span class="cline-any cline-yes">3x</span> +<span class="cline-any cline-yes">36x</span> +<span class="cline-any cline-yes">31x</span> +<span class="cline-any cline-yes">6x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">3x</span> -<span class="cline-any cline-yes">2x</span> -<span class="cline-any cline-yes">2x</span> -<span class="cline-any cline-yes">2x</span> -<span class="cline-any cline-yes">2x</span> -<span class="cline-any cline-yes">2x</span> +<span class="cline-any cline-yes">6x</span> +<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-yes">5x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">2x</span> +<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">5x</span> <span class="cline-any cline-yes">2x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-no"> </span> <span class="cline-any cline-no"> </span> @@ -455,25 +481,19 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">23x</span> -<span class="cline-any cline-yes">23x</span> +<span class="cline-any cline-yes">31x</span> +<span class="cline-any cline-yes">31x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">24x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">2x</span> +<span class="cline-any cline-yes">36x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">2x</span> -<span class="cline-any cline-yes">1x</span> -<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">31x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> @@ -488,29 +508,45 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">24x</span> -<span class="cline-any cline-yes">15x</span> -<span class="cline-any cline-yes">15x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">31x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">24x</span> -<span class="cline-any cline-yes">24x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">24x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">27x</span> -<span class="cline-any cline-yes">14x</span> +<span class="cline-any cline-yes">31x</span> +<span class="cline-any cline-yes">31x</span> +<span class="cline-any cline-yes">31x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">13x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">31x</span> +<span class="cline-any cline-yes">31x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">31x</span> +<span class="cline-any cline-yes">31x</span> +<span class="cline-any cline-yes">31x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">36x</span> <span class="cline-any cline-yes">21x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">20x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">44x</span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -620,6 +656,7 @@ export default function FeedItems() { useEffect(() => { fetchItems(); setSelectedIndex(-1); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [feedId, tagName, filterFn, searchParams]); @@ -668,6 +705,13 @@ export default function FeedItems() { } scrollToItem(nextIndex); } + + // If we're now on the last item and there are more items to load, + // trigger loading them so the next 'j' press will work + if (nextIndex === items.length - 1 && hasMore && !loadingMore) { + fetchItems(String(items[items.length - 1]._id)); + } + return nextIndex; }); <span class="missing-if-branch" title="if path not taken" >I</span>} else if (e.key === 'k') { @@ -690,22 +734,16 @@ export default function FeedItems() { window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); - }, [items]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [items, hasMore, loadingMore]); useEffect(() => { - const observer = new IntersectionObserver( + // Observer for marking items as read + const itemObserver = new IntersectionObserver( (entries) => { entries.forEach((entry) => { - // Infinity scroll sentinel - if (entry.target.id === 'load-more-sentinel') { - <span class="missing-if-branch" title="else path not taken" >E</span>if (entry.isIntersecting && !loadingMore && hasMore && items.length > 0) { - fetchItems(String(items[items.length - 1]._id)); - } - return; - } - // If item is not intersecting and is above the viewport, it's been scrolled past <span class="missing-if-branch" title="else path not taken" >E</span>if (!entry.isIntersecting && entry.boundingClientRect.top < 0) { const index = Number(entry.target.getAttribute('data-index')); @@ -721,15 +759,31 @@ export default function FeedItems() { { root: null, threshold: 0 } ); + // Observer for infinite scroll (less aggressive, must be fully visible) + const sentinelObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + <span class="missing-if-branch" title="else path not taken" >E</span>if (entry.isIntersecting && !loadingMore && hasMore && items.length > 0) { + fetchItems(String(items[items.length - 1]._id)); + } + }); + }, + { root: null, threshold: 1.0 } + ); + items.forEach((_, index) => { const el = document.getElementById(`item-${index}`); - <span class="missing-if-branch" title="else path not taken" >E</span>if (el) observer.observe(el); + <span class="missing-if-branch" title="else path not taken" >E</span>if (el) itemObserver.observe(el); }); const sentinel = document.getElementById('load-more-sentinel'); - if (sentinel) observer.observe(sentinel); + if (sentinel) sentinelObserver.observe(sentinel); - return () => observer.disconnect(); + return () => { + itemObserver.disconnect(); + sentinelObserver.disconnect(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [items, loadingMore, hasMore]); if (loading) return <div className="feed-items-loading">Loading items...</div>; @@ -769,7 +823,7 @@ export default function FeedItems() { <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/FeedList.css.html b/frontend/coverage/src/components/FeedList.css.html index 2b93e18..d892e77 100644 --- a/frontend/coverage/src/components/FeedList.css.html +++ b/frontend/coverage/src/components/FeedList.css.html @@ -236,7 +236,87 @@ <a name='L171'></a><a href='#L171'>171</a> <a name='L172'></a><a href='#L172'>172</a> <a name='L173'></a><a href='#L173'>173</a> -<a name='L174'></a><a href='#L174'>174</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<a name='L174'></a><a href='#L174'>174</a> +<a name='L175'></a><a href='#L175'>175</a> +<a name='L176'></a><a href='#L176'>176</a> +<a name='L177'></a><a href='#L177'>177</a> +<a name='L178'></a><a href='#L178'>178</a> +<a name='L179'></a><a href='#L179'>179</a> +<a name='L180'></a><a href='#L180'>180</a> +<a name='L181'></a><a href='#L181'>181</a> +<a name='L182'></a><a href='#L182'>182</a> +<a name='L183'></a><a href='#L183'>183</a> +<a name='L184'></a><a href='#L184'>184</a> +<a name='L185'></a><a href='#L185'>185</a> +<a name='L186'></a><a href='#L186'>186</a> +<a name='L187'></a><a href='#L187'>187</a> +<a name='L188'></a><a href='#L188'>188</a> +<a name='L189'></a><a href='#L189'>189</a> +<a name='L190'></a><a href='#L190'>190</a> +<a name='L191'></a><a href='#L191'>191</a> +<a name='L192'></a><a href='#L192'>192</a> +<a name='L193'></a><a href='#L193'>193</a> +<a name='L194'></a><a href='#L194'>194</a> +<a name='L195'></a><a href='#L195'>195</a> +<a name='L196'></a><a href='#L196'>196</a> +<a name='L197'></a><a href='#L197'>197</a> +<a name='L198'></a><a href='#L198'>198</a> +<a name='L199'></a><a href='#L199'>199</a> +<a name='L200'></a><a href='#L200'>200</a> +<a name='L201'></a><a href='#L201'>201</a> +<a name='L202'></a><a href='#L202'>202</a> +<a name='L203'></a><a href='#L203'>203</a> +<a name='L204'></a><a href='#L204'>204</a> +<a name='L205'></a><a href='#L205'>205</a> +<a name='L206'></a><a href='#L206'>206</a> +<a name='L207'></a><a href='#L207'>207</a> +<a name='L208'></a><a href='#L208'>208</a> +<a name='L209'></a><a href='#L209'>209</a> +<a name='L210'></a><a href='#L210'>210</a> +<a name='L211'></a><a href='#L211'>211</a> +<a name='L212'></a><a href='#L212'>212</a> +<a name='L213'></a><a href='#L213'>213</a> +<a name='L214'></a><a href='#L214'>214</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -411,10 +491,13 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">.feed-list { padding: 1rem; - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-family: var(--font-heading); color: #777; /* specific v1 color */ font-size: 0.8rem; + background: var(--sidebar-bg); + min-height: 100%; + flex: 1; } .feed-list h1.logo { @@ -429,9 +512,6 @@ z-index: 10; padding-bottom: 0.5rem; color: var(--text-color); - /* Usually dark/white depending on theme, v1 was white on blue? No, white on fixed header? No, v1 logo class says color: white. But sidebar is #ccc. */ - /* In v1 logo was fixed top left (blue header bar?). In v2 sidebar is #ccc. - Let's use theme text color but maybe bolder? */ } /* Override logo color if necessary for themes */ @@ -466,11 +546,25 @@ margin: 1rem 0 0.25rem 0; cursor: pointer; user-select: none; - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-family: var(--font-heading); color: #333; /* Darker than list items */ text-transform: lowercase; font-variant: small-caps; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.caret { + display: inline-block; + font-size: 0.6rem; + transition: transform 0.2s ease; + color: #777; +} + +.caret.expanded { + transform: rotate(90deg); } .filter-list, @@ -537,19 +631,25 @@ .nav-section { margin-top: 2rem; - border-top: 1px solid var(--border-color, #999); - padding-top: 0.5rem; + border-top: 1px solid var(--border-color, #eee); + padding-top: 1rem; } .logout-link { text-align: left; width: 100%; color: #777; - /* Make logout less prominent */ + display: block; +} + +.nav-link, +.logout-link { + padding: 0.25rem 0; } .logout-link:hover { color: var(--link-color, blue); + text-decoration: underline; } .theme-section { @@ -559,20 +659,40 @@ .theme-selector { display: flex; gap: 0.5rem; + margin-top: 0.5rem; } .theme-selector button { - background: transparent; - border: 1px solid var(--border-color, #999); + background: rgba(0, 0, 0, 0.05); + border: none; cursor: pointer; - padding: 0.1rem 0.3rem; - font-size: 0.9rem; - border-radius: 0; + padding: 0.4rem; + font-size: 1rem; + border-radius: 8px; + line-height: 1; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; +} + +.theme-selector button:hover { + background: rgba(0, 0, 0, 0.1); + transform: translateY(-2px); } .theme-selector button.active { background: var(--border-color, #999); color: white; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +.theme-dark .theme-selector button { + background: rgba(255, 255, 255, 0.1); +} + +.theme-dark .theme-selector button:hover { + background: rgba(255, 255, 255, 0.2); } /* Scrollbar styling for webkit */ @@ -589,7 +709,7 @@ <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/FeedList.tsx.html b/frontend/coverage/src/components/FeedList.tsx.html index acb2ede..4061422 100644 --- a/frontend/coverage/src/components/FeedList.tsx.html +++ b/frontend/coverage/src/components/FeedList.tsx.html @@ -23,30 +23,30 @@ <div class='clearfix'> <div class='fl pad1y space-right2'> - <span class="strong">79.54% </span> + <span class="strong">87.27% </span> <span class="quiet">Statements</span> - <span class='fraction'>35/44</span> + <span class='fraction'>48/55</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">64.86% </span> + <span class="strong">70% </span> <span class="quiet">Branches</span> - <span class='fraction'>24/37</span> + <span class='fraction'>35/50</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">64.7% </span> + <span class="strong">78.94% </span> <span class="quiet">Functions</span> - <span class='fraction'>11/17</span> + <span class='fraction'>15/19</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">82.05% </span> + <span class="strong">90% </span> <span class="quiet">Lines</span> - <span class='fraction'>32/39</span> + <span class='fraction'>45/50</span> </div> @@ -61,7 +61,7 @@ </div> </template> </div> - <div class='status-line medium'></div> + <div class='status-line high'></div> <pre><table class="coverage"> <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a> <a name='L2'></a><a href='#L2'>2</a> @@ -248,7 +248,34 @@ <a name='L183'></a><a href='#L183'>183</a> <a name='L184'></a><a href='#L184'>184</a> <a name='L185'></a><a href='#L185'>185</a> -<a name='L186'></a><a href='#L186'>186</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<a name='L186'></a><a href='#L186'>186</a> +<a name='L187'></a><a href='#L187'>187</a> +<a name='L188'></a><a href='#L188'>188</a> +<a name='L189'></a><a href='#L189'>189</a> +<a name='L190'></a><a href='#L190'>190</a> +<a name='L191'></a><a href='#L191'>191</a> +<a name='L192'></a><a href='#L192'>192</a> +<a name='L193'></a><a href='#L193'>193</a> +<a name='L194'></a><a href='#L194'>194</a> +<a name='L195'></a><a href='#L195'>195</a> +<a name='L196'></a><a href='#L196'>196</a> +<a name='L197'></a><a href='#L197'>197</a> +<a name='L198'></a><a href='#L198'>198</a> +<a name='L199'></a><a href='#L199'>199</a> +<a name='L200'></a><a href='#L200'>200</a> +<a name='L201'></a><a href='#L201'>201</a> +<a name='L202'></a><a href='#L202'>202</a> +<a name='L203'></a><a href='#L203'>203</a> +<a name='L204'></a><a href='#L204'>204</a> +<a name='L205'></a><a href='#L205'>205</a> +<a name='L206'></a><a href='#L206'>206</a> +<a name='L207'></a><a href='#L207'>207</a> +<a name='L208'></a><a href='#L208'>208</a> +<a name='L209'></a><a href='#L209'>209</a> +<a name='L210'></a><a href='#L210'>210</a> +<a name='L211'></a><a href='#L211'>211</a> +<a name='L212'></a><a href='#L212'>212</a> +<a name='L213'></a><a href='#L213'>213</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -263,62 +290,85 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">13x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">13x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">22x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-no"> </span> -<span class="cline-any cline-no"> </span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">11x</span> +<span class="cline-any cline-yes">11x</span> <span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">2x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">22x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">13x</span> -<span class="cline-any cline-yes">6x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">4x</span> -<span class="cline-any cline-yes">4x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">4x</span> -<span class="cline-any cline-yes">4x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">2x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">4x</span> -<span class="cline-any cline-yes">4x</span> -<span class="cline-any cline-yes">4x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">22x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">13x</span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">9x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">7x</span> +<span class="cline-any cline-yes">7x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">7x</span> +<span class="cline-any cline-yes">7x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">7x</span> +<span class="cline-any cline-yes">7x</span> <span class="cline-any cline-yes">7x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">6x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">6x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">22x</span> +<span class="cline-any cline-yes">13x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">12x</span> +<span class="cline-any cline-yes">2x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">12x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> @@ -330,7 +380,8 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-no"> </span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -384,6 +435,8 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">2x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -415,6 +468,7 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -437,36 +491,49 @@ import { Link, useNavigate, useSearchParams, useLocation, useParams } from 'react-router-dom'; import type { Feed, Category } from '../types'; import './FeedList.css'; +import './FeedListVariants.css'; import { apiFetch } from '../utils'; export default function FeedList({ theme, setTheme, setSidebarVisible, + isMobile, }: { theme: string; setTheme: (t: string) => void; setSidebarVisible: (visible: boolean) => void; + isMobile: boolean; }) { const [feeds, setFeeds] = useState<Feed[]>([]); const [tags, setTags] = useState<Category[]>([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [feedsExpanded, setFeedsExpanded] = useState(false); + const [tagsExpanded, setTagsExpanded] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const location = useLocation(); const { feedId, tagName } = useParams(); + const sidebarVariant = searchParams.get('sidebar') || localStorage.getItem('neko-sidebar-variant') || 'glass'; + + useEffect(() => { + const variant = searchParams.get('sidebar'); + <span class="missing-if-branch" title="if path not taken" >I</span>if (variant) { +<span class="cstat-no" title="statement not covered" > localStorage.setItem('neko-sidebar-variant', variant);</span> + } + }, [searchParams]); + const currentFilter = searchParams.get('filter') || (location.pathname === '/' && !feedId && !tagName ? 'unread' : <span class="branch-1 cbranch-no" title="branch not covered" >'');</span> - const handleSearch = <span class="fstat-no" title="function not covered" >(e</span>: React.FormEvent) => { -<span class="cstat-no" title="statement not covered" > e.preventDefault();</span> -<span class="cstat-no" title="statement not covered" > if (searchQuery.trim()) {</span> -<span class="cstat-no" title="statement not covered" > navigate(`/?q=${encodeURIComponent(searchQuery.trim())}`);</span> + const handleSearch = (e: React.FormEvent) => { + e.preventDefault(); + <span class="missing-if-branch" title="else path not taken" >E</span>if (searchQuery.trim()) { + navigate(`/?q=${encodeURIComponent(searchQuery.trim())}`); } }; @@ -474,15 +541,25 @@ export default function FeedList({ setFeedsExpanded(!feedsExpanded); }; + const toggleTags = <span class="fstat-no" title="function not covered" >() => {</span> +<span class="cstat-no" title="statement not covered" > setTagsExpanded(!tagsExpanded);</span> + }; + + const handleLinkClick = () => { + <span class="missing-if-branch" title="else path not taken" >E</span>if (isMobile) { + setSidebarVisible(false); + } + }; + useEffect(() => { Promise.all([ apiFetch('/api/feed/').then((res) => { <span class="missing-if-branch" title="if path not taken" >I</span>if (!res.ok) <span class="cstat-no" title="statement not covered" >throw new Error('Failed to fetch feeds');</span> - return res.json(); + return res.json() as Promise<Feed[]>; }), apiFetch('/api/tag').then((res) => { <span class="missing-if-branch" title="if path not taken" >I</span>if (!res.ok) <span class="cstat-no" title="statement not covered" >throw new Error('Failed to fetch tags');</span> - return res.json(); + return res.json() as Promise<Category[]>; }), ]) .then(([feedsData, tagsData]) => { @@ -504,7 +581,7 @@ export default function FeedList({ }; return ( - <div className="feed-list"> + <div className={`feed-list variant-${sidebarVariant}`}> <h1 className="logo" onClick={<span class="fstat-no" title="function not covered" >() => <span class="cstat-no" title="statement not covered" >s</span>etSidebarVisible(false)}></span> 🐱 </h1> @@ -515,7 +592,7 @@ export default function FeedList({ type="search" placeholder="search..." value={searchQuery} - onChange={<span class="fstat-no" title="function not covered" >(e</span>) => <span class="cstat-no" title="statement not covered" >setSearchQuery(e.target.value)}</span> + onChange={(e) => setSearchQuery(e.target.value)} className="search-input" /> </form> @@ -524,17 +601,17 @@ export default function FeedList({ <div className="filter-section"> <ul className="filter-list"> <li className="unread_filter"> - <Link to="/?filter=unread" className={currentFilter === 'unread' ? 'active' : <span class="branch-1 cbranch-no" title="branch not covered" >''}></span> + <Link to="/?filter=unread" className={currentFilter === 'unread' ? 'active' : <span class="branch-1 cbranch-no" title="branch not covered" >''} o</span>nClick={handleLinkClick}> unread </Link> </li> <li className="all_filter"> - <Link to="/?filter=all" className={currentFilter === 'all' ? <span class="branch-0 cbranch-no" title="branch not covered" >'active' : '</span>'}> + <Link to="/?filter=all" className={currentFilter === 'all' ? <span class="branch-0 cbranch-no" title="branch not covered" >'active' : '</span>'} onClick={handleLinkClick}> all </Link> </li> <li className="starred_filter"> - <Link to="/?filter=starred" className={currentFilter === 'starred' ? <span class="branch-0 cbranch-no" title="branch not covered" >'active' : '</span>'}> + <Link to="/?filter=starred" className={currentFilter === 'starred' ? <span class="branch-0 cbranch-no" title="branch not covered" >'active' : '</span>'} onClick={handleLinkClick}> starred </Link> </li> @@ -542,26 +619,29 @@ export default function FeedList({ </div> <div className="tag-section"> - <h4 onClick={<span class="fstat-no" title="function not covered" >() => {</span> }} className="section-header"> - Tags + <h4 onClick={toggleTags} className="section-header"> + <span className={`caret ${tagsExpanded ? 'expanded' : <span class="branch-1 cbranch-no" title="branch not covered" >''}</span>`}>▶</span> Tags </h4> - <ul className="tag-list-items"> - {tags.map((tag) => ( - <li key={tag.title} className="tag-item"> - <Link - to={`/tag/${encodeURIComponent(tag.title)}`} - className={`tag-link ${tagName === tag.title ? <span class="branch-0 cbranch-no" title="branch not covered" >'active' : '</span>'}`} - > - {tag.title} - </Link> - </li> - ))} - </ul> + {tagsExpanded && ( + <ul className="tag-list-items"> + {tags.map((tag) => ( + <li key={tag.title} className="tag-item"> + <Link + to={`/tag/${encodeURIComponent(tag.title)}`} + className={`tag-link ${tagName === tag.title ? <span class="branch-0 cbranch-no" title="branch not covered" >'active' : '</span>'}`} + onClick={handleLinkClick} + > + {tag.title} + </Link> + </li> + ))} + </ul> + )} </div> <div className="feed-section"> <h4 onClick={toggleFeeds} className="section-header"> - Feeds + <span className={`caret ${feedsExpanded ? 'expanded' : ''}`}>▶</span> Feeds </h4> {feedsExpanded && (feeds.length === 0 ? ( @@ -573,6 +653,7 @@ export default function FeedList({ <Link to={`/feed/${feed._id}`} className={`feed-title ${feedId === String(feed._id) ? <span class="branch-0 cbranch-no" title="branch not covered" >'active' : '</span>'}`} + onClick={handleLinkClick} > {feed.title || <span class="branch-1 cbranch-no" title="branch not covered" >feed.url}</span> </Link> @@ -585,7 +666,7 @@ export default function FeedList({ <div className="nav-section"> <ul className="nav-list"> <li> - <Link to="/settings" className="nav-link"> + <Link to="/settings" className="nav-link" onClick={handleLinkClick}> settings </Link> </li> @@ -625,7 +706,7 @@ export default function FeedList({ <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/Login.css.html b/frontend/coverage/src/components/Login.css.html index 031618b..140a86b 100644 --- a/frontend/coverage/src/components/Login.css.html +++ b/frontend/coverage/src/components/Login.css.html @@ -259,7 +259,7 @@ button[type='submit']:hover { <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/Login.tsx.html b/frontend/coverage/src/components/Login.tsx.html index 43fb613..111dcba 100644 --- a/frontend/coverage/src/components/Login.tsx.html +++ b/frontend/coverage/src/components/Login.tsx.html @@ -25,7 +25,7 @@ <div class='fl pad1y space-right2'> <span class="strong">100% </span> <span class="quiet">Statements</span> - <span class='fraction'>17/17</span> + <span class='fraction'>20/20</span> </div> @@ -39,14 +39,14 @@ <div class='fl pad1y space-right2'> <span class="strong">100% </span> <span class="quiet">Functions</span> - <span class='fraction'>3/3</span> + <span class='fraction'>4/4</span> </div> <div class='fl pad1y space-right2'> <span class="strong">100% </span> <span class="quiet">Lines</span> - <span class='fraction'>17/17</span> + <span class='fraction'>20/20</span> </div> @@ -119,18 +119,30 @@ <a name='L54'></a><a href='#L54'>54</a> <a name='L55'></a><a href='#L55'>55</a> <a name='L56'></a><a href='#L56'>56</a> -<a name='L57'></a><a href='#L57'>57</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<a name='L57'></a><a href='#L57'>57</a> +<a name='L58'></a><a href='#L58'>58</a> +<a name='L59'></a><a href='#L59'>59</a> +<a name='L60'></a><a href='#L60'>60</a> +<a name='L61'></a><a href='#L61'>61</a> +<a name='L62'></a><a href='#L62'>62</a> +<a name='L63'></a><a href='#L63'>63</a> +<a name='L64'></a><a href='#L64'>64</a> +<a name='L65'></a><a href='#L65'>65</a> +<a name='L66'></a><a href='#L66'>66</a> +<a name='L67'></a><a href='#L67'>67</a> +<a name='L68'></a><a href='#L68'>68</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> -<span class="cline-any cline-yes">14x</span> -<span class="cline-any cline-yes">14x</span> +<span class="cline-any cline-yes">17x</span> +<span class="cline-any cline-yes">17x</span> +<span class="cline-any cline-yes">17x</span> +<span class="cline-any cline-yes">17x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> +<span class="cline-any cline-yes">17x</span> <span class="cline-any cline-yes">3x</span> <span class="cline-any cline-yes">3x</span> <span class="cline-any cline-neutral"> </span> @@ -138,6 +150,7 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">3x</span> <span class="cline-any cline-yes">3x</span> +<span class="cline-any cline-yes">3x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">3x</span> <span class="cline-any cline-neutral"> </span> @@ -155,10 +168,19 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> +<span class="cline-any cline-yes">17x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">3x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -182,6 +204,7 @@ import './Login.css'; import { apiFetch } from '../utils'; export default function Login() { + const [username, setUsername] = useState('neko'); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const navigate = useNavigate(); @@ -193,6 +216,7 @@ export default function Login() { try { // Use URLSearchParams to send as form-urlencoded, matching backend expectation const params = new URLSearchParams(); + params.append('username', username); params.append('password', password); const res = await apiFetch('/api/login', { @@ -206,7 +230,7 @@ export default function Login() { const data = await res.json(); setError(data.message || <span class="branch-1 cbranch-no" title="branch not covered" >'Login failed')</span>; } - } catch (err) { + } catch (_err) { setError('Network error'); } }; @@ -216,6 +240,15 @@ export default function Login() { <form onSubmit={handleSubmit} className="login-form"> <h1>neko rss mode</h1> <div className="form-group"> + <label htmlFor="username">username</label> + <input + id="username" + type="text" + value={username} + onChange={(e) => setUsername(e.target.value)} + /> + </div> + <div className="form-group"> <label htmlFor="password">password</label> <input id="password" @@ -238,7 +271,7 @@ export default function Login() { <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/Settings.css.html b/frontend/coverage/src/components/Settings.css.html index 28a1915..4109bba 100644 --- a/frontend/coverage/src/components/Settings.css.html +++ b/frontend/coverage/src/components/Settings.css.html @@ -223,7 +223,86 @@ <a name='L158'></a><a href='#L158'>158</a> <a name='L159'></a><a href='#L159'>159</a> <a name='L160'></a><a href='#L160'>160</a> -<a name='L161'></a><a href='#L161'>161</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<a name='L161'></a><a href='#L161'>161</a> +<a name='L162'></a><a href='#L162'>162</a> +<a name='L163'></a><a href='#L163'>163</a> +<a name='L164'></a><a href='#L164'>164</a> +<a name='L165'></a><a href='#L165'>165</a> +<a name='L166'></a><a href='#L166'>166</a> +<a name='L167'></a><a href='#L167'>167</a> +<a name='L168'></a><a href='#L168'>168</a> +<a name='L169'></a><a href='#L169'>169</a> +<a name='L170'></a><a href='#L170'>170</a> +<a name='L171'></a><a href='#L171'>171</a> +<a name='L172'></a><a href='#L172'>172</a> +<a name='L173'></a><a href='#L173'>173</a> +<a name='L174'></a><a href='#L174'>174</a> +<a name='L175'></a><a href='#L175'>175</a> +<a name='L176'></a><a href='#L176'>176</a> +<a name='L177'></a><a href='#L177'>177</a> +<a name='L178'></a><a href='#L178'>178</a> +<a name='L179'></a><a href='#L179'>179</a> +<a name='L180'></a><a href='#L180'>180</a> +<a name='L181'></a><a href='#L181'>181</a> +<a name='L182'></a><a href='#L182'>182</a> +<a name='L183'></a><a href='#L183'>183</a> +<a name='L184'></a><a href='#L184'>184</a> +<a name='L185'></a><a href='#L185'>185</a> +<a name='L186'></a><a href='#L186'>186</a> +<a name='L187'></a><a href='#L187'>187</a> +<a name='L188'></a><a href='#L188'>188</a> +<a name='L189'></a><a href='#L189'>189</a> +<a name='L190'></a><a href='#L190'>190</a> +<a name='L191'></a><a href='#L191'>191</a> +<a name='L192'></a><a href='#L192'>192</a> +<a name='L193'></a><a href='#L193'>193</a> +<a name='L194'></a><a href='#L194'>194</a> +<a name='L195'></a><a href='#L195'>195</a> +<a name='L196'></a><a href='#L196'>196</a> +<a name='L197'></a><a href='#L197'>197</a> +<a name='L198'></a><a href='#L198'>198</a> +<a name='L199'></a><a href='#L199'>199</a> +<a name='L200'></a><a href='#L200'>200</a> +<a name='L201'></a><a href='#L201'>201</a> +<a name='L202'></a><a href='#L202'>202</a> +<a name='L203'></a><a href='#L203'>203</a> +<a name='L204'></a><a href='#L204'>204</a> +<a name='L205'></a><a href='#L205'>205</a> +<a name='L206'></a><a href='#L206'>206</a> +<a name='L207'></a><a href='#L207'>207</a> +<a name='L208'></a><a href='#L208'>208</a> +<a name='L209'></a><a href='#L209'>209</a> +<a name='L210'></a><a href='#L210'>210</a> +<a name='L211'></a><a href='#L211'>211</a> +<a name='L212'></a><a href='#L212'>212</a> +<a name='L213'></a><a href='#L213'>213</a> +<a name='L214'></a><a href='#L214'>214</a> +<a name='L215'></a><a href='#L215'>215</a> +<a name='L216'></a><a href='#L216'>216</a> +<a name='L217'></a><a href='#L217'>217</a> +<a name='L218'></a><a href='#L218'>218</a> +<a name='L219'></a><a href='#L219'>219</a> +<a name='L220'></a><a href='#L220'>220</a> +<a name='L221'></a><a href='#L221'>221</a> +<a name='L222'></a><a href='#L222'>222</a> +<a name='L223'></a><a href='#L223'>223</a> +<a name='L224'></a><a href='#L224'>224</a> +<a name='L225'></a><a href='#L225'>225</a> +<a name='L226'></a><a href='#L226'>226</a> +<a name='L227'></a><a href='#L227'>227</a> +<a name='L228'></a><a href='#L228'>228</a> +<a name='L229'></a><a href='#L229'>229</a> +<a name='L230'></a><a href='#L230'>230</a> +<a name='L231'></a><a href='#L231'>231</a> +<a name='L232'></a><a href='#L232'>232</a> +<a name='L233'></a><a href='#L233'>233</a> +<a name='L234'></a><a href='#L234'>234</a> +<a name='L235'></a><a href='#L235'>235</a> +<a name='L236'></a><a href='#L236'>236</a> +<a name='L237'></a><a href='#L237'>237</a> +<a name='L238'></a><a href='#L238'>238</a> +<a name='L239'></a><a href='#L239'>239</a> +<a name='L240'></a><a href='#L240'>240</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -383,18 +462,151 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">.settings-page { - padding: 2rem; +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">.settings-page.variant-glass { + padding: 2.5rem; max-width: 800px; margin: 0 auto; + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-radius: 24px; + border: 1px solid rgba(255, 255, 255, 0.1); + font-family: system-ui, -apple-system, sans-serif; + color: var(--text-color); + margin-top: 2rem; + margin-bottom: 2rem; +} + +.settings-page.variant-glass h2, +.settings-page.variant-glass h3 { + font-weight: 700; + letter-spacing: -0.02em; + color: var(--text-color); + opacity: 0.9; } -.add-feed-section { - background: var(--sidebar-bg); +.add-feed-section, +.appearance-section, +.import-section, +.export-section, +.feed-list-section { + background: rgba(255, 255, 255, 0.03); padding: 1.5rem; - border-radius: 8px; + border-radius: 16px; margin-bottom: 2rem; - border: 1px solid var(--border-color); + border: 1px solid rgba(255, 255, 255, 0.05); + transition: all 0.3s ease; +} + +.add-feed-section:hover, +.appearance-section:hover, +.import-section:hover, +.export-section:hover, +.feed-list-section:hover { + background: rgba(255, 255, 255, 0.06); + border-color: rgba(255, 255, 255, 0.1); +} + +.font-selector { + display: flex; + align-items: center; + gap: 1rem; +} + +.font-select { + padding: 0.6rem 1rem; + border: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(0, 0, 0, 0.1); + color: var(--text-color); + border-radius: 20px; + font-size: 1rem; + min-width: 200px; + cursor: pointer; + outline: none; + transition: border-color 0.2s; +} + +.font-select:focus { + border-color: rgba(255, 255, 255, 0.3); } .add-feed-form { @@ -404,32 +616,45 @@ .feed-input { flex: 1; - padding: 0.5rem; - border: 1px solid var(--border-color); - background: var(--bg-color); + padding: 0.6rem 1.2rem; + border: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(0, 0, 0, 0.1); color: var(--text-color); - border-radius: 4px; + border-radius: 20px; font-size: 1rem; + outline: none; + transition: border-color 0.2s; +} + +.feed-input:focus { + border-color: rgba(255, 255, 255, 0.3); } .error-message { - color: #d32f2f; + color: #ff5252; margin-top: 1rem; + font-weight: 600; } .settings-feed-list { list-style: none; padding: 0; - border: 1px solid var(--border-color); - border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: 12px; + overflow: hidden; } .settings-feed-item { display: flex; justify-content: space-between; align-items: center; - padding: 1rem; - border-bottom: 1px solid var(--border-color); + padding: 1.2rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.05); + transition: background 0.2s; +} + +.settings-feed-item:hover { + background: rgba(255, 255, 255, 0.02); } .settings-feed-item:last-child { @@ -439,109 +664,121 @@ .feed-info { display: flex; flex-direction: column; + gap: 0.2rem; } .feed-title { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; - font-weight: bold; - font-size: 1.1rem; + font-weight: 600; + font-size: 1.05rem; + opacity: 0.9; } .feed-url { color: var(--text-color); - opacity: 0.6; - font-size: 0.9rem; + opacity: 0.5; + font-size: 0.85rem; } .delete-btn { - background: #ff5252; - color: white; - border: none; + background: rgba(255, 82, 82, 0.15); + color: #ff8a80; + border: 1px solid rgba(255, 82, 82, 0.2); padding: 0.5rem 1rem; - border-radius: 4px; + border-radius: 12px; cursor: pointer; + font-weight: 600; + transition: all 0.2s; } -.delete-btn:hover { - background: #ff1744; -} - -.delete-btn:disabled { - background: #ffcdd2; - cursor: not-allowed; +.delete-btn:hover:not(:disabled) { + background: rgba(255, 82, 82, 0.3); + color: #fff; + border-color: rgba(255, 82, 82, 0.4); + transform: scale(1.05); } .import-export-section { display: flex; gap: 2rem; - margin-bottom: 2rem; } @media (max-width: 600px) { + .settings-page.variant-glass { + padding: 1.5rem; + margin-top: 1rem; + } + + .add-feed-form { + flex-direction: column; + } + .import-export-section { flex-direction: column; + gap: 1rem; } -} -.import-section, -.export-section { - flex: 1; - background: var(--sidebar-bg); - padding: 1.5rem; - border-radius: 8px; - border: 1px solid var(--border-color); + .settings-feed-item { + flex-direction: column; + align-items: flex-start; + gap: 1rem; + } } .import-form { display: flex; flex-direction: column; - gap: 1rem; + gap: 1.2rem; } .file-input { font-size: 0.9rem; max-width: 100%; + color: var(--text-color); + opacity: 0.8; } .export-buttons { display: flex; - gap: 1rem; + gap: 0.8rem; flex-wrap: wrap; } .export-btn { display: inline-block; - padding: 0.5rem 1rem; - background: var(--bg-color); - color: var(--link-color); + padding: 0.6rem 1.2rem; + background: rgba(255, 255, 255, 0.05); + color: var(--text-color); text-decoration: none; - border: 1px solid var(--border-color); - border-radius: 4px; - font-weight: bold; - text-align: center; - min-width: 70px; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + font-weight: 600; + transition: all 0.2s; } .export-btn:hover { - background: var(--sidebar-bg); + background: rgba(255, 255, 255, 0.1); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } -button { +button:not(.delete-btn) { cursor: pointer; - padding: 0.5rem 1rem; - border-radius: 4px; - border: 1px solid var(--border-color); - background: var(--bg-color); + padding: 0.6rem 1.2rem; + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.1); color: var(--text-color); - font-weight: bold; + font-weight: 600; + transition: all 0.2s; } -button:hover:not(:disabled) { - background: var(--sidebar-bg); +button:not(.delete-btn):hover:not(:disabled) { + background: rgba(255, 255, 255, 0.2); + transform: scale(1.02); } button:disabled { - opacity: 0.5; + opacity: 0.4; cursor: not-allowed; }</pre></td></tr></table></pre> @@ -550,7 +787,7 @@ button:disabled { <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/Settings.tsx.html b/frontend/coverage/src/components/Settings.tsx.html index 3d8d219..892218e 100644 --- a/frontend/coverage/src/components/Settings.tsx.html +++ b/frontend/coverage/src/components/Settings.tsx.html @@ -23,30 +23,30 @@ <div class='clearfix'> <div class='fl pad1y space-right2'> - <span class="strong">56.25% </span> + <span class="strong">80% </span> <span class="quiet">Statements</span> - <span class='fraction'>36/64</span> + <span class='fraction'>60/75</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">41.66% </span> + <span class="strong">66.66% </span> <span class="quiet">Branches</span> - <span class='fraction'>10/24</span> + <span class='fraction'>20/30</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">63.63% </span> + <span class="strong">85.18% </span> <span class="quiet">Functions</span> - <span class='fraction'>14/22</span> + <span class='fraction'>23/27</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">62.5% </span> + <span class="strong">87.87% </span> <span class="quiet">Lines</span> - <span class='fraction'>35/56</span> + <span class='fraction'>58/66</span> </div> @@ -61,7 +61,7 @@ </div> </template> </div> - <div class='status-line medium'></div> + <div class='status-line high'></div> <pre><table class="coverage"> <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a> <a name='L2'></a><a href='#L2'>2</a> @@ -243,55 +243,138 @@ <a name='L178'></a><a href='#L178'>178</a> <a name='L179'></a><a href='#L179'>179</a> <a name='L180'></a><a href='#L180'>180</a> -<a name='L181'></a><a href='#L181'>181</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<a name='L181'></a><a href='#L181'>181</a> +<a name='L182'></a><a href='#L182'>182</a> +<a name='L183'></a><a href='#L183'>183</a> +<a name='L184'></a><a href='#L184'>184</a> +<a name='L185'></a><a href='#L185'>185</a> +<a name='L186'></a><a href='#L186'>186</a> +<a name='L187'></a><a href='#L187'>187</a> +<a name='L188'></a><a href='#L188'>188</a> +<a name='L189'></a><a href='#L189'>189</a> +<a name='L190'></a><a href='#L190'>190</a> +<a name='L191'></a><a href='#L191'>191</a> +<a name='L192'></a><a href='#L192'>192</a> +<a name='L193'></a><a href='#L193'>193</a> +<a name='L194'></a><a href='#L194'>194</a> +<a name='L195'></a><a href='#L195'>195</a> +<a name='L196'></a><a href='#L196'>196</a> +<a name='L197'></a><a href='#L197'>197</a> +<a name='L198'></a><a href='#L198'>198</a> +<a name='L199'></a><a href='#L199'>199</a> +<a name='L200'></a><a href='#L200'>200</a> +<a name='L201'></a><a href='#L201'>201</a> +<a name='L202'></a><a href='#L202'>202</a> +<a name='L203'></a><a href='#L203'>203</a> +<a name='L204'></a><a href='#L204'>204</a> +<a name='L205'></a><a href='#L205'>205</a> +<a name='L206'></a><a href='#L206'>206</a> +<a name='L207'></a><a href='#L207'>207</a> +<a name='L208'></a><a href='#L208'>208</a> +<a name='L209'></a><a href='#L209'>209</a> +<a name='L210'></a><a href='#L210'>210</a> +<a name='L211'></a><a href='#L211'>211</a> +<a name='L212'></a><a href='#L212'>212</a> +<a name='L213'></a><a href='#L213'>213</a> +<a name='L214'></a><a href='#L214'>214</a> +<a name='L215'></a><a href='#L215'>215</a> +<a name='L216'></a><a href='#L216'>216</a> +<a name='L217'></a><a href='#L217'>217</a> +<a name='L218'></a><a href='#L218'>218</a> +<a name='L219'></a><a href='#L219'>219</a> +<a name='L220'></a><a href='#L220'>220</a> +<a name='L221'></a><a href='#L221'>221</a> +<a name='L222'></a><a href='#L222'>222</a> +<a name='L223'></a><a href='#L223'>223</a> +<a name='L224'></a><a href='#L224'>224</a> +<a name='L225'></a><a href='#L225'>225</a> +<a name='L226'></a><a href='#L226'>226</a> +<a name='L227'></a><a href='#L227'>227</a> +<a name='L228'></a><a href='#L228'>228</a> +<a name='L229'></a><a href='#L229'>229</a> +<a name='L230'></a><a href='#L230'>230</a> +<a name='L231'></a><a href='#L231'>231</a> +<a name='L232'></a><a href='#L232'>232</a> +<a name='L233'></a><a href='#L233'>233</a> +<a name='L234'></a><a href='#L234'>234</a> +<a name='L235'></a><a href='#L235'>235</a> +<a name='L236'></a><a href='#L236'>236</a> +<a name='L237'></a><a href='#L237'>237</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-yes">9x</span> +<span class="cline-any cline-yes">9x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">9x</span> +<span class="cline-any cline-yes">9x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">9x</span> +<span class="cline-any cline-yes">9x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-no"> </span> +<span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> -<span class="cline-any cline-yes">14x</span> -<span class="cline-any cline-yes">14x</span> -<span class="cline-any cline-yes">14x</span> +<span class="cline-any cline-yes">34x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> +<span class="cline-any cline-yes">7x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> -<span class="cline-any cline-yes">4x</span> -<span class="cline-any cline-yes">4x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">4x</span> -<span class="cline-any cline-yes">4x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-yes">2x</span> +<span class="cline-any cline-yes">2x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">4x</span> -<span class="cline-any cline-yes">4x</span> +<span class="cline-any cline-yes">2x</span> +<span class="cline-any cline-yes">2x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-no"> </span> -<span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> -<span class="cline-any cline-yes">3x</span> +<span class="cline-any cline-yes">2x</span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> @@ -301,12 +384,22 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">1x</span> <span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-yes">1x</span> @@ -319,35 +412,28 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> -<span class="cline-any cline-no"> </span> -<span class="cline-any cline-no"> </span> -<span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-no"> </span> -<span class="cline-any cline-no"> </span> -<span class="cline-any cline-no"> </span> -<span class="cline-any cline-no"> </span> +<span class="cline-any cline-yes">34x</span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-no"> </span> -<span class="cline-any cline-no"> </span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-yes">1x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-no"> </span> <span class="cline-any cline-no"> </span> -<span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-no"> </span> -<span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">34x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">14x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -375,8 +461,32 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">2x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">1x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-no"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -403,7 +513,9 @@ <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> -<span class="cline-any cline-yes">5x</span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-neutral"> </span> +<span class="cline-any cline-yes">6x</span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> <span class="cline-any cline-neutral"> </span> @@ -428,15 +540,22 @@ import type { Feed } from '../types'; import './Settings.css'; import { apiFetch } from '../utils'; -export default function Settings() { +interface SettingsProps { + fontTheme?: string; + setFontTheme?: (t: string) => void; +} + +export default function Settings({ fontTheme, setFontTheme }: SettingsProps) { const [feeds, setFeeds] = useState<Feed[]>([]); + /* ... existing state ... */ const [newFeedUrl, setNewFeedUrl] = useState(''); const [loading, setLoading] = useState(false); const [error, setError] = useState<string | null>(null); const [importFile, setImportFile] = useState<File | null>(null); - const fetchFeeds = () => { + /* ... existing fetchFeeds ... */ + const fetchFeeds = React.useCallback(() => { setLoading(true); apiFetch('/api/feed/') .then((res) => { @@ -451,12 +570,14 @@ export default function Settings() { <span class="cstat-no" title="statement not covered" > setError(err.message);</span> <span class="cstat-no" title="statement not covered" > setLoading(false);</span> }); - }; + }, []); useEffect(() => { + // eslint-disable-next-line fetchFeeds(); - }, []); + }, [fetchFeeds]); + /* ... existing handlers ... */ const handleAddFeed = (e: React.FormEvent) => { e.preventDefault(); <span class="missing-if-branch" title="if path not taken" >I</span>if (!newFeedUrl) <span class="cstat-no" title="statement not covered" >return;</span> @@ -468,16 +589,16 @@ export default function Settings() { body: JSON.stringify({ url: newFeedUrl }), }) .then((res) => { - <span class="missing-if-branch" title="if path not taken" >I</span>if (!res.ok) <span class="cstat-no" title="statement not covered" >throw new Error('Failed to add feed');</span> + if (!res.ok) throw new Error('Failed to add feed'); return res.json(); }) .then(() => { setNewFeedUrl(''); fetchFeeds(); }) - .catch(<span class="fstat-no" title="function not covered" >(e</span>rr) => { -<span class="cstat-no" title="statement not covered" > setError(err.message);</span> -<span class="cstat-no" title="statement not covered" > setLoading(false);</span> + .catch((err) => { + setError(err.message); + setLoading(false); }); }; @@ -499,27 +620,46 @@ export default function Settings() { }); }; - const handleImport = <span class="fstat-no" title="function not covered" >(e</span>: React.FormEvent) => { -<span class="cstat-no" title="statement not covered" > e.preventDefault();</span> -<span class="cstat-no" title="statement not covered" > if (!importFile) <span class="cstat-no" title="statement not covered" >return;</span></span> + const handleImport = (e: React.FormEvent) => { + e.preventDefault(); + <span class="missing-if-branch" title="if path not taken" >I</span>if (!importFile) <span class="cstat-no" title="statement not covered" >return;</span> -<span class="cstat-no" title="statement not covered" > setLoading(true);</span> - const formData = <span class="cstat-no" title="statement not covered" >new FormData();</span> -<span class="cstat-no" title="statement not covered" > formData.append('file', importFile);</span> -<span class="cstat-no" title="statement not covered" > formData.append('format', 'opml');</span> + setLoading(true); + const formData = new FormData(); + formData.append('file', importFile); + formData.append('format', 'opml'); -<span class="cstat-no" title="statement not covered" > apiFetch('/api/import', {</span> + apiFetch('/api/import', { method: 'POST', body: formData, }) - .then(<span class="fstat-no" title="function not covered" >(r</span>es) => { -<span class="cstat-no" title="statement not covered" > if (!res.ok) <span class="cstat-no" title="statement not covered" >throw new Error('Failed to import feeds');</span></span> -<span class="cstat-no" title="statement not covered" > return res.json();</span> + .then((res) => { + <span class="missing-if-branch" title="if path not taken" >I</span>if (!res.ok) <span class="cstat-no" title="statement not covered" >throw new Error('Failed to import feeds');</span> + return res.json(); }) - .then(<span class="fstat-no" title="function not covered" >() => {</span> -<span class="cstat-no" title="statement not covered" > setImportFile(null);</span> -<span class="cstat-no" title="statement not covered" > fetchFeeds();</span> -<span class="cstat-no" title="statement not covered" > alert('Import successful!');</span> + .then(() => { + setImportFile(null); + fetchFeeds(); + alert('Import successful!'); + }) + .catch(<span class="fstat-no" title="function not covered" >(e</span>rr) => { +<span class="cstat-no" title="statement not covered" > setError(err.message);</span> +<span class="cstat-no" title="statement not covered" > setLoading(false);</span> + }); + }; + + const handleCrawl = () => { + setLoading(true); + apiFetch('/api/crawl', { + method: 'POST', + }) + .then((res) => { + <span class="missing-if-branch" title="if path not taken" >I</span>if (!res.ok) <span class="cstat-no" title="statement not covered" >throw new Error('Failed to start crawl');</span> + return res.json(); + }) + .then(() => { + setLoading(false); + alert('Crawl started!'); }) .catch(<span class="fstat-no" title="function not covered" >(e</span>rr) => { <span class="cstat-no" title="statement not covered" > setError(err.message);</span> @@ -528,9 +668,29 @@ export default function Settings() { }; return ( - <div className="settings-page"> + <div className="settings-page variant-glass"> <h2>Settings</h2> + {setFontTheme && ( + <div className="appearance-section"> + <h3>Appearance</h3> + <div className="font-selector"> + <label htmlFor="font-theme-select">Font Theme:</label> + <select + id="font-theme-select" + value={fontTheme || <span class="branch-1 cbranch-no" title="branch not covered" >'default'}</span> + onChange={(e) => setFontTheme(e.target.value)} + className="font-select" + > + <option value="default">Default</option> + <option value="serif">Serif</option> + <option value="sans">Sans-Serif</option> + <option value="mono">Monospace</option> + </select> + </div> + </div> + )} + <div className="add-feed-section"> <h3>Add New Feed</h3> <form onSubmit={handleAddFeed} className="add-feed-form"> @@ -556,11 +716,12 @@ export default function Settings() { <input type="file" accept=".opml,.xml,.txt" - onChange={<span class="fstat-no" title="function not covered" >(e</span>) => <span class="cstat-no" title="statement not covered" >setImportFile(e.target.files?.[0] || null)}</span> + aria-label="Import Feeds" + onChange={(e) => setImportFile(e.target.files?.[0] || <span class="branch-1 cbranch-no" title="branch not covered" >null)</span>} className="file-input" disabled={loading} /> - <button type="submit" disabled={!importFile || <span class="branch-1 cbranch-no" title="branch not covered" >loading}></span> + <button type="submit" disabled={!importFile || loading}> Import </button> </form> @@ -574,9 +735,16 @@ export default function Settings() { <a href="/api/export/json" className="export-btn">JSON</a> </div> </div> + + <div className="crawl-section"> + <h3>Actions</h3> + <button onClick={handleCrawl} disabled={loading} className="crawl-btn"> + Crawl All Feeds Now + </button> + </div> </div> - {error && <span class="branch-1 cbranch-no" title="branch not covered" ><p className="error-message">{error}</p>}</span> + {error && <p className="error-message">{error}</p>} <div className="feed-list-section"> <h3>Manage Feeds</h3> @@ -610,7 +778,7 @@ export default function Settings() { <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> diff --git a/frontend/coverage/src/components/index.html b/frontend/coverage/src/components/index.html index 66ca900..fc333bb 100644 --- a/frontend/coverage/src/components/index.html +++ b/frontend/coverage/src/components/index.html @@ -23,30 +23,30 @@ <div class='clearfix'> <div class='fl pad1y space-right2'> - <span class="strong">79.57% </span> + <span class="strong">86.21% </span> <span class="quiet">Statements</span> - <span class='fraction'>226/284</span> + <span class='fraction'>269/312</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">70.17% </span> + <span class="strong">74.61% </span> <span class="quiet">Branches</span> - <span class='fraction'>120/171</span> + <span class='fraction'>144/193</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">75.9% </span> + <span class="strong">84.94% </span> <span class="quiet">Functions</span> - <span class='fraction'>63/83</span> + <span class='fraction'>79/93</span> </div> <div class='fl pad1y space-right2'> - <span class="strong">81.78% </span> + <span class="strong">88.81% </span> <span class="quiet">Lines</span> - <span class='fraction'>211/258</span> + <span class='fraction'>254/286</span> </div> @@ -61,7 +61,7 @@ </div> </template> </div> - <div class='status-line medium'></div> + <div class='status-line high'></div> <div class="pad1"> <table class="coverage-summary"> <thead> @@ -125,17 +125,17 @@ <tr> <td class="file high" data-value="FeedItems.tsx"><a href="FeedItems.tsx.html">FeedItems.tsx</a></td> - <td data-value="88.97" class="pic high"> - <div class="chart"><div class="cover-fill" style="width: 88%"></div><div class="cover-empty" style="width: 12%"></div></div> + <td data-value="89.23" class="pic high"> + <div class="chart"><div class="cover-fill" style="width: 89%"></div><div class="cover-empty" style="width: 11%"></div></div> </td> - <td data-value="88.97" class="pct high">88.97%</td> - <td data-value="127" class="abs high">113/127</td> - <td data-value="75.3" class="pct medium">75.3%</td> - <td data-value="81" class="abs medium">61/81</td> - <td data-value="86.2" class="pct high">86.2%</td> - <td data-value="29" class="abs high">25/29</td> - <td data-value="88.69" class="pct high">88.69%</td> - <td data-value="115" class="abs high">102/115</td> + <td data-value="89.23" class="pct high">89.23%</td> + <td data-value="130" class="abs high">116/130</td> + <td data-value="76.19" class="pct medium">76.19%</td> + <td data-value="84" class="abs medium">64/84</td> + <td data-value="87.09" class="pct high">87.09%</td> + <td data-value="31" class="abs high">27/31</td> + <td data-value="89.07" class="pct high">89.07%</td> + <td data-value="119" class="abs high">106/119</td> </tr> <tr> @@ -154,18 +154,33 @@ </tr> <tr> - <td class="file medium" data-value="FeedList.tsx"><a href="FeedList.tsx.html">FeedList.tsx</a></td> - <td data-value="79.54" class="pic medium"> - <div class="chart"><div class="cover-fill" style="width: 79%"></div><div class="cover-empty" style="width: 21%"></div></div> + <td class="file high" data-value="FeedList.tsx"><a href="FeedList.tsx.html">FeedList.tsx</a></td> + <td data-value="87.27" class="pic high"> + <div class="chart"><div class="cover-fill" style="width: 87%"></div><div class="cover-empty" style="width: 13%"></div></div> </td> - <td data-value="79.54" class="pct medium">79.54%</td> - <td data-value="44" class="abs medium">35/44</td> - <td data-value="64.86" class="pct medium">64.86%</td> - <td data-value="37" class="abs medium">24/37</td> - <td data-value="64.7" class="pct medium">64.7%</td> - <td data-value="17" class="abs medium">11/17</td> - <td data-value="82.05" class="pct high">82.05%</td> - <td data-value="39" class="abs high">32/39</td> + <td data-value="87.27" class="pct high">87.27%</td> + <td data-value="55" class="abs high">48/55</td> + <td data-value="70" class="pct medium">70%</td> + <td data-value="50" class="abs medium">35/50</td> + <td data-value="78.94" class="pct medium">78.94%</td> + <td data-value="19" class="abs medium">15/19</td> + <td data-value="90" class="pct high">90%</td> + <td data-value="50" class="abs high">45/50</td> + </tr> + +<tr> + <td class="file empty" data-value="FeedListVariants.css"><a href="FeedListVariants.css.html">FeedListVariants.css</a></td> + <td data-value="0" class="pic empty"> + <div class="chart"><div class="cover-fill" style="width: 0%"></div><div class="cover-empty" style="width: 100%"></div></div> + </td> + <td data-value="0" class="pct empty">0%</td> + <td data-value="0" class="abs empty">0/0</td> + <td data-value="0" class="pct empty">0%</td> + <td data-value="0" class="abs empty">0/0</td> + <td data-value="0" class="pct empty">0%</td> + <td data-value="0" class="abs empty">0/0</td> + <td data-value="0" class="pct empty">0%</td> + <td data-value="0" class="abs empty">0/0</td> </tr> <tr> @@ -189,13 +204,13 @@ <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div> </td> <td data-value="100" class="pct high">100%</td> - <td data-value="17" class="abs high">17/17</td> + <td data-value="20" class="abs high">20/20</td> <td data-value="83.33" class="pct high">83.33%</td> <td data-value="6" class="abs high">5/6</td> <td data-value="100" class="pct high">100%</td> - <td data-value="3" class="abs high">3/3</td> + <td data-value="4" class="abs high">4/4</td> <td data-value="100" class="pct high">100%</td> - <td data-value="17" class="abs high">17/17</td> + <td data-value="20" class="abs high">20/20</td> </tr> <tr> @@ -214,18 +229,18 @@ </tr> <tr> - <td class="file medium" data-value="Settings.tsx"><a href="Settings.tsx.html">Settings.tsx</a></td> - <td data-value="56.25" class="pic medium"> - <div class="chart"><div class="cover-fill" style="width: 56%"></div><div class="cover-empty" style="width: 44%"></div></div> + <td class="file high" data-value="Settings.tsx"><a href="Settings.tsx.html">Settings.tsx</a></td> + <td data-value="80" class="pic high"> + <div class="chart"><div class="cover-fill" style="width: 80%"></div><div class="cover-empty" style="width: 20%"></div></div> </td> - <td data-value="56.25" class="pct medium">56.25%</td> - <td data-value="64" class="abs medium">36/64</td> - <td data-value="41.66" class="pct low">41.66%</td> - <td data-value="24" class="abs low">10/24</td> - <td data-value="63.63" class="pct medium">63.63%</td> - <td data-value="22" class="abs medium">14/22</td> - <td data-value="62.5" class="pct medium">62.5%</td> - <td data-value="56" class="abs medium">35/56</td> + <td data-value="80" class="pct high">80%</td> + <td data-value="75" class="abs high">60/75</td> + <td data-value="66.66" class="pct medium">66.66%</td> + <td data-value="30" class="abs medium">20/30</td> + <td data-value="85.18" class="pct high">85.18%</td> + <td data-value="27" class="abs high">23/27</td> + <td data-value="87.87" class="pct high">87.87%</td> + <td data-value="66" class="abs high">58/66</td> </tr> </tbody> @@ -236,7 +251,7 @@ <div class='footer quiet pad2 space-top1 center small'> Code coverage generated by <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a> - at 2026-02-14T18:02:09.004Z + at 2026-02-15T05:30:50.842Z </div> <script src="../../prettify.js"></script> <script> |
