From 3e3b9a2bfd568880199c7e4277540e69677d3c88 Mon Sep 17 00:00:00 2001 From: ak Date: Tue, 11 Aug 2026 23:20:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BB=E9=A2=98=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=E7=82=B9=E7=B3=BB=E7=BB=9F=EF=BC=8810=20?= =?UTF-8?q?=E4=B8=AA=E6=A0=87=E5=87=86=E4=BD=8D=E7=BD=AE=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E5=A4=9A=E6=9D=A1=E6=B3=A8=E5=85=A5=E5=9D=97?= =?UTF-8?q?=E5=8F=AF=E6=8E=92=E5=BA=8F/=E5=90=AF=E5=81=9C=EF=BC=8Cstylevar?= =?UTF-8?q?=20=E5=8F=98=E9=87=8F=E5=A4=8D=E6=B4=BB=EF=BC=89+=20=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E4=B8=BB=E9=A2=98=E6=B3=A8=E5=85=A5=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E9=A1=B5=EF=BC=88Tab=20=E5=88=86=E5=8C=BA=EF=BC=89+=20?= =?UTF-8?q?=E7=BC=93=E5=AD=98/=E8=AE=BE=E7=BD=AE=E6=94=B6=E8=BF=9B?= =?UTF-8?q?=E9=A1=B6=E9=83=A8=E7=94=A8=E6=88=B7=E4=B8=8B=E6=8B=89=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=EF=BC=88Livewire=20action=20=E5=8D=B3=E6=97=B6?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Blog/Providers/ThemeServiceProvider.php | 3 + app/Blog/Support/ThemeInjector.php | 78 ++++++++++ app/Filament/Pages/CacheManager.php | 64 -------- app/Filament/Pages/ThemeInject.php | 142 ++++++++++++++++++ app/Providers/Filament/AdminPanelProvider.php | 30 ++++ docs/themes.md | 24 +++ resources/views/archives.blade.php | 1 + resources/views/comments.blade.php | 1 + .../filament/pages/cache-manager.blade.php | 37 ----- .../filament/pages/theme-inject.blade.php | 10 ++ resources/views/index.blade.php | 1 + resources/views/links.blade.php | 1 + resources/views/list.blade.php | 1 + resources/views/login.blade.php | 1 + resources/views/partials/footer.blade.php | 1 + resources/views/partials/head.blade.php | 1 + resources/views/partials/header.blade.php | 1 + resources/views/partials/sidebar.blade.php | 4 +- resources/views/profile.blade.php | 1 + resources/views/register.blade.php | 1 + resources/views/search.blade.php | 1 + resources/views/show.blade.php | 2 + resources/views/tag.blade.php | 1 + resources/views/tags.blade.php | 1 + resources/views/welcome.blade.php | 3 +- .../ZWDH4qIxdjA1Y1zOPnYNzYHUuAKtzmkAthumb.jpg | 1 + .../hXab5DqiEEtDFzsnryDlO3OkysylTul9.jpg | 1 + .../O2FCtIW3pSu4aA2iHD63oB4c90tPk7yS.jpg | 1 + .../gB24YI2JgqpPtmlBfLntnVwR12qsN3kmthumb.jpg | 1 + .../Y00iz8YxrfVJXTLhgALO81WeHBks9wbj.jpg | 1 + .../pdu9I7UCBX8aulItvEBphpLs3LKsbfbEthumb.jpg | 1 + .../hcKL76xaA3bBqp0IlIEPr1NSqGw8FfyH.jpg | 1 + .../n1Zcr9eJOQjDba94J4kcBJM1cMBD4ovkthumb.jpg | 1 + .../0asTs9KL8LRHVAcVNYIyWIn5D6boRtXf.jpg | 1 + .../N20MlWlYroGKwNedSUAsIj922i4FvPkcthumb.jpg | 1 + .../OmMDGqKDsGGpHy9lzCzNKZa0qFAMWaGxthumb.jpg | 1 + .../RiSxMj1XnyUmrvVGVWPWruHdcCjMtcLm.jpg | 1 + .../3oKKksDkOkLkQjvA9OU4HIHlex6TSKVZ.jpg | 1 + .../dzPJucuok8RcjlvHaBzTZYTRLD4OaBjnthumb.jpg | 1 + .../k8AydZyiyECNfhtHbG8FtMsnemzPieqJthumb.jpg | 1 + .../ukNR34F4XKgPZJFo7w9UlNkbYO4UVqOb.jpg | 1 + .../Q4NkkUu4YrN9HwpW8WKL7DvXmnzgbODi.jpg | 1 + .../ppi5raROVYete6tAFd6Ce2TZvC2tQsn7thumb.jpg | 1 + .../KRB2RJwMqwqzcbT8dNiq4dUcaR3F8Eijthumb.jpg | 1 + .../wz04P1bLUvb3Qcy2QhhVg8fWJxfIAb7o.jpg | 1 + .../YQe7Z6QKDvACpLFy9NLVqPcfKnrvU89Lthumb.jpg | 1 + .../qVtNJzaAKGKZdWQXFALAuyo8255sh2vj.jpg | 1 + .../o5X32bTtaNN1ddYxeGZzgDxC2BdYfNq7thumb.jpg | 1 + .../ssfIBvDQ3Qc3cZZYd9ryj6zbuMALcJzl.jpg | 1 + .../hs0M6WqsEbLRksYZtbUuVf0iK8vYWqyFthumb.jpg | 1 + .../jnp4bNv2QuUJ4zK73PBd6nks1VIkOZm4.jpg | 1 + .../IcqkAqCD68TFPRBM9Eb30zyzQ89e9YPPthumb.jpg | 1 + .../hf83FKyO8i3yTsh97mo5rSlJ35HfvToh.jpg | 1 + .../CHiWw0riukRbBSxyhvHIRzpL5q9fW8Fb.jpg | 1 + .../IvdFMx6yYzE5gmGFkirab4rF42wSFnKjthumb.jpg | 1 + .../m1Nn3A8nxv4RpEAsye3ENrKw14XJE9Ch.jpg | 1 + .../pFmXDHuZTG4aX4Un2WiE6ygETF9cfOQXthumb.jpg | 1 + .../MDq7Z6hZG88qYA30onNe7KSyzkS60Nxz.jpg | 1 + .../lemL9t7dQOSSgUDnxNORorLyPpQe0yuCthumb.jpg | 1 + .../TEDAyEDnWOxdIVzdd5mwkl2V5NaamJPothumb.jpg | 1 + .../cGmrOcF7gh19bDRYbsXQclcEvIt7ZGbB.jpg | 1 + .../Odea91A5qoIMQf8CLo6cXJQeKVeTSz0Cthumb.jpg | 1 + .../t7hNb7KYPsU9BOVLOhGT2lf8FoSUJRMp.jpg | 1 + .../8QeM8JbJBbOkgGtEtqeTDWkXprwnr50B.jpg | 1 + .../YlxMxiwKERQURzCEPkG1UFkpDMo4rcZPthumb.jpg | 1 + .../fCg91KDWlf5yhlOP9yudorDRO0ZpOvLg.jpg | 1 + .../u36Uwf3Nl7T7nXRvlW7nNEfppBCLNIDlthumb.jpg | 1 + .../4WGJF1qp84u3gtjDQtUUX40UEygNQMXGthumb.jpg | 1 + .../mrnUMjqEUqrH5pmVpS6lWUdDG31J7TkS.jpg | 1 + .../7QngyoYDMIgLtWLXduu194ebjf5mPT9R.jpg | 1 + .../gwdUbAxTHyoxtHFHcs0wSWjkIpuxVu0Uthumb.jpg | 1 + .../Iqkiw05V5CyDuatpYwpkq7gVt7FsftQI.jpg | 1 + .../XOmPOw41UlZHh6IVhwP7U8rMKE48TA5ythumb.jpg | 1 + .../GYc7vRIJAB9fArSbS1gHpsHAczu5pSVx.jpg | 1 + .../lC3IiCpD2nMyw8uwQCsKbiNKIQ7nho5Vthumb.jpg | 1 + .../OXkcAkboHDo9UZ3dWwfoFulw6aqgVhHF.jpg | 1 + .../XWQbPPuCVe5mqKqgYl0wayxayFwCZ9fLthumb.jpg | 1 + .../0bkctdy3CkYmdcjWV6MuZtGJKqSUF2rV.jpg | 1 + .../rKHQRLP55R3RxiiaPWPl6W9XjKzgqnm7thumb.jpg | 1 + .../4Pt01Imtm1Ao7rnTiHZVVOnAQI5QD8BM.jpg | 1 + .../xCL5zTCylnTgM2J38Zcysj6ZOb8YeiFfthumb.jpg | 1 + .../KvYAhygJA5KYsyf2XHw0MTP4g2rVDwHP.jpg | 1 + .../NHHzeMgDn9Wyi9hDg09RjA2YGGnUWuiithumb.jpg | 1 + .../NCWx3rFNVgXHuVjMjwdS50x1ix65HcOTthumb.jpg | 1 + .../zNJ38PDV3EGXlu4b2gKGF3TSsXlZ9lTS.jpg | 1 + tests/Feature/ThemeInjectTest.php | 100 ++++++++++++ themes/modern/views/partials/footer.blade.php | 1 + themes/modern/views/partials/head.blade.php | 1 + themes/modern/views/partials/header.blade.php | 1 + themes/sablog/views/index.blade.php | 1 + themes/sablog/views/list.blade.php | 1 + themes/sablog/views/partials/footer.blade.php | 1 + themes/sablog/views/partials/head.blade.php | 1 + themes/sablog/views/partials/header.blade.php | 1 + .../sablog/views/partials/sidebar.blade.php | 4 +- themes/sablog/views/search.blade.php | 1 + themes/sablog/views/show.blade.php | 5 +- themes/sablog/views/tag.blade.php | 1 + 98 files changed, 485 insertions(+), 105 deletions(-) create mode 100644 app/Blog/Support/ThemeInjector.php delete mode 100644 app/Filament/Pages/CacheManager.php create mode 100644 app/Filament/Pages/ThemeInject.php delete mode 100644 resources/views/filament/pages/cache-manager.blade.php create mode 100644 resources/views/filament/pages/theme-inject.blade.php create mode 100644 storage/media-library/temp/0cYDGWb1nNVeWnUfnt3nqg3OPSMdNtJE/ZWDH4qIxdjA1Y1zOPnYNzYHUuAKtzmkAthumb.jpg create mode 100644 storage/media-library/temp/0cYDGWb1nNVeWnUfnt3nqg3OPSMdNtJE/hXab5DqiEEtDFzsnryDlO3OkysylTul9.jpg create mode 100644 storage/media-library/temp/0m1Vdj3skNSNcnkcJnaQG9G5vJ2YlDTd/O2FCtIW3pSu4aA2iHD63oB4c90tPk7yS.jpg create mode 100644 storage/media-library/temp/0m1Vdj3skNSNcnkcJnaQG9G5vJ2YlDTd/gB24YI2JgqpPtmlBfLntnVwR12qsN3kmthumb.jpg create mode 100644 storage/media-library/temp/4hemPIK1WtapM6UzcsiiRCEgb0IKkA4e/Y00iz8YxrfVJXTLhgALO81WeHBks9wbj.jpg create mode 100644 storage/media-library/temp/4hemPIK1WtapM6UzcsiiRCEgb0IKkA4e/pdu9I7UCBX8aulItvEBphpLs3LKsbfbEthumb.jpg create mode 100644 storage/media-library/temp/5737vNz7Ifuo9VYdEXqZfXKmodF4M51N/hcKL76xaA3bBqp0IlIEPr1NSqGw8FfyH.jpg create mode 100644 storage/media-library/temp/5737vNz7Ifuo9VYdEXqZfXKmodF4M51N/n1Zcr9eJOQjDba94J4kcBJM1cMBD4ovkthumb.jpg create mode 100644 storage/media-library/temp/6N8LqDgOYvHD6POisqc7dXP247PjCkxz/0asTs9KL8LRHVAcVNYIyWIn5D6boRtXf.jpg create mode 100644 storage/media-library/temp/6N8LqDgOYvHD6POisqc7dXP247PjCkxz/N20MlWlYroGKwNedSUAsIj922i4FvPkcthumb.jpg create mode 100644 storage/media-library/temp/6NcnLAd0ntQ6k1JmNDZmMxbpEMgwvFpY/OmMDGqKDsGGpHy9lzCzNKZa0qFAMWaGxthumb.jpg create mode 100644 storage/media-library/temp/6NcnLAd0ntQ6k1JmNDZmMxbpEMgwvFpY/RiSxMj1XnyUmrvVGVWPWruHdcCjMtcLm.jpg create mode 100644 storage/media-library/temp/8KgeUQ553H3wNbLPnBgp6P9eeDIrIHkr/3oKKksDkOkLkQjvA9OU4HIHlex6TSKVZ.jpg create mode 100644 storage/media-library/temp/8KgeUQ553H3wNbLPnBgp6P9eeDIrIHkr/dzPJucuok8RcjlvHaBzTZYTRLD4OaBjnthumb.jpg create mode 100644 storage/media-library/temp/AgtXDp2GUJijEi4s0o1LPbC3XRoUp2ik/k8AydZyiyECNfhtHbG8FtMsnemzPieqJthumb.jpg create mode 100644 storage/media-library/temp/AgtXDp2GUJijEi4s0o1LPbC3XRoUp2ik/ukNR34F4XKgPZJFo7w9UlNkbYO4UVqOb.jpg create mode 100644 storage/media-library/temp/DDcEimfU2PGWy6xIebsSq80kya10ULkz/Q4NkkUu4YrN9HwpW8WKL7DvXmnzgbODi.jpg create mode 100644 storage/media-library/temp/DDcEimfU2PGWy6xIebsSq80kya10ULkz/ppi5raROVYete6tAFd6Ce2TZvC2tQsn7thumb.jpg create mode 100644 storage/media-library/temp/ERgt5uKVR534JpuFw4uRdMWBPxaUlN0y/KRB2RJwMqwqzcbT8dNiq4dUcaR3F8Eijthumb.jpg create mode 100644 storage/media-library/temp/ERgt5uKVR534JpuFw4uRdMWBPxaUlN0y/wz04P1bLUvb3Qcy2QhhVg8fWJxfIAb7o.jpg create mode 100644 storage/media-library/temp/HMILdg4Fx548uG3pEEpzb1LWZe7lB3lt/YQe7Z6QKDvACpLFy9NLVqPcfKnrvU89Lthumb.jpg create mode 100644 storage/media-library/temp/HMILdg4Fx548uG3pEEpzb1LWZe7lB3lt/qVtNJzaAKGKZdWQXFALAuyo8255sh2vj.jpg create mode 100644 storage/media-library/temp/J92Z32szpuqBgAzpJjcOVXBeS9cCFQt1/o5X32bTtaNN1ddYxeGZzgDxC2BdYfNq7thumb.jpg create mode 100644 storage/media-library/temp/J92Z32szpuqBgAzpJjcOVXBeS9cCFQt1/ssfIBvDQ3Qc3cZZYd9ryj6zbuMALcJzl.jpg create mode 100644 storage/media-library/temp/K1Ydse92aUqvaXyoEG7pX3Egujtmti4L/hs0M6WqsEbLRksYZtbUuVf0iK8vYWqyFthumb.jpg create mode 100644 storage/media-library/temp/K1Ydse92aUqvaXyoEG7pX3Egujtmti4L/jnp4bNv2QuUJ4zK73PBd6nks1VIkOZm4.jpg create mode 100644 storage/media-library/temp/Kkf36Ju1tp2WKjQ9XdgxDIVP59YgiocZ/IcqkAqCD68TFPRBM9Eb30zyzQ89e9YPPthumb.jpg create mode 100644 storage/media-library/temp/Kkf36Ju1tp2WKjQ9XdgxDIVP59YgiocZ/hf83FKyO8i3yTsh97mo5rSlJ35HfvToh.jpg create mode 100644 storage/media-library/temp/PgJhvxNPxYKsWDeBgJYUdTjMg0KIjLYU/CHiWw0riukRbBSxyhvHIRzpL5q9fW8Fb.jpg create mode 100644 storage/media-library/temp/PgJhvxNPxYKsWDeBgJYUdTjMg0KIjLYU/IvdFMx6yYzE5gmGFkirab4rF42wSFnKjthumb.jpg create mode 100644 storage/media-library/temp/PweBlTjyuhUgghI2v14wha42P97Y9oBp/m1Nn3A8nxv4RpEAsye3ENrKw14XJE9Ch.jpg create mode 100644 storage/media-library/temp/PweBlTjyuhUgghI2v14wha42P97Y9oBp/pFmXDHuZTG4aX4Un2WiE6ygETF9cfOQXthumb.jpg create mode 100644 storage/media-library/temp/TqyjMIspUusnGdTpVs8xW2aFSObB3ZG2/MDq7Z6hZG88qYA30onNe7KSyzkS60Nxz.jpg create mode 100644 storage/media-library/temp/TqyjMIspUusnGdTpVs8xW2aFSObB3ZG2/lemL9t7dQOSSgUDnxNORorLyPpQe0yuCthumb.jpg create mode 100644 storage/media-library/temp/VaVm2WhaXvQH9wrZGOltDxGwYAyLXC3e/TEDAyEDnWOxdIVzdd5mwkl2V5NaamJPothumb.jpg create mode 100644 storage/media-library/temp/VaVm2WhaXvQH9wrZGOltDxGwYAyLXC3e/cGmrOcF7gh19bDRYbsXQclcEvIt7ZGbB.jpg create mode 100644 storage/media-library/temp/WyEkeKZhtcLwV204aDnAazvuenBpTQ7T/Odea91A5qoIMQf8CLo6cXJQeKVeTSz0Cthumb.jpg create mode 100644 storage/media-library/temp/WyEkeKZhtcLwV204aDnAazvuenBpTQ7T/t7hNb7KYPsU9BOVLOhGT2lf8FoSUJRMp.jpg create mode 100644 storage/media-library/temp/ebcwvJsiRaAPrTlkDbSNncl3B2YBXZgA/8QeM8JbJBbOkgGtEtqeTDWkXprwnr50B.jpg create mode 100644 storage/media-library/temp/ebcwvJsiRaAPrTlkDbSNncl3B2YBXZgA/YlxMxiwKERQURzCEPkG1UFkpDMo4rcZPthumb.jpg create mode 100644 storage/media-library/temp/edAg2NFIeqXb0ZOImXX0FRQl2FHQkMnQ/fCg91KDWlf5yhlOP9yudorDRO0ZpOvLg.jpg create mode 100644 storage/media-library/temp/edAg2NFIeqXb0ZOImXX0FRQl2FHQkMnQ/u36Uwf3Nl7T7nXRvlW7nNEfppBCLNIDlthumb.jpg create mode 100644 storage/media-library/temp/fWcyZFcRYm4ybJVhTKFJNBt7FYnM3xA6/4WGJF1qp84u3gtjDQtUUX40UEygNQMXGthumb.jpg create mode 100644 storage/media-library/temp/fWcyZFcRYm4ybJVhTKFJNBt7FYnM3xA6/mrnUMjqEUqrH5pmVpS6lWUdDG31J7TkS.jpg create mode 100644 storage/media-library/temp/masIt7aTiOgr1SfVGcpp5dkeIzTJIMX9/7QngyoYDMIgLtWLXduu194ebjf5mPT9R.jpg create mode 100644 storage/media-library/temp/masIt7aTiOgr1SfVGcpp5dkeIzTJIMX9/gwdUbAxTHyoxtHFHcs0wSWjkIpuxVu0Uthumb.jpg create mode 100644 storage/media-library/temp/nBzRRTOqe564vv01nZGZ4LmKDhmKEpW0/Iqkiw05V5CyDuatpYwpkq7gVt7FsftQI.jpg create mode 100644 storage/media-library/temp/nBzRRTOqe564vv01nZGZ4LmKDhmKEpW0/XOmPOw41UlZHh6IVhwP7U8rMKE48TA5ythumb.jpg create mode 100644 storage/media-library/temp/rcGCwB525AcT2H2p5a3WNZUj8RdMsCDA/GYc7vRIJAB9fArSbS1gHpsHAczu5pSVx.jpg create mode 100644 storage/media-library/temp/rcGCwB525AcT2H2p5a3WNZUj8RdMsCDA/lC3IiCpD2nMyw8uwQCsKbiNKIQ7nho5Vthumb.jpg create mode 100644 storage/media-library/temp/sSvsWWZ28AVmEb7mAxiN9UwoRW07dK30/OXkcAkboHDo9UZ3dWwfoFulw6aqgVhHF.jpg create mode 100644 storage/media-library/temp/sSvsWWZ28AVmEb7mAxiN9UwoRW07dK30/XWQbPPuCVe5mqKqgYl0wayxayFwCZ9fLthumb.jpg create mode 100644 storage/media-library/temp/tObMHekws9nYn8lNCWpIPl9TlfE7uOZJ/0bkctdy3CkYmdcjWV6MuZtGJKqSUF2rV.jpg create mode 100644 storage/media-library/temp/tObMHekws9nYn8lNCWpIPl9TlfE7uOZJ/rKHQRLP55R3RxiiaPWPl6W9XjKzgqnm7thumb.jpg create mode 100644 storage/media-library/temp/vf73dq37BXJKJ8I2YFfXHwMDrhRvM8Hy/4Pt01Imtm1Ao7rnTiHZVVOnAQI5QD8BM.jpg create mode 100644 storage/media-library/temp/vf73dq37BXJKJ8I2YFfXHwMDrhRvM8Hy/xCL5zTCylnTgM2J38Zcysj6ZOb8YeiFfthumb.jpg create mode 100644 storage/media-library/temp/yU2OEoTcm0h5p6GPslXWSj0B6QkG0mro/KvYAhygJA5KYsyf2XHw0MTP4g2rVDwHP.jpg create mode 100644 storage/media-library/temp/yU2OEoTcm0h5p6GPslXWSj0B6QkG0mro/NHHzeMgDn9Wyi9hDg09RjA2YGGnUWuiithumb.jpg create mode 100644 storage/media-library/temp/yeH9dkQqctZaE2La3Xe5TPUm6u1lFFYX/NCWx3rFNVgXHuVjMjwdS50x1ix65HcOTthumb.jpg create mode 100644 storage/media-library/temp/yeH9dkQqctZaE2La3Xe5TPUm6u1lFFYX/zNJ38PDV3EGXlu4b2gKGF3TSsXlZ9lTS.jpg create mode 100644 tests/Feature/ThemeInjectTest.php diff --git a/app/Blog/Providers/ThemeServiceProvider.php b/app/Blog/Providers/ThemeServiceProvider.php index 3233728..bb1cdc9 100644 --- a/app/Blog/Providers/ThemeServiceProvider.php +++ b/app/Blog/Providers/ThemeServiceProvider.php @@ -28,5 +28,8 @@ class ThemeServiceProvider extends ServiceProvider ['index', 'show', 'list', 'archives', 'tags', 'tag', 'search', 'links', 'comments', 'login', 'register', 'profile', 'membership.*', 'payments.*'], SidebarComposer::class ); + + // 主题注入点:广告/统计/临时链接(多条、可排序、可启停) + \App\Blog\Support\ThemeInjector::registerComposer(); } } diff --git a/app/Blog/Support/ThemeInjector.php b/app/Blog/Support/ThemeInjector.php new file mode 100644 index 0000000..5d72139 --- /dev/null +++ b/app/Blog/Support/ThemeInjector.php @@ -0,0 +1,78 @@ + '页头( 前)', + 'header' => '页头下方', + 'sidebar_top' => '侧边栏顶部', + 'sidebar_bottom' => '侧边栏底部', + 'content_top' => '内容区顶部', + 'content_bottom' => '内容区底部', + 'post_content_top' => '文章正文前', + 'post_content_bottom' => '文章正文后', + 'footer' => '页脚前', + 'body_end' => '页面末尾( 前)', + ]; + + /** + * 读取某一注入点的所有注入块(多条,已排序、已过滤停用), + * 并把插件追加的 HTML 合并进来。 + */ + public static function blocksFor(string $point): array + { + $raw = Setting::get('inject.blocks', []); + $raw = is_array($raw) ? $raw : (json_decode((string) $raw, true) ?: []); + + $blocks = collect($raw) + ->filter(fn (array $b) => ($b['point'] ?? null) === $point && ($b['enabled'] ?? true)) + ->sortBy(fn (array $b) => (int) ($b['sort'] ?? 0)) + ->pluck('html') + ->filter() + ->values() + ->all(); + + $extra = (string) app(PluginManager::class)->applyFilters("theme.inject.{$point}", ''); + + if ($extra !== '') { + $blocks[] = $extra; + } + + return $blocks; + } + + /** + * 注册 View Composer:渲染前台视图前把各注入点内容 push 到对应 @stack。 + */ + public static function registerComposer(): void + { + $views = ['index', 'show', 'list', 'archives', 'tags', 'tag', 'search', 'links', 'comments', 'login', 'register', 'profile', 'membership.*', 'payments.*']; + + \Illuminate\Support\Facades\View::composer($views, function (\Illuminate\View\View $view) { + foreach (array_keys(self::POINTS) as $point) { + foreach (self::blocksFor($point) as $html) { + $view->getFactory()->startPush("theme:{$point}", $html); + } + } + }); + } +} diff --git a/app/Filament/Pages/CacheManager.php b/app/Filament/Pages/CacheManager.php deleted file mode 100644 index d12d2b7..0000000 --- a/app/Filament/Pages/CacheManager.php +++ /dev/null @@ -1,64 +0,0 @@ -title('前台页面缓存已清空')->success()->send(); - } - - public function flushSidebar(): void - { - foreach (['blog.sidebar.categories', 'blog.sidebar.recent_posts', 'blog.sidebar.recent_comments', 'blog.sidebar.hot_tags', 'blog.sidebar.links', 'blog.sidebar.stats'] as $key) { - Cache::forget($key); - } - Notification::make()->title('侧边栏缓存已清空')->success()->send(); - } - - public function flushSettings(): void - { - \App\Models\Setting::flushCache(); - Cache::forget('attach.legacy_ids'); - Notification::make()->title('设置缓存已清空')->success()->send(); - } - - public function flushAll(): void - { - PageCacheMiddleware::flush(); - \App\Models\Setting::flushCache(); - Cache::flush(); - Notification::make()->title('全部缓存已清空')->success()->send(); - } - - public function recompile(): void - { - Artisan::call('view:clear'); - Artisan::call('route:clear'); - Artisan::call('config:clear'); - Notification::make()->title('视图/路由/配置缓存已重建')->success()->send(); - } - - public function getPageCacheCountProperty(): int - { - return PageCacheMiddleware::count(); - } -} diff --git a/app/Filament/Pages/ThemeInject.php b/app/Filament/Pages/ThemeInject.php new file mode 100644 index 0000000..3e59aaf --- /dev/null +++ b/app/Filament/Pages/ThemeInject.php @@ -0,0 +1,142 @@ +form->fill([ + 'inject' => $this->normalizeBlocks(Setting::get('inject.blocks', [])), + 'theme_vars' => app(ThemeManager::class)->variables(), + ]); + } + + public function form(Schema $schema): Schema + { + $tabs = []; + $i = 0; + + foreach (ThemeInjector::POINTS as $point => $label) { + $tabs[] = Tab::make(($i + 1).'. '.$label) + ->schema([ + Repeater::make("inject.{$point}") + ->label('注入块(可多条,按排序渲染)') + ->schema([ + TextInput::make('title')->label('名称')->placeholder('如:百度统计')->columnSpan(2), + Textarea::make('html')->label('内容(HTML)')->rows(3)->columnSpanFull(), + TextInput::make('sort')->label('排序')->numeric()->default(0)->columnSpan(1), + Toggle::make('enabled')->label('启用')->default(true)->columnSpan(1), + ]) + ->columns(3) + ->defaultItems(0) + ->collapsible() + ->addActionLabel('添加一条'), + ]); + $i++; + } + + $tabs[] = Tab::make('主题变量(stylevar)') + ->schema([ + KeyValue::make('theme_vars') + ->label('当前主题变量:视图用 {{ theme(\'var\', \'key\') }} 引用') + ->keyLabel('变量名') + ->valueLabel('内容(HTML)') + ->reorderable() + ->columnSpanFull(), + ]); + + return $schema + ->components([ + Tabs::make('inject-tabs') + ->tabs($tabs), + ]) + ->statePath('data'); + } + + public function save(): void + { + $data = $this->form->getState(); + + $blocks = []; + foreach ($data['inject'] ?? [] as $point => $items) { + foreach ($items ?? [] as $item) { + if (trim((string) ($item['html'] ?? '')) === '') { + continue; + } + $blocks[] = [ + 'point' => $point, + 'title' => $item['title'] ?? '', + 'html' => $item['html'], + 'sort' => (int) ($item['sort'] ?? 0), + 'enabled' => (bool) ($item['enabled'] ?? true), + ]; + } + } + + Setting::set('inject.blocks', $blocks); + Setting::set('theme_vars_'.app(ThemeManager::class)->active(), $data['theme_vars'] ?? []); + + Notification::make()->title('注入内容已保存')->success()->send(); + } + + protected function getFormActions(): array + { + return [ + Action::make('save')->label('保存')->submit('save'), + ]; + } + + private function normalizeBlocks(mixed $blocks): array + { + if (! is_array($blocks)) { + $blocks = json_decode((string) $blocks, true) ?: []; + } + + $normalized = []; + foreach ($blocks as $b) { + $point = $b['point'] ?? null; + if (! $point) { + continue; + } + $normalized[$point][] = [ + 'title' => $b['title'] ?? '', + 'html' => $b['html'] ?? '', + 'sort' => (int) ($b['sort'] ?? 0), + 'enabled' => (bool) ($b['enabled'] ?? true), + ]; + } + + return $normalized; + } +} diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index d9946e9..a2ae23a 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -44,6 +44,36 @@ class AdminPanelProvider extends PanelProvider ->brandName(config('blog.name')) ->sidebarWidth('13rem') ->maxContentWidth(\Filament\Support\Enums\Width::Full) + ->userMenuItems([ + // 工具:清空缓存(Livewire action,即时通知) + \Filament\Actions\Action::make('flush-page-cache') + ->label('清空前台缓存') + ->icon('heroicon-o-bolt') + ->color('warning') + ->action(function (): void { + \App\Blog\Support\PageCacheMiddleware::flush(); + \Filament\Notifications\Notification::make()->title('前台页面缓存已清空')->success()->send(); + }), + \Filament\Actions\Action::make('flush-all-cache') + ->label('清空全部缓存') + ->icon('heroicon-o-trash') + ->color('danger') + ->requiresConfirmation() + ->action(function (): void { + \App\Blog\Support\PageCacheMiddleware::flush(); + \App\Models\Setting::flushCache(); + \Illuminate\Support\Facades\Cache::flush(); + \Filament\Notifications\Notification::make()->title('全部缓存已清空')->success()->send(); + }), + \Filament\Actions\Action::make('blog-settings') + ->label('博客设置') + ->icon('heroicon-o-cog-6-tooth') + ->url(fn (): string => \App\Filament\Pages\BlogSettings::getUrl()), + \Filament\Actions\Action::make('theme-inject') + ->label('主题注入') + ->icon('heroicon-o-squares-plus') + ->url(fn (): string => \App\Filament\Pages\ThemeInject::getUrl()), + ]) ->navigationGroups([ NavigationGroup::make('内容'), NavigationGroup::make('管理'), diff --git a/docs/themes.md b/docs/themes.md index 40eb082..f6fbc2c 100644 --- a/docs/themes.md +++ b/docs/themes.md @@ -100,6 +100,30 @@ themes/{name}/ - 开发期:`GET /themes/{name}/assets/{path}` 流式返回(带缓存头) - 生产:`php artisan theme:publish` 复制到 `public/themes/`,由 Web 服务器托管 +## 内容注入点(广告 / 统计 / 临时链接) + +主题视图内置 10 个注入点(Blade `@stack`),后台「主题注入」页管理: + +| 注入点 | 位置 | 典型用途 | +|--------|------|----------| +| `theme:head` | `` 前 | 统计代码、广告、验证 | +| `theme:header` | 页头下方 | 顶部横幅/公告 | +| `theme:sidebar_top` | 侧边栏顶部 | 首屏广告 | +| `theme:sidebar_bottom` | 侧边栏底部 | 广告/临时链接 | +| `theme:content_top` | 内容区顶部 | 列表/文章上方横幅 | +| `theme:content_bottom` | 内容区底部 | 分页后广告 | +| `theme:post_content_top` | 文章正文前 | 正文顶部广告 | +| `theme:post_content_bottom` | 文章正文后 | 正文底部广告 | +| `theme:footer` | 页脚前 | 版权上方声明 | +| `theme:body_end` | `` 前 | 统计代码 | + +特性: +- **同一位置可添加多条**注入块(名称 + HTML + 排序 + 启停),按排序渲染 +- 插件可通过 filter `theme.inject.{point}` 追加 +- 主题变量(stylevar 复活):后台「主题注入」→「主题变量」Tab,视图用 `{{ theme('var', 'key') }}` 引用任意 HTML + +新主题须在对应 partial/视图放置 `@stack('theme:xxx')` 才能接收注入。 + ## 预览图 `theme.json` 的 `screenshot` 指向 `assets/` 下的预览图(如 `screenshot.png`),后台主题管理以卡片形式展示。可用无头浏览器截图生成:`node` + playwright 打开站点首页保存为 `themes/{name}/assets/screenshot.png`。 diff --git a/resources/views/archives.blade.php b/resources/views/archives.blade.php index 725c9b6..ce0e0b6 100644 --- a/resources/views/archives.blade.php +++ b/resources/views/archives.blade.php @@ -28,5 +28,6 @@ @include('partials.sidebar') @include('partials.footer') +@stack('theme:body_end') diff --git a/resources/views/comments.blade.php b/resources/views/comments.blade.php index 85a8e2a..ee2751a 100644 --- a/resources/views/comments.blade.php +++ b/resources/views/comments.blade.php @@ -24,5 +24,6 @@ @include('partials.sidebar') @include('partials.footer') +@stack('theme:body_end') diff --git a/resources/views/filament/pages/cache-manager.blade.php b/resources/views/filament/pages/cache-manager.blade.php deleted file mode 100644 index dc36706..0000000 --- a/resources/views/filament/pages/cache-manager.blade.php +++ /dev/null @@ -1,37 +0,0 @@ - -
- -

- 匿名访客的首页/列表/文章/归档等页面按 URL 缓存(TTL {{ config('blog.page_cache_ttl') }} 秒), - 文章浏览量由独立端点统计,不受缓存影响。发布/编辑文章后建议清空本缓存。 -

-
- 清空页面缓存 -
-
- - -

- 侧边栏(分类/最新文章/评论/标签/友链/统计)与站点设置、附件映射的缓存,最长 1 小时。 -

-
- 清空侧边栏 - 清空设置 -
-
- - -

清空应用全部缓存(含上述所有 + 其他临时缓存)。

-
- 清空全部缓存 -
-
- - -

清除并重建 Blade 视图 / 路由 / 配置编译缓存(发布或更新代码后使用)。

-
- 重建编译缓存 -
-
-
-
diff --git a/resources/views/filament/pages/theme-inject.blade.php b/resources/views/filament/pages/theme-inject.blade.php new file mode 100644 index 0000000..fa235e3 --- /dev/null +++ b/resources/views/filament/pages/theme-inject.blade.php @@ -0,0 +1,10 @@ + + +
+ {{ $this->form }} +
+ 保存 +
+
+
+
diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php index 5262de5..2981305 100644 --- a/resources/views/index.blade.php +++ b/resources/views/index.blade.php @@ -21,5 +21,6 @@ @include('partials.sidebar') @include('partials.footer') +@stack('theme:body_end') diff --git a/resources/views/links.blade.php b/resources/views/links.blade.php index 97be616..cb80ab6 100644 --- a/resources/views/links.blade.php +++ b/resources/views/links.blade.php @@ -19,5 +19,6 @@ @include('partials.sidebar') @include('partials.footer') +@stack('theme:body_end') diff --git a/resources/views/list.blade.php b/resources/views/list.blade.php index 33d50df..32feac2 100644 --- a/resources/views/list.blade.php +++ b/resources/views/list.blade.php @@ -19,5 +19,6 @@ @include('partials.sidebar') @include('partials.footer') +@stack('theme:body_end') diff --git a/resources/views/login.blade.php b/resources/views/login.blade.php index b0e0605..d2de3a1 100644 --- a/resources/views/login.blade.php +++ b/resources/views/login.blade.php @@ -25,5 +25,6 @@ @include('partials.footer') +@stack('theme:body_end') diff --git a/resources/views/partials/footer.blade.php b/resources/views/partials/footer.blade.php index 8c2ee05..b4e19b4 100644 --- a/resources/views/partials/footer.blade.php +++ b/resources/views/partials/footer.blade.php @@ -1,3 +1,4 @@ +@stack('theme:footer')