From 5f51ce1ed04780974f2bdb94b36376bfe6b58f3a Mon Sep 17 00:00:00 2001 From: lq Date: Thu, 13 Aug 2026 21:14:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E9=A1=B5=E9=9D=A2=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 9 + pnpm-workspace.yaml | 5 + src/components/CollectionSwitch.vue | 68 +- src/components/CommandPalette.vue | 214 ++- src/components/StyleGallery.vue | 194 ++- src/data/corpProfiles.js | 704 +++++++++- src/data/labStyles.js | 511 +++++++ src/data/profile.js | 76 + src/data/styles.js | 1233 +++++++++++++++++ src/pages/CorpHome.vue | 61 +- src/pages/Home.vue | 62 +- src/pages/LabHome.vue | 65 +- src/pages/corp/EcomDutyFreePage.vue | 375 ++++- src/pages/corp/EcomFreshPage.vue | 315 ++++- src/pages/corp/EcomSalePage.vue | 304 +++- src/pages/corp/EcomToyPage.vue | 298 +++- src/pages/corp/HomeBabyPage.vue | 262 +++- src/pages/corp/HomeButlerPage.vue | 256 +++- src/pages/corp/HomeCleanPage.vue | 266 +++- src/pages/corp/HomeWarmPage.vue | 282 +++- src/pages/corp/MedClinicPage.vue | 255 +++- src/pages/corp/MedDentalPage.vue | 316 +++++ src/pages/corp/MedFamilyPage.vue | 272 +++- src/pages/corp/MedHospitalPage.vue | 288 +++- src/pages/corp/MedOnlinePage.vue | 347 +++++ src/pages/corp/PharmaBiotechPage.vue | 283 +++- src/pages/corp/PharmaModernPage.vue | 268 +++- src/pages/corp/PharmaStorePage.vue | 295 +++- src/pages/corp/PharmaTcmPage.vue | 284 +++- src/pages/corp/SaasBiPage.vue | 248 +++- src/pages/corp/SaasBuilderPage.vue | 298 +++- src/pages/corp/SaasClassicPage.vue | 310 ++++- src/pages/corp/SaasCollabPage.vue | 246 +++- src/pages/corp/SaasCrmPage.vue | 255 +++- src/pages/corp/TechChipPage.vue | 280 +++- src/pages/corp/TechEnterprisePage.vue | 315 ++++- src/pages/corp/TechHardwarePage.vue | 261 +++- src/pages/corp/TechOpensourcePage.vue | 225 ++- src/pages/corp/TechSpacePage.vue | 299 +++- src/pages/corp/TravelInkPage.vue | 319 ++++- src/pages/corp/TravelIslandPage.vue | 314 ++++- src/pages/corp/TravelOldtownPage.vue | 289 +++- src/pages/corp/TravelParkPage.vue | 274 +++- src/pages/corp/TravelSkiPage.vue | 304 +++- src/pages/corp/ecom/PremiumDetail.vue | 199 +++ src/pages/corp/furn/AtelierProducts.vue | 105 +- src/pages/corp/furn/MilanoHome.vue | 2 +- src/pages/corp/furn/MilanoProducts.vue | 310 ++++- src/pages/corp/furn/MingHome.vue | 2 +- src/pages/corp/furn/MingProducts.vue | 289 +++- src/pages/corp/furn/WabiHome.vue | 2 +- src/pages/corp/furn/WabiProducts.vue | 280 +++- src/pages/lab/AudioViz.vue | 286 ++++ src/pages/lab/ChatAi.vue | 331 +++++ src/pages/lab/CursorFx.vue | 289 ++++ src/pages/lab/Dice3d.vue | 327 +++++ src/pages/lab/Fireworks.vue | 270 ++++ src/pages/lab/FlipClock.vue | 277 ++++ src/pages/lab/Gallery3d.vue | 344 +++++ src/pages/lab/Game2048.vue | 362 +++++ src/pages/lab/Globe3d.vue | 333 +++++ src/pages/lab/GradientMaker.vue | 334 +++++ src/pages/lab/HabitTracker.vue | 392 ++++++ src/pages/lab/JsonBox.vue | 302 ++++ src/pages/lab/Kanban.vue | 337 +++++ src/pages/lab/MemoryFlip.vue | 244 ++++ src/pages/lab/Minesweeper.vue | 333 +++++ src/pages/lab/ParticleText.vue | 271 ++++ src/pages/lab/Pomodoro.vue | 300 ++++ src/pages/lab/RegexTester.vue | 321 +++++ src/pages/lab/ResponsivePreview.vue | 251 ++++ src/pages/lab/ShadowMaker.vue | 342 +++++ src/pages/lab/Snake.vue | 369 +++++ src/pages/lab/Solar3d.vue | 323 +++++ src/pages/lab/StockSim.vue | 343 +++++ src/pages/lab/SvgTheater.vue | 217 +++ src/pages/lab/Text3d.vue | 311 +++++ src/pages/lab/TextDiff.vue | 301 ++++ src/pages/lab/TextFx.vue | 264 ++++ src/pages/lab/VoxelBuilder.vue | 355 +++++ src/pages/lab/WeatherApp.vue | 387 ++++++ src/pages/styles/AuroraPage.vue | 181 ++- src/pages/styles/AwardPage.vue | 581 ++++++++ src/pages/styles/BauhausPage.vue | 213 ++- src/pages/styles/BentoPage.vue | 217 ++- src/pages/styles/BikiniBottomPage.vue | 666 +++++++++ src/pages/styles/BilibiliPage.vue | 712 ++++++++++ src/pages/styles/BiosPage.vue | 388 ++++++ src/pages/styles/BlackboardPage.vue | 478 +++++++ src/pages/styles/BlueprintPage.vue | 229 ++- src/pages/styles/BoardGamePage.vue | 560 ++++++++ src/pages/styles/BoardingPassPage.vue | 192 ++- src/pages/styles/BomberPage.vue | 721 ++++++++++ src/pages/styles/BrutalismPage.vue | 183 ++- src/pages/styles/CandyPage.vue | 216 ++- src/pages/styles/CassettePage.vue | 631 +++++++++ src/pages/styles/CctvPage.vue | 650 +++++++++ src/pages/styles/CheckupPage.vue | 250 ++++ src/pages/styles/CircusPage.vue | 591 ++++++++ src/pages/styles/ClayPage.vue | 181 ++- src/pages/styles/CollagePage.vue | 207 ++- src/pages/styles/CreditsPage.vue | 232 +++- src/pages/styles/CrossfirePage.vue | 738 ++++++++++ src/pages/styles/CrtTvPage.vue | 147 +- src/pages/styles/CyberpunkPage.vue | 194 ++- src/pages/styles/DanmakuPage.vue | 205 ++- src/pages/styles/DashboardPage.vue | 241 +++- src/pages/styles/DatingPage.vue | 655 +++++++++ src/pages/styles/DeepseaPage.vue | 595 ++++++++ src/pages/styles/DoodlePage.vue | 163 ++- src/pages/styles/DosFmPage.vue | 429 ++++++ src/pages/styles/DouyinPage.vue | 588 ++++++++ src/pages/styles/EinkPage.vue | 498 +++++++ src/pages/styles/EmailInboxPage.vue | 489 +++++++ src/pages/styles/FoodDeliveryPage.vue | 759 ++++++++++ src/pages/styles/GameboyPage.vue | 117 +- src/pages/styles/GlassPage.vue | 157 ++- src/pages/styles/GuofengPage.vue | 223 ++- src/pages/styles/HauntedHousePage.vue | 732 ++++++++++ src/pages/styles/IdePage.vue | 80 +- src/pages/styles/IpodPage.vue | 97 +- src/pages/styles/JayChouPage.vue | 910 ++++++++++++ src/pages/styles/JayPianoPage.vue | 1136 +++++++++++++++ src/pages/styles/LeatherPage.vue | 560 ++++++++ src/pages/styles/LegoManualPage.vue | 747 ++++++++++ src/pages/styles/LockscreenPage.vue | 273 +++- src/pages/styles/LolPage.vue | 757 ++++++++++ src/pages/styles/LuxuryPage.vue | 217 ++- src/pages/styles/MacosPage.vue | 259 +++- src/pages/styles/MagazinePage.vue | 234 +++- src/pages/styles/MarioPage.vue | 812 +++++++++++ src/pages/styles/MedievalPage.vue | 195 ++- src/pages/styles/MemphisPage.vue | 212 ++- src/pages/styles/MetroPage.vue | 230 ++- src/pages/styles/MickeyPage.vue | 720 ++++++++++ src/pages/styles/MinimalPage.vue | 92 +- src/pages/styles/MonsterMoviePage.vue | 647 +++++++++ src/pages/styles/MusicArtistPage.vue | 699 ++++++++++ src/pages/styles/NeonSignPage.vue | 192 ++- src/pages/styles/NeteasePage.vue | 433 ++++++ src/pages/styles/NeumorphismPage.vue | 224 ++- src/pages/styles/NewspaperPage.vue | 149 +- src/pages/styles/OuijaPage.vue | 739 ++++++++++ src/pages/styles/PagerPage.vue | 142 +- src/pages/styles/PapercutPage.vue | 592 ++++++++ src/pages/styles/PassportPage.vue | 156 ++- src/pages/styles/PixelPage.vue | 170 ++- src/pages/styles/PolaroidPage.vue | 136 +- src/pages/styles/PopArtPage.vue | 213 ++- src/pages/styles/PsychedelicPage.vue | 499 +++++++ src/pages/styles/ReceiptPage.vue | 143 +- src/pages/styles/RetroPrintPage.vue | 198 ++- src/pages/styles/SeerPage.vue | 713 ++++++++++ src/pages/styles/SkiSafariPage.vue | 818 +++++++++++ src/pages/styles/SlideshowPage.vue | 510 +++++++ src/pages/styles/SnowBrosPage.vue | 603 ++++++++ src/pages/styles/SpacePage.vue | 195 ++- src/pages/styles/SteamPage.vue | 188 ++- src/pages/styles/StreamingShelfPage.vue | 645 +++++++++ src/pages/styles/SurrealismPage.vue | 643 +++++++++ src/pages/styles/SwissPage.vue | 222 ++- src/pages/styles/TalismanPage.vue | 734 ++++++++++ src/pages/styles/TamagotchiPage.vue | 110 +- src/pages/styles/TarotPage.vue | 554 ++++++++ src/pages/styles/TelegramPage.vue | 169 ++- src/pages/styles/TeletextPage.vue | 424 ++++++ src/pages/styles/TerminalPage.vue | 103 +- src/pages/styles/TerrazzoPage.vue | 586 ++++++++ src/pages/styles/TiebaPage.vue | 490 +++++++ src/pages/styles/TypewriterPage.vue | 139 +- src/pages/styles/UkiyoePage.vue | 618 +++++++++ src/pages/styles/VaporwavePage.vue | 191 ++- src/pages/styles/VendingPage.vue | 563 ++++++++ src/pages/styles/VhsPage.vue | 704 ++++++++++ src/pages/styles/VinylPage.vue | 189 +++ src/pages/styles/WatercolorPage.vue | 190 ++- src/pages/styles/WechatPage.vue | 171 ++- src/pages/styles/WeiboPage.vue | 416 ++++++ src/pages/styles/WikiPage.vue | 151 +- src/pages/styles/Win11Page.vue | 193 ++- src/pages/styles/Win8Page.vue | 523 +++++++ src/pages/styles/Win98Page.vue | 148 +- src/pages/styles/WrappedPage.vue | 188 +++ src/pages/styles/XiaohongshuPage.vue | 527 +++++++ src/pages/styles/Y2kPage.vue | 206 ++- src/pages/styles/ZenPage.vue | 172 ++- src/pages/styles/ZhihuPage.vue | 404 ++++++ src/pages/styles/sub/AuroraStationPage.vue | 193 +++ src/pages/styles/sub/AwardGalleryPage.vue | 177 +++ src/pages/styles/sub/BauhausComposePage.vue | 173 +++ src/pages/styles/sub/BentoArrangePage.vue | 211 +++ src/pages/styles/sub/BiliVideoPage.vue | 437 ++++++ src/pages/styles/sub/BiosOverclockPage.vue | 274 ++++ src/pages/styles/sub/BlackboardQuizPage.vue | 229 +++ src/pages/styles/sub/BlueprintReviewPage.vue | 217 +++ src/pages/styles/sub/BoardGameFlyPage.vue | 321 +++++ src/pages/styles/sub/BoardingCheckinPage.vue | 246 ++++ src/pages/styles/sub/BomberMazePage.vue | 317 +++++ src/pages/styles/sub/BrutalWallPage.vue | 241 ++++ src/pages/styles/sub/CandyGachaPage.vue | 262 ++++ src/pages/styles/sub/CassetteMixPage.vue | 280 ++++ src/pages/styles/sub/CctvGridPage.vue | 228 +++ src/pages/styles/sub/CfRangePage.vue | 291 ++++ src/pages/styles/sub/CheckupBookPage.vue | 200 +++ src/pages/styles/sub/CircusShowPage.vue | 205 +++ src/pages/styles/sub/ClayStudioPage.vue | 216 +++ src/pages/styles/sub/CollageDeskPage.vue | 235 ++++ src/pages/styles/sub/CreditsBlooperPage.vue | 198 +++ src/pages/styles/sub/CrtChannelsPage.vue | 342 +++++ src/pages/styles/sub/CyberAugmentPage.vue | 235 ++++ src/pages/styles/sub/DanmakuPoolPage.vue | 270 ++++ .../styles/sub/DashboardBigscreenPage.vue | 273 ++++ src/pages/styles/sub/DatingChatPage.vue | 219 +++ src/pages/styles/sub/DeepseaDivePage.vue | 244 ++++ src/pages/styles/sub/DoodleBoardPage.vue | 244 ++++ src/pages/styles/sub/DosRadioPage.vue | 267 ++++ src/pages/styles/sub/DouyinLivePage.vue | 391 ++++++ src/pages/styles/sub/EinkShelfPage.vue | 233 ++++ src/pages/styles/sub/EmailComposePage.vue | 223 +++ src/pages/styles/sub/FoodOrderPage.vue | 284 ++++ src/pages/styles/sub/GameboyStackPage.vue | 285 ++++ src/pages/styles/sub/GlassLabPage.vue | 221 +++ src/pages/styles/sub/GuofengSealPage.vue | 252 ++++ src/pages/styles/sub/HauntedFlashPage.vue | 220 +++ src/pages/styles/sub/IdeGolfPage.vue | 294 ++++ src/pages/styles/sub/IpodCoverflowPage.vue | 221 +++ src/pages/styles/sub/KrustyCookPage.vue | 334 +++++ src/pages/styles/sub/LeatherEmbossPage.vue | 259 ++++ src/pages/styles/sub/LegoBuildPage.vue | 317 +++++ src/pages/styles/sub/LockPatternPage.vue | 261 ++++ src/pages/styles/sub/LolBuildPage.vue | 311 +++++ src/pages/styles/sub/LuxuryAtelierPage.vue | 262 ++++ src/pages/styles/sub/MacLaunchpadPage.vue | 240 ++++ src/pages/styles/sub/MagazineArchivePage.vue | 210 +++ src/pages/styles/sub/MarioRunPage.vue | 298 ++++ src/pages/styles/sub/MedievalQuestPage.vue | 228 +++ src/pages/styles/sub/MemphisMakerPage.vue | 211 +++ src/pages/styles/sub/MetroRidePage.vue | 276 ++++ src/pages/styles/sub/MickeyToolPage.vue | 266 ++++ src/pages/styles/sub/MinimalNotesPage.vue | 155 +++ src/pages/styles/sub/MonsterScreeningPage.vue | 220 +++ src/pages/styles/sub/MusicTourPage.vue | 324 +++++ src/pages/styles/sub/NeonCustomPage.vue | 245 ++++ src/pages/styles/sub/NeteasePlayerPage.vue | 331 +++++ src/pages/styles/sub/NeuConsolePage.vue | 246 ++++ src/pages/styles/sub/NewspaperArchivePage.vue | 175 +++ src/pages/styles/sub/OuijaAskPage.vue | 283 ++++ src/pages/styles/sub/PagerStationPage.vue | 199 +++ src/pages/styles/sub/PapercutWindowPage.vue | 214 +++ src/pages/styles/sub/PassportStampPage.vue | 193 +++ src/pages/styles/sub/PixelCatchPage.vue | 220 +++ src/pages/styles/sub/PolaroidDarkroomPage.vue | 277 ++++ src/pages/styles/sub/PopComicPage.vue | 190 +++ src/pages/styles/sub/PsyKaleidoPage.vue | 171 +++ src/pages/styles/sub/ReceiptKioskPage.vue | 216 +++ src/pages/styles/sub/RetroPressPage.vue | 251 ++++ src/pages/styles/sub/SeerBattlePage.vue | 301 ++++ src/pages/styles/sub/SkiRunPage.vue | 279 ++++ src/pages/styles/sub/SlideProjectorPage.vue | 208 +++ src/pages/styles/sub/SnowRollPage.vue | 256 ++++ src/pages/styles/sub/SpaceEvaPage.vue | 250 ++++ src/pages/styles/sub/SteamAchievePage.vue | 208 +++ src/pages/styles/sub/StreamingPlayPage.vue | 297 ++++ src/pages/styles/sub/SurrealDreamPage.vue | 200 +++ src/pages/styles/sub/SwissLayoutPage.vue | 172 +++ src/pages/styles/sub/TalismanDrawPage.vue | 288 ++++ src/pages/styles/sub/TamagotchiCarePage.vue | 239 ++++ src/pages/styles/sub/TarotDrawPage.vue | 218 +++ src/pages/styles/sub/TelegramMorsePage.vue | 291 ++++ src/pages/styles/sub/TeletextPagesPage.vue | 243 ++++ src/pages/styles/sub/TerminalShellPage.vue | 240 ++++ src/pages/styles/sub/TerrazzoMixerPage.vue | 209 +++ src/pages/styles/sub/TiebaThreadPage.vue | 279 ++++ src/pages/styles/sub/TypewriterLetterPage.vue | 212 +++ src/pages/styles/sub/UkiyoePrintPage.vue | 255 ++++ src/pages/styles/sub/VaporMallPage.vue | 199 +++ src/pages/styles/sub/VendingRestockPage.vue | 244 ++++ src/pages/styles/sub/VhsStorePage.vue | 238 ++++ src/pages/styles/sub/VinylDeckPage.vue | 324 +++++ src/pages/styles/sub/WatercolorMixPage.vue | 210 +++ src/pages/styles/sub/WechatMomentsPage.vue | 225 +++ src/pages/styles/sub/WeiboHotPage.vue | 162 +++ src/pages/styles/sub/WikiHistoryPage.vue | 177 +++ src/pages/styles/sub/Win11SettingsPage.vue | 334 +++++ src/pages/styles/sub/Win8TileEditPage.vue | 234 ++++ src/pages/styles/sub/Win98ControlPage.vue | 302 ++++ src/pages/styles/sub/WrappedStoryPage.vue | 188 +++ src/pages/styles/sub/XhsNotePage.vue | 364 +++++ src/pages/styles/sub/Y2kScanPage.vue | 284 ++++ src/pages/styles/sub/ZenSandPage.vue | 191 +++ src/pages/styles/sub/ZhihuAnswerPage.vue | 225 +++ src/router/index.js | 20 +- 293 files changed, 89673 insertions(+), 328 deletions(-) create mode 100644 pnpm-workspace.yaml create mode 100644 src/pages/lab/AudioViz.vue create mode 100644 src/pages/lab/ChatAi.vue create mode 100644 src/pages/lab/CursorFx.vue create mode 100644 src/pages/lab/Dice3d.vue create mode 100644 src/pages/lab/Fireworks.vue create mode 100644 src/pages/lab/FlipClock.vue create mode 100644 src/pages/lab/Gallery3d.vue create mode 100644 src/pages/lab/Game2048.vue create mode 100644 src/pages/lab/Globe3d.vue create mode 100644 src/pages/lab/GradientMaker.vue create mode 100644 src/pages/lab/HabitTracker.vue create mode 100644 src/pages/lab/JsonBox.vue create mode 100644 src/pages/lab/Kanban.vue create mode 100644 src/pages/lab/MemoryFlip.vue create mode 100644 src/pages/lab/Minesweeper.vue create mode 100644 src/pages/lab/ParticleText.vue create mode 100644 src/pages/lab/Pomodoro.vue create mode 100644 src/pages/lab/RegexTester.vue create mode 100644 src/pages/lab/ResponsivePreview.vue create mode 100644 src/pages/lab/ShadowMaker.vue create mode 100644 src/pages/lab/Snake.vue create mode 100644 src/pages/lab/Solar3d.vue create mode 100644 src/pages/lab/StockSim.vue create mode 100644 src/pages/lab/SvgTheater.vue create mode 100644 src/pages/lab/Text3d.vue create mode 100644 src/pages/lab/TextDiff.vue create mode 100644 src/pages/lab/TextFx.vue create mode 100644 src/pages/lab/VoxelBuilder.vue create mode 100644 src/pages/lab/WeatherApp.vue create mode 100644 src/pages/styles/AwardPage.vue create mode 100644 src/pages/styles/BikiniBottomPage.vue create mode 100644 src/pages/styles/BilibiliPage.vue create mode 100644 src/pages/styles/BiosPage.vue create mode 100644 src/pages/styles/BlackboardPage.vue create mode 100644 src/pages/styles/BoardGamePage.vue create mode 100644 src/pages/styles/BomberPage.vue create mode 100644 src/pages/styles/CassettePage.vue create mode 100644 src/pages/styles/CctvPage.vue create mode 100644 src/pages/styles/CircusPage.vue create mode 100644 src/pages/styles/CrossfirePage.vue create mode 100644 src/pages/styles/DatingPage.vue create mode 100644 src/pages/styles/DeepseaPage.vue create mode 100644 src/pages/styles/DosFmPage.vue create mode 100644 src/pages/styles/DouyinPage.vue create mode 100644 src/pages/styles/EinkPage.vue create mode 100644 src/pages/styles/EmailInboxPage.vue create mode 100644 src/pages/styles/FoodDeliveryPage.vue create mode 100644 src/pages/styles/HauntedHousePage.vue create mode 100644 src/pages/styles/JayChouPage.vue create mode 100644 src/pages/styles/JayPianoPage.vue create mode 100644 src/pages/styles/LeatherPage.vue create mode 100644 src/pages/styles/LegoManualPage.vue create mode 100644 src/pages/styles/LolPage.vue create mode 100644 src/pages/styles/MarioPage.vue create mode 100644 src/pages/styles/MickeyPage.vue create mode 100644 src/pages/styles/MonsterMoviePage.vue create mode 100644 src/pages/styles/MusicArtistPage.vue create mode 100644 src/pages/styles/NeteasePage.vue create mode 100644 src/pages/styles/OuijaPage.vue create mode 100644 src/pages/styles/PapercutPage.vue create mode 100644 src/pages/styles/PsychedelicPage.vue create mode 100644 src/pages/styles/SeerPage.vue create mode 100644 src/pages/styles/SkiSafariPage.vue create mode 100644 src/pages/styles/SlideshowPage.vue create mode 100644 src/pages/styles/SnowBrosPage.vue create mode 100644 src/pages/styles/StreamingShelfPage.vue create mode 100644 src/pages/styles/SurrealismPage.vue create mode 100644 src/pages/styles/TalismanPage.vue create mode 100644 src/pages/styles/TarotPage.vue create mode 100644 src/pages/styles/TeletextPage.vue create mode 100644 src/pages/styles/TerrazzoPage.vue create mode 100644 src/pages/styles/TiebaPage.vue create mode 100644 src/pages/styles/UkiyoePage.vue create mode 100644 src/pages/styles/VendingPage.vue create mode 100644 src/pages/styles/VhsPage.vue create mode 100644 src/pages/styles/WeiboPage.vue create mode 100644 src/pages/styles/Win8Page.vue create mode 100644 src/pages/styles/XiaohongshuPage.vue create mode 100644 src/pages/styles/ZhihuPage.vue create mode 100644 src/pages/styles/sub/AuroraStationPage.vue create mode 100644 src/pages/styles/sub/AwardGalleryPage.vue create mode 100644 src/pages/styles/sub/BauhausComposePage.vue create mode 100644 src/pages/styles/sub/BentoArrangePage.vue create mode 100644 src/pages/styles/sub/BiliVideoPage.vue create mode 100644 src/pages/styles/sub/BiosOverclockPage.vue create mode 100644 src/pages/styles/sub/BlackboardQuizPage.vue create mode 100644 src/pages/styles/sub/BlueprintReviewPage.vue create mode 100644 src/pages/styles/sub/BoardGameFlyPage.vue create mode 100644 src/pages/styles/sub/BoardingCheckinPage.vue create mode 100644 src/pages/styles/sub/BomberMazePage.vue create mode 100644 src/pages/styles/sub/BrutalWallPage.vue create mode 100644 src/pages/styles/sub/CandyGachaPage.vue create mode 100644 src/pages/styles/sub/CassetteMixPage.vue create mode 100644 src/pages/styles/sub/CctvGridPage.vue create mode 100644 src/pages/styles/sub/CfRangePage.vue create mode 100644 src/pages/styles/sub/CheckupBookPage.vue create mode 100644 src/pages/styles/sub/CircusShowPage.vue create mode 100644 src/pages/styles/sub/ClayStudioPage.vue create mode 100644 src/pages/styles/sub/CollageDeskPage.vue create mode 100644 src/pages/styles/sub/CreditsBlooperPage.vue create mode 100644 src/pages/styles/sub/CrtChannelsPage.vue create mode 100644 src/pages/styles/sub/CyberAugmentPage.vue create mode 100644 src/pages/styles/sub/DanmakuPoolPage.vue create mode 100644 src/pages/styles/sub/DashboardBigscreenPage.vue create mode 100644 src/pages/styles/sub/DatingChatPage.vue create mode 100644 src/pages/styles/sub/DeepseaDivePage.vue create mode 100644 src/pages/styles/sub/DoodleBoardPage.vue create mode 100644 src/pages/styles/sub/DosRadioPage.vue create mode 100644 src/pages/styles/sub/DouyinLivePage.vue create mode 100644 src/pages/styles/sub/EinkShelfPage.vue create mode 100644 src/pages/styles/sub/EmailComposePage.vue create mode 100644 src/pages/styles/sub/FoodOrderPage.vue create mode 100644 src/pages/styles/sub/GameboyStackPage.vue create mode 100644 src/pages/styles/sub/GlassLabPage.vue create mode 100644 src/pages/styles/sub/GuofengSealPage.vue create mode 100644 src/pages/styles/sub/HauntedFlashPage.vue create mode 100644 src/pages/styles/sub/IdeGolfPage.vue create mode 100644 src/pages/styles/sub/IpodCoverflowPage.vue create mode 100644 src/pages/styles/sub/KrustyCookPage.vue create mode 100644 src/pages/styles/sub/LeatherEmbossPage.vue create mode 100644 src/pages/styles/sub/LegoBuildPage.vue create mode 100644 src/pages/styles/sub/LockPatternPage.vue create mode 100644 src/pages/styles/sub/LolBuildPage.vue create mode 100644 src/pages/styles/sub/LuxuryAtelierPage.vue create mode 100644 src/pages/styles/sub/MacLaunchpadPage.vue create mode 100644 src/pages/styles/sub/MagazineArchivePage.vue create mode 100644 src/pages/styles/sub/MarioRunPage.vue create mode 100644 src/pages/styles/sub/MedievalQuestPage.vue create mode 100644 src/pages/styles/sub/MemphisMakerPage.vue create mode 100644 src/pages/styles/sub/MetroRidePage.vue create mode 100644 src/pages/styles/sub/MickeyToolPage.vue create mode 100644 src/pages/styles/sub/MinimalNotesPage.vue create mode 100644 src/pages/styles/sub/MonsterScreeningPage.vue create mode 100644 src/pages/styles/sub/MusicTourPage.vue create mode 100644 src/pages/styles/sub/NeonCustomPage.vue create mode 100644 src/pages/styles/sub/NeteasePlayerPage.vue create mode 100644 src/pages/styles/sub/NeuConsolePage.vue create mode 100644 src/pages/styles/sub/NewspaperArchivePage.vue create mode 100644 src/pages/styles/sub/OuijaAskPage.vue create mode 100644 src/pages/styles/sub/PagerStationPage.vue create mode 100644 src/pages/styles/sub/PapercutWindowPage.vue create mode 100644 src/pages/styles/sub/PassportStampPage.vue create mode 100644 src/pages/styles/sub/PixelCatchPage.vue create mode 100644 src/pages/styles/sub/PolaroidDarkroomPage.vue create mode 100644 src/pages/styles/sub/PopComicPage.vue create mode 100644 src/pages/styles/sub/PsyKaleidoPage.vue create mode 100644 src/pages/styles/sub/ReceiptKioskPage.vue create mode 100644 src/pages/styles/sub/RetroPressPage.vue create mode 100644 src/pages/styles/sub/SeerBattlePage.vue create mode 100644 src/pages/styles/sub/SkiRunPage.vue create mode 100644 src/pages/styles/sub/SlideProjectorPage.vue create mode 100644 src/pages/styles/sub/SnowRollPage.vue create mode 100644 src/pages/styles/sub/SpaceEvaPage.vue create mode 100644 src/pages/styles/sub/SteamAchievePage.vue create mode 100644 src/pages/styles/sub/StreamingPlayPage.vue create mode 100644 src/pages/styles/sub/SurrealDreamPage.vue create mode 100644 src/pages/styles/sub/SwissLayoutPage.vue create mode 100644 src/pages/styles/sub/TalismanDrawPage.vue create mode 100644 src/pages/styles/sub/TamagotchiCarePage.vue create mode 100644 src/pages/styles/sub/TarotDrawPage.vue create mode 100644 src/pages/styles/sub/TelegramMorsePage.vue create mode 100644 src/pages/styles/sub/TeletextPagesPage.vue create mode 100644 src/pages/styles/sub/TerminalShellPage.vue create mode 100644 src/pages/styles/sub/TerrazzoMixerPage.vue create mode 100644 src/pages/styles/sub/TiebaThreadPage.vue create mode 100644 src/pages/styles/sub/TypewriterLetterPage.vue create mode 100644 src/pages/styles/sub/UkiyoePrintPage.vue create mode 100644 src/pages/styles/sub/VaporMallPage.vue create mode 100644 src/pages/styles/sub/VendingRestockPage.vue create mode 100644 src/pages/styles/sub/VhsStorePage.vue create mode 100644 src/pages/styles/sub/VinylDeckPage.vue create mode 100644 src/pages/styles/sub/WatercolorMixPage.vue create mode 100644 src/pages/styles/sub/WechatMomentsPage.vue create mode 100644 src/pages/styles/sub/WeiboHotPage.vue create mode 100644 src/pages/styles/sub/WikiHistoryPage.vue create mode 100644 src/pages/styles/sub/Win11SettingsPage.vue create mode 100644 src/pages/styles/sub/Win8TileEditPage.vue create mode 100644 src/pages/styles/sub/Win98ControlPage.vue create mode 100644 src/pages/styles/sub/WrappedStoryPage.vue create mode 100644 src/pages/styles/sub/XhsNotePage.vue create mode 100644 src/pages/styles/sub/Y2kScanPage.vue create mode 100644 src/pages/styles/sub/ZenSandPage.vue create mode 100644 src/pages/styles/sub/ZhihuAnswerPage.vue diff --git a/package.json b/package.json index 005484d..d4094fa 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "axios": "^1.6.2", "lucide-vue-next": "^0.507.0", "pinia": "^2.1.7", + "pinyin-pro": "^3.28.2", "swiper": "^11.0.5", "tailwindcss": "^4.1.4", "three": "^0.185.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ceabea2..2027eef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,9 @@ importers: pinia: specifier: ^2.1.7 version: 2.3.1(vue@3.5.13) + pinyin-pro: + specifier: ^3.28.2 + version: 3.28.2 swiper: specifier: ^11.0.5 version: 11.2.6 @@ -903,6 +906,7 @@ packages: lucide-vue-next@0.507.0: resolution: {integrity: sha512-n0AZRmez4xq5vu5ZOfnrhC5wKBpu5tpwDHA6Ue2+sKyJv3USAPxqIerXLbdYbkHRW1tVZ3U9GE1MACsu6X/Z7Q==} + deprecated: Package deprecated. Please use @lucide/vue instead. peerDependencies: vue: '>=3.0.1' @@ -962,6 +966,9 @@ packages: typescript: optional: true + pinyin-pro@3.28.2: + resolution: {integrity: sha512-jV38yxXHLfidirMC4hrXasLDozLCSq/4DfX88GnHcSEJ2+GpSedG6I9VOiEXJu6iQ5dbJC/RjmzyMuS5h/wH5A==} + postcss@8.5.3: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} @@ -1833,6 +1840,8 @@ snapshots: transitivePeerDependencies: - '@vue/composition-api' + pinyin-pro@3.28.2: {} + postcss@8.5.3: dependencies: nanoid: 3.3.11 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..ee14c69 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,5 @@ +allowBuilds: + '@parcel/watcher': set this to true or false + core-js: set this to true or false + esbuild: set this to true or false + vue-demi: set this to true or false diff --git a/src/components/CollectionSwitch.vue b/src/components/CollectionSwitch.vue index 1f3e9c0..ea47326 100644 --- a/src/components/CollectionSwitch.vue +++ b/src/components/CollectionSwitch.vue @@ -18,6 +18,10 @@ onMounted(() => { if (sentinel.value) io.observe(sentinel.value) }) onBeforeUnmount(() => io?.disconnect()) + +function openSearch() { + window.dispatchEvent(new Event('open-cmdk')) +} @@ -59,14 +70,63 @@ onBeforeUnmount(() => io?.disconnect()) box-shadow 0.25s ease; } .cs-wrap.stuck { - background: rgba(12, 14, 19, 0.82); - -webkit-backdrop-filter: blur(14px); - backdrop-filter: blur(14px); - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); + background: + linear-gradient(color-mix(in srgb, var(--cs-accent) 9%, transparent), transparent 46%), + rgba(8, 10, 15, 0.96); + -webkit-backdrop-filter: blur(16px) saturate(1.2); + backdrop-filter: blur(16px) saturate(1.2); + box-shadow: + 0 10px 30px rgba(0, 0, 0, 0.4), + inset 0 2px 0 color-mix(in srgb, var(--cs-accent) 55%, transparent); +} +.cs-wrap.stuck .cs { + background: #1c202c; + border-color: #3c4356; } .cs-in { max-width: 1280px; margin: 0 auto; + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + flex-wrap: wrap; +} +.cs-search { + display: inline-flex; + align-items: center; + gap: 8px; + border: 1px solid #262935; + background: #12141b; + color: #9aa0b5; + font-size: 12.5px; + letter-spacing: 0.04em; + border-radius: 12px; + padding: 9px 14px; + cursor: pointer; + transition: all 0.18s ease; +} +.cs-search svg { + width: 14px; + height: 14px; +} +.cs-search kbd { + font-family: 'Space Grotesk', Consolas, monospace; + font-size: 10px; + color: #6b7188; + border: 1px solid #2b2f3d; + border-bottom-width: 2px; + border-radius: 5px; + padding: 2px 6px; +} +.cs-search:hover { + border-color: var(--cs-accent); + color: #f3f4f8; +} +.cs-wrap.stuck .cs-search { + background: #1c202c; + border-color: #3c4356; + color: #d3d7e4; } .cs { display: inline-flex; diff --git a/src/components/CommandPalette.vue b/src/components/CommandPalette.vue index d04ecd2..82c7a70 100644 --- a/src/components/CommandPalette.vue +++ b/src/components/CommandPalette.vue @@ -12,13 +12,122 @@ const active = ref(0) const inputEl = ref(null) const listEl = ref(null) -/* 全量条目 */ +/* 全量条目:顶层页 + 各自的子页面 */ +const expand = (list, base, group) => + list.flatMap((s) => [ + { path: `${base}/${s.id}`, title: s.title, sub: s.intro, group }, + ...(s.subPages || []).map((p) => ({ + path: `${base}/${s.id}/${p.path}`, + title: `${s.title} · ${p.title}`, + sub: s.intro, + group: `${group} · 子页面`, + })), + ]) + const all = [ - ...styleList.map((s) => ({ path: `/style/${s.id}`, title: s.title, sub: s.intro, group: '个人页面' })), - ...corpStyleList.map((s) => ({ path: `/corp/${s.id}`, title: s.title, sub: s.intro, group: '企业官网' })), - ...labList.map((s) => ({ path: `/lab/${s.id}`, title: s.title, sub: s.intro, group: '实验室' })), + ...expand(styleList, '/style', '个人页面'), + ...expand(corpStyleList, '/corp', '企业官网'), + ...expand(labList, '/lab', '实验室'), ] +/* ---------- 拼音索引(懒加载 pinyin-pro,首次打开时构建) ---------- */ +const indexReady = ref(false) +let pinyinOf = null +const pyCache = new Map() + +function charPinyin(ch) { + if (pyCache.has(ch)) return pyCache.get(ch) + let full + if (/[\u4e00-\u9fff]/.test(ch)) { + full = pinyinOf(ch, { toneType: 'none' }).toLowerCase() + } else { + full = ch.toLowerCase() + } + const v = { full, first: full[0] || '' } + pyCache.set(ch, v) + return v +} +/* 生成:小写原文 + 全拼串/首拼串(带每字符起点表,用于把命中反查回汉字区间) */ +function analyze(text) { + const chars = [...text] + const full = { str: '', starts: [] } + const first = { str: '', starts: [] } + for (const ch of chars) { + const p = charPinyin(ch) + full.starts.push(full.str.length) + full.str += p.full + first.starts.push(first.str.length) + first.str += p.first + } + return { lower: text.toLowerCase(), full, first, len: chars.length } +} +async function buildIndex() { + if (indexReady.value) return + const mod = await import('pinyin-pro') + pinyinOf = mod.pinyin + for (const item of all) { + item.ix = { title: analyze(item.title), sub: analyze(item.sub || '') } + } + indexReady.value = true +} + +/* 拼音串命中位置 → 原文字符区间 */ +function charRange(map, pos, len, totalChars) { + const starts = map.starts + let a = 0 + while (a + 1 < starts.length && starts[a + 1] <= pos) a++ + let b = a + const end = pos + len + while (b + 1 < starts.length && starts[b + 1] < end) b++ + return [[a, Math.min(b + 1, totalChars)]] +} +/* 单字段匹配:原文 > 全拼 > 首拼,返回 {tier, pos, ranges} */ +function matchField(ix, kwRaw, kwPy) { + const p0 = ix.lower.indexOf(kwRaw) + if (p0 >= 0) return { tier: 0, pos: p0, ranges: [[p0, p0 + kwRaw.length]] } + if (!kwPy) return null + const p1 = ix.full.str.indexOf(kwPy) + if (p1 >= 0) return { tier: 1, pos: p1, ranges: charRange(ix.full, p1, kwPy.length, ix.len) } + const p2 = ix.first.str.indexOf(kwPy) + if (p2 >= 0) return { tier: 2, pos: p2, ranges: charRange(ix.first, p2, kwPy.length, ix.len) } + return null +} +/* 条目打分:标题命中权重远高于简介;命中越靠前、标题越短加分 */ +function matchItem(item, kwRaw, kwPy) { + const canPy = indexReady.value && item.ix + const tIx = canPy ? item.ix.title : { lower: item.title.toLowerCase(), full: { str: '', starts: [] }, first: { str: '', starts: [] }, len: item.title.length } + const sIx = canPy ? item.ix.sub : { lower: (item.sub || '').toLowerCase(), full: { str: '', starts: [] }, first: { str: '', starts: [] }, len: (item.sub || '').length } + const tm = matchField(tIx, kwRaw, canPy ? kwPy : '') + const sm = matchField(sIx, kwRaw, canPy ? kwPy : '') + if (!tm && !sm) { + if (item.path.toLowerCase().includes(kwRaw)) return { score: 12, tRanges: [], sRanges: [] } + return null + } + let score = 0 + if (tm) { + score += [100, 70, 58][tm.tier] + if (tm.pos === 0) score += 16 + score += Math.max(0, 8 - tm.pos) + score += Math.max(0, 10 - [...item.title].length) + } + if (sm) score += [36, 22, 16][sm.tier] + return { score, tRanges: tm ? tm.ranges : [], sRanges: sm ? sm.ranges : [] } +} +/* 把命中区间切成高亮分段 */ +function segs(text, ranges) { + if (!ranges || !ranges.length) return [{ t: text, h: false }] + const chars = [...text] + const out = [] + let cur = 0 + for (const [a, b] of ranges) { + if (a > cur) out.push({ t: chars.slice(cur, a).join(''), h: false }) + out.push({ t: chars.slice(a, b).join(''), h: true }) + cur = b + } + if (cur < chars.length) out.push({ t: chars.slice(cur).join(''), h: false }) + return out +} + function recent() { try { return JSON.parse(localStorage.getItem('recent-visits') || '[]').slice(0, 5) @@ -27,22 +136,39 @@ function recent() { } } -/* 分组结果:无关键词时 = 最近 + 各组前几条;有关键词时 = 匹配项 */ +/* 分组结果:无关键词 = 最近 + 各组前几条;有关键词 = 拼音聚合搜索,按匹配度排序 */ const groups = computed(() => { - const kw = q.value.trim().toLowerCase() + // 依赖 indexReady,索引就绪后自动用拼音重算 + void indexReady.value + const kwRaw = q.value.trim().toLowerCase() + const kwPy = kwRaw.replace(/\s+/g, '') const out = [] - if (!kw) { + if (!kwRaw) { const rc = recent() - if (rc.length) out.push({ name: '最近浏览', items: rc.map((r) => ({ path: r.path, title: r.title, sub: '', group: '最近' })) }) + if (rc.length) out.push({ name: '最近浏览', items: rc.map((r) => ({ path: r.path, title: r.title, sub: '', group: '最近', tSegs: null, sSegs: null })) }) for (const name of ['个人页面', '企业官网', '实验室']) { out.push({ name, items: all.filter((i) => i.group === name).slice(0, 4) }) } } else { - const hit = all.filter((i) => `${i.title} ${i.sub} ${i.path}`.toLowerCase().includes(kw)) - for (const name of ['个人页面', '企业官网', '实验室']) { - const items = hit.filter((i) => i.group === name).slice(0, 8) - if (items.length) out.push({ name, items }) + const scored = [] + for (const item of all) { + const m = matchItem(item, kwRaw, kwPy) + if (m) { + scored.push({ + ...item, + score: m.score, + tSegs: segs(item.title, m.tRanges), + sSegs: item.sub ? segs(item.sub, m.sRanges) : null, + }) + } } + scored.sort((a, b) => b.score - a.score) + for (const name of ['个人页面', '企业官网', '实验室']) { + // startsWith 使「xx · 子页面」条目归入父分组一起展示 + const items = scored.filter((i) => i.group.startsWith(name)).slice(0, 8) + if (items.length) out.push({ name, items, top: items[0].score }) + } + out.sort((a, b) => (b.top || 0) - (a.top || 0)) } // 固定操作 out.push({ @@ -50,7 +176,7 @@ const groups = computed(() => { items: [ { path: '__random__', title: '随机传送', sub: '闭上眼睛跳到任何一页', group: '操作' }, { path: '/compare', title: '风格对比', sub: '左右两个页面并排看', group: '操作' }, - ].filter((i) => !kw || i.title.includes(q.value.trim()) || `${i.title}${i.sub}`.toLowerCase().includes(kw)), + ].filter((i) => !kwRaw || i.title.includes(q.value.trim()) || `${i.title}${i.sub}`.toLowerCase().includes(kwRaw)), }) return out.filter((g) => g.items.length) }) @@ -60,6 +186,7 @@ function show() { open.value = true q.value = '' active.value = 0 + buildIndex() nextTick(() => inputEl.value?.focus()) } function hide() { @@ -105,8 +232,14 @@ function scrollActive() { } watch(q, () => (active.value = 0)) -onMounted(() => window.addEventListener('keydown', onKey)) -onBeforeUnmount(() => window.removeEventListener('keydown', onKey)) +onMounted(() => { + window.addEventListener('keydown', onKey) + window.addEventListener('open-cmdk', show) +}) +onBeforeUnmount(() => { + window.removeEventListener('keydown', onKey) + window.removeEventListener('open-cmdk', show) +}) @@ -253,9 +403,9 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey)) background: #262935; color: #a7abbe; } -.cp-item-badge[data-g='个人页面'] { background: rgba(124, 108, 255, 0.2); color: #b9aeff; } -.cp-item-badge[data-g='企业官网'] { background: rgba(47, 123, 255, 0.2); color: #8fb6ff; } -.cp-item-badge[data-g='实验室'] { background: rgba(245, 158, 11, 0.18); color: #fcd34d; } +.cp-item-badge[data-g^='个人页面'] { background: rgba(124, 108, 255, 0.2); color: #b9aeff; } +.cp-item-badge[data-g^='企业官网'] { background: rgba(47, 123, 255, 0.2); color: #8fb6ff; } +.cp-item-badge[data-g^='实验室'] { background: rgba(245, 158, 11, 0.18); color: #fcd34d; } .cp-item-badge[data-g='操作'] { background: rgba(94, 234, 212, 0.16); color: #5eead4; } .cp-item-main { flex: 1; @@ -276,6 +426,28 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey)) overflow: hidden; text-overflow: ellipsis; } +.cp-hit { + font-style: normal; + color: #ffd97a; + background: rgba(255, 217, 122, 0.14); + border-radius: 3px; + padding: 0 1px; +} +.cp-score { + font-style: normal; + font-family: 'Space Grotesk', Consolas, monospace; + font-size: 10px; + color: #565c70; + border: 1px solid #2b2f3d; + border-radius: 5px; + padding: 2px 6px; + flex-shrink: 0; + font-variant-numeric: tabular-nums; +} +.cp-item.on .cp-score { + color: #b9aeff; + border-color: rgba(124, 108, 255, 0.4); +} .cp-item-go { font-style: normal; font-size: 11px; diff --git a/src/components/StyleGallery.vue b/src/components/StyleGallery.vue index cf20984..20e112f 100644 --- a/src/components/StyleGallery.vue +++ b/src/components/StyleGallery.vue @@ -1,5 +1,5 @@ @@ -289,13 +377,44 @@ const filtered = computed(() => { backdrop-filter 0.25s ease; } .sg-sticky.stuck { - background: rgba(12, 14, 19, 0.82); - -webkit-backdrop-filter: blur(14px); - backdrop-filter: blur(14px); - border-color: rgba(255, 255, 255, 0.07); + background: + linear-gradient(color-mix(in srgb, var(--sg-accent) 9%, transparent), transparent 46%), + rgba(8, 10, 15, 0.96); + -webkit-backdrop-filter: blur(16px) saturate(1.2); + backdrop-filter: blur(16px) saturate(1.2); + border-color: color-mix(in srgb, var(--sg-accent) 22%, rgba(255, 255, 255, 0.08)); border-top-color: transparent; - box-shadow: 0 18px 40px rgba(0, 0, 0, 0.4); + box-shadow: + 0 18px 44px rgba(0, 0, 0, 0.55), + inset 0 2px 0 color-mix(in srgb, var(--sg-accent) 55%, transparent); } +/* 吸顶时:控件提亮一档,与深色栏底拉开层次 */ +.sg-sticky.stuck .sg-search { + background: #1c202c; + border-color: #3a4052; +} +.sg-sticky.stuck .sg-search input { color: #ffffff; } +.sg-sticky.stuck .sg-chips button { + background: #1c202c; + border-color: #3c4356; + color: #d3d7e4; +} +.sg-sticky.stuck .sg-chips button i { + background: rgba(255, 255, 255, 0.1); + color: #9aa0b5; +} +.sg-sticky.stuck .sg-chips button.on { + background: var(--sg-accent); + border-color: transparent; + color: #fff; + box-shadow: 0 4px 16px color-mix(in srgb, var(--sg-accent) 45%, transparent); +} +.sg-sticky.stuck .sg-lucky { + background: #1c202c; + border-color: #3c4356; + color: #d3d7e4; +} +.sg-sticky.stuck .sg-count { color: #8a90a5; } .sg-tools { display: flex; @@ -591,6 +710,9 @@ const filtered = computed(() => { border: 1px solid #262935; border-radius: 16px; overflow: hidden; + /* 离屏卡片跳过渲染,滚动性能兜底 */ + content-visibility: auto; + contain-intrinsic-size: auto 300px; transition: transform 0.22s ease, border-color 0.22s ease, @@ -1173,6 +1295,42 @@ const filtered = computed(() => { line-height: 1.6; } +/* 触底加载 */ +.sg-more { + text-align: center; + padding: 22px 0 4px; +} +.sg-load-sentinel { + display: block; + height: 1px; +} +.sg-loading { + display: inline-flex; + align-items: center; + gap: 9px; + margin: 0; + font-size: 12px; + color: #565c70; + letter-spacing: 0.08em; +} +.sg-loading i { + width: 14px; + height: 14px; + border-radius: 50%; + border: 2px solid #2b2f3d; + border-top-color: var(--sg-accent); + animation: sg-spin 0.8s linear infinite; +} +@keyframes sg-spin { + to { transform: rotate(1turn); } +} +.sg-alldone { + margin: 0; + font-size: 11.5px; + color: #454b5e; + letter-spacing: 0.12em; +} + .sg-empty { text-align: center; padding: 70px 20px 60px; diff --git a/src/data/corpProfiles.js b/src/data/corpProfiles.js index bebfdbc..469a0cf 100644 --- a/src/data/corpProfiles.js +++ b/src/data/corpProfiles.js @@ -24,10 +24,66 @@ export const corpProfiles = { { value: '24h', label: '客服在线' }, ], cases: [ - { name: '云朵羽绒被', tag: '居家', desc: '95% 白鹅绒,轻若云朵,暖如拥抱', image: img('ng-ecom-quilt'), price: '¥599' }, - { name: '晨光手冲壶', tag: '厨房', desc: '细口控流,在家复刻咖啡馆的清晨', image: img('ng-ecom-kettle'), price: '¥239' }, - { name: '山野露营灯', tag: '户外', desc: '三档暖光,续航 72 小时的小太阳', image: img('ng-ecom-lamp'), price: '¥129' }, - { name: '绵云棉袜礼盒', tag: '服饰', desc: '新疆长绒棉,一盒装下整个冬天', image: img('ng-ecom-socks'), price: '¥89' }, + { + name: '云朵羽绒被', tag: '居家', desc: '95% 白鹅绒,轻若云朵,暖如拥抱', image: img('ng-ecom-quilt'), price: '¥599', + story: '买手团队在丹东的鹅场里蹲了三个月,只为等一批当季头拨白鹅绒。充绒车间恒温恒湿,每床被子出厂前都要过一遍「抱一下」的手感关——机器测蓬松度,人测幸福感。', + highlights: ['95% 白鹅绒,蓬松度 800+,轻若无物', '60 支贡缎防钻绒面料,缝线走双针', '可水洗设计,附赠收纳呼吸袋', '每床附检测报告,绒朵可溯源到鹅场'], + timeline: [ + { at: '2024.09', event: '丹东鹅场直采签约,锁定头拨绒' }, + { at: '2024.11', event: '首批 5000 床上架,双 11 当日售罄' }, + { at: '2025.03', event: '复购率破 46%,追加春秋薄款' }, + ], + metrics: [ + { label: '好评率', value: '99.2%' }, + { label: '复购率', value: '46%' }, + { label: '累计销量', value: '18万+' }, + ], + }, + { + name: '晨光手冲壶', tag: '厨房', desc: '细口控流,在家复刻咖啡馆的清晨', image: img('ng-ecom-kettle'), price: '¥239', + story: '设计师本人是十年手冲党,受不了市面上「水流忽粗忽细」的壶,索性和潮州的五金老厂一起开模。壶嘴内径改了 11 版,最终做到倾角 45 度时水流稳定成一条 3 毫米的细线。', + highlights: ['鹅颈壶嘴 11 版打磨,水流稳定 3mm', '304 不锈钢一体拉伸,无焊缝', '木纹手柄隔热,冬天握着也暖', '兼容电陶炉与明火'], + timeline: [ + { at: '2025.01', event: '与潮州五金厂联合开模' }, + { at: '2025.05', event: '众筹上线,3 小时达成目标' }, + { at: '2025.08', event: '入选站内「年度厨房好物」榜单' }, + ], + metrics: [ + { label: '好评率', value: '98.7%' }, + { label: '众筹达成', value: '1240%' }, + { label: '累计销量', value: '7.2万' }, + ], + }, + { + name: '山野露营灯', tag: '户外', desc: '三档暖光,续航 72 小时的小太阳', image: img('ng-ecom-lamp'), price: '¥129', + story: '团队带着七盏样灯去了三次莫干山营地,最后留下这一盏:暖光不招虫、挂钩能倒吊、淋一夜雨也没事。回城的路上大家给它起名「小太阳」,因为收帐篷时谁都舍不得关灯。', + highlights: ['3 档暖光 + SOS 模式,露营徒步两相宜', 'IPX5 防泼溅,淋雨照常工作', '5000mAh 反向充电,兼职充电宝', '磁吸底座 + 倒吊挂钩,怎么挂都行'], + timeline: [ + { at: '2024.06', event: '三次营地实测定稿' }, + { at: '2024.08', event: '上架即登户外类目热销第一' }, + { at: '2025.06', event: '第二代增加无极调光' }, + ], + metrics: [ + { label: '好评率', value: '98.9%' }, + { label: '续航实测', value: '72h' }, + { label: '累计销量', value: '23万+' }, + ], + }, + { + name: '绵云棉袜礼盒', tag: '服饰', desc: '新疆长绒棉,一盒装下整个冬天', image: img('ng-ecom-socks'), price: '¥89', + story: '一双袜子被退回 3 次的话,大多数平台会下架它,我们选择去阿克苏找更好的棉。绵云用的是 137 级新疆长绒棉,纱线在袜口处特意放松半针——为了不勒出「袜子印」。', + highlights: ['137 级新疆长绒棉,柔软亲肤', '袜口松半针工艺,不勒腿不滑落', '七双一盒对应一周,配色像天气', '可降解玉米纤维包装'], + timeline: [ + { at: '2024.10', event: '阿克苏棉田直采签约' }, + { at: '2024.12', event: '礼盒上线,成为年货爆款' }, + { at: '2025.09', event: '推出儿童尺码亲子款' }, + ], + metrics: [ + { label: '好评率', value: '99.4%' }, + { label: '复购率', value: '52%' }, + { label: '累计销量', value: '31万盒' }, + ], + }, ], testimonials: [ { text: '在严选买东西不用做功课,闭眼下单就行,省下的时间又能摸鱼了。', author: '阿糕', role: '五年老用户' }, @@ -60,10 +116,66 @@ export const corpProfiles = { { value: '30 城', label: '巡展足迹' }, ], cases: [ - { name: '未完成的蓝', tag: '绘画特展', desc: '17 位艺术家对「蓝」的 63 次追问', image: img('ng-art-blue'), year: '2026' }, - { name: '纸上山水', tag: '水墨新语', desc: '当代水墨的褶皱、留白与呼吸', image: img('ng-art-ink'), year: '2025' }, - { name: '机器梦境', tag: '新媒体', desc: '算法生成影像的沉浸式六幕剧场', image: img('ng-art-dream'), year: '2025' }, - { name: '童年再来一次', tag: '互动装置', desc: '可以踩、可以躺、可以尖叫的展厅', image: img('ng-art-child'), year: '2024' }, + { + name: '未完成的蓝', tag: '绘画特展', desc: '17 位艺术家对「蓝」的 63 次追问', image: img('ng-art-blue'), year: '2026', + story: '策展缘起于一封艺术家来信:「蓝色画到一半,我总是停下来。」我们邀请 17 位艺术家交出他们「没画完」的蓝色作品,把犹豫、涂改与留白原样示人——未完成,也是一种诚实。', + highlights: ['63 件作品全部为「未完成态」首次公开', '展厅按色温从钴蓝渐变到月白', '每件作品旁陈列艺术家的涂改手稿', '出口处设「你来画完」共创画墙'], + timeline: [ + { at: '2025.06', event: '向 40 位艺术家发出「未完成」邀请' }, + { at: '2026.01', event: '特展开幕,首周即预约满员' }, + { at: '2026.05', event: '共创画墙累计 1.2 万笔观众笔触' }, + ], + metrics: [ + { label: '参展艺术家', value: '17 位' }, + { label: '展出作品', value: '63 件' }, + { label: '观展人次', value: '9.8万' }, + ], + }, + { + name: '纸上山水', tag: '水墨新语', desc: '当代水墨的褶皱、留白与呼吸', image: img('ng-art-ink'), year: '2025', + story: '把宣纸揉皱再展开,墨会沿着折痕走出山脊——这是参展艺术家白也的成名技法。本展把 28 件当代水墨挂进一条可以「走进去」的纸廊,观众踩过的地板也是一张会晕墨的纸。', + highlights: ['28 件当代水墨 + 1 条沉浸式纸廊', '地面感应互动:脚步落处墨晕荡开', '每周六艺术家现场示范「皱纸成山」', '限量 200 份宣纸拓印伴手礼'], + timeline: [ + { at: '2025.03', event: '纸廊结构打样,试纸 700 米' }, + { at: '2025.04', event: '开展,登同城展览热榜第一' }, + { at: '2025.07', event: '巡展至苏州、成都两站' }, + ], + metrics: [ + { label: '展出作品', value: '28 件' }, + { label: '巡展城市', value: '3 城' }, + { label: '观展人次', value: '7.4万' }, + ], + }, + { + name: '机器梦境', tag: '新媒体', desc: '算法生成影像的沉浸式六幕剧场', image: img('ng-art-dream'), year: '2025', + story: '我们把一个生成模型训练了 90 天,喂给它的全部素材是美术馆闭馆后的监控画面。它「梦」出的六幕影像,有空无一人的展厅里自己亮起的灯,也有画框里流动的云。剧场每 40 分钟轮回一次,没有两场完全相同。', + highlights: ['六幕生成影像,每场实时演算不重复', '270° 环幕 + 32 声道空间音频', '梦境素材全部来自本馆闭馆监控', '尾厅可输入一句话生成你的专属梦'], + timeline: [ + { at: '2024.12', event: '模型训练启动,素材 4000 小时' }, + { at: '2025.05', event: '首演,单日最高排队 3 小时' }, + { at: '2025.10', event: '获年度新媒体艺术展提名' }, + ], + metrics: [ + { label: '剧场幕数', value: '6 幕' }, + { label: '单场时长', value: '40 min' }, + { label: '观展人次', value: '11万' }, + ], + }, + { + name: '童年再来一次', tag: '互动装置', desc: '可以踩、可以躺、可以尖叫的展厅', image: img('ng-art-child'), year: '2024', + story: '这是一场「禁止安静」的展览。弹珠轨道有两层楼高,纸飞机可以真的投进云里,尖叫声会被收集起来变成展厅顶部的烟花投影。开展第三天,我们把「请勿触摸」的牌子全部撤掉了。', + highlights: ['9 组可触碰、可攀爬的大型装置', '尖叫声实时转化为穹顶烟花投影', '成人观众需由儿童「带领」入场的反向规则', '闭展前夜举办成人专场「加时赛」'], + timeline: [ + { at: '2024.05', event: '装置安全测试,承重验收通过' }, + { at: '2024.06', event: '儿童节开展,亲子票秒罄' }, + { at: '2024.09', event: '闭展成人专场一票难求' }, + ], + metrics: [ + { label: '互动装置', value: '9 组' }, + { label: '亲子家庭', value: '3.2万组' }, + { label: '收集尖叫', value: '48万次' }, + ], + }, ], testimonials: [ { text: '每次来拾光都像被人轻轻拍了拍肩膀:嘿,生活还有别的可能。', author: '林小满', role: '年卡观众' }, @@ -96,10 +208,66 @@ export const corpProfiles = { { value: '66 年', label: '制药历史' }, ], cases: [ - { name: '安神定志丸', tag: '经典名方', desc: '古方安神,现代工艺微丸缓释', image: img('ng-pharma-anshen') }, - { name: '川贝润肺膏', tag: '呼吸系统', desc: '川贝母道地直采,低温熬制', image: img('ng-pharma-runfei') }, - { name: '小儿健脾颗粒', tag: '儿科用药', desc: '口感重新调配,孩子不抗拒', image: img('ng-pharma-jianpi') }, - { name: '三七通络片', tag: '心脑血管', desc: '文山三七,指纹图谱批批质控', image: img('ng-pharma-sanqi') }, + { + name: '安神定志丸', tag: '经典名方', desc: '古方安神,现代工艺微丸缓释', image: img('ng-pharma-anshen'), + story: '方出《医学心悟》,原为汤剂,煎煮费时且药效峰谷明显。研发团队用微丸缓释技术把一天三煎改成一日两服,药物在体内平稳释放 12 小时——古人的方子,今天的睡法。', + highlights: ['源自清代《医学心悟》经典原方', '微丸缓释,血药浓度平稳 12 小时', '远志、茯苓等主材全部道地直采', '不含褪黑素,不形成依赖'], + timeline: [ + { at: '2019.04', event: '立项,古方现代化改造启动' }, + { at: '2022.08', event: '获批上市,首批投产 200 万盒' }, + { at: '2024.03', event: '入选省级中药保护品种' }, + ], + metrics: [ + { label: '缓释时长', value: '12h' }, + { label: '批间一致性', value: '99.6%' }, + { label: '年销量', value: '900万盒' }, + ], + }, + { + name: '川贝润肺膏', tag: '呼吸系统', desc: '川贝母道地直采,低温熬制', image: img('ng-pharma-runfei'), + story: '川贝母只认松潘高原的,采挖季药材科的同事在海拔 3400 米住了一个月。熬膏改用 60℃ 低温真空浓缩,苦杏仁苷这些怕热的成分留住了,膏体却比老工艺更透亮。', + highlights: ['松潘道地川贝母,基地直采', '60℃ 低温真空浓缩,活性成分保留率高', '不加蔗糖,以梨汁与蜂蜜调味', '附赠定量勺,儿童剂量一目了然'], + timeline: [ + { at: '2020.10', event: '松潘川贝基地共建签约' }, + { at: '2021.11', event: '低温熬制产线投产' }, + { at: '2023.12', event: '连续两年冬季呼吸类目销量第一' }, + ], + metrics: [ + { label: '川贝含量', value: '≥8%' }, + { label: '活性保留率', value: '96%' }, + { label: '年销量', value: '600万瓶' }, + ], + }, + { + name: '小儿健脾颗粒', tag: '儿科用药', desc: '口感重新调配,孩子不抗拒', image: img('ng-pharma-jianpi'), + story: '儿科药最大的敌人是「吐出来」。我们请 120 个孩子做了三轮盲测口味,把苦味阈值压到儿童感知线以下,又把颗粒做成温水 10 秒速溶——喂药这件事,第一次不用捏鼻子了。', + highlights: ['120 名儿童三轮口味盲测定型', '苦味掩蔽技术,入口微甜带山楂香', '温水 10 秒速溶,不挂杯不结块', '独立条包,剂量按年龄阶梯划分'], + timeline: [ + { at: '2021.03', event: '儿童口感盲测项目启动' }, + { at: '2022.06', event: '上市,进入 3000 家连锁药房' }, + { at: '2025.01', event: '获儿科医师推荐品牌奖' }, + ], + metrics: [ + { label: '口感盲测', value: '120 人' }, + { label: '速溶时间', value: '10s' }, + { label: '药房覆盖', value: '3000+' }, + ], + }, + { + name: '三七通络片', tag: '心脑血管', desc: '文山三七,指纹图谱批批质控', image: img('ng-pharma-sanqi'), + story: '三七的皂苷含量随产地、年份波动极大,我们给每一批原料建立指纹图谱,像比对指纹一样比对成分曲线,相似度低于 98% 整批退回。慢病用药,稳定比什么都重要。', + highlights: ['文山春三七,三年七起收', '指纹图谱批批比对,相似度 ≥98%', '总皂苷含量恒定 ±2% 以内', '薄膜包衣,吞服无苦味'], + timeline: [ + { at: '2018.09', event: '文山三七 GAP 基地签约' }, + { at: '2020.05', event: '指纹图谱质控体系上线' }, + { at: '2024.11', event: '累计服用患者破 300 万' }, + ], + metrics: [ + { label: '图谱相似度', value: '≥98%' }, + { label: '皂苷波动', value: '±2%' }, + { label: '服用患者', value: '300万+' }, + ], + }, ], testimonials: [ { text: '他们的溯源码是真的能扫出药田坐标,采购验收特别踏实。', author: '刘主任', role: '连锁药房采购' }, @@ -132,10 +300,66 @@ export const corpProfiles = { { value: '24h', label: '急诊值守' }, ], cases: [ - { name: '心血管中心', tag: '重点专科', desc: '胸痛中心认证,绿色通道 30 分钟响应', image: img('ng-med-heart') }, - { name: '骨科与运动医学', tag: '特色专科', desc: '关节镜微创,运动员同款康复方案', image: img('ng-med-bone') }, - { name: '妇儿健康中心', tag: '温馨专区', desc: '从产检到儿保的一条走廊', image: img('ng-med-mom') }, - { name: '口腔医学中心', tag: '舒适化诊疗', desc: '无痛种植与儿童早期矫治', image: img('ng-med-dental') }, + { + name: '心血管中心', tag: '重点专科', desc: '胸痛中心认证,绿色通道 30 分钟响应', image: img('ng-med-heart'), + story: '心梗抢救拼的是「门球时间」——从进门到血管开通的每一分钟。中心把心电图前移到救护车上,导管室 24 小时热备,去年平均门球时间压到 52 分钟,比国家标准快了近一半。', + highlights: ['国家级胸痛中心认证单位', '救护车心电图实时回传,入院即手术', '导管室 24 小时热备,节假日无休', '术后随访管家制,一人一档跟满一年'], + timeline: [ + { at: '2019.06', event: '通过国家胸痛中心认证' }, + { at: '2022.03', event: '门球时间进入全省前十' }, + { at: '2025.08', event: '年介入手术量突破 2000 台' }, + ], + metrics: [ + { label: '门球时间', value: '52 min' }, + { label: '年介入手术', value: '2000+' }, + { label: '抢救成功率', value: '98.4%' }, + ], + }, + { + name: '骨科与运动医学', tag: '特色专科', desc: '关节镜微创,运动员同款康复方案', image: img('ng-med-bone'), + story: '科室的康复厅更像健身房:等速肌力仪、反重力跑台、水疗池一字排开。半月板术后第二天就能在跑台上「减重」行走,省队退役的康复师会陪你把每一个动作做标准。', + highlights: ['关节镜微创,切口不足 1cm', '反重力跑台,术后 48 小时下地', '省队同源康复团队一对一带练', '运动损伤门诊周末照常开诊'], + timeline: [ + { at: '2020.09', event: '运动医学中心独立成科' }, + { at: '2023.05', event: '成为省马拉松协会官方医疗伙伴' }, + { at: '2025.02', event: '关节镜年手术量破 1500 台' }, + ], + metrics: [ + { label: '微创切口', value: '<1cm' }, + { label: '年关节镜', value: '1500 台' }, + { label: '重返运动率', value: '93%' }, + ], + }, + { + name: '妇儿健康中心', tag: '温馨专区', desc: '从产检到儿保的一条走廊', image: img('ng-med-mom'), + story: '中心的动线是照着一个家庭的十个月设计的:产检、分娩、月子、儿保在同一条走廊完成,孕期建档后由同一组医护跟到孩子一岁。走廊尽头的墙上,贴满了在这里出生的宝宝照片。', + highlights: ['产检到儿保一条走廊,不用换院区', '一组医护从建档跟到宝宝周岁', '家庭化产房,爸爸可全程陪产', '儿保打疫苗有「勇敢者奖章」'], + timeline: [ + { at: '2018.03', event: '妇儿中心启用,首月建档 300 组' }, + { at: '2021.10', event: '家庭化产房扩至 12 间' }, + { at: '2024.12', event: '累计迎接新生儿 1 万名' }, + ], + metrics: [ + { label: '新生儿', value: '10000+' }, + { label: '陪产率', value: '87%' }, + { label: '建档家庭', value: '2.6万组' }, + ], + }, + { + name: '口腔医学中心', tag: '舒适化诊疗', desc: '无痛种植与儿童早期矫治', image: img('ng-med-dental'), + story: '很多人怕看牙,怕的是那台钻头的声音。中心把候诊区做成了咖啡馆的样子,诊室里可以戴耳机看电影,儿童诊室的天花板是星空投影——治疗结束,不少孩子问下次什么时候再来。', + highlights: ['笑气镇静 + 计算机控麻,全程无痛', '数字化种植导板,误差小于 0.1mm', '儿童星空诊室,看牙像看电影', '免费口腔档案,每半年提醒复查'], + timeline: [ + { at: '2019.11', event: '舒适化诊疗体系上线' }, + { at: '2022.07', event: '数字化种植中心投用' }, + { at: '2025.04', event: '儿童早矫案例突破 5000 例' }, + ], + metrics: [ + { label: '种植误差', value: '<0.1mm' }, + { label: '儿童早矫', value: '5000 例' }, + { label: '复诊守约率', value: '91%' }, + ], + }, ], testimonials: [ { text: '夜里孩子发烧,线上问诊十分钟出方案,药一早就送到了。', author: '糕爸', role: '互联网医院用户' }, @@ -168,10 +392,66 @@ export const corpProfiles = { { value: '12亿', label: '设备搭载量' }, ], cases: [ - { name: '跃迁 X1 芯片', tag: '旗舰芯片', desc: '7nm 制程,128 TOPS 端侧算力', image: img('ng-tech-chip') }, - { name: '星尘卫星载荷', tag: '航天计算', desc: '在轨 AI 推理,图像即拍即析', image: img('ng-tech-sat') }, - { name: '磐石边缘服务器', tag: '工业边缘', desc: '产线质检延迟压到 8ms', image: img('ng-tech-edge') }, - { name: '跃迁开发者云', tag: '工具链', desc: '3 行命令完成模型端侧化', image: img('ng-tech-cloud') }, + { + name: '跃迁 X1 芯片', tag: '旗舰芯片', desc: '7nm 制程,128 TOPS 端侧算力', image: img('ng-tech-chip'), + story: '立项时只有一句话:把数据中心那颗「电老虎」塞进巴掌大的设备里。架构组重写了访存调度,把大模型推理最耗电的数据搬运砍掉了六成——X1 流片回来那晚,实验室的灯亮到天亮。', + highlights: ['自研「跃迁」架构 NPU,7nm 制程', '128 TOPS 端侧算力,功耗仅 8W', '访存优化,数据搬运能耗降低 60%', '原生支持 INT4/FP8 混合精度'], + timeline: [ + { at: '2023.02', event: '架构冻结,启动流片' }, + { at: '2023.11', event: '一次流片成功,点亮即跑通' }, + { at: '2024.06', event: '量产出货,搭载设备破百万' }, + ], + metrics: [ + { label: '端侧算力', value: '128 TOPS' }, + { label: '典型功耗', value: '8W' }, + { label: '能效比提升', value: '4.2×' }, + ], + }, + { + name: '星尘卫星载荷', tag: '航天计算', desc: '在轨 AI 推理,图像即拍即析', image: img('ng-tech-sat'), + story: '遥感卫星拍一张图传回地面要 40 分钟,林火早烧过了山脊。星尘把推理放到天上:图像在轨分析,只把「哪里着火了」这几 KB 传回来。抗辐照设计经历了三轮单粒子翻转测试,老工程师说这是他做过最「顶」的板子。', + highlights: ['在轨 AI 推理,告警延迟从 40min 到 90s', '抗辐照加固,单粒子翻转自恢复', '-55℃~125℃ 军规级温度范围', '已随 6 颗遥感卫星在轨服役'], + timeline: [ + { at: '2022.08', event: '通过航天级环境试验' }, + { at: '2023.04', event: '首发载荷随卫星入轨' }, + { at: '2025.07', event: '在轨累计识别林火告警 1200 次' }, + ], + metrics: [ + { label: '告警时延', value: '90s' }, + { label: '在轨卫星', value: '6 颗' }, + { label: '在轨时长', value: '2 年+' }, + ], + }, + { + name: '磐石边缘服务器', tag: '工业边缘', desc: '产线质检延迟压到 8ms', image: img('ng-tech-edge'), + story: '客户的产线一分钟过 300 个零件,质检模型慢一毫秒,零件就堆一排。磐石把推理延迟压到 8ms,机身无风扇全铝散热,车间的油雾和铁屑都进不去——装上之后,三年没人碰过它,这是最好的评价。', + highlights: ['单帧推理延迟 8ms,产线不停等', '无风扇全铝机身,IP65 防尘防油雾', '-40℃~85℃ 宽温,车间直装', '双电源热备,断电秒切不丢帧'], + timeline: [ + { at: '2023.06', event: '首批部署 3C 装配产线' }, + { at: '2024.03', event: '通过工业环境 EMC 认证' }, + { at: '2025.05', event: '部署产线突破 800 条' }, + ], + metrics: [ + { label: '推理延迟', value: '8ms' }, + { label: '部署产线', value: '800+' }, + { label: '无故障运行', value: '99.99%' }, + ], + }, + { + name: '跃迁开发者云', tag: '工具链', desc: '3 行命令完成模型端侧化', image: img('ng-tech-cloud'), + story: '硬件卖得再好,开发者用不起来就是零。工具链团队立了个军令状:模型从云端到板子,不许超过 3 行命令。现在 `qleap compile`、`qleap quantize`、`qleap deploy` 三连,十分钟出活,文档站的口碑比芯片还好。', + highlights: ['3 行命令完成编译、量化、部署', '自动混合精度,精度损失 <0.5%', '云端真机池,没板子也能调试', '中文文档 + 示例仓库 200 个'], + timeline: [ + { at: '2023.09', event: '工具链 1.0 随 X1 同步发布' }, + { at: '2024.08', event: '注册开发者破 5 万' }, + { at: '2025.06', event: '开源核心编译器,首周 3k Star' }, + ], + metrics: [ + { label: '注册开发者', value: '5万+' }, + { label: '部署耗时', value: '10 min' }, + { label: '精度损失', value: '<0.5%' }, + ], + }, ], testimonials: [ { text: '同样的模型,跑在 X1 上功耗直接砍半,我们的无人机续航多了 11 分钟。', author: '张工', role: '无人机厂商 CTO' }, @@ -204,10 +484,66 @@ export const corpProfiles = { { value: '320 种', label: '动植物记录' }, ], cases: [ - { name: '云顶日出', tag: '观景台', desc: '海拔 1800 米,云海翻涌如潮', image: img('ng-travel-sunrise') }, - { name: '雾漫竹海', tag: '徒步线', desc: '晨雾里的十里竹廊与鸟鸣', image: img('ng-travel-bamboo') }, - { name: '星空营地', tag: '过夜体验', desc: '零光污染,银河肉眼可见', image: img('ng-travel-star') }, - { name: '古枫温泉', tag: '温泉区', desc: '千年枫树下的露天暖汤', image: img('ng-travel-spring') }, + { + name: '云顶日出', tag: '观景台', desc: '海拔 1800 米,云海翻涌如潮', image: img('ng-travel-sunrise'), + story: '凌晨四点半,首班索道亮灯,车厢里都是揉眼睛的人。二十分钟后海拔 1800 米,云海在脚下翻涌,太阳跳出来的那一瞬,观景台上总会响起一片压低声音的「哇」。工作人员说,这声「哇」他们听了二十年,还是会跟着看。', + highlights: ['海拔 1800 米观景台,云海出现率 62%', '日出季加开凌晨首班索道', '台上供应免费姜茶与租借冲锋衣', '气象站每晚 8 点发布次日云海预报'], + timeline: [ + { at: '04:30', event: '首班索道发车,备好姜茶' }, + { at: '05:20', event: '抵达云顶,占好机位' }, + { at: '05:47', event: '日出跃出云海,快门声一片' }, + ], + metrics: [ + { label: '云海出现率', value: '62%' }, + { label: '索道耗时', value: '20 min' }, + { label: '年观日人次', value: '38万' }, + ], + }, + { + name: '雾漫竹海', tag: '徒步线', desc: '晨雾里的十里竹廊与鸟鸣', image: img('ng-travel-bamboo'), + story: '这条 12 公里的木栈道是照着「老人也能走完」修的:坡度不超过 8 度,每一公里一座歇脚亭。晨雾未散时进山最好,竹叶滴水,鸟鸣在雾里显得特别近,走到第七座亭子,卖竹筒饭的大姐会准时掀开蒸笼。', + highlights: ['12km 全木栈道,最大坡度 8°', '沿途 12 座歇脚亭,亭亭有故事', '第七亭竹筒饭,只在上午出笼', '晨雾观赏最佳时段 6:00-9:00'], + timeline: [ + { at: '06:00', event: '东门进山,雾气正浓' }, + { at: '08:30', event: '第七亭竹筒饭出笼' }, + { at: '11:00', event: '走完全程,领徒步纪念章' }, + ], + metrics: [ + { label: '栈道全长', value: '12km' }, + { label: '最大坡度', value: '8°' }, + { label: '徒步完成率', value: '96%' }, + ], + }, + { + name: '星空营地', tag: '过夜体验', desc: '零光污染,银河肉眼可见', image: img('ng-travel-star'), + story: '营地在山谷背风处,方圆十公里没有一盏路灯,是华东少有的「暗夜保护区」。晚上九点熄掉全部营地灯,只留地面的红光引导带,躺在帐篷前的观星椅上,银河就横在头顶——很多客人说,那是他们第一次真的看见银河。', + highlights: ['暗夜保护区,肉眼可见银河', '每晚九点「熄灯仪式」+ 星空讲解', '帐篷配电热毯与观星椅', '天文志愿者驻场,望远镜免费用'], + timeline: [ + { at: '17:00', event: '入营,领装备扎帐篷' }, + { at: '21:00', event: '熄灯仪式,银河升起' }, + { at: '05:30', event: '帐篷里看第一缕晨光' }, + ], + metrics: [ + { label: '光污染等级', value: 'Bortle 2' }, + { label: '帐篷位', value: '86 顶' }, + { label: '旺季预订率', value: '100%' }, + ], + }, + { + name: '古枫温泉', tag: '温泉区', desc: '千年枫树下的露天暖汤', image: img('ng-travel-spring'), + story: '泉眼在千年古枫的根系旁,水温常年 41℃,富含偏硅酸。秋天最妙:红叶落在汤面上,雾气往枫树梢上飘。九个汤池按水温排成一条溪线,泡到第五池,山里的手机信号刚好消失——这是设计师故意的。', + highlights: ['千年古枫下的 9 池露天汤', '偏硅酸型温泉,水温恒定 41℃', '秋季「枫汤」限定,落叶入池', '汤区无信号设计,强制放空'], + timeline: [ + { at: '2001.05', event: '泉眼勘定,首池开汤' }, + { at: '2019.10', event: '九池溪线改造完成' }, + { at: '2025.11', event: '「枫汤」入选省级温泉名录' }, + ], + metrics: [ + { label: '水温', value: '41℃' }, + { label: '露天汤池', value: '9 池' }, + { label: '年泡汤人次', value: '26万' }, + ], + }, ], testimonials: [ { text: '在星空营地看到银河的那一刻,孩子安静了整整十分钟。', author: '一家四口', role: '亲子游客' }, @@ -240,10 +576,66 @@ export const corpProfiles = { { value: '300万', label: '服务家庭' }, ], cases: [ - { name: '全屋大扫除', tag: '爆款套餐', desc: '4 小时两人组,年前焕新首选', image: img('ng-home-clean'), price: '¥299 起' }, - { name: '开荒保洁', tag: '新居必备', desc: '装修交付后的第一次深呼吸', image: img('ng-home-new'), price: '¥6/㎡' }, - { name: '衣橱整理', tag: '整理收纳', desc: '注册整理师陪你告别乱衣山', image: img('ng-home-closet'), price: '¥499 起' }, - { name: '金牌月嫂', tag: '母婴护理', desc: '10 年经验,26 天贴身照护', image: img('ng-home-baby'), price: '¥12800 起' }, + { + name: '全屋大扫除', tag: '爆款套餐', desc: '4 小时两人组,年前焕新首选', image: img('ng-home-clean'), price: '¥299 起', + story: '这个套餐是被年前的订单「逼」出来的:一个人干八小时太累,两个人干四小时刚好。阿姨两人一组,一人主攻厨卫重油区,一人负责全屋除尘归位,收尾时会用检查清单逐项打勾——37 项,一项不落。', + highlights: ['两人组同时开工,4 小时焕新全屋', '厨卫重油区蒸汽机深度处理', '37 项验收清单,逐项打勾交付', '自带全套工具耗材,不用您家一块抹布'], + timeline: [ + { at: 'T-1 天', event: '客服确认户型与重点区域' }, + { at: '当日 09:00', event: '两人组上门,工具消毒开工' }, + { at: '当日 13:00', event: '37 项清单验收,拍照交付' }, + ], + metrics: [ + { label: '服务时长', value: '4h×2 人' }, + { label: '验收项', value: '37 项' }, + { label: '好评率', value: '99.1%' }, + ], + }, + { + name: '开荒保洁', tag: '新居必备', desc: '装修交付后的第一次深呼吸', image: img('ng-home-new'), price: '¥6/㎡', + story: '装修队撤场后的房子,粉尘会藏在每一条缝里。开荒组带着工业吸尘器和铲刀进场,先除大件建渣,再铲胶点漆点,最后全屋三遍擦拭。交付标准只有一句话:白手套抹过窗轨,不见灰。', + highlights: ['工业级吸尘设备,粉尘不扬尘', '铲胶除漆专项处理,不伤台面', '全屋三遍擦拭,窗轨白手套验收', '按平米计价,无隐形加项'], + timeline: [ + { at: '第 1 步', event: '建渣清运与全屋吸尘' }, + { at: '第 2 步', event: '胶点漆点专项铲除' }, + { at: '第 3 步', event: '三遍擦拭,白手套验收' }, + ], + metrics: [ + { label: '计价', value: '¥6/㎡' }, + { label: '验收标准', value: '白手套' }, + { label: '返工率', value: '<0.8%' }, + ], + }, + { + name: '衣橱整理', tag: '整理收纳', desc: '注册整理师陪你告别乱衣山', image: img('ng-home-closet'), price: '¥499 起', + story: '整理师小柯的口头禅是「衣服不用叠得漂亮,要拿得顺手」。服务从聊天开始:先弄清你的穿衣习惯,再把衣橱按使用频率重新分区,常穿的在黄金视线区,过季的真空上顶柜。三个月后回访,九成客户的衣橱还保持着原样。', + highlights: ['注册整理师持证上门', '按穿衣习惯分区,不是按好看分区', '赠送分区标签与真空收纳袋', '三个月免费回访一次'], + timeline: [ + { at: '第 1 小时', event: '沟通习惯,全部取出分类' }, + { at: '第 2-3 小时', event: '按频率分区上架' }, + { at: '3 个月后', event: '免费回访,微调布局' }, + ], + metrics: [ + { label: '维持率', value: '90%' }, + { label: '平均耗时', value: '3.5h' }, + { label: '好评率', value: '99.3%' }, + ], + }, + { + name: '金牌月嫂', tag: '母婴护理', desc: '10 年经验,26 天贴身照护', image: img('ng-home-baby'), price: '¥12800 起', + story: '平台 5 万服务者里,能挂「金牌」的月嫂只有 6%:10 年以上经验、高级母婴护理证、近两年好评率 98% 以上,三条缺一不可。上户前有一次两小时的见面沟通,聊喂养观念也聊生活习惯——合得来,比什么都重要。', + highlights: ['10 年+ 经验,高级母婴护理证', '上户前两小时见面沟通,不合适免费换', '每日护理日志,喂养睡眠一目了然', '平台督导每周电话回访'], + timeline: [ + { at: '预产期前 1 月', event: '面试沟通,签约锁档' }, + { at: '出院当日', event: '月嫂上户,交接护理计划' }, + { at: '第 26 天', event: '离户交接,留下喂养手册' }, + ], + metrics: [ + { label: '金牌占比', value: '6%' }, + { label: '服务天数', value: '26 天' }, + { label: '续单率', value: '71%' }, + ], + }, ], testimonials: [ { text: '阿姨来之前发了健康证和实名认证,干完活厨房亮得能照镜子。', author: '年糕妈', role: '包月用户' }, @@ -276,10 +668,66 @@ export const corpProfiles = { { value: '99.99%', label: '服务可用性' }, ], cases: [ - { name: '深思·问答', tag: '通用助手', desc: '企业知识库秒答,引用可溯源', image: img('ng-ai-chat') }, - { name: '深思·代码', tag: '研发提效', desc: '补全、评审、重构一条龙', image: img('ng-ai-code') }, - { name: '深思·医疗', tag: '行业模型', desc: '病历结构化与辅助诊断建议', image: img('ng-ai-med') }, - { name: '深思·质检', tag: '工业视觉', desc: '产线缺陷检出率 99.7%', image: img('ng-ai-qc') }, + { + name: '深思·问答', tag: '通用助手', desc: '企业知识库秒答,引用可溯源', image: img('ng-ai-chat'), + story: '企业知识库最尴尬的场景:答案说得头头是道,一问出处就哑火。深思·问答坚持「每句话都有脚注」,回答里的每个结论都挂着原文引用,点开直达文档段落。上线客户里流传一句话:它比老员工更清楚制度在哪一页。', + highlights: ['回答逐句挂引用,点击直达原文', '128K 上下文,一次读完整本员工手册', '支持 40+ 文档格式自动解析入库', '幻觉率低于 1.2%,行业最低档'], + timeline: [ + { at: '2023.06', event: '内测,首批 50 家企业接入' }, + { at: '2024.01', event: '引用溯源 2.0,支持段落级定位' }, + { at: '2025.03', event: '服务企业破 2000 家' }, + ], + metrics: [ + { label: '幻觉率', value: '<1.2%' }, + { label: '首响时间', value: '0.8s' }, + { label: '企业客户', value: '2000+' }, + ], + }, + { + name: '深思·代码', tag: '研发提效', desc: '补全、评审、重构一条龙', image: img('ng-ai-code'), + story: '训练语料里有 2.8 亿次真实代码评审记录,所以它挑毛病的口吻像个温和的资深工程师:先说哪里写得好,再指出空指针风险。有客户统计过,接入后代码评审周期从 2.3 天缩到 6 小时,吵架次数也少了。', + highlights: ['补全、评审、重构、单测四合一', '评审意见带修复建议,一键应用', '私有代码不出域,支持离线部署', '兼容主流 IDE 与 CI 流水线'], + timeline: [ + { at: '2023.10', event: '发布,首月装机 3 万' }, + { at: '2024.07', event: '单测生成覆盖率提升至 85%' }, + { at: '2025.05', event: '进驻 12 家银行研发体系' }, + ], + metrics: [ + { label: '评审提速', value: '9×' }, + { label: '采纳率', value: '64%' }, + { label: '装机量', value: '40万+' }, + ], + }, + { + name: '深思·医疗', tag: '行业模型', desc: '病历结构化与辅助诊断建议', image: img('ng-ai-med'), + story: '医生写病历平均要花门诊时间的三分之一。深思·医疗听得懂诊室对话,实时生成结构化病历,医生只需核对签名;辅助诊断模块给出的每条建议都标注了指南出处与置信度——它做建议者,不做决定者。', + highlights: ['诊室语音实时转结构化病历', '辅助建议逐条标注指南出处', '通过医疗器械软件二类备案', '院内私有化部署,数据零出院'], + timeline: [ + { at: '2024.03', event: '三甲医院试点,科室 12 个' }, + { at: '2024.12', event: '取得二类医疗器械备案' }, + { at: '2025.09', event: '落地医院突破 80 家' }, + ], + metrics: [ + { label: '病历耗时', value: '-70%' }, + { label: '结构化准确率', value: '98.1%' }, + { label: '落地医院', value: '80+' }, + ], + }, + { + name: '深思·质检', tag: '工业视觉', desc: '产线缺陷检出率 99.7%', image: img('ng-ai-qc'), + story: '客户产线上的缺陷样本太少,传统视觉方案「见得少就认不出」。深思·质检用大模型底座做小样本泛化,50 张缺陷图就能冷启动,两周内检出率爬到 99.7%。质检老师傅从「盯屏幕」转岗「教模型」,眼睛终于不酸了。', + highlights: ['50 张样本冷启动,两周达产', '缺陷检出率 99.7%,漏检自动回流学习', '兼容磐石边缘服务器,延迟 8ms', '检出结果自动生成质检报表'], + timeline: [ + { at: '2024.05', event: '3C 产线首个标杆案例落地' }, + { at: '2025.01', event: '小样本冷启动方案发布' }, + { at: '2025.10', event: '部署产线 300 条' }, + ], + metrics: [ + { label: '检出率', value: '99.7%' }, + { label: '冷启动样本', value: '50 张' }, + { label: '部署产线', value: '300+' }, + ], + }, ], testimonials: [ { text: '知识库问答上线一个月,客服工单量降了 43%。', author: '运营 VP', role: '连锁零售集团' }, @@ -312,10 +760,66 @@ export const corpProfiles = { { value: '46 项', label: '生态集成' }, ], cases: [ - { name: '敏捷研发看板', tag: '研发团队', desc: '需求到发布全流程在线追踪', image: img('ng-saas-kanban') }, - { name: '多人协同文档', tag: '全员协作', desc: '一篇文档承载会议到复盘', image: img('ng-saas-doc') }, - { name: '自动化审批', tag: '行政人事', desc: '报销单据 OCR 自动填写', image: img('ng-saas-flow') }, - { name: '经营数据看板', tag: '管理层', desc: '每天早上一张全局驾驶舱', image: img('ng-saas-bi') }, + { + name: '敏捷研发看板', tag: '研发团队', desc: '需求到发布全流程在线追踪', image: img('ng-saas-kanban'), + story: '看板的设计原则是「谁都不用改习惯」:产品拖卡片,研发关联代码分支,测试勾验收项,发布时 changelog 自动生成。上线这个功能前,我们旁听了 47 场站会,把大家口头同步的信息全部搬进了卡片。', + highlights: ['需求-开发-测试-发布全链路一张板', '卡片关联代码分支,合并自动流转', '迭代燃尽图与延期风险自动预警', 'changelog 一键生成,发版不熬夜'], + timeline: [ + { at: '2022.04', event: '看板 1.0 上线' }, + { at: '2023.09', event: '新增燃尽预警与依赖图' }, + { at: '2025.02', event: '服务研发团队突破 4 万个' }, + ], + metrics: [ + { label: '研发团队', value: '4万+' }, + { label: '延期率下降', value: '38%' }, + { label: '日活跃卡片', value: '600万' }, + ], + }, + { + name: '多人协同文档', tag: '全员协作', desc: '一篇文档承载会议到复盘', image: img('ng-saas-doc'), + story: '我们观察到一个会议的完整生命周期:会前拟议程、会中记结论、会后追待办。协同文档把这三件事装进同一篇文档:议程模板一键插入,结论划词即可@人,待办自动同步到项目看板——散会时,纪要已经发出去了。', + highlights: ['百人同时编辑,光标互不打架', '划词评论 @人,消息直达', '待办块自动同步项目看板', '历史版本无限回溯,谁改的一目了然'], + timeline: [ + { at: '2021.08', event: '文档内测,首批 800 团队' }, + { at: '2023.03', event: '待办与看板双向同步上线' }, + { at: '2025.06', event: '累计创建文档破 2 亿篇' }, + ], + metrics: [ + { label: '并发编辑', value: '100 人' }, + { label: '累计文档', value: '2亿篇' }, + { label: '同步延迟', value: '<200ms' }, + ], + }, + { + name: '自动化审批', tag: '行政人事', desc: '报销单据 OCR 自动填写', image: img('ng-saas-flow'), + story: '财务同事统计过,一张报销单平均要被退回 1.7 次,原因五花八门:发票抬头错、金额对不上、附件漏传。现在拍照上传,OCR 自动识别发票并校验抬头税号,不合规当场提示——退回率降到 0.2 次,财务和员工终于相看两不厌。', + highlights: ['发票 OCR 识别准确率 99.5%', '抬头税号自动校验,不合规当场拦截', '审批流拖拽搭建,老板手机一键批', '进度实时可查,不用问「到哪了」'], + timeline: [ + { at: '2022.11', event: 'OCR 报销上线' }, + { at: '2024.04', event: '新增差旅标准自动核验' }, + { at: '2025.08', event: '月均处理单据 900 万张' }, + ], + metrics: [ + { label: 'OCR 准确率', value: '99.5%' }, + { label: '退回率', value: '-88%' }, + { label: '月均单据', value: '900万' }, + ], + }, + { + name: '经营数据看板', tag: '管理层', desc: '每天早上一张全局驾驶舱', image: img('ng-saas-bi'), + story: '老板们的痛点出奇一致:数据散在八个系统里,开会前要人肉汇总成 PPT。经营看板把项目、销售、财务数据自动汇成一张驾驶舱,每天早上八点推送到手机。有位客户 CEO 说,他现在开晨会只带一部手机。', + highlights: ['多系统数据自动汇聚,零人工报表', '每日 8 点驾驶舱推送到手机', '指标异动自动标红并追溯原因', '看板权限按角色精细控制'], + timeline: [ + { at: '2023.05', event: '驾驶舱模板发布' }, + { at: '2024.10', event: '异动归因分析上线' }, + { at: '2025.07', event: '企业管理层日活破 30 万' }, + ], + metrics: [ + { label: '接入数据源', value: '46 种' }, + { label: '报表耗时', value: '-95%' }, + { label: '管理层日活', value: '30万' }, + ], + }, ], testimonials: [ { text: '把 Jira、飞书文档、钉钉审批合成一个,新人培训成本几乎为零。', author: '效能负责人', role: '200 人研发团队' }, @@ -352,14 +856,126 @@ export const corpProfiles = { { value: '9 城', label: '线下展厅' }, ], products: [ - { id: 'cloud-sofa', name: '云栖沙发', en: 'CLOUD SOFA', cat: '客厅', price: 28800, material: '白蜡木 · 羊毛混纺', size: 'W2400 × D980 × H820', desc: '把一朵云安放在客厅正中央,坐感松弛而不失支撑。', seed: 'xumu-sofa' }, - { id: 'ridge-table', name: '山形茶几', en: 'RIDGE LOW TABLE', cat: '客厅', price: 9600, material: '黑胡桃木整板', size: 'W1200 × D600 × H360', desc: '一整块黑胡桃顺纹开料,桌沿保留山形原木边。', seed: 'xumu-ridge' }, - { id: 'moon-chair', name: '月洞圈椅', en: 'MOON CHAIR', cat: '书房', price: 12400, material: '黑胡桃木 · 手工藤编', size: 'W620 × D580 × H780', desc: '圈椅的月洞轮廓削到最薄,藤面透气,久坐生凉。', seed: 'xumu-moon' }, - { id: 'strata-table', name: '叠影餐桌', en: 'STRATA TABLE', cat: '餐厨', price: 19800, material: '鱼肚白大理石 · 黄铜', size: 'W1800 × D900 × H750', desc: '石纹如水波叠影,黄铜桌脚在灯下泛暖光。', seed: 'xumu-strata' }, - { id: 'veil-shelf', name: '屏风书架', en: 'VEIL SHELF', cat: '书房', price: 15200, material: '白橡木 · 长虹玻璃', size: 'W900 × D350 × H1900', desc: '一半是书架,一半是屏风,光透过长虹玻璃变得朦胧。', seed: 'xumu-veil' }, - { id: 'halo-lamp', name: '拾光落地灯', en: 'HALO LAMP', cat: '客厅', price: 4900, material: '拉丝黄铜 · 亚麻灯罩', size: 'Φ450 × H1620', desc: '灯罩手工裱亚麻,开灯时像屋里升起一轮小月亮。', seed: 'xumu-halo' }, - { id: 'nimbus-bed', name: '眠云大床', en: 'NIMBUS BED', cat: '卧室', price: 32000, material: '白蜡木 · 头层牛皮', size: 'W1800 × D2100 × H1050', desc: '床头以牛皮软包裹木,倚靠时是恰到好处的温柔。', seed: 'xumu-nimbus' }, - { id: 'pebble-side', name: '石纹边几', en: 'PEBBLE SIDE', cat: '客厅', price: 6800, material: '罗马洞石', size: 'Φ500 × H520', desc: '像从河滩捡回的一枚卵石,孔隙里藏着时间。', seed: 'xumu-pebble' }, + { + id: 'cloud-sofa', name: '云栖沙发', en: 'CLOUD SOFA', cat: '客厅', price: 28800, material: '白蜡木 · 羊毛混纺', size: 'W2400 × D980 × H820', desc: '把一朵云安放在客厅正中央,坐感松弛而不失支撑。', seed: 'xumu-sofa', + story: '设计师阿禾的手稿第一页写着:「不要让人坐得端正。」云栖的坐深特意放宽到 68cm,靠背倾角试了 14 版,最终停在让人「陷进去但起得来」的 108 度。羊毛混纺面料织了三次才对得上她要的云灰色。', + highlights: ['坐深 68cm,倾角 108°,窝陷感与支撑兼得', '白蜡木框架榫卯连接,不用一颗螺钉', '羊毛混纺三织定色,全拆洗设计', '坐垫高回弹分层填充,十年不塌'], + timeline: [ + { at: '2023.03', event: '第 14 版倾角打样定型' }, + { at: '2023.09', event: '设计上海首发,当场订出 40 套' }, + { at: '2025.01', event: '成为品牌年度销量冠军' }, + ], + metrics: [ + { label: '打样版本', value: '14 版' }, + { label: '质保', value: '5 年' }, + { label: '年销量', value: '2600 套' }, + ], + }, + { + id: 'ridge-table', name: '山形茶几', en: 'RIDGE LOW TABLE', cat: '客厅', price: 9600, material: '黑胡桃木整板', size: 'W1200 × D600 × H360', desc: '一整块黑胡桃顺纹开料,桌沿保留山形原木边。', seed: 'xumu-ridge', + story: '每一张山形茶几的桌沿都不一样——那是这棵树自己长出来的轮廓。木工组长老宋挑板极苛刻,一批板材里顺纹、无节、山形好看的不到一成,所以它每月限量 60 张,编号刻在桌底。', + highlights: ['整板黑胡桃顺纹开料,不拼板', '桌沿保留天然原木边,每张独一无二', '桌底手工刻限量编号', '木蜡油涂装,可局部打磨翻新'], + timeline: [ + { at: '2022.06', event: '首批 30 张上市即售罄' }, + { at: '2023.04', event: '启用桌底编号制' }, + { at: '2025.03', event: '累计编号刻到 No.1800' }, + ], + metrics: [ + { label: '选板率', value: '<10%' }, + { label: '月限量', value: '60 张' }, + { label: '累计编号', value: '1800+' }, + ], + }, + { + id: 'moon-chair', name: '月洞圈椅', en: 'MOON CHAIR', cat: '书房', price: 12400, material: '黑胡桃木 · 手工藤编', size: 'W620 × D580 × H780', desc: '圈椅的月洞轮廓削到最薄,藤面透气,久坐生凉。', seed: 'xumu-moon', + story: '圈椅是明式家具的骨,月洞是园林的眼,把两者合在一起时,最难的是「削薄」:椅圈最细处只有 22mm,要过三年四季的湿度考验。藤面请的是 68 岁的老篾匠,一张椅面要编整整两天。', + highlights: ['椅圈最细处 22mm,过四季湿度测试', '老篾匠手工藤编,一椅两天', '榫卯 32 处,整椅无金属件', '坐面藤编可单独更换,椅架传代'], + timeline: [ + { at: '2021.10', event: '椅圈削薄工艺定型' }, + { at: '2022.05', event: '获当代家具设计金奖' }, + { at: '2024.08', event: '进驻 9 城全部展厅' }, + ], + metrics: [ + { label: '榫卯节点', value: '32 处' }, + { label: '编藤耗时', value: '2 天/张' }, + { label: '设计奖项', value: '金奖' }, + ], + }, + { + id: 'strata-table', name: '叠影餐桌', en: 'STRATA TABLE', cat: '餐厨', price: 19800, material: '鱼肚白大理石 · 黄铜', size: 'W1800 × D900 × H750', desc: '石纹如水波叠影,黄铜桌脚在灯下泛暖光。', seed: 'xumu-strata', + story: '这张桌子的石材是采购团队在矿区挑了三天的「鱼肚白」,水波纹要连贯地流过整张桌面,对花误差不超过 5mm。黄铜桌脚不做镀层,用的是会慢慢氧化的本色——设计师说,让它跟着你家的饭菜香一起变旧。', + highlights: ['鱼肚白大理石整面对花,误差 <5mm', '本色黄铜桌脚,岁月自然包浆', '石面纳米封釉,酱油红酒不渗色', '桌脚可调平,老房子地面也稳'], + timeline: [ + { at: '2023.02', event: '矿区选石,定下首批 8 块板' }, + { at: '2023.11', event: '上市,首月售出 120 张' }, + { at: '2025.06', event: '推出 W2200 十人加长版' }, + ], + metrics: [ + { label: '对花误差', value: '<5mm' }, + { label: '防渗测试', value: '48h' }, + { label: '年销量', value: '900 张' }, + ], + }, + { + id: 'veil-shelf', name: '屏风书架', en: 'VEIL SHELF', cat: '书房', price: 15200, material: '白橡木 · 长虹玻璃', size: 'W900 × D350 × H1900', desc: '一半是书架,一半是屏风,光透过长虹玻璃变得朦胧。', seed: 'xumu-veil', + story: '小户型客户常问:书房和客厅怎么分?屏风书架给的答案是「别分死」。朝客厅的一面是长虹玻璃,书房的灯光透过来是一片朦胧的竖纹;朝书房的一面是开放格,伸手就够到常读的那排书。', + highlights: ['书架 + 屏风二合一,轻隔断不压抑', '长虹玻璃透光不透形', '层板承重 30kg,大部头随便放', '双面可用,免靠墙自立稳固'], + timeline: [ + { at: '2022.09', event: '小户型调研 200 户后立项' }, + { at: '2023.06', event: '上市,成为小户型爆款' }, + { at: '2024.12', event: '新增 W1200 宽体版本' }, + ], + metrics: [ + { label: '层板承重', value: '30kg' }, + { label: '占地进深', value: '35cm' }, + { label: '年销量', value: '1500 组' }, + ], + }, + { + id: 'halo-lamp', name: '拾光落地灯', en: 'HALO LAMP', cat: '客厅', price: 4900, material: '拉丝黄铜 · 亚麻灯罩', size: 'Φ450 × H1620', desc: '灯罩手工裱亚麻,开灯时像屋里升起一轮小月亮。', seed: 'xumu-halo', + story: '灯罩师傅裱亚麻时不用胶水,用的是传统的米浆——胶水裱的布透光发死,米浆裱的布透光是活的,有呼吸感。灯的色温定在 2700K,是团队在样板间熬了七个夜晚选出来的「不赶客的暖」。', + highlights: ['亚麻灯罩米浆手工裱制,透光温润', '2700K 暖光,无级调光', '拉丝黄铜灯杆,配重底座防倾倒', '脚踏开关,窝在沙发里也够得着'], + timeline: [ + { at: '2023.07', event: '米浆裱罩工艺复原成功' }, + { at: '2024.02', event: '上市,配套云栖沙发热卖' }, + { at: '2025.05', event: '推出短杆台灯版本' }, + ], + metrics: [ + { label: '色温', value: '2700K' }, + { label: '裱罩耗时', value: '1 天/顶' }, + { label: '年销量', value: '3200 台' }, + ], + }, + { + id: 'nimbus-bed', name: '眠云大床', en: 'NIMBUS BED', cat: '卧室', price: 32000, material: '白蜡木 · 头层牛皮', size: 'W1800 × D2100 × H1050', desc: '床头以牛皮软包裹木,倚靠时是恰到好处的温柔。', seed: 'xumu-nimbus', + story: '床头软包的牛皮选的是头层小牛皮,鞣制到「靠上去像手背蹭过」的软度。床架接缝全部倒圆角,半夜起身踢到也不疼——这个细节来自客服整理的 300 条真实反馈,睡眠这件事,细节即正义。', + highlights: ['头层小牛皮床头,倚靠零压感', '床架全倒圆角,夜起不磕碰', '排骨架实木密排,静音无异响', '床脚预留扫地机器人高度'], + timeline: [ + { at: '2022.12', event: '300 条用户反馈归纳立项' }, + { at: '2023.10', event: '上市,登卧室类目口碑榜首' }, + { at: '2025.04', event: '推出 W2000 大杭版本' }, + ], + metrics: [ + { label: '圆角处理', value: '100%' }, + { label: '静音测试', value: '0 异响' }, + { label: '年销量', value: '1100 张' }, + ], + }, + { + id: 'pebble-side', name: '石纹边几', en: 'PEBBLE SIDE', cat: '客厅', price: 6800, material: '罗马洞石', size: 'Φ500 × H520', desc: '像从河滩捡回的一枚卵石,孔隙里藏着时间。', seed: 'xumu-pebble', + story: '罗马洞石的孔隙是亿万年沉积的气泡,很多厂家会用腻子把孔填平,我们偏要留着——那是石头的呼吸。每一只边几的孔隙分布都不同,像每一枚卵石都有自己的河流。台面做了食品级封护,咖啡渍一擦就掉。', + highlights: ['天然罗马洞石,孔隙原貌保留', '食品级封护,饮渍一擦即净', '整石车削成型,无拼接', '底部软木垫,推动不伤地板'], + timeline: [ + { at: '2023.05', event: '洞石孔隙封护方案定型' }, + { at: '2024.01', event: '上市,首批 200 只售罄' }, + { at: '2025.02', event: '新增碳灰色石款' }, + ], + metrics: [ + { label: '单件重量', value: '38kg' }, + { label: '封护等级', value: '食品级' }, + { label: '年销量', value: '2400 只' }, + ], + }, ], testimonials: [ { text: '沙发到家那天,师傅调平用了半小时。这种较真,让我相信它真能用二十年。', author: '室内设计师 林女士', role: '上海 · 云栖沙发用户' }, diff --git a/src/data/labStyles.js b/src/data/labStyles.js index e8f5678..d6257a5 100644 --- a/src/data/labStyles.js +++ b/src/data/labStyles.js @@ -4,6 +4,7 @@ export const labCategories = [ { key: 'visual', label: '视觉动效' }, { key: 'three', label: '3D 交互' }, { key: 'tool', label: '趣味工具' }, + { key: 'game', label: '小游戏' }, { key: 'app', label: '应用仿真' }, ] @@ -178,4 +179,514 @@ export const labList = [ }, component: () => import('../pages/lab/Car3dPage.vue'), }, + { + id: 'particle-text', + num: 'L11', + industry: 'visual', + industryLabel: '视觉动效', + title: '粒子文字', + intro: '上千粒子聚散成字,鼠标划过被打散又弹回,可输入任意文字', + cover: { + kind: 'hud', + ck: 'rgba(94,234,212,.6)', + sub: 'PARTICLES · 弹簧回位', + bg: 'radial-gradient(2px 2px at 30% 40%, #5eead4, transparent), radial-gradient(2px 2px at 38% 44%, #f472b6, transparent), radial-gradient(2px 2px at 46% 38%, #facc15, transparent), radial-gradient(2px 2px at 54% 46%, #818cf8, transparent), radial-gradient(2px 2px at 62% 40%, #5eead4, transparent), radial-gradient(2px 2px at 70% 44%, #fb923c, transparent), #0e1119', + motif: '糕', + style: { color: 'rgba(94,234,212,.9)', fontSize: '44px', textShadow: '0 0 24px rgba(94,234,212,.6)', letterSpacing: '0.1em' }, + }, + component: () => import('../pages/lab/ParticleText.vue'), + }, + { + id: 'cursor-fx', + num: 'L12', + industry: 'visual', + industryLabel: '视觉动效', + title: '鼠标特效陈列', + intro: '拖尾、聚光灯揭示、磁性按钮、3D 视差卡,四个展区各给光标一种能力', + cover: { + kind: 'frame', + ck: 'rgba(244,114,182,.5)', + sub: 'POINTER PLAYGROUND', + bg: 'radial-gradient(circle 60px at 68% 40%, rgba(94,234,212,.16), transparent), radial-gradient(circle at 30% 34%, #f472b6 0 5px, transparent 6px), radial-gradient(circle at 36% 44%, #facc15 0 4px, transparent 5px), radial-gradient(circle at 43% 52%, #818cf8 0 3px, transparent 4px), #10131c', + motif: '➤', + style: { color: '#e8ecf4', fontSize: '34px', transform: 'rotate(-18deg) translate(8px, -6px)', textShadow: '0 8px 20px rgba(0,0,0,.6)' }, + }, + component: () => import('../pages/lab/CursorFx.vue'), + }, + { + id: 'text-fx', + num: 'L13', + industry: 'visual', + industryLabel: '视觉动效', + title: '文字动效图鉴', + intro: '八种纯 CSS 文字特效:打字机、故障、波浪、流光…可重播可复制', + cover: { + kind: 'terminal', + ck: '#818cf8', + sub: 'COPY THE CSS →', + bg: 'linear-gradient(rgba(129,140,248,.5) 0 0) 12% 40%/30% 3px no-repeat, linear-gradient(rgba(94,234,212,.5) 0 0) 12% 56%/44% 3px no-repeat, linear-gradient(rgba(244,114,182,.5) 0 0) 12% 72%/24% 3px no-repeat, #0d1017', + motif: 'Aa', + style: { color: 'transparent', fontFamily: '"Space Grotesk", sans-serif', fontWeight: 700, fontSize: '44px', background: 'linear-gradient(90deg,#5eead4,#818cf8,#f472b6)', WebkitBackgroundClip: 'text', backgroundClip: 'text', transform: 'translateX(30px)' }, + }, + component: () => import('../pages/lab/TextFx.vue'), + }, + { + id: 'flip-clock', + num: 'L14', + industry: 'visual', + industryLabel: '视觉动效', + title: '翻页时钟', + intro: '机械翻页牌每秒下翻,3D 旋转拼出真实翻页,可切 12/24 小时', + cover: { + kind: 'frame', + ck: 'rgba(245,158,11,.4)', + sub: 'FLIP · 每秒一翻', + bg: 'linear-gradient(#20242f 0 0) 22% 44%/20% 38% no-repeat, linear-gradient(#20242f 0 0) 45% 44%/20% 38% no-repeat, linear-gradient(#20242f 0 0) 74% 44%/20% 38% no-repeat, linear-gradient(rgba(0,0,0,.8) 0 0) 0 49%/100% 2px no-repeat, #0b0e14', + motif: '12:47', + style: { color: '#f4f6fa', fontFamily: '"Space Grotesk", monospace', fontWeight: 700, fontSize: '34px', letterSpacing: '0.06em' }, + }, + component: () => import('../pages/lab/FlipClock.vue'), + }, + { + id: 'fireworks', + num: 'L15', + industry: 'visual', + industryLabel: '视觉动效', + title: '烟花模拟器', + intro: '点夜空放烟花:上升、绽放、重力余烬,四套配色主题', + cover: { + kind: 'hud', + ck: 'rgba(255,94,196,.55)', + sub: 'CLICK TO LAUNCH', + bg: 'radial-gradient(circle at 50% 40%, rgba(255,210,63,.9) 0 2px, transparent 3px), radial-gradient(circle at 42% 32%, rgba(255,94,196,.8) 0 2px, transparent 3px), radial-gradient(circle at 58% 32%, rgba(94,234,212,.8) 0 2px, transparent 3px), radial-gradient(circle at 44% 48%, rgba(129,140,248,.8) 0 2px, transparent 3px), radial-gradient(circle at 56% 48%, rgba(251,146,60,.8) 0 2px, transparent 3px), radial-gradient(circle at 50% 24%, rgba(255,210,63,.7) 0 2px, transparent 3px), #070910', + motif: '✸', + style: { color: '#ffd23f', fontSize: '40px', textShadow: '0 0 30px rgba(255,210,63,.8)', transform: 'translateY(-4px)' }, + }, + component: () => import('../pages/lab/Fireworks.vue'), + }, + { + id: 'audio-viz', + num: 'L16', + industry: 'visual', + industryLabel: '视觉动效', + title: '音频可视化', + intro: 'Web Audio 振荡器合成 8-bit 琶音,频谱柱/示波器/环形三种画法', + cover: { + kind: 'terminal', + ck: '#5eead4', + sub: 'AnalyserNode · fft 256', + bg: 'linear-gradient(#5eead4 0 0) 10% 84%/6% 40% no-repeat, linear-gradient(#38bdf8 0 0) 22% 84%/6% 62% no-repeat, linear-gradient(#818cf8 0 0) 34% 84%/6% 30% no-repeat, linear-gradient(#f472b6 0 0) 46% 84%/6% 74% no-repeat, linear-gradient(#facc15 0 0) 58% 84%/6% 48% no-repeat, linear-gradient(#fb923c 0 0) 70% 84%/6% 58% no-repeat, linear-gradient(#5eead4 0 0) 82% 84%/6% 36% no-repeat, #0a0d14', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/AudioViz.vue'), + }, + { + id: 'svg-theater', + num: 'L17', + industry: 'visual', + industryLabel: '视觉动效', + title: 'SVG 描边剧场', + intro: '四幅线稿自己画自己:dashoffset 描边动画,可调速重播', + cover: { + kind: 'frame', + ck: 'rgba(94,234,212,.5)', + sub: 'STROKE-DASHOFFSET', + bg: 'linear-gradient(48deg, transparent 46%, rgba(94,234,212,.8) 46.5% 47.5%, transparent 48%) 30% 40%/60% 50% no-repeat, linear-gradient(-48deg, transparent 46%, rgba(129,140,248,.8) 46.5% 47.5%, transparent 48%) 54% 40%/60% 50% no-repeat, radial-gradient(circle at 74% 28%, transparent 0 12px, rgba(244,114,182,.7) 13px 14.5px, transparent 15px), #0e1119', + motif: '✎', + style: { color: '#5eead4', fontSize: '36px', transform: 'translate(40px, 22px) rotate(-12deg)' }, + }, + component: () => import('../pages/lab/SvgTheater.vue'), + }, + { + id: 'globe-3d', + num: 'L18', + industry: 'three', + industryLabel: '3D 交互', + title: '3D 地球', + intro: '线框地球 + 七个城市标记,拖拽环绕,点标记看城市故事', + cover: { + kind: 'hud', + ck: 'rgba(43,106,148,.8)', + sub: 'LAT 30.27° · LON 120.15°', + bg: 'radial-gradient(circle at 50% 50%, #0e2233 0 30%, transparent 31%), radial-gradient(circle at 50% 50%, transparent 0 29%, rgba(43,106,148,.5) 29.5% 30.5%, transparent 31% ), radial-gradient(circle at 58% 42%, #f59e0b 0 3px, transparent 4px), radial-gradient(1px 1px at 22% 24%, #8899bb, transparent), radial-gradient(1px 1px at 80% 68%, #8899bb, transparent), radial-gradient(1.4px 1.4px at 70% 18%, #8899bb, transparent), #080a10', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/Globe3d.vue'), + }, + { + id: 'gallery-3d', + num: 'L19', + industry: 'three', + industryLabel: '3D 交互', + title: '3D 展厅漫游', + intro: '第一人称白盒展厅:拖拽转头、前进后退,六幅程序化生成的画', + cover: { + kind: 'frame', + ck: 'rgba(242,239,232,.4)', + sub: 'WALK · DRAG · CLICK', + bg: 'linear-gradient(#f59e0b 0 0) 18% 40%/14% 30% no-repeat, linear-gradient(#5eead4 0 0) 43% 40%/14% 30% no-repeat, linear-gradient(#818cf8 0 0) 68% 40%/14% 30% no-repeat, linear-gradient(#241f1a 0 0) 15% 38%/20% 36% no-repeat, linear-gradient(#241f1a 0 0) 40% 38%/20% 36% no-repeat, linear-gradient(#241f1a 0 0) 65% 38%/20% 36% no-repeat, linear-gradient(178deg, #f2efe8 0 76%, #2a2530 76%)', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/Gallery3d.vue'), + }, + { + id: 'dice-3d', + num: 'L20', + industry: 'three', + industryLabel: '3D 交互', + title: '3D 骰子', + intro: '抛起翻滚落定,四元数插值让点数稳稳朝上,带投掷记录', + cover: { + kind: 'frame', + ck: 'rgba(94,234,212,.35)', + sub: 'SLERP · 手气检测', + bg: 'linear-gradient(#faf6ee 0 0) 38% 40%/24% 34% no-repeat, radial-gradient(circle at 45% 47%, #d9463c 0 5px, transparent 6px), radial-gradient(circle at 55% 60%, #23262e 0 4px, transparent 5px), radial-gradient(ellipse 50% 12% at 50% 82%, rgba(29,70,54,.9), transparent 70%), radial-gradient(ellipse at 50% 20%, #131824, #0a0d13)', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/Dice3d.vue'), + }, + { + id: 'solar-3d', + num: 'L21', + industry: 'three', + industryLabel: '3D 交互', + title: '太阳系模拟', + intro: '八大行星按相对周期公转,可调时间流速,点行星看档案', + cover: { + kind: 'hud', + ck: 'rgba(255,176,32,.5)', + sub: 'T ×1.0 · 8 PLANETS', + bg: 'radial-gradient(circle at 30% 50%, #ffb020 0 9px, rgba(255,123,32,.35) 10px 14px, transparent 15px), radial-gradient(circle at 30% 50%, transparent 0 22px, rgba(42,53,80,.9) 22.5px 23.5px, transparent 24px 34px, rgba(42,53,80,.7) 34.5px 35.5px, transparent 36px 48px, rgba(42,53,80,.5) 48.5px 49.5px, transparent 50px), radial-gradient(circle at 52% 42%, #4a90d9 0 3.5px, transparent 4.5px), radial-gradient(circle at 66% 62%, #d9c28a 0 5px, transparent 6px), radial-gradient(1px 1px at 80% 22%, #99aacc, transparent), #05070c', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/Solar3d.vue'), + }, + { + id: 'voxel-builder', + num: 'L22', + industry: 'three', + industryLabel: '3D 交互', + title: '体素积木', + intro: '3D 像素建造:点面放块右键拆除,八色调色板,作品存本地', + cover: { + kind: 'blueprintgrid', + ck: 'rgba(94,234,212,.5)', + sub: 'VOXEL · 自动保存', + bg: 'linear-gradient(#f59e0b 0 0) 40% 58%/13% 18% no-repeat, linear-gradient(#5eead4 0 0) 53% 58%/13% 18% no-repeat, linear-gradient(#f472b6 0 0) 46.5% 40%/13% 18% no-repeat, linear-gradient(rgba(42,53,80,.8) 0 0) 0 78%/100% 1.5px no-repeat, #0d1017', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/VoxelBuilder.vue'), + }, + { + id: 'text-3d', + num: 'L23', + industry: 'three', + industryLabel: '3D 交互', + title: '3D 文字铸造', + intro: '5×7 体素字模铸出立体字,糖果/鎏金/霓虹/素白四种材质', + cover: { + kind: 'frame', + ck: 'rgba(244,114,182,.45)', + sub: 'A-Z · 0-9 · ♥', + bg: 'linear-gradient(#f472b6 0 0) 30% 40%/8% 30% no-repeat, linear-gradient(#5eead4 0 0) 41% 40%/8% 30% no-repeat, linear-gradient(#facc15 0 0) 52% 40%/8% 30% no-repeat, linear-gradient(#818cf8 0 0) 63% 40%/8% 30% no-repeat, linear-gradient(rgba(34,43,68,.8) 0 0) 0 82%/100% 1.5px no-repeat, #0d1017', + motif: '3D', + style: { color: '#f472b6', fontFamily: '"Press Start 2P", monospace', fontSize: '22px', transform: 'translateY(28px)' }, + }, + component: () => import('../pages/lab/Text3d.vue'), + }, + { + id: 'responsive-preview', + num: 'L24', + industry: 'tool', + industryLabel: '趣味工具', + title: '多端断点预览器', + intro: '手机/平板/笔记本三种视口同屏预览本站任意页面', + cover: { + kind: 'frame', + ck: 'rgba(94,234,212,.4)', + sub: '393 · 768 · 1440', + bg: 'linear-gradient(#1c202b 0 0) 16% 50%/14% 52% no-repeat, linear-gradient(#fff 0 0) 16% 50%/10% 44% no-repeat, linear-gradient(#1c202b 0 0) 45% 52%/22% 56% no-repeat, linear-gradient(#fff 0 0) 45% 52%/18% 48% no-repeat, linear-gradient(#1c202b 0 0) 79% 54%/30% 44% no-repeat, linear-gradient(#fff 0 0) 79% 51%/26% 34% no-repeat, #0e1119', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/ResponsivePreview.vue'), + }, + { + id: 'gradient-maker', + num: 'L25', + industry: 'tool', + industryLabel: '趣味工具', + title: 'CSS 渐变生成器', + intro: '线性/径向/锥形,六个色标拖着调,一键复制 CSS', + cover: { + kind: 'holo', + ck: '#f472b6', + sub: 'linear · radial · conic', + bg: 'linear-gradient(135deg, #f59e0b, #f472b6 48%, #818cf8)', + motif: '◐', + style: { color: '#fff', fontSize: '42px', textShadow: '0 10px 30px rgba(0,0,0,.4)' }, + }, + component: () => import('../pages/lab/GradientMaker.vue'), + }, + { + id: 'shadow-maker', + num: 'L26', + industry: 'tool', + industryLabel: '趣味工具', + title: '阴影调配器', + intro: '六层 box-shadow 叠着调,浅底深底随时切,预设直接抄', + cover: { + kind: 'frame', + ck: 'rgba(35,38,46,.3)', + sub: 'x · y · blur · spread', + bg: 'linear-gradient(#fff 0 0) 50% 40%/38% 30% no-repeat, radial-gradient(ellipse 46% 14% at 54% 66%, rgba(15,23,42,.4), transparent 70%), #eef1f6', + motif: '❏', + style: { color: '#23262e', fontSize: '30px', transform: 'translateY(-8px)' }, + }, + component: () => import('../pages/lab/ShadowMaker.vue'), + }, + { + id: 'regex-tester', + num: 'L27', + industry: 'tool', + industryLabel: '趣味工具', + title: '正则实验台', + intro: '实时高亮命中,g/i/m/s 标志与捕获组,常用预设一键装填', + cover: { + kind: 'terminal', + ck: '#fbbf24', + sub: '/\\b1[3-9]\\d{9}\\b/g', + bg: 'linear-gradient(rgba(245,158,11,.35) 0 0) 18% 46%/22% 8% no-repeat, linear-gradient(rgba(245,158,11,.35) 0 0) 58% 62%/26% 8% no-repeat, linear-gradient(rgba(232,236,244,.14) 0 0) 12% 30%/70% 3px no-repeat, linear-gradient(rgba(232,236,244,.14) 0 0) 12% 62%/40% 3px no-repeat, #10131c', + motif: '.*', + style: { color: '#fbbf24', fontFamily: 'Consolas, monospace', fontSize: '40px', fontWeight: 700 }, + }, + component: () => import('../pages/lab/RegexTester.vue'), + }, + { + id: 'json-box', + num: 'L28', + industry: 'tool', + industryLabel: '趣味工具', + title: 'JSON 工具箱', + intro: '格式化、压缩、树形浏览与体积统计,错误位置直接报', + cover: { + kind: 'terminal', + ck: '#93a6f4', + sub: 'parse · format · tree', + bg: 'linear-gradient(rgba(147,166,244,.4) 0 0) 16% 34%/20% 6% no-repeat, linear-gradient(rgba(125,212,135,.4) 0 0) 26% 48%/26% 6% no-repeat, linear-gradient(rgba(251,191,36,.4) 0 0) 26% 62%/16% 6% no-repeat, linear-gradient(rgba(244,114,182,.4) 0 0) 16% 76%/12% 6% no-repeat, #10131c', + motif: '{ }', + style: { color: '#93a6f4', fontFamily: 'Consolas, monospace', fontSize: '38px', fontWeight: 700, transform: 'translateX(24px)' }, + }, + component: () => import('../pages/lab/JsonBox.vue'), + }, + { + id: 'ascii-art', + num: 'L29', + industry: 'tool', + industryLabel: '趣味工具', + title: 'ASCII 字符画', + intro: '图片按亮度转字符画,四种字符集可反相,全程本地处理', + cover: { + kind: 'terminal', + ck: '#7dd487', + sub: '@%#*+=-:. · local only', + bg: '#0d1017', + motif: '@#*.', + style: { color: '#7dd487', fontFamily: 'Consolas, monospace', fontSize: '32px', letterSpacing: '0.14em' }, + }, + component: () => import('../pages/lab/AsciiArt.vue'), + }, + { + id: 'text-diff', + num: 'L30', + industry: 'tool', + industryLabel: '趣味工具', + title: '文本 Diff 对比', + intro: 'LCS 行级对比 + 字符级高亮,左右两栏像代码评审', + cover: { + kind: 'frame', + ck: 'rgba(251,191,36,.4)', + sub: '+2 −1 ±1', + bg: 'linear-gradient(rgba(125,212,135,.2) 0 0) 54% 38%/44% 12% no-repeat, linear-gradient(rgba(251,113,133,.2) 0 0) 8% 56%/40% 12% no-repeat, linear-gradient(rgba(232,236,244,.1) 0 0) 50% 0/1.5px 100% no-repeat, #0d1017', + motif: '⇄', + style: { color: '#fbbf24', fontSize: '38px' }, + }, + component: () => import('../pages/lab/TextDiff.vue'), + }, + { + id: 'pomodoro', + num: 'L31', + industry: 'tool', + industryLabel: '趣味工具', + title: '番茄钟', + intro: '25+5 专注循环,完成数与专注时长存本地,四个番茄换大休', + cover: { + kind: 'frame', + ck: 'rgba(251,113,133,.45)', + sub: '25:00 · FOCUS', + bg: 'radial-gradient(circle at 50% 50%, transparent 0 26%, rgba(251,113,133,.9) 26.5% 30%, rgba(255,255,255,.08) 30.5% 33%, transparent 33.5%), #10131c', + motif: '25′', + style: { color: '#fb7185', fontFamily: '"Space Grotesk", sans-serif', fontWeight: 700, fontSize: '30px' }, + }, + component: () => import('../pages/lab/Pomodoro.vue'), + }, + { + id: 'habit-tracker', + num: 'L32', + industry: 'tool', + industryLabel: '趣味工具', + title: '习惯打卡', + intro: '20 周热力图 + 连击天数,点格子补卡,全部存本地', + cover: { + kind: 'grid', + ck: 'rgba(47,191,143,.4)', + sub: 'STREAK 12 DAYS', + bg: 'radial-gradient(circle 5px at 20% 36%, #2fbf8f 97%, transparent) , radial-gradient(circle 5px at 30% 36%, #2fbf8f 97%, transparent), radial-gradient(circle 5px at 40% 52%, #2fbf8f 97%, transparent), radial-gradient(circle 5px at 50% 36%, rgba(47,191,143,.5) 97%, transparent), radial-gradient(circle 5px at 60% 68%, #2fbf8f 97%, transparent), radial-gradient(circle 5px at 70% 52%, rgba(47,191,143,.5) 97%, transparent), radial-gradient(circle 5px at 80% 36%, #2fbf8f 97%, transparent), #10131c', + motif: '✓', + style: { color: '#2fbf8f', fontSize: '40px', fontWeight: 700, textShadow: '0 0 20px rgba(47,191,143,.6)', transform: 'translateY(14px)' }, + }, + component: () => import('../pages/lab/HabitTracker.vue'), + }, + { + id: 'game-2048', + num: 'L33', + industry: 'game', + industryLabel: '小游戏', + title: '2048', + intro: '方向键或滑动合并,最高分存本地,目标那块青色的砖', + cover: { + kind: 'pixelframe', + ck: '#f59e0b', + sub: 'SCORE 0 · BEST ???', + bg: 'linear-gradient(#d9924a 0 0) 22% 32%/22% 30% no-repeat, linear-gradient(#e0603c 0 0) 46% 32%/22% 30% no-repeat, linear-gradient(#e6c04e 0 0) 22% 66%/22% 30% no-repeat, linear-gradient(#5eead4 0 0) 46% 66%/22% 30% no-repeat, linear-gradient(#2a2f3d 0 0) 70% 32%/22% 30% no-repeat, linear-gradient(#3a3f52 0 0) 70% 66%/22% 30% no-repeat, #171b26', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/Game2048.vue'), + }, + { + id: 'snake', + num: 'L34', + industry: 'game', + industryLabel: '小游戏', + title: '贪吃蛇', + intro: '经典 17×17 棋盘,三档速度,吃粉色年糕丸子变长', + cover: { + kind: 'pixelframe', + ck: '#5eead4', + sub: 'WASD · 3 SPEEDS', + bg: 'linear-gradient(#5eead4 0 0) 26% 40%/10% 12% no-repeat, linear-gradient(rgba(94,234,212,.75) 0 0) 36% 40%/10% 12% no-repeat, linear-gradient(rgba(94,234,212,.55) 0 0) 46% 40%/10% 12% no-repeat, linear-gradient(rgba(94,234,212,.4) 0 0) 46% 52%/10% 12% no-repeat, radial-gradient(circle at 72% 66%, #f472b6 0 7px, transparent 8px), #0d1017', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/Snake.vue'), + }, + { + id: 'minesweeper', + num: 'L35', + industry: 'game', + industryLabel: '小游戏', + title: '扫雷', + intro: '左键翻开右键插旗,双击数字快开,首点必安全', + cover: { + kind: 'pixelframe', + ck: '#fb7185', + sub: '💣 10 · ⏱ 000', + bg: 'linear-gradient(#3a3f52 0 0) 24% 34%/16% 22% no-repeat, linear-gradient(#3a3f52 0 0) 42% 34%/16% 22% no-repeat, linear-gradient(#12151f 0 0) 60% 34%/16% 22% no-repeat, linear-gradient(#3a3f52 0 0) 24% 60%/16% 22% no-repeat, linear-gradient(#12151f 0 0) 42% 60%/16% 22% no-repeat, linear-gradient(#3a3f52 0 0) 60% 60%/16% 22% no-repeat, #171b26', + motif: '🚩', + style: { fontSize: '30px', transform: 'translate(30px, -14px)' }, + }, + component: () => import('../pages/lab/Minesweeper.vue'), + }, + { + id: 'memory-flip', + num: 'L36', + industry: 'game', + industryLabel: '小游戏', + title: '翻牌记忆', + intro: '十六张小吃牌配对,步数计分,最佳纪录存本地', + cover: { + kind: 'frame', + ck: 'rgba(94,234,212,.35)', + sub: 'MOVES 0 · PAIR 0/8', + bg: 'linear-gradient(150deg,#2b2f42,#1d2130) 16% 30%/18% 30% no-repeat, linear-gradient(150deg,#2b2f42,#1d2130) 38% 30%/18% 30% no-repeat, linear-gradient(150deg, rgba(94,234,212,.3), rgba(94,234,212,.08)) 60% 30%/18% 30% no-repeat, linear-gradient(150deg,#2b2f42,#1d2130) 82% 30%/18% 30% no-repeat, linear-gradient(150deg,#2b2f42,#1d2130) 16% 68%/18% 30% no-repeat, linear-gradient(150deg, rgba(94,234,212,.3), rgba(94,234,212,.08)) 38% 68%/18% 30% no-repeat, linear-gradient(150deg,#2b2f42,#1d2130) 60% 68%/18% 30% no-repeat, linear-gradient(150deg,#2b2f42,#1d2130) 82% 68%/18% 30% no-repeat, #0d1017', + motif: '🍡', + style: { fontSize: '26px', transform: 'translate(24px, 14px)' }, + }, + component: () => import('../pages/lab/MemoryFlip.vue'), + }, + { + id: 'kanban', + num: 'L37', + industry: 'app', + industryLabel: '应用仿真', + title: '看板任务', + intro: '三列看板拖拽流转,增删卡片,数据自动存本地', + cover: { + kind: 'window', + os: 'mac', + winTitle: '看板 — 待办 3 · 进行中 2', + bg: 'linear-gradient(#171b26 0 0) 6% 56%/27% 74% no-repeat, linear-gradient(#171b26 0 0) 37% 56%/27% 74% no-repeat, linear-gradient(#171b26 0 0) 68% 56%/27% 74% no-repeat, linear-gradient(#262b3a 0 0) 8.5% 40%/22% 16% no-repeat, linear-gradient(#262b3a 0 0) 8.5% 62%/22% 16% no-repeat, linear-gradient(#262b3a 0 0) 39.5% 44%/22% 16% no-repeat, linear-gradient(#262b3a 0 0) 70.5% 48%/22% 16% no-repeat, #10131c', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/Kanban.vue'), + }, + { + id: 'stock-sim', + num: 'L38', + industry: 'app', + industryLabel: '应用仿真', + title: '模拟看盘', + intro: '随机漫步 K 线每秒一根,四只虚构股票,红涨绿跌', + cover: { + kind: 'hud', + ck: 'rgba(240,81,81,.55)', + sub: 'NG.2026 ▲ +2.47%', + bg: 'linear-gradient(#f05151 0 0) 20% 50%/4% 30% no-repeat, linear-gradient(#2fbf8f 0 0) 30% 56%/4% 22% no-repeat, linear-gradient(#f05151 0 0) 40% 40%/4% 36% no-repeat, linear-gradient(#f05151 0 0) 50% 34%/4% 30% no-repeat, linear-gradient(#2fbf8f 0 0) 60% 44%/4% 24% no-repeat, linear-gradient(#f05151 0 0) 70% 30%/4% 34% no-repeat, linear-gradient(rgba(245,158,11,.6) 0 0) 0 32%/100% 1.5px no-repeat, #0d1017', + motif: '', + style: {}, + }, + component: () => import('../pages/lab/StockSim.vue'), + }, + { + id: 'weather-app', + num: 'L39', + industry: 'app', + industryLabel: '应用仿真', + title: '天气 App', + intro: '四座城市四套 CSS 天气动效:雨丝、飘雪、烈日、云层', + cover: { + kind: 'frame', + ck: 'rgba(255,255,255,.3)', + sub: '杭州 24° · 小雨转代码', + bg: 'linear-gradient(rgba(180,210,255,.6) 0 0) 24% 30%/1.5px 16% no-repeat, linear-gradient(rgba(180,210,255,.5) 0 0) 38% 44%/1.5px 14% no-repeat, linear-gradient(rgba(180,210,255,.6) 0 0) 55% 26%/1.5px 16% no-repeat, linear-gradient(rgba(180,210,255,.5) 0 0) 70% 48%/1.5px 13% no-repeat, linear-gradient(175deg, #2b3a55, #131a28)', + motif: '24°', + style: { color: '#f2f4fa', fontWeight: 200, fontSize: '52px' }, + }, + component: () => import('../pages/lab/WeatherApp.vue'), + }, + { + id: 'chat-ai', + num: 'L40', + industry: 'app', + industryLabel: '应用仿真', + title: 'AI 聊天助手', + intro: '诚实的人工智障:正则规则 + 打字机回复,可真输入,记录存本地', + cover: { + kind: 'window', + os: 'mac', + winTitle: '年糕助手 — 对方正在输入…', + bg: 'linear-gradient(#1d2130 0 0) 16% 34%/44% 15% no-repeat, linear-gradient(#f59e0b 0 0) 82% 56%/38% 15% no-repeat, linear-gradient(#1d2130 0 0) 20% 78%/30% 15% no-repeat, #10131c', + motif: '🍡', + style: { fontSize: '32px', transform: 'translate(-56px, 4px)' }, + }, + component: () => import('../pages/lab/ChatAi.vue'), + }, ] diff --git a/src/data/profile.js b/src/data/profile.js index 9f033b1..4ef41ce 100644 --- a/src/data/profile.js +++ b/src/data/profile.js @@ -31,7 +31,26 @@ export const profile = { { name: 'CodeMochi', alias: '代码年糕', + slug: 'codemochi', desc: '开源代码片段管理工具,支持全文搜索、标签体系与一键分享,已收获 2.3k Star。', + story: + '起因很朴素:收藏的代码片段散落在便签、聊天记录和七个不同的 gist 里,找一段防抖函数要翻十分钟。索性给自己造一个「代码抽屉」,没想到把全文搜索做丝滑之后,Star 就一路涨了起来。', + highlights: [ + '倒排索引进 IndexedDB,千条片段输入即搜,零后端', + '标签体系支持嵌套与批量整理,收藏狂魔友好', + '一键生成分享卡片,带语法高亮与暗色主题', + 'README 被三个技术周刊转载过(小骄傲)', + ], + timeline: [ + { at: '2025.02', event: '深夜被「找不到片段」逼疯,立项' }, + { at: '2025.04', event: '搜索方案推翻重写,卡顿从 300ms 降到 8ms' }, + { at: '2025.06', event: '登上趋势榜,单日 +400 Star' }, + ], + metrics: [ + { label: 'Star', value: '2.3k' }, + { label: '周下载', value: '4.6k' }, + { label: '测试覆盖', value: '92%' }, + ], tags: ['Vue 3', 'TypeScript', 'IndexedDB'], year: '2025', stars: '2.3k', @@ -40,7 +59,26 @@ export const profile = { { name: '糯米终端', alias: 'NuomiTerm', + slug: 'nuomiterm', desc: '终端美化主题与 CLI 工具集:一条命令换主题、自带年糕色板与状态栏组件。', + story: + '给同事演示代码时,黑底白字的终端被吐槽「像上世纪」。一怒之下写了套主题引擎,第一版配色是粉色的——组里用了一周没人卸载,只提了一个需求:出个深色版,叫「夜宵年糕」。', + highlights: [ + '一条命令切换主题,支持 12 套内置配色', + '状态栏组件化:Git 分支、电量、时间自由拼装', + 'Rust 实现,冷启动 3ms,无感知', + '配色文件是纯 TOML,改起来像调色盘', + ], + timeline: [ + { at: '2024.03', event: '被吐槽终端太丑,连夜写出原型' }, + { at: '2024.05', event: '重写为 Rust,性能起飞' }, + { at: '2024.09', event: '「夜宵年糕」深色版发布,好评如潮' }, + ], + metrics: [ + { label: 'Star', value: '1.1k' }, + { label: '内置主题', value: '12 套' }, + { label: '冷启动', value: '3ms' }, + ], tags: ['Rust', 'Shell', 'CLI'], year: '2024', stars: '1.1k', @@ -49,7 +87,26 @@ export const profile = { { name: 'TodoRice', alias: '饭粒清单', + slug: 'todorice', desc: '极简待办 Web 应用,离线可用的 PWA,把每件小事都当作一粒米认真对待。', + story: + '试过七八个待办应用,不是功能太多就是要登录开会员。我要的只是「打开、写下、划掉」三件事。于是做了这个离线优先的清单:没有账号,没有推送,数据全在你自己的设备里,像口袋里的一把米。', + highlights: [ + '离线优先 PWA,飞机上也能记事', + '零账号零后端,数据完全属于你', + '完成动画是一粒米落进碗里(音效可关)', + '全键盘操作,手不离键盘记完一天', + ], + timeline: [ + { at: '2024.01', event: '对市面待办应用全部失望,动手' }, + { at: '2024.02', event: 'PWA 离线方案打磨完成' }, + { at: '2024.06', event: '被效率类博主推荐,用户破万' }, + ], + metrics: [ + { label: 'Star', value: '860' }, + { label: '月活', value: '1.2w' }, + { label: '离线可用', value: '100%' }, + ], tags: ['Vue 3', 'Pinia', 'PWA'], year: '2024', stars: '860', @@ -58,7 +115,26 @@ export const profile = { { name: '像素厨房', alias: 'Pixel Kitchen', + slug: 'pixel-kitchen', desc: '用 Canvas 手搓的做饭小游戏:翻锅、颠勺、摆盘,全凭手速与直觉。', + story: + '大学时期的作品,最初只是想练 Canvas。写着写着把家里的菜谱都做进去了:火候是进度条,颠勺是节奏点,摆盘是拖拽拼图。妈妈玩到第三关说「你这个火候不对」,于是有了史上最严格的一次用户测试。', + highlights: [ + '纯 Canvas 手写渲染,零游戏引擎依赖', + '16 道菜 48 个关卡,难度曲线亲妈调校', + '手速判定系统:完美/良好/翻车三档', + '像素素材全部自绘,一格一格点出来的', + ], + timeline: [ + { at: '2023.03', event: '为练 Canvas 立项,先做了口锅' }, + { at: '2023.07', event: '关卡系统重构,加入节奏判定' }, + { at: '2023.11', event: '在同学间流传,收获第一批玩家' }, + ], + metrics: [ + { label: 'Star', value: '540' }, + { label: '关卡', value: '48' }, + { label: '最高连击', value: '127' }, + ], tags: ['Canvas', 'TypeScript', 'Game'], year: '2023', stars: '540', diff --git a/src/data/styles.js b/src/data/styles.js index f3e1f7c..422d4bf 100644 --- a/src/data/styles.js +++ b/src/data/styles.js @@ -5,11 +5,13 @@ export const styleCategories = [ { key: 'art', label: '设计流派' }, { key: 'ui', label: '界面潮流' }, { key: 'retro', label: '复古怀旧' }, + { key: 'game', label: '游戏动漫' }, { key: 'os', label: '系统界面' }, { key: 'app', label: '应用媒体' }, { key: 'paper', label: '纸品手作' }, { key: 'object', label: '拟真物件' }, { key: 'neon', label: '暗夜光效' }, + { key: 'horror', label: '恐怖惊悚' }, ] export const styleList = [ @@ -29,6 +31,9 @@ export const styleList = [ style: { color: '#16161a', fontWeight: 300, letterSpacing: '0.06em' }, }, component: () => import('../pages/styles/MinimalPage.vue'), + subPages: [ + { path: 'notes', title: '留白笔记', component: () => import('../pages/styles/sub/MinimalNotesPage.vue') }, + ], }, { id: 'terminal', @@ -50,6 +55,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/TerminalPage.vue'), + subPages: [ + { path: 'shell', title: '交互终端', component: () => import('../pages/styles/sub/TerminalShellPage.vue') }, + ], }, { id: 'glass', @@ -67,6 +75,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/GlassPage.vue'), + subPages: [ + { path: 'lab', title: '玻璃实验室', component: () => import('../pages/styles/sub/GlassLabPage.vue') }, + ], }, { id: 'neumorphism', @@ -84,6 +95,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/NeumorphismPage.vue'), + subPages: [ + { path: 'console', title: '拟态控制台', component: () => import('../pages/styles/sub/NeuConsolePage.vue') }, + ], }, { id: 'brutalism', @@ -104,6 +118,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/BrutalismPage.vue'), + subPages: [ + { path: 'wall', title: '大字报墙', component: () => import('../pages/styles/sub/BrutalWallPage.vue') }, + ], }, { id: 'cyberpunk', @@ -126,6 +143,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/CyberpunkPage.vue'), + subPages: [ + { path: 'augment', title: '义体改造舱', component: () => import('../pages/styles/sub/CyberAugmentPage.vue') }, + ], }, { id: 'pixel', @@ -147,6 +167,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/PixelPage.vue'), + subPages: [ + { path: 'coin', title: '金币雨', component: () => import('../pages/styles/sub/PixelCatchPage.vue') }, + ], }, { id: 'newspaper', @@ -168,6 +191,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/NewspaperPage.vue'), + subPages: [ + { path: 'archive', title: '旧报档案馆', component: () => import('../pages/styles/sub/NewspaperArchivePage.vue') }, + ], }, { id: 'bento', @@ -182,6 +208,9 @@ export const styleList = [ style: { color: '#111827', fontWeight: 700 }, }, component: () => import('../pages/styles/BentoPage.vue'), + subPages: [ + { path: 'arrange', title: '便当格自由拼', component: () => import('../pages/styles/sub/BentoArrangePage.vue') }, + ], }, { id: 'memphis', @@ -199,6 +228,9 @@ export const styleList = [ style: { color: '#ff4d6d', textShadow: '5px 5px 0 #00b8a9' }, }, component: () => import('../pages/styles/MemphisPage.vue'), + subPages: [ + { path: 'maker', title: '海报生成器', component: () => import('../pages/styles/sub/MemphisMakerPage.vue') }, + ], }, { id: 'swiss', @@ -220,6 +252,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/SwissPage.vue'), + subPages: [ + { path: 'layout', title: '网格排版器', component: () => import('../pages/styles/sub/SwissLayoutPage.vue') }, + ], }, { id: 'doodle', @@ -237,6 +272,9 @@ export const styleList = [ style: { color: '#3b3b3b', fontFamily: '"Long Cang", cursive' }, }, component: () => import('../pages/styles/DoodlePage.vue'), + subPages: [ + { path: 'board', title: '涂鸦画板', component: () => import('../pages/styles/sub/DoodleBoardPage.vue') }, + ], }, { id: 'vaporwave', @@ -258,6 +296,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/VaporwavePage.vue'), + subPages: [ + { path: 'mall', title: '午夜商场', component: () => import('../pages/styles/sub/VaporMallPage.vue') }, + ], }, { id: 'zen', @@ -275,6 +316,9 @@ export const styleList = [ style: { color: '#2b2b28', fontFamily: '"Ma Shan Zheng", KaiTi, serif' }, }, component: () => import('../pages/styles/ZenPage.vue'), + subPages: [ + { path: 'sand', title: '枯山水耙沙', component: () => import('../pages/styles/sub/ZenSandPage.vue') }, + ], }, { id: 'clay', @@ -289,6 +333,9 @@ export const styleList = [ style: { color: '#ff8bc2', textShadow: '0 12px 0 rgba(214,105,160,.4)' }, }, component: () => import('../pages/styles/ClayPage.vue'), + subPages: [ + { path: 'studio', title: '捏黏土', component: () => import('../pages/styles/sub/ClayStudioPage.vue') }, + ], }, { id: 'dashboard', @@ -306,6 +353,9 @@ export const styleList = [ style: { color: '#3fb950', fontFamily: 'Consolas, monospace' }, }, component: () => import('../pages/styles/DashboardPage.vue'), + subPages: [ + { path: 'bigscreen', title: '年度数据大屏', component: () => import('../pages/styles/sub/DashboardBigscreenPage.vue') }, + ], }, { id: 'collage', @@ -323,6 +373,9 @@ export const styleList = [ style: { color: '#333', textShadow: '4px 4px 0 #f2c14e' }, }, component: () => import('../pages/styles/CollagePage.vue'), + subPages: [ + { path: 'desk', title: '拼贴工作台', component: () => import('../pages/styles/sub/CollageDeskPage.vue') }, + ], }, { id: 'luxury', @@ -344,6 +397,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/LuxuryPage.vue'), + subPages: [ + { path: 'atelier', title: '私人订制工坊', component: () => import('../pages/styles/sub/LuxuryAtelierPage.vue') }, + ], }, { id: 'candy', @@ -361,6 +417,9 @@ export const styleList = [ style: { color: '#ff7ba9', fontFamily: '"ZCOOL KuaiLe", sans-serif' }, }, component: () => import('../pages/styles/CandyPage.vue'), + subPages: [ + { path: 'gacha', title: '扭蛋糖果机', component: () => import('../pages/styles/sub/CandyGachaPage.vue') }, + ], }, { id: 'aurora', @@ -375,6 +434,9 @@ export const styleList = [ style: { color: '#eafcf6', textShadow: '0 0 20px rgba(120,255,220,.8)' }, }, component: () => import('../pages/styles/AuroraPage.vue'), + subPages: [ + { path: 'station', title: '极光观测站', component: () => import('../pages/styles/sub/AuroraStationPage.vue') }, + ], }, { id: 'guofeng', @@ -395,6 +457,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/GuofengPage.vue'), + subPages: [ + { path: 'seal', title: '印章工坊', component: () => import('../pages/styles/sub/GuofengSealPage.vue') }, + ], }, { id: 'retro-print', @@ -412,6 +477,9 @@ export const styleList = [ style: { color: '#5c3d2e', fontFamily: '"Shrikhand", serif' }, }, component: () => import('../pages/styles/RetroPrintPage.vue'), + subPages: [ + { path: 'press', title: '活字排版车间', component: () => import('../pages/styles/sub/RetroPressPage.vue') }, + ], }, { id: 'medieval', @@ -429,6 +497,9 @@ export const styleList = [ style: { color: '#8b1e2d', textShadow: '0 2px 0 rgba(212,175,55,.7)' }, }, component: () => import('../pages/styles/MedievalPage.vue'), + subPages: [ + { path: 'quests', title: '公会任务板', component: () => import('../pages/styles/sub/MedievalQuestPage.vue') }, + ], }, { id: 'win98', @@ -446,6 +517,9 @@ export const styleList = [ style: { color: '#c3f0ec', fontSize: '44px', textShadow: '3px 3px 0 #004f4f' }, }, component: () => import('../pages/styles/Win98Page.vue'), + subPages: [ + { path: 'control', title: '控制面板', component: () => import('../pages/styles/sub/Win98ControlPage.vue') }, + ], }, { id: 'ide', @@ -467,6 +541,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/IdePage.vue'), + subPages: [ + { path: 'golf', title: '代码高尔夫', component: () => import('../pages/styles/sub/IdeGolfPage.vue') }, + ], }, { id: 'magazine', @@ -488,6 +565,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/MagazinePage.vue'), + subPages: [ + { path: 'archive', title: '往期档案', component: () => import('../pages/styles/sub/MagazineArchivePage.vue') }, + ], }, { id: 'receipt', @@ -510,6 +590,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/ReceiptPage.vue'), + subPages: [ + { path: 'kiosk', title: '自助点单机', component: () => import('../pages/styles/sub/ReceiptKioskPage.vue') }, + ], }, { id: 'boarding-pass', @@ -527,6 +610,9 @@ export const styleList = [ style: { color: '#e8b64c', textShadow: '0 4px 14px rgba(0,0,0,.35)' }, }, component: () => import('../pages/styles/BoardingPassPage.vue'), + subPages: [ + { path: 'checkin', title: '值机选座', component: () => import('../pages/styles/sub/BoardingCheckinPage.vue') }, + ], }, { id: 'metro', @@ -544,6 +630,9 @@ export const styleList = [ style: { color: '#17171a', fontSize: '30px' }, }, component: () => import('../pages/styles/MetroPage.vue'), + subPages: [ + { path: 'ride', title: '乘车体验', component: () => import('../pages/styles/sub/MetroRidePage.vue') }, + ], }, { id: 'blueprint', @@ -561,6 +650,9 @@ export const styleList = [ style: { color: '#eaf2ff', fontFamily: 'Consolas, monospace' }, }, component: () => import('../pages/styles/BlueprintPage.vue'), + subPages: [ + { path: 'review', title: '图纸审阅', component: () => import('../pages/styles/sub/BlueprintReviewPage.vue') }, + ], }, { id: 'vinyl', @@ -575,6 +667,9 @@ export const styleList = [ style: { color: '#3a2f1d', fontSize: '26px' }, }, component: () => import('../pages/styles/VinylPage.vue'), + subPages: [ + { path: 'deck', title: '唱机操作台', component: () => import('../pages/styles/sub/VinylDeckPage.vue') }, + ], }, { id: 'space', @@ -592,6 +687,9 @@ export const styleList = [ style: { color: '#f5f7ff', textShadow: '0 0 18px rgba(160,180,255,.9)' }, }, component: () => import('../pages/styles/SpacePage.vue'), + subPages: [ + { path: 'eva', title: 'EVA 舱外漂移', component: () => import('../pages/styles/sub/SpaceEvaPage.vue') }, + ], }, { id: 'watercolor', @@ -608,6 +706,9 @@ export const styleList = [ style: { color: '#4a6fa5', fontFamily: 'KaiTi, "Noto Serif SC", serif' }, }, component: () => import('../pages/styles/WatercolorPage.vue'), + subPages: [ + { path: 'mix', title: '湿染画布', component: () => import('../pages/styles/sub/WatercolorMixPage.vue') }, + ], }, { id: 'bauhaus', @@ -625,6 +726,9 @@ export const styleList = [ style: { color: '#111', fontWeight: 900, fontSize: '44px' }, }, component: () => import('../pages/styles/BauhausPage.vue'), + subPages: [ + { path: 'compose', title: '构成练习', component: () => import('../pages/styles/sub/BauhausComposePage.vue') }, + ], }, { id: 'pop-art', @@ -647,6 +751,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/PopArtPage.vue'), + subPages: [ + { path: 'comic', title: '四格漫画机', component: () => import('../pages/styles/sub/PopComicPage.vue') }, + ], }, { id: 'y2k', @@ -669,6 +776,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/Y2kPage.vue'), + subPages: [ + { path: 'scan', title: '千年虫检测', component: () => import('../pages/styles/sub/Y2kScanPage.vue') }, + ], }, { id: 'aero', @@ -686,6 +796,9 @@ export const styleList = [ style: { color: 'rgba(255,255,255,.95)', textShadow: '0 4px 10px rgba(30,90,140,.4)' }, }, component: () => import('../pages/styles/AeroPage.vue'), + subPages: [ + { path: 'gadgets', title: '侧边栏小工具', component: () => import('../pages/styles/sub/AeroGadgetsPage.vue') }, + ], }, { id: 'neon-sign', @@ -708,6 +821,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/NeonSignPage.vue'), + subPages: [ + { path: 'custom', title: '霓虹灯定制铺', component: () => import('../pages/styles/sub/NeonCustomPage.vue') }, + ], }, { id: 'macos', @@ -725,6 +841,9 @@ export const styleList = [ style: { color: '#fff', textShadow: '0 6px 18px rgba(40,30,90,.45)' }, }, component: () => import('../pages/styles/MacosPage.vue'), + subPages: [ + { path: 'launchpad', title: '启动台', component: () => import('../pages/styles/sub/MacLaunchpadPage.vue') }, + ], }, { id: 'typewriter', @@ -745,6 +864,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/TypewriterPage.vue'), + subPages: [ + { path: 'letter', title: '深夜写信室', component: () => import('../pages/styles/sub/TypewriterLetterPage.vue') }, + ], }, { id: 'telegram', @@ -767,6 +889,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/TelegramPage.vue'), + subPages: [ + { path: 'morse', title: '摩斯发报机', component: () => import('../pages/styles/sub/TelegramMorsePage.vue') }, + ], }, { id: 'polaroid', @@ -789,6 +914,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/PolaroidPage.vue'), + subPages: [ + { path: 'darkroom', title: '暗房显影', component: () => import('../pages/styles/sub/PolaroidDarkroomPage.vue') }, + ], }, { id: 'win11', @@ -810,6 +938,9 @@ export const styleList = [ }, }, component: () => import('../pages/styles/Win11Page.vue'), + subPages: [ + { path: 'settings', title: '设置中心', component: () => import('../pages/styles/sub/Win11SettingsPage.vue') }, + ], }, { id: 'gameboy', @@ -827,6 +958,9 @@ export const styleList = [ style: { color: '#33440c', fontFamily: '"Press Start 2P", monospace', fontSize: '15px', transform: 'translateY(-14px)' }, }, component: () => import('../pages/styles/GameboyPage.vue'), + subPages: [ + { path: 'stack', title: '方块堆塔', component: () => import('../pages/styles/sub/GameboyStackPage.vue') }, + ], }, { id: 'ipod', @@ -844,6 +978,9 @@ export const styleList = [ style: {}, }, component: () => import('../pages/styles/IpodPage.vue'), + subPages: [ + { path: 'coverflow', title: '专辑长廊', component: () => import('../pages/styles/sub/IpodCoverflowPage.vue') }, + ], }, { id: 'crt-tv', @@ -861,6 +998,9 @@ export const styleList = [ style: {}, }, component: () => import('../pages/styles/CrtTvPage.vue'), + subPages: [ + { path: 'channels', title: '节目单', component: () => import('../pages/styles/sub/CrtChannelsPage.vue') }, + ], }, { id: 'tamagotchi', @@ -878,6 +1018,9 @@ export const styleList = [ style: { color: '#3f5222', fontSize: '24px', transform: 'translateY(-4px)' }, }, component: () => import('../pages/styles/TamagotchiPage.vue'), + subPages: [ + { path: 'care', title: '深度照顾模式', component: () => import('../pages/styles/sub/TamagotchiCarePage.vue') }, + ], }, { id: 'pager', @@ -895,6 +1038,9 @@ export const styleList = [ style: { color: '#24350f', fontFamily: 'Consolas, monospace', fontSize: '26px', fontWeight: 700, transform: 'translateX(-18px)', letterSpacing: '0.14em' }, }, component: () => import('../pages/styles/PagerPage.vue'), + subPages: [ + { path: 'station', title: '寻呼台', component: () => import('../pages/styles/sub/PagerStationPage.vue') }, + ], }, { id: 'wrapped', @@ -912,6 +1058,9 @@ export const styleList = [ style: { color: '#fff', fontFamily: '"Space Grotesk", sans-serif', fontWeight: 700, fontSize: '30px', textShadow: '0 8px 30px rgba(0,0,0,.35)' }, }, component: () => import('../pages/styles/WrappedPage.vue'), + subPages: [ + { path: 'story', title: '故事模式', component: () => import('../pages/styles/sub/WrappedStoryPage.vue') }, + ], }, { id: 'danmaku', @@ -929,6 +1078,9 @@ export const styleList = [ style: { color: '#fb7299', fontSize: '40px', textShadow: '0 0 20px rgba(251,114,153,.6)' }, }, component: () => import('../pages/styles/DanmakuPage.vue'), + subPages: [ + { path: 'pool', title: '弹幕池调控室', component: () => import('../pages/styles/sub/DanmakuPoolPage.vue') }, + ], }, { id: 'wechat-chat', @@ -946,6 +1098,9 @@ export const styleList = [ style: {}, }, component: () => import('../pages/styles/WechatPage.vue'), + subPages: [ + { path: 'moments', title: '朋友圈', component: () => import('../pages/styles/sub/WechatMomentsPage.vue') }, + ], }, { id: 'steam', @@ -963,6 +1118,9 @@ export const styleList = [ style: { color: '#d4af37', fontFamily: '"Space Grotesk", Consolas, monospace', fontSize: '28px', fontWeight: 700, letterSpacing: '0.1em' }, }, component: () => import('../pages/styles/SteamPage.vue'), + subPages: [ + { path: 'achievements', title: '成就墙', component: () => import('../pages/styles/sub/SteamAchievePage.vue') }, + ], }, { id: 'lockscreen', @@ -980,6 +1138,9 @@ export const styleList = [ style: { color: '#fff', fontSize: '44px', fontWeight: 700, textShadow: '0 6px 26px rgba(0,0,0,.4)' }, }, component: () => import('../pages/styles/LockscreenPage.vue'), + subPages: [ + { path: 'pattern', title: '图案解锁', component: () => import('../pages/styles/sub/LockPatternPage.vue') }, + ], }, { id: 'passport', @@ -997,6 +1158,9 @@ export const styleList = [ style: { color: '#b8a06a', fontFamily: '"Ma Shan Zheng", cursive', fontSize: '30px', transform: 'translateY(-12px)' }, }, component: () => import('../pages/styles/PassportPage.vue'), + subPages: [ + { path: 'stamps', title: '出入境集章', component: () => import('../pages/styles/sub/PassportStampPage.vue') }, + ], }, { id: 'checkup', @@ -1014,6 +1178,9 @@ export const styleList = [ style: { color: '#1667d9', fontSize: '30px', transform: 'translate(-64px, -34px)' }, }, component: () => import('../pages/styles/CheckupPage.vue'), + subPages: [ + { path: 'book', title: '复查预约', component: () => import('../pages/styles/sub/CheckupBookPage.vue') }, + ], }, { id: 'credits', @@ -1031,6 +1198,9 @@ export const styleList = [ style: {}, }, component: () => import('../pages/styles/CreditsPage.vue'), + subPages: [ + { path: 'bloopers', title: 'NG 花絮', component: () => import('../pages/styles/sub/CreditsBlooperPage.vue') }, + ], }, { id: 'wiki', @@ -1048,5 +1218,1068 @@ export const styleList = [ style: { color: '#202122', fontFamily: '"Playfair Display", Georgia, serif', fontSize: '48px', transform: 'translateX(-30px)' }, }, component: () => import('../pages/styles/WikiPage.vue'), + subPages: [ + { path: 'history', title: '编辑历史', component: () => import('../pages/styles/sub/WikiHistoryPage.vue') }, + ], + }, + { + id: 'art-deco', + num: '58', + industry: 'art', + industryLabel: '设计流派', + title: '装饰艺术 Art Deco', + intro: '香槟金扇形与对称细框,盖茨比时代的排场', + cover: { + kind: 'gilt', + ck: '#d4b46a', + sub: 'LE MAGNIFIQUE · MMXXVI', + bg: 'conic-gradient(from 180deg at 50% 0%, transparent 0 40%, rgba(212,180,106,.4) 40.5% 41.5%, transparent 42% 46%, rgba(212,180,106,.4) 46.5% 47.5%, transparent 48% 52%, rgba(212,180,106,.4) 52.5% 53.5%, transparent 54% 58%, rgba(212,180,106,.4) 58.5% 59.5%, transparent 60%), linear-gradient(175deg, #101410, #0a0d0b)', + motif: 'NG', + style: { color: '#e8c982', fontFamily: '"Playfair Display", serif', fontWeight: 700, fontSize: '40px', letterSpacing: '0.12em' }, + }, + component: () => import('../pages/styles/ArtDecoPage.vue'), + subPages: [ + { path: 'cabaret', title: '歌舞厅节目单', component: () => import('../pages/styles/sub/ArtDecoCabaretPage.vue') }, + ], + }, + { + id: 'surrealism', + num: '59', + industry: 'art', + industryLabel: '设计流派', + title: '超现实主义', + intro: '天上飘着门与融化的钟,影子比云先落地', + cover: { + kind: 'frame', + ck: 'rgba(43,58,74,.4)', + sub: 'CECI N’EST PAS UNE PAGE', + bg: 'radial-gradient(ellipse 30% 14% at 30% 78%, rgba(43,58,74,.3), transparent 70%), linear-gradient(#4a3a2e 0 0) 30% 30%/13% 26% no-repeat, linear-gradient(178deg, #8fb6d9, #c9d9e8 45%, #e8d9c9 70%, #d9b98f)', + motif: '◷', + style: { color: '#4a3a2e', fontSize: '46px', transform: 'translate(46px, 10px) rotate(-14deg)' }, + }, + component: () => import('../pages/styles/SurrealismPage.vue'), + subPages: [ + { path: 'dream', title: '梦境房间', component: () => import('../pages/styles/sub/SurrealDreamPage.vue') }, + ], + }, + { + id: 'ukiyoe', + num: '60', + industry: 'art', + industryLabel: '设计流派', + title: '浮世绘', + intro: '木刻大浪、团扇技能与四景版画,浮世一页', + cover: { + kind: 'frame', + ck: 'rgba(51,48,42,.75)', + sub: '神奈川 · 糕浪里', + bg: 'radial-gradient(circle at 78% 26%, #c45a3e 0 13px, transparent 14px), radial-gradient(circle at 16% 108%, #2e5d84 0 34%, transparent 35%), radial-gradient(circle at 52% 122%, #1d3a52 0 36%, transparent 37%), linear-gradient(#f2e8d5 60%, #d9cba8)', + motif: '浪', + style: { color: '#1d3a52', fontFamily: '"Ma Shan Zheng", cursive', fontSize: '52px' }, + }, + component: () => import('../pages/styles/UkiyoePage.vue'), + subPages: [ + { path: 'print', title: '套色印刷', component: () => import('../pages/styles/sub/UkiyoePrintPage.vue') }, + ], + }, + { + id: 'psychedelic', + num: '61', + industry: 'art', + industryLabel: '设计流派', + title: '迷幻海报', + intro: '液态大字与同心圆波纹,一张 60s 演出海报', + cover: { + kind: 'holo', + ck: '#ff5ec4', + sub: 'TURN ON · TUNE IN', + bg: 'repeating-radial-gradient(circle at 50% 58%, rgba(255,233,163,.22) 0 9px, transparent 9px 20px), conic-gradient(from 40deg at 50% 55%, #ff5ec4, #ffb020, #5eead4, #9b5cff, #ff5ec4)', + motif: '☮', + style: { color: '#2b0a3d', fontSize: '52px', textShadow: '0 0 18px rgba(255,233,163,.8)' }, + }, + component: () => import('../pages/styles/PsychedelicPage.vue'), + subPages: [ + { path: 'kaleido', title: '万花筒', component: () => import('../pages/styles/sub/PsyKaleidoPage.vue') }, + ], + }, + { + id: 'leather', + num: '62', + industry: 'ui', + industryLabel: '界面潮流', + title: '皮革拟物', + intro: '棕革缝线、铆钉烫金,一本手工皮面简历', + cover: { + kind: 'gilt', + ck: 'rgba(232,201,130,.75)', + sub: 'HANDCRAFTED · EST.2001', + bg: 'repeating-linear-gradient(52deg, rgba(0,0,0,.12) 0 2px, transparent 2px 7px), radial-gradient(ellipse at 30% 16%, rgba(255,255,255,.08), transparent 55%), linear-gradient(165deg, #6b4226, #472b18)', + motif: '¶', + style: { color: '#e8c982', fontFamily: '"Playfair Display", serif', fontSize: '44px', textShadow: '0 -2px 1px rgba(0,0,0,.7), 0 2px 1px rgba(255,236,180,.25)' }, + }, + component: () => import('../pages/styles/LeatherPage.vue'), + subPages: [ + { path: 'emboss', title: '皮标烫印台', component: () => import('../pages/styles/sub/LeatherEmbossPage.vue') }, + ], + }, + { + id: 'eink', + num: '63', + industry: 'ui', + industryLabel: '界面潮流', + title: '墨水屏阅读器', + intro: '灰阶无背光,实体按键翻页带整屏反色刷新', + cover: { + kind: 'frame', + ck: 'rgba(110,106,96,.8)', + sub: '87% · 无背光 · 第 1/4 页', + bg: 'linear-gradient(rgba(87,84,76,.8) 0 0) 50% 26%/54% 2.5px no-repeat, linear-gradient(rgba(87,84,76,.35) 0 0) 50% 40%/54% 1.5px no-repeat, linear-gradient(rgba(87,84,76,.35) 0 0) 50% 50%/54% 1.5px no-repeat, linear-gradient(rgba(87,84,76,.35) 0 0) 50% 60%/40% 1.5px no-repeat, #eceae3', + motif: '墨', + style: { color: '#2e2c28', fontFamily: '"Noto Serif SC", serif', fontWeight: 600, fontSize: '40px', transform: 'translateY(16px)' }, + }, + component: () => import('../pages/styles/EinkPage.vue'), + subPages: [ + { path: 'shelf', title: '墨水屏书架', component: () => import('../pages/styles/sub/EinkShelfPage.vue') }, + ], + }, + { + id: 'terrazzo', + num: '64', + industry: 'ui', + industryLabel: '界面潮流', + title: '水磨石', + intro: '奶油底上撒彩色碎屑,米兰工作室的地面美学', + cover: { + kind: 'frame', + ck: 'rgba(51,48,42,.4)', + sub: 'STUDIO · MILANO 1983', + bg: 'radial-gradient(circle 9px at 22% 30%, #e07856 97%, transparent), radial-gradient(circle 7px at 68% 22%, #3d7068 97%, transparent), radial-gradient(circle 8px at 84% 66%, #e8b64c 97%, transparent), radial-gradient(circle 6px at 38% 72%, #7a89c2 97%, transparent), radial-gradient(circle 5px at 54% 44%, #c25e78 97%, transparent), radial-gradient(circle 4px at 12% 62%, #8a9a5b 97%, transparent), #f4efe6', + motif: 'T.', + style: { color: '#33302a', fontFamily: '"Space Grotesk", sans-serif', fontWeight: 700, fontSize: '40px' }, + }, + component: () => import('../pages/styles/TerrazzoPage.vue'), + subPages: [ + { path: 'mixer', title: '骨料配色器', component: () => import('../pages/styles/sub/TerrazzoMixerPage.vue') }, + ], + }, + { + id: 'cassette', + num: '65', + industry: 'retro', + industryLabel: '复古怀旧', + title: '磁带随身听', + intro: 'A 面技能 B 面作品,卷带会转,翻面有 3D 动画', + cover: { + kind: 'ticket', + ck: 'rgba(232,182,76,.7)', + sub: 'TYPE II · 90min · SIDE A', + bg: 'linear-gradient(#ede4d3 0 0) 50% 26%/64% 26% no-repeat, radial-gradient(circle at 34% 62%, #ede4d3 0 9px, #0f0c09 9.5px 14px, transparent 15px), radial-gradient(circle at 66% 62%, #ede4d3 0 6px, #0f0c09 6.5px 14px, transparent 15px), linear-gradient(170deg, #3a332b, #26211c)', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/CassettePage.vue'), + subPages: [ + { path: 'mix', title: '混音带制作台', component: () => import('../pages/styles/sub/CassetteMixPage.vue') }, + ], + }, + { + id: 'arcade', + num: '66', + industry: 'retro', + industryLabel: '复古怀旧', + title: '街机厅', + intro: '投币选人,技能是格斗角色,作品是一排机台', + cover: { + kind: 'neonbox', + ck: '#ff2bd6', + sub: 'INSERT COIN · CREDIT 00', + bg: 'radial-gradient(circle at 50% 0%, rgba(255,43,214,.3), transparent 55%), repeating-linear-gradient(0deg, rgba(0,0,0,.35) 0 2px, transparent 2px 4px), #120a1e', + motif: '1P', + style: { color: '#ffd23f', fontFamily: '"Press Start 2P", monospace', fontSize: '26px', textShadow: '3px 3px 0 #ff2bd6' }, + }, + component: () => import('../pages/styles/ArcadePage.vue'), + subPages: [ + { path: 'breakout', title: '打砖块机台', component: () => import('../pages/styles/sub/ArcadeBreakoutPage.vue') }, + ], + }, + { + id: 'vhs', + num: '67', + industry: 'retro', + industryLabel: '复古怀旧', + title: 'VHS 录像带', + intro: '走带 OSD、故障色偏与追踪线,快进会起雪花', + cover: { + kind: 'hud', + ck: 'rgba(125,255,154,.7)', + sub: 'SP 0:42:19 · JAN.1 2001', + bg: 'linear-gradient(#ece5d8 0 0) 50% 38%/58% 22% no-repeat, radial-gradient(circle at 36% 70%, #3d3d4a 0 8px, transparent 9px), radial-gradient(circle at 64% 70%, #3d3d4a 0 8px, transparent 9px), repeating-linear-gradient(0deg, rgba(255,255,255,.03) 0 1px, transparent 1px 3px), #0d0d12', + motif: 'PLAY ▶', + style: { color: '#7dff9a', fontFamily: 'Consolas, monospace', fontSize: '22px', letterSpacing: '0.14em', textShadow: '2px 0 rgba(255,43,214,.6), -2px 0 rgba(0,240,255,.6)', transform: 'translateY(-30px)' }, + }, + component: () => import('../pages/styles/VhsPage.vue'), + subPages: [ + { path: 'store', title: '录像带出租店', component: () => import('../pages/styles/sub/VhsStorePage.vue') }, + ], + }, + { + id: 'teletext', + num: '68', + industry: 'retro', + industryLabel: '复古怀旧', + title: '图文电视', + intro: 'P100 色块字符页,底部四色键换台', + cover: { + kind: 'terminal', + ck: '#ffff00', + sub: 'P100 · NIANGAO TEXT', + bg: 'linear-gradient(#ff0000 0 0) 8% 88%/18% 8% no-repeat, linear-gradient(#00ff00 0 0) 32% 88%/18% 8% no-repeat, linear-gradient(#ffff00 0 0) 56% 88%/18% 8% no-repeat, linear-gradient(#00ffff 0 0) 80% 88%/18% 8% no-repeat, #000', + motif: 'P100', + style: { color: '#ffff00', fontFamily: 'Consolas, monospace', fontSize: '34px', fontWeight: 700, transform: 'scaleY(1.3) translateY(-6px)' }, + }, + component: () => import('../pages/styles/TeletextPage.vue'), + subPages: [ + { path: 'pages', title: '页码导航', component: () => import('../pages/styles/sub/TeletextPagesPage.vue') }, + ], + }, + { + id: 'slideshow', + num: '69', + industry: 'retro', + industryLabel: '复古怀旧', + title: '幻灯片放映机', + intro: '暗房光束里咔哒换片,片仓装着整个人生', + cover: { + kind: 'frame', + ck: 'rgba(232,221,202,.35)', + sub: 'CAROUSEL · SLIDE 01/12', + bg: 'linear-gradient(#f6efdd 0 0) 50% 40%/56% 44% no-repeat, linear-gradient(#fff 0 0) 50% 40%/62% 52% no-repeat, radial-gradient(ellipse at 50% 30%, #262024 0%, #141013 70%)', + motif: '▦', + style: { color: '#b5432e', fontSize: '34px', transform: 'translateY(-8px)' }, + }, + component: () => import('../pages/styles/SlideshowPage.vue'), + subPages: [ + { path: 'projector', title: '手动放映机', component: () => import('../pages/styles/sub/SlideProjectorPage.vue') }, + ], + }, + { + id: 'dos-fm', + num: '70', + industry: 'os', + industryLabel: '系统界面', + title: 'DOS 文件管理器', + intro: '蓝底双栏 NC 风,技能是文件,F 键真的能按', + cover: { + kind: 'terminal', + ck: '#55ffff', + sub: 'C:\\NIANGAO> dir /w', + bg: 'linear-gradient(rgba(85,255,255,.6) 0 0) 6% 30%/40% 2px no-repeat, linear-gradient(rgba(85,255,255,.6) 0 0) 54% 30%/40% 2px no-repeat, linear-gradient(#00a8a8 0 0) 6% 46%/40% 9% no-repeat, linear-gradient(rgba(255,255,255,.25) 0 0) 54% 46%/40% 9% no-repeat, #0000a8', + motif: 'F10', + style: { color: '#ffff55', fontFamily: 'Consolas, monospace', fontSize: '30px', transform: 'translateY(18px)' }, + }, + component: () => import('../pages/styles/DosFmPage.vue'), + subPages: [ + { path: 'radio', title: '点歌台', component: () => import('../pages/styles/sub/DosRadioPage.vue') }, + ], + }, + { + id: 'bios', + num: '71', + industry: 'os', + industryLabel: '系统界面', + title: 'BIOS 设置', + intro: '蓝底 Setup Utility,技能全部 Enabled', + cover: { + kind: 'frame', + ck: 'rgba(214,214,214,.55)', + sub: 'F10 Save and Exit', + bg: 'linear-gradient(#d6d6d6 0 0) 0 0/100% 14% no-repeat, linear-gradient(rgba(214,214,214,.3) 0 0) 68% 14%/1.5px 86% no-repeat, linear-gradient(rgba(255,255,136,.5) 0 0) 8% 34%/34% 5% no-repeat, linear-gradient(rgba(102,204,255,.5) 0 0) 8% 50%/26% 5% no-repeat, linear-gradient(rgba(102,204,255,.35) 0 0) 8% 64%/30% 5% no-repeat, #0033aa', + motif: 'BIOS', + style: { color: '#ffff88', fontFamily: 'Consolas, monospace', fontSize: '26px', fontWeight: 700, transform: 'translate(-40px, 14px)' }, + }, + component: () => import('../pages/styles/BiosPage.vue'), + subPages: [ + { path: 'overclock', title: '超频实验室', component: () => import('../pages/styles/sub/BiosOverclockPage.vue') }, + ], + }, + { + id: 'win8-tiles', + num: '72', + industry: 'os', + industryLabel: '系统界面', + title: 'Win8 磁贴', + intro: 'Metro 开始屏,动态磁贴每隔几秒翻个面', + cover: { + kind: 'frame', + ck: 'rgba(255,255,255,.2)', + sub: '开始 · {{ 磁贴会自己翻面 }}', + bg: 'linear-gradient(#2672ec 0 0) 6% 24%/42% 34% no-repeat, linear-gradient(#00a300 0 0) 52% 24%/20% 34% no-repeat, linear-gradient(#da532c 0 0) 76% 24%/20% 34% no-repeat, linear-gradient(#8c0095 0 0) 6% 64%/20% 34% no-repeat, linear-gradient(#00aba9 0 0) 30% 64%/42% 34% no-repeat, linear-gradient(#ae113d 0 0) 76% 64%/20% 34% no-repeat, linear-gradient(160deg, #1c0e46, #251258)', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/Win8Page.vue'), + subPages: [ + { path: 'edit', title: '磁贴编辑', component: () => import('../pages/styles/sub/Win8TileEditPage.vue') }, + ], + }, + { + id: 'android-home', + num: '73', + industry: 'os', + industryLabel: '系统界面', + title: '安卓桌面', + intro: 'Material You 小组件桌面,底部抽屉能拉起来', + cover: { + kind: 'frame', + ck: 'rgba(74,63,102,.4)', + sub: '21:47 · Material You', + bg: 'linear-gradient(#4a3f66 0 0) 50% 34%/74% 24% no-repeat, radial-gradient(circle at 30% 72%, #d96a8b 0 13px, transparent 14px), radial-gradient(circle at 50% 72%, #4a9d7f 0 13px, transparent 14px), radial-gradient(circle at 70% 72%, #d9924a 0 13px, transparent 14px), radial-gradient(ellipse 90% 40% at 80% -6%, rgba(255,200,170,.55), transparent 60%), linear-gradient(170deg, #f4e5dc, #dbe4f2)', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/AndroidPage.vue'), + subPages: [ + { path: 'panel', title: '通知中心', component: () => import('../pages/styles/sub/AndroidPanelPage.vue') }, + ], + }, + { + id: 'music-artist', + num: '74', + industry: 'app', + industryLabel: '应用媒体', + title: '音乐艺人主页', + intro: '认证艺人页:热门单曲是技能,专辑是作品', + cover: { + kind: 'frame', + ck: 'rgba(232,85,109,.5)', + sub: '月度听众 218,433', + bg: 'linear-gradient(rgba(255,255,255,.16) 0 0) 8% 78%/30% 5% no-repeat, linear-gradient(rgba(255,255,255,.16) 0 0) 8% 88%/44% 5% no-repeat, radial-gradient(circle at 82% 30%, #e8556d 0 15%, transparent 16%), radial-gradient(ellipse 80% 90% at 85% 10%, rgba(232,85,109,.4), transparent 60%), linear-gradient(178deg, #43121f, #121014)', + motif: '▶', + style: { color: '#fff', fontSize: '34px', background: '#e8556d', width: '58px', height: '58px', display: 'grid', placeItems: 'center', borderRadius: '50%', transform: 'translate(-60px, 20px)' }, + }, + component: () => import('../pages/styles/MusicArtistPage.vue'), + subPages: [ + { path: 'tour', title: '巡演购票', component: () => import('../pages/styles/sub/MusicTourPage.vue') }, + ], + }, + { + id: 'dating-swipe', + num: '75', + industry: 'app', + industryLabel: '应用媒体', + title: '交友滑卡', + intro: '左滑右滑,把技能都右滑完会配对成功', + cover: { + kind: 'frame', + ck: 'rgba(176,87,109,.35)', + sub: 'LIKE ♥ · 距离你 0.5km', + bg: 'linear-gradient(#fff 0 0) 50% 44%/56% 64% no-repeat, linear-gradient(#f9d2e2 0 0) 50% 30%/56% 36% no-repeat, linear-gradient(#fff 0 0) 38% 50%/56% 64% no-repeat, linear-gradient(170deg, #fdf2f4, #eef0fc)', + motif: '♥', + style: { color: '#f2506e', fontSize: '44px', textShadow: '0 10px 24px rgba(242,80,110,.4)', transform: 'translateY(-6px)' }, + }, + component: () => import('../pages/styles/DatingPage.vue'), + subPages: [ + { path: 'chat', title: '配对聊天', component: () => import('../pages/styles/sub/DatingChatPage.vue') }, + ], + }, + { + id: 'food-delivery', + num: '76', + industry: 'app', + industryLabel: '应用媒体', + title: '外卖点单', + intro: '技能是招牌菜,加购结算,月售 2360 单', + cover: { + kind: 'frame', + ck: 'rgba(38,40,46,.25)', + sub: '★4.9 · 蓝骑士专送 28 分钟', + bg: 'linear-gradient(#26282e 0 0) 50% 88%/78% 11% no-repeat, linear-gradient(#fff 0 0) 50% 52%/78% 26% no-repeat, linear-gradient(#ffd524 0 0) 0 0/100% 38% no-repeat, #f5f6f8', + motif: '🛵', + style: { fontSize: '44px', transform: 'translateY(-24px)', filter: 'drop-shadow(0 8px 12px rgba(255,150,0,.4))' }, + }, + component: () => import('../pages/styles/FoodDeliveryPage.vue'), + subPages: [ + { path: 'order', title: '下单配送', component: () => import('../pages/styles/sub/FoodOrderPage.vue') }, + ], + }, + { + id: 'email-inbox', + num: '77', + industry: 'app', + industryLabel: '应用媒体', + title: '邮箱收件箱', + intro: '三栏邮箱,每封邮件都是一段人生通知', + cover: { + kind: 'window', + os: 'mac', + winTitle: '收件箱 (3) — hi@niangao.dev', + bg: 'linear-gradient(#e8ecfb 0 0) 0 24px/34% 100% no-repeat, linear-gradient(#4a63d0 0 0) 5% 36%/24% 9% no-repeat, linear-gradient(#e4e7ee 0 0) 42% 34%/50% 5% no-repeat, linear-gradient(#e4e7ee 0 0) 42% 48%/40% 5% no-repeat, linear-gradient(#e4e7ee 0 0) 42% 62%/46% 5% no-repeat, #fbfcfe', + motif: '✉', + style: { color: '#4a63d0', fontSize: '36px', transform: 'translate(56px, 26px)' }, + }, + component: () => import('../pages/styles/EmailInboxPage.vue'), + subPages: [ + { path: 'compose', title: '写邮件', component: () => import('../pages/styles/sub/EmailComposePage.vue') }, + ], + }, + { + id: 'streaming-shelf', + num: '78', + industry: 'app', + industryLabel: '应用媒体', + title: '流媒体片架', + intro: '首页海报排架 hover 放大,人生剧集 98% 匹配', + cover: { + kind: 'frame', + ck: 'rgba(227,59,78,.5)', + sub: '#1 · 今日程序员榜', + bg: 'linear-gradient(160deg, #43265e, #241436) 6% 76%/26% 34% no-repeat, linear-gradient(160deg, #14406e, #0c2440) 38% 76%/26% 34% no-repeat, linear-gradient(160deg, #5e2626, #361414) 70% 76%/26% 34% no-repeat, radial-gradient(ellipse 70% 60% at 78% 10%, rgba(227,59,78,.45), transparent 60%), #101014', + motif: 'N', + style: { color: '#e33b4e', fontWeight: 900, fontSize: '52px', textShadow: '0 0 30px rgba(227,59,78,.6)', transform: 'translateY(-16px)' }, + }, + component: () => import('../pages/styles/StreamingShelfPage.vue'), + subPages: [ + { path: 'play', title: '播放页', component: () => import('../pages/styles/sub/StreamingPlayPage.vue') }, + ], + }, + { + id: 'papercut', + num: '79', + industry: 'paper', + industryLabel: '纸品手作', + title: '中式剪纸', + intro: '大红镂空窗花、灯笼技能串与一副对联', + cover: { + kind: 'guofeng', + ck: '#ffe9c9', + seal: '剪', + bg: 'radial-gradient(circle at 50% 44%, #ffe9c9 0 15%, transparent 16%), repeating-conic-gradient(from 22deg at 50% 44%, rgba(255,233,201,.85) 0 9deg, transparent 9deg 45deg), repeating-linear-gradient(45deg, rgba(150,20,16,.35) 0 2px, transparent 2px 14px), linear-gradient(170deg, #b31f16, #8e150e)', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/PapercutPage.vue'), + subPages: [ + { path: 'window', title: '剪窗花', component: () => import('../pages/styles/sub/PapercutWindowPage.vue') }, + ], + }, + { + id: 'blackboard', + num: '80', + industry: 'paper', + industryLabel: '纸品手作', + title: '黑板粉笔', + intro: '墨绿板面手写体,课程表、黑板报与粉笔槽', + cover: { + kind: 'frame', + ck: 'rgba(255,215,106,.5)', + sub: '第 8 周 · 值日生:年糕', + bg: 'linear-gradient(rgba(255,215,106,.8) 0 0) 50% 34%/44% 3px no-repeat, linear-gradient(rgba(247,168,196,.7) 0 0) 30% 56%/28% 3px no-repeat, linear-gradient(rgba(158,230,195,.6) 0 0) 66% 70%/24% 3px no-repeat, radial-gradient(ellipse 60% 40% at 26% 20%, rgba(255,255,255,.05), transparent 60%), #234436', + motif: '板書', + style: { color: '#f4f0e4', fontFamily: '"Long Cang", cursive', fontSize: '42px', textShadow: '0 0 8px rgba(244,240,228,.35)', transform: 'rotate(-2deg)' }, + }, + component: () => import('../pages/styles/BlackboardPage.vue'), + subPages: [ + { path: 'quiz', title: '随堂小测', component: () => import('../pages/styles/sub/BlackboardQuizPage.vue') }, + ], + }, + { + id: 'award', + num: '81', + industry: 'paper', + industryLabel: '纸品手作', + title: '小学奖状', + intro: '红花烫金边三好学生,一面贴满奖状的墙', + cover: { + kind: 'gilt', + ck: '#d8ab4a', + sub: '以资鼓励 · 特发此状', + bg: 'radial-gradient(circle at 82% 74%, rgba(179,64,46,.4) 0 26px, transparent 27px), radial-gradient(ellipse at 50% 0%, rgba(255,215,106,.25), transparent 55%), #fdf8ea', + motif: '奖 状', + style: { color: '#b3402e', fontFamily: '"Noto Serif SC", serif', fontWeight: 900, fontSize: '38px', letterSpacing: '0.5em', textIndent: '0.5em', textShadow: '0 2px 0 rgba(216,171,74,.5)' }, + }, + component: () => import('../pages/styles/AwardPage.vue'), + subPages: [ + { path: 'gallery', title: '奖杯陈列室', component: () => import('../pages/styles/sub/AwardGalleryPage.vue') }, + ], + }, + { + id: 'tarot', + num: '82', + industry: 'object', + industryLabel: '拟真物件', + title: '塔罗牌阵', + intro: '技能六芒牌阵,点牌翻面读牌意', + cover: { + kind: 'gilt', + ck: 'rgba(232,201,130,.7)', + sub: '月光牌屋 · 只占技术运', + bg: 'linear-gradient(#241c48 0 0) 30% 50%/22% 62% no-repeat, linear-gradient(#f4ead0 0 0) 56% 44%/22% 62% no-repeat, radial-gradient(1.5px 1.5px at 80% 24%, rgba(232,201,130,.9), transparent), radial-gradient(ellipse at 50% -10%, #2e2450, #171232 60%)', + motif: '✶', + style: { color: '#e8c982', fontSize: '30px', textShadow: '0 0 22px rgba(232,201,130,.9)', transform: 'translate(-31px, 4px)' }, + }, + component: () => import('../pages/styles/TarotPage.vue'), + subPages: [ + { path: 'draw', title: '三牌阵占卜', component: () => import('../pages/styles/sub/TarotDrawPage.vue') }, + ], + }, + { + id: 'vending', + num: '83', + industry: 'object', + industryLabel: '拟真物件', + title: '自动售货机', + intro: '投币买技能饮料,作品盲盒真的会掉下来', + cover: { + kind: 'frame', + ck: 'rgba(255,244,224,.4)', + sub: 'CREDIT: 0 · 点击投币', + bg: 'linear-gradient(#1c1424 0 0) 50% 42%/64% 52% no-repeat, linear-gradient(#4ea6d9 0 0) 30% 30%/13% 20% no-repeat, linear-gradient(#5cc26a 0 0) 47% 30%/13% 20% no-repeat, linear-gradient(#e8a03c 0 0) 64% 30%/13% 20% no-repeat, linear-gradient(#7c6cff 0 0) 30% 56%/13% 18% no-repeat, linear-gradient(#ff7c9e 0 0) 47% 56%/13% 18% no-repeat, linear-gradient(#4dd0b2 0 0) 64% 56%/13% 18% no-repeat, linear-gradient(170deg, #d94f4f, #b23a3a)', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/VendingPage.vue'), + subPages: [ + { path: 'restock', title: '补货员小游戏', component: () => import('../pages/styles/sub/VendingRestockPage.vue') }, + ], + }, + { + id: 'lego-manual', + num: '84', + industry: 'object', + industryLabel: '拟真物件', + title: '积木说明书', + intro: '分步拼装一个我,咬合强度即技能熟练度', + cover: { + kind: 'frame', + ck: 'rgba(35,38,46,.5)', + sub: 'SET N° 2001 · 25+ ', + bg: 'linear-gradient(#d94f3c 0 0) 26% 60%/17% 15% no-repeat, linear-gradient(#2b7bd9 0 0) 43.5% 60%/17% 15% no-repeat, linear-gradient(#3fa64d 0 0) 61% 60%/17% 15% no-repeat, linear-gradient(#23262e 0 0) 26% 44%/52% 3px no-repeat, linear-gradient(160deg, #ffd900, #ffb800)', + motif: '⌇', + style: { color: '#23262e', fontWeight: 900, fontSize: '40px', transform: 'translateY(-28px) rotate(90deg)' }, + }, + component: () => import('../pages/styles/LegoManualPage.vue'), + subPages: [ + { path: 'build', title: '拼装台', component: () => import('../pages/styles/sub/LegoBuildPage.vue') }, + ], + }, + { + id: 'board-game', + num: '85', + industry: 'object', + industryLabel: '拟真物件', + title: '人生桌游', + intro: '掷骰子走格子,走到终点领联系方式', + cover: { + kind: 'grid', + ck: 'rgba(51,64,46,.3)', + sub: 'ROLL THE DICE · 15 格', + bg: 'linear-gradient(#cdeacb 0 0) 12% 28%/22% 24% no-repeat, linear-gradient(#dbe8fb 0 0) 40% 28%/22% 24% no-repeat, linear-gradient(#fbdbe4 0 0) 68% 28%/22% 24% no-repeat, linear-gradient(#f3f0d8 0 0) 26% 62%/22% 24% no-repeat, linear-gradient(#f9e2b8 0 0) 54% 62%/22% 24% no-repeat, #eef0e4', + motif: '🎲', + style: { fontSize: '40px', transform: 'translate(58px, 26px) rotate(12deg)', filter: 'drop-shadow(0 6px 8px rgba(51,64,46,.35))' }, + }, + component: () => import('../pages/styles/BoardGamePage.vue'), + subPages: [ + { path: 'fly', title: '人生飞行棋', component: () => import('../pages/styles/sub/BoardGameFlyPage.vue') }, + ], + }, + { + id: 'deepsea', + num: '86', + industry: 'neon', + industryLabel: '暗夜光效', + title: '深海荧光', + intro: '水母提灯,发光浮游生物驮着技能上浮', + cover: { + kind: 'hud', + ck: 'rgba(94,234,212,.55)', + sub: '深度 -3800m · 生物荧光', + bg: 'radial-gradient(ellipse 30% 22% at 50% 34%, rgba(255,158,203,.75), rgba(155,92,255,.35) 60%, transparent 75%), radial-gradient(3px 3px at 24% 70%, rgba(94,234,212,.8), transparent), radial-gradient(2px 2px at 72% 58%, rgba(94,234,212,.7), transparent), radial-gradient(2.5px 2.5px at 58% 84%, rgba(255,158,203,.6), transparent), linear-gradient(180deg, #04222e, #020a14)', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/DeepseaPage.vue'), + subPages: [ + { path: 'dive', title: '深潜图鉴', component: () => import('../pages/styles/sub/DeepseaDivePage.vue') }, + ], + }, + { + id: 'astrolabe', + num: '87', + industry: 'neon', + industryLabel: '暗夜光效', + title: '占星星图', + intro: '金线蚀刻星盘,技能连成年糕座,悬停读星等', + cover: { + kind: 'gilt', + ck: 'rgba(212,183,106,.7)', + sub: '年糕座 · 观测 No.25', + bg: 'radial-gradient(circle at 50% 50%, transparent 0 24%, rgba(212,183,106,.5) 24.5% 25.5%, transparent 26% 34%, rgba(212,183,106,.3) 34.5% 35.5%, transparent 36%), radial-gradient(1.6px 1.6px at 38% 38%, #f2ebd8, transparent), radial-gradient(1.4px 1.4px at 64% 56%, #f2ebd8, transparent), radial-gradient(1.2px 1.2px at 50% 28%, #d4b76a, transparent), radial-gradient(ellipse at 50% 0%, #14203d, #070c1a)', + motif: '✦', + style: { color: '#f2ebd8', fontSize: '24px', textShadow: '0 0 18px rgba(212,183,106,.95)', transform: 'translate(18px, -12px)' }, + }, + component: () => import('../pages/styles/AstrolabePage.vue'), + subPages: [ + { path: 'connect', title: '连星成座', component: () => import('../pages/styles/sub/AstroConnectPage.vue') }, + ], + }, + { + id: 'mario', + num: '88', + industry: 'game', + industryLabel: '游戏动漫', + title: '马里奥', + intro: '蓝天砖块金币水管的 1-1 关,顶砖块真的蹦金币', + cover: { + kind: 'pixelframe', + ck: '#fbd000', + sub: 'WORLD 1-1 · COIN ×00', + bg: 'linear-gradient(#e49820 0 0) 30% 44%/13% 13% no-repeat, linear-gradient(#e49820 0 0) 46% 44%/13% 13% no-repeat, linear-gradient(#e49820 0 0) 62% 44%/13% 13% no-repeat, linear-gradient(#3fa64d 0 0) 78% 66%/14% 34% no-repeat, radial-gradient(circle at 20% 22%, #fcfcfc 0 8px, transparent 9px), linear-gradient(#e45c10 0 0) 0 100%/100% 14% no-repeat, #5c94fc', + motif: '?', + style: { color: '#fce0a8', fontFamily: '"Press Start 2P", monospace', fontSize: '20px', transform: 'translate(-31px, -8px)' }, + }, + component: () => import('../pages/styles/MarioPage.vue'), + subPages: [ + { path: 'run', title: '1-1 跑酷', component: () => import('../pages/styles/sub/MarioRunPage.vue') }, + ], + }, + { + id: 'circus', + num: '89', + industry: 'game', + industryLabel: '游戏动漫', + title: '马戏团', + intro: '红白帐篷下狮子跳火圈,一圈一个技能', + cover: { + kind: 'frame', + ck: 'rgba(232,182,76,.6)', + sub: '今晚 8 点 · 加演一场', + bg: 'radial-gradient(circle at 50% 60%, transparent 0 17%, #cf3345 17.5% 22%, #e8b64c 22.5% 24%, transparent 24.5%), repeating-linear-gradient(90deg, #cf3345 0 26px, #f6ead2 26px 52px) 0 0/100% 22% no-repeat, radial-gradient(ellipse 90% 50% at 50% 115%, rgba(232,182,76,.2), transparent 60%), #1c1030', + motif: '🦁', + style: { fontSize: '38px', transform: 'translateY(10px)', filter: 'drop-shadow(0 6px 10px rgba(0,0,0,.5))' }, + }, + component: () => import('../pages/styles/CircusPage.vue'), + subPages: [ + { path: 'show', title: '互动马戏', component: () => import('../pages/styles/sub/CircusShowPage.vue') }, + ], + }, + { + id: 'snow-bros', + num: '90', + industry: 'game', + industryLabel: '游戏动漫', + title: '雪人兄弟', + intro: '冰蓝塔楼一层一技能,点雪球推下楼再滚回来', + cover: { + kind: 'pixelframe', + ck: '#7fd4ff', + sub: 'FLOOR 1-6 · SNOW!', + bg: 'radial-gradient(circle at 32% 62%, #fff 0 13px, #d8ecf8 14px 17px, transparent 18px), radial-gradient(circle at 3px 3px, rgba(234,244,255,.85) 1.2px, transparent 2px) 0 0/34px 34px, linear-gradient(#b8e2f8 0 0) 0 78%/100% 7px no-repeat, linear-gradient(180deg, #0c1c3d, #1c4a74)', + motif: '☃', + style: { color: '#eaf4ff', fontSize: '40px', transform: 'translate(30px, -10px)', textShadow: '0 0 20px rgba(127,212,255,.8)' }, + }, + component: () => import('../pages/styles/SnowBrosPage.vue'), + subPages: [ + { path: 'roll', title: '推雪球', component: () => import('../pages/styles/sub/SnowRollPage.vue') }, + ], + }, + { + id: 'bomber', + num: '91', + industry: 'game', + industryLabel: '游戏动漫', + title: '炸弹堂', + intro: '俯视网格放炸弹,十字爆炸开砖块炸出技能', + cover: { + kind: 'pixelframe', + ck: '#7c6cff', + sub: 'BOMB! · 技能 0/6', + bg: 'linear-gradient(#6e648f 0 0) 26% 30%/16% 22% no-repeat, linear-gradient(#6e648f 0 0) 58% 30%/16% 22% no-repeat, linear-gradient(#c98a4b 0 0) 42% 56%/16% 22% no-repeat, linear-gradient(#c98a4b 0 0) 74% 56%/16% 22% no-repeat, linear-gradient(#3d3161 0 0) 8% 8%/84% 84% no-repeat, #17102a', + motif: '💣', + style: { fontSize: '36px', transform: 'translate(-26px, 12px)', filter: 'drop-shadow(0 0 14px rgba(255,176,32,.7))' }, + }, + component: () => import('../pages/styles/BomberPage.vue'), + subPages: [ + { path: 'maze', title: '炸墙寻宝', component: () => import('../pages/styles/sub/BomberMazePage.vue') }, + ], + }, + { + id: 'ski-safari', + num: '92', + industry: 'game', + industryLabel: '游戏动漫', + title: '滑雪大冒险', + intro: '无尽滑坡身后追着 deadline 雪崩,点击后空翻', + cover: { + kind: 'frame', + ck: 'rgba(35,64,92,.3)', + sub: '3,721m · 雪崩:急了', + bg: 'radial-gradient(circle at 82% 18%, #ffd76a 0 11px, transparent 12px), radial-gradient(circle at 12% 66%, #fff 0 16px, #dcebf5 17px 22px, transparent 23px), radial-gradient(circle at 26% 58%, #fff 0 12px, transparent 13px), linear-gradient(-7deg, #fff 0 34%, transparent 34.5%), linear-gradient(180deg, #aee3f7, #d8f1fb)', + motif: '⛷', + style: { fontSize: '42px', transform: 'translate(14px, -6px) rotate(-8deg)', filter: 'drop-shadow(0 6px 8px rgba(35,64,92,.3))' }, + }, + component: () => import('../pages/styles/SkiSafariPage.vue'), + subPages: [ + { path: 'run', title: '雪崩快跑', component: () => import('../pages/styles/sub/SkiRunPage.vue') }, + ], + }, + { + id: 'lol', + num: '93', + industry: 'game', + industryLabel: '游戏动漫', + title: '英雄联盟', + intro: '海克斯金框选人界面,锁定英雄看熟练度与战绩', + cover: { + kind: 'hud', + ck: 'rgba(200,170,110,.65)', + sub: 'BAN / PICK · 30s', + bg: 'linear-gradient(#0a1e2c 0 0) 16% 40%/16% 26% no-repeat, linear-gradient(#0a1e2c 0 0) 35% 40%/16% 26% no-repeat, linear-gradient(rgba(10,200,185,.35) 0 0) 54% 40%/16% 26% no-repeat, linear-gradient(#0a1e2c 0 0) 73% 40%/16% 26% no-repeat, linear-gradient(rgba(200,170,110,.5) 0 0) 16% 74%/73% 2px no-repeat, radial-gradient(ellipse 70% 44% at 82% 0%, rgba(12,74,96,.55), transparent 62%), #071019', + motif: '⌛', + style: { color: '#0ac8b9', fontSize: '30px', transform: 'translate(0, 24px)', textShadow: '0 0 18px rgba(10,200,185,.7)' }, + }, + component: () => import('../pages/styles/LolPage.vue'), + subPages: [ + { path: 'build', title: '出装模拟器', component: () => import('../pages/styles/sub/LolBuildPage.vue') }, + ], + }, + { + id: 'crossfire', + num: '94', + industry: 'game', + industryLabel: '游戏动漫', + title: '穿越火线', + intro: 'FPS 视窗:准星跟手、点击开火留弹孔、击杀播报', + cover: { + kind: 'hud', + ck: 'rgba(125,232,125,.6)', + sub: 'ROUND 25 · 爆破模式', + bg: 'linear-gradient(rgba(125,232,125,.8) 0 0) 50% 50%/2px 16% no-repeat, linear-gradient(rgba(125,232,125,.8) 0 0) 50% 50%/12% 2px no-repeat, radial-gradient(circle at 50% 50%, transparent 0 10%, rgba(125,232,125,.28) 10.5% 11.5%, transparent 12%), repeating-linear-gradient(45deg, rgba(122,134,92,.12) 0 18px, transparent 18px 36px), linear-gradient(170deg, #1d2416, #12160c)', + motif: '30', + style: { color: '#f0f3e4', fontFamily: '"Space Grotesk", monospace', fontSize: '30px', fontWeight: 700, transform: 'translate(74px, 34px)' }, + }, + component: () => import('../pages/styles/CrossfirePage.vue'), + subPages: [ + { path: 'range', title: '靶场特训', component: () => import('../pages/styles/sub/CfRangePage.vue') }, + ], + }, + { + id: 'seer', + num: '95', + industry: 'game', + industryLabel: '游戏动漫', + title: '赛尔号', + intro: '蓝白舰桥点精灵球放出技能精灵,项目是登陆过的星球', + cover: { + kind: 'frame', + ck: 'rgba(142,208,255,.5)', + sub: '船长权限 · 能源 100%', + bg: 'radial-gradient(circle at 30% 56%, #4ea6d9 0 13px, #10234a 13.5px 16px, #e4eeff 16.5px 19px, transparent 20px), radial-gradient(circle at 68% 40%, hsl(150 62% 46%) 0 15px, transparent 16px), radial-gradient(1.4px 1.4px at 84% 20%, #fff, transparent), radial-gradient(1px 1px at 16% 24%, #fff, transparent), radial-gradient(ellipse 90% 60% at 50% -14%, #1c3a6e, #0a1530)', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/SeerPage.vue'), + subPages: [ + { path: 'battle', title: '精灵对战', component: () => import('../pages/styles/sub/SeerBattlePage.vue') }, + ], + }, + { + id: 'jay-chou', + num: '96', + industry: 'retro', + industryLabel: '复古怀旧', + title: '周杰伦致敬', + intro: '礼帽黑胶专辑墙,还有一间能录音跟谱的钢琴房', + cover: { + kind: 'frame', + ck: 'rgba(201,184,242,.4)', + sub: '「糕调」巡回 · 哎哟不错哦', + bg: 'linear-gradient(#fdfcf8 0 0) 12% 78%/9% 34% no-repeat, linear-gradient(#fdfcf8 0 0) 22.5% 78%/9% 34% no-repeat, linear-gradient(#fdfcf8 0 0) 33% 78%/9% 34% no-repeat, linear-gradient(#fdfcf8 0 0) 43.5% 78%/9% 34% no-repeat, linear-gradient(#17121f 0 0) 17% 68%/5% 20% no-repeat, linear-gradient(#17121f 0 0) 28% 68%/5% 20% no-repeat, radial-gradient(ellipse 60% 36% at 22% 0%, rgba(122,92,220,.4), transparent 60%), #100c16', + motif: '♪', + style: { color: '#c9b8f2', fontSize: '44px', transform: 'translate(50px, -22px)', textShadow: '0 0 24px rgba(122,92,220,.7)' }, + }, + component: () => import('../pages/styles/JayChouPage.vue'), + subPages: [ + { path: 'piano', title: '杰伦钢琴房', component: () => import('../pages/styles/JayPianoPage.vue') }, + ], + }, + { + id: 'bikini-bottom', + num: '97', + industry: 'game', + industryLabel: '游戏动漫', + title: '比奇堡', + intro: '菠萝屋、上浮气泡与连点组装的美味蟹堡', + cover: { + kind: 'crayon', + ck: 'rgba(255,231,92,.8)', + sub: '贝壳街 124 号 · 我准备好了!', + bg: 'radial-gradient(circle at 24% 62%, #ffb838 0 22px, #b26c18 22.5px 25px, transparent 26px), radial-gradient(circle at 78% 30%, rgba(255,255,255,.5) 0 7px, transparent 8px), radial-gradient(circle at 64% 66%, rgba(255,255,255,.4) 0 5px, transparent 6px), linear-gradient(180deg, #56c2e8, #2e9ad0)', + motif: '🍍', + style: { fontSize: '40px', transform: 'translate(38px, 8px)', filter: 'drop-shadow(0 6px 10px rgba(18,58,84,.4))' }, + }, + component: () => import('../pages/styles/BikiniBottomPage.vue'), + subPages: [ + { path: 'cook', title: '蟹堡王打工', component: () => import('../pages/styles/sub/KrustyCookPage.vue') }, + ], + }, + { + id: 'mickey', + num: '98', + industry: 'game', + industryLabel: '游戏动漫', + title: '米奇妙妙屋风', + intro: '三圆头卡片、抽妙妙工具,还能让全页跳热狗舞', + cover: { + kind: 'crayon', + ck: '#f2503c', + sub: '哦!妙妙工具!', + bg: 'radial-gradient(circle at 33% 30%, #22180f 0 12px, transparent 13px), radial-gradient(circle at 67% 30%, #22180f 0 12px, transparent 13px), radial-gradient(circle at 50% 52%, #22180f 0 24px, transparent 25px), radial-gradient(circle 4px at 14% 78%, #f2503c 97%, transparent), radial-gradient(circle 4px at 82% 72%, #4ea6d9 97%, transparent), radial-gradient(circle 4px at 62% 86%, #ffd23f 97%, transparent), linear-gradient(175deg, #fff8e8, #ffefd0)', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/MickeyPage.vue'), + subPages: [ + { path: 'tool', title: '妙妙工具屋', component: () => import('../pages/styles/sub/MickeyToolPage.vue') }, + ], + }, + { + id: 'ouija', + num: '99', + industry: 'horror', + industryLabel: '恐怖惊悚', + title: '通灵板', + intro: '午夜降灵:提问后乩板滑动,逐字母拼出回答', + cover: { + kind: 'gilt', + ck: 'rgba(217,198,168,.45)', + sub: 'SÉANCE · 00:00', + bg: 'linear-gradient(160deg, rgba(85,64,43,.95), rgba(58,40,24,.95)) 50% 40%/26% 34% no-repeat, radial-gradient(circle at 50% 36%, rgba(236,217,184,.35) 0 7px, transparent 8px), repeating-linear-gradient(84deg, rgba(0,0,0,.24) 0 4px, transparent 4px 30px), linear-gradient(170deg, #3a2818, #17100c)', + motif: 'A·Z', + style: { color: '#d9c6a8', fontFamily: '"Playfair Display", serif', fontSize: '22px', letterSpacing: '0.3em', transform: 'translateY(34px)' }, + }, + component: () => import('../pages/styles/OuijaPage.vue'), + subPages: [ + { path: 'ask', title: '降灵问答', component: () => import('../pages/styles/sub/OuijaAskPage.vue') }, + ], + }, + { + id: 'haunted-house', + num: '100', + industry: 'horror', + industryLabel: '恐怖惊悚', + title: '凶宅出售', + intro: '幽灵地产急售独栋:缺陷依法披露,看房请赶白天', + cover: { + kind: 'frame', + ck: 'rgba(154,122,208,.4)', + sub: '¥25,999/整栋 · 急售', + bg: 'radial-gradient(circle at 80% 20%, #f4eed8 0 9px, transparent 10px), linear-gradient(#0c0916 0 0) 38% 30%/6% 10% no-repeat, conic-gradient(from 90deg at 50% 0%, transparent 42%, #0c0916 42% 58%, transparent 58%) 50% 22%/44% 22% no-repeat, linear-gradient(#231a36 0 0) 50% 52%/34% 38% no-repeat, linear-gradient(rgba(255,223,142,.85) 0 0) 42% 48%/7% 9% no-repeat, linear-gradient(180deg, #1c1430 0 74%, #0f0b18 74%)', + motif: '👻', + style: { fontSize: '26px', transform: 'translate(-44px, -14px)', filter: 'drop-shadow(0 0 12px rgba(207,196,221,.6))' }, + }, + component: () => import('../pages/styles/HauntedHousePage.vue'), + subPages: [ + { path: 'explore', title: '手电探房', component: () => import('../pages/styles/sub/HauntedFlashPage.vue') }, + ], + }, + { + id: 'cctv', + num: '101', + industry: 'horror', + industryLabel: '恐怖惊悚', + title: '深夜监控', + intro: '四分屏 CCTV,03:33 的走廊偶尔会走过一个影子', + cover: { + kind: 'terminal', + ck: '#7de89a', + sub: 'CAM-03 · 03:33:33 REC', + bg: 'linear-gradient(rgba(184,196,188,.12) 0 0) 50% 0/1.5px 100% no-repeat, linear-gradient(rgba(184,196,188,.12) 0 0) 0 52%/100% 1.5px no-repeat, radial-gradient(circle at 78% 24%, rgba(224,81,81,.9) 0 4px, transparent 5px), linear-gradient(rgba(4,5,4,.9) 0 0) 30% 78%/7% 24% no-repeat, repeating-linear-gradient(0deg, rgba(0,0,0,.3) 0 2px, transparent 2px 4px), #0c0f0d', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/CctvPage.vue'), + subPages: [ + { path: 'grid', title: '九路监控', component: () => import('../pages/styles/sub/CctvGridPage.vue') }, + ], + }, + { + id: 'talisman', + num: '102', + industry: 'horror', + industryLabel: '恐怖惊悚', + title: '镇魂符咒', + intro: '中式义庄:红灯笼忽明忽暗,点击贴符封印代码妖', + cover: { + kind: 'guofeng', + ck: 'rgba(216,200,168,.55)', + seal: '封', + bg: 'linear-gradient(#e8c96a 0 0) 50% 44%/17% 52% no-repeat, radial-gradient(circle at 50% 30%, rgba(138,32,24,.85) 0 7px, transparent 8px), radial-gradient(ellipse at 16% 12%, rgba(192,57,43,.5) 0 12%, transparent 30%), repeating-linear-gradient(90deg, rgba(0,0,0,.32) 0 2px, transparent 2px 56px), #100b09', + motif: '', + style: {}, + }, + component: () => import('../pages/styles/TalismanPage.vue'), + subPages: [ + { path: 'draw', title: '画符开光', component: () => import('../pages/styles/sub/TalismanDrawPage.vue') }, + ], + }, + { + id: 'monster-movie', + num: '103', + industry: 'horror', + industryLabel: '恐怖惊悚', + title: '怪物片场夜', + intro: '午夜双片连映:滴血片名、跑马灯与会眨眼的海报', + cover: { + kind: 'neonbox', + ck: '#e2a13c', + sub: 'MIDNIGHT · ADMIT ONE', + bg: 'radial-gradient(circle at 40% 42%, #ffd76a 0 4px, hsl(16 80% 52%) 5px 8px, transparent 9px), radial-gradient(circle at 60% 42%, #ffd76a 0 4px, hsl(16 80% 52%) 5px 8px, transparent 9px), radial-gradient(ellipse 66% 36% at 50% 0%, rgba(226,116,36,.25), transparent 60%), linear-gradient(178deg, #2a1430, #150d1c)', + motif: '代码怪物', + style: { color: '#f2503c', fontFamily: '"Noto Serif SC", serif', fontWeight: 900, fontSize: '30px', textShadow: '0 0 20px rgba(242,80,60,.6), 3px 4px 0 #6e1810', transform: 'translateY(26px)' }, + }, + component: () => import('../pages/styles/MonsterMoviePage.vue'), + subPages: [ + { path: 'screening', title: '午夜放映厅', component: () => import('../pages/styles/sub/MonsterScreeningPage.vue') }, + ], + }, + { + id: 'bilibili-space', + num: '104', + industry: 'app', + industryLabel: '应用媒体', + title: 'B站空间风', + intro: 'UP主个人空间:投稿墙、充电榜,进视频页发弹幕一键三连', + cover: { + kind: 'app', + ck: '#fb7299', + sub: '2.3万粉丝 · LV6', + bg: 'radial-gradient(circle at 24% 22%, rgba(0,174,236,.5), transparent 50%), linear-gradient(rgba(255,255,255,.92) 0 0) 50% 72%/78% 34% no-repeat, linear-gradient(150deg, #7ec3e8, #f6c3d4)', + motif: '(゜-゜)つロ', + style: { color: '#4a6b80', fontSize: '17px', fontWeight: 700, transform: 'translateY(-24px)' }, + }, + component: () => import('../pages/styles/BilibiliPage.vue'), + subPages: [ + { path: 'video', title: '视频播放页', component: () => import('../pages/styles/sub/BiliVideoPage.vue') }, + ], + }, + { + id: 'douyin', + num: '105', + industry: 'app', + industryLabel: '应用媒体', + title: '竖屏短视频风', + intro: '全屏上下滑的信息流,双击点赞,还能进直播间刷礼物', + cover: { + kind: 'app', + ck: '#fe2c55', + sub: '@年糕崽崽 · 推荐', + bg: 'radial-gradient(circle at 30% 26%, rgba(37,244,238,.35), transparent 55%), radial-gradient(circle at 76% 74%, rgba(254,44,85,.4), transparent 55%), linear-gradient(#0a0a0c, #16161c)', + motif: '❤', + style: { color: '#fe2c55', fontSize: '40px', transform: 'translate(46px, -30px) rotate(12deg)', textShadow: '0 0 24px rgba(254,44,85,.7), -60px 34px 0 rgba(37,244,238,.5)' }, + }, + component: () => import('../pages/styles/DouyinPage.vue'), + subPages: [ + { path: 'live', title: '直播间', component: () => import('../pages/styles/sub/DouyinLivePage.vue') }, + ], + }, + { + id: 'xiaohongshu', + num: '106', + industry: 'app', + industryLabel: '应用媒体', + title: '种草笔记风', + intro: '双列瀑布流笔记,标签筛选,点进详情轮播图集收藏到专辑', + cover: { + kind: 'app', + ck: '#ff2442', + sub: '2.3w 粉丝 · 15.6w 获赞', + bg: 'linear-gradient(#fff 0 0) 26% 40%/38% 56% no-repeat, linear-gradient(#fff 0 0) 74% 56%/38% 66% no-repeat, linear-gradient(160deg, #ffe3e8, #ffd0d8)', + motif: '📕', + style: { fontSize: '34px', transform: 'translate(0, -6px)' }, + }, + component: () => import('../pages/styles/XiaohongshuPage.vue'), + subPages: [ + { path: 'note', title: '笔记详情', component: () => import('../pages/styles/sub/XhsNotePage.vue') }, + ], + }, + { + id: 'zhihu', + num: '107', + industry: 'app', + industryLabel: '应用媒体', + title: '问答社区风', + intro: '「如何评价年糕崽崽?」赞同反对随你投,还有本人匿名回答', + cover: { + kind: 'app', + ck: '#056de8', + sub: '1024 人关注 · 52.3万浏览', + bg: 'linear-gradient(rgba(255,255,255,.95) 0 0) 50% 30%/80% 30% no-repeat, linear-gradient(rgba(255,255,255,.8) 0 0) 50% 66%/80% 26% no-repeat, linear-gradient(150deg, #d5e6fb, #ecf3fc)', + motif: '?', + style: { color: '#056de8', fontSize: '48px', fontWeight: 900, transform: 'translate(52px, -30px)' }, + }, + component: () => import('../pages/styles/ZhihuPage.vue'), + subPages: [ + { path: 'answer', title: '回答详情', component: () => import('../pages/styles/sub/ZhihuAnswerPage.vue') }, + ], + }, + { + id: 'netease-music', + num: '108', + industry: 'app', + industryLabel: '应用媒体', + title: '云村歌单风', + intro: '人生歌单配热评文化,黑胶播放页唱针会落下,歌词逐行亮', + cover: { + kind: 'app', + ck: '#ec4141', + sub: '糕调FM · 999+热评', + bg: 'repeating-radial-gradient(circle at 50% 50%, #17181c 0 3px, #222329 3px 6px) 50% 50%/64% 64% no-repeat, radial-gradient(circle at 50% 50%, #ec4141 0 9%, transparent 10%), linear-gradient(150deg, #26272d, #131418)', + motif: '♪', + style: { color: '#ec4141', fontSize: '38px', transform: 'translate(52px, -34px)', textShadow: '0 0 20px rgba(236,65,65,.6)' }, + }, + component: () => import('../pages/styles/NeteasePage.vue'), + subPages: [ + { path: 'player', title: '黑胶播放页', component: () => import('../pages/styles/sub/NeteasePlayerPage.vue') }, + ], + }, + { + id: 'weibo', + num: '109', + industry: 'app', + industryLabel: '应用媒体', + title: '围脖信息流风', + intro: '转评赞信息流可发帖,热搜榜实时浮动,点词条吃瓜', + cover: { + kind: 'app', + ck: '#ff8200', + sub: '#年糕崽崽开源新作# 沸', + bg: 'linear-gradient(rgba(255,255,255,.94) 0 0) 50% 62%/80% 52% no-repeat, linear-gradient(120deg, #ffb35c, #ff8200)', + motif: '🔥', + style: { fontSize: '32px', transform: 'translate(54px, -38px)' }, + }, + component: () => import('../pages/styles/WeiboPage.vue'), + subPages: [ + { path: 'hot', title: '热搜榜', component: () => import('../pages/styles/sub/WeiboHotPage.vue') }, + ], + }, + { + id: 'tieba', + num: '110', + industry: 'app', + industryLabel: '应用媒体', + title: '贴吧盖楼风', + intro: '年糕吧签到攒经验,进帖子盖楼回复,楼中楼都给你做了', + cover: { + kind: 'app', + ck: '#3385ff', + sub: '年糕吧 · 关注 23333', + bg: 'linear-gradient(rgba(255,255,255,.95) 0 0) 50% 24%/80% 18% no-repeat, linear-gradient(rgba(255,255,255,.85) 0 0) 50% 48%/80% 18% no-repeat, linear-gradient(rgba(255,255,255,.75) 0 0) 50% 72%/80% 18% no-repeat, linear-gradient(150deg, #9ec5ff, #3385ff)', + motif: '糕', + style: { color: '#fff', fontFamily: '"Ma Shan Zheng", cursive', fontSize: '30px', transform: 'translate(-56px, -34px)', textShadow: '0 4px 12px rgba(20,60,140,.5)' }, + }, + component: () => import('../pages/styles/TiebaPage.vue'), + subPages: [ + { path: 'thread', title: '盖楼串', component: () => import('../pages/styles/sub/TiebaThreadPage.vue') }, + ], }, ] diff --git a/src/pages/CorpHome.vue b/src/pages/CorpHome.vue index b30232e..2b4bed2 100644 --- a/src/pages/CorpHome.vue +++ b/src/pages/CorpHome.vue @@ -40,6 +40,7 @@ import { styleList } from '../data/styles' diff --git a/src/pages/corp/EcomFreshPage.vue b/src/pages/corp/EcomFreshPage.vue index 3b88c3b..1e0f651 100644 --- a/src/pages/corp/EcomFreshPage.vue +++ b/src/pages/corp/EcomFreshPage.vue @@ -12,6 +12,18 @@ function addCart(name) { } const freshTags = ['今日现摘', '产地直发', '冰鲜锁味', '有机认证'] + +/* 产地直采签 */ +const selIdx = ref(-1) +const sel = ref(null) +function openTag(i) { + selIdx.value = i + sel.value = c.cases[i] +} +function closeTag() { + selIdx.value = -1 + sel.value = null +}