map / index.html
PH70248's picture
Deploy stable labels and current local release
373d92a verified
Raw
History Blame Contribute Delete
17.1 kB
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>World Citybook | 全球「城市路书」地图</title>
<link rel="icon" href="data:," />
<link rel="stylesheet" href="src/styles.css?v=20260714-predeploy-010" />
<link rel="stylesheet" href="src/ticket-clip.css?v=20260714-predeploy-010" />
</head>
<body>
<main class="atlas-shell">
<section class="map-stage" aria-label="世界地图底座">
<canvas id="halftoneCanvas" class="halftone-canvas" aria-hidden="true"></canvas>
<div id="cityTileLayer" class="city-tile-layer" aria-hidden="true"></div>
<header class="hero-copy" aria-label="项目介绍">
<p class="hero-kicker">全球「城市路书」地图</p>
<h1><span class="hero-title__word hero-title__word--world"><span class="hero-title__initial">W</span><span class="hero-title__rest">orld</span></span><br /><span class="hero-title__word hero-title__word--citybook">Cit<span class="hero-title__citybook-y">y</span>boo<span class="hero-title__citybook-k">k</span></span></h1>
<p class="hero-tagline">自由探索,在空间叙事与地方书写中读懂城市</p>
<form class="search-capsule" role="search" aria-label="搜索城市路书">
<span class="search-mark" aria-hidden="true"></span>
<input type="search" placeholder="搜索国家、城市、书名、作者或主题" autocomplete="off" aria-controls="searchResults" aria-expanded="false" />
<button class="search-clear" type="button" aria-label="清除搜索"></button>
<button class="search-suggestion" type="button" hidden aria-label="使用推荐搜索词"></button>
<div id="searchResults" class="search-results" role="listbox" aria-label="搜索推荐" hidden></div>
</form>
</header>
<button id="themeToggle" class="theme-toggle" type="button" aria-label="切换暗色模式" aria-pressed="false">
<span class="theme-toggle__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" focusable="false">
<circle cx="12" cy="12" r="4.2"></circle>
<path d="M12 2.8v2.1M12 19.1v2.1M4.2 4.2l1.5 1.5M18.3 18.3l1.5 1.5M2.8 12h2.1M19.1 12h2.1M4.2 19.8l1.5-1.5M18.3 5.7l1.5-1.5"></path>
</svg>
</span>
<span class="theme-toggle__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" focusable="false">
<path d="M18.7 15.5A7.8 7.8 0 0 1 8.5 5.3 7.9 7.9 0 1 0 18.7 15.5Z"></path>
</svg>
</span>
<span class="theme-toggle__knob" aria-hidden="true"></span>
</button>
<button id="bookshelfToggle" class="bookshelf-toggle" type="button" aria-label="打开我的书架">
<svg class="bookshelf-toggle__icon" viewBox="0 0 24 24" focusable="false" aria-hidden="true">
<path d="M4.5 19.2h15"></path>
<path d="M6.2 5.4v13.8"></path>
<path d="M10.2 6.3v12.9"></path>
<path d="M14.4 4.8l2.9 13.8"></path>
<path d="M4.5 8.5h6.8"></path>
</svg>
<span id="bookshelfCount" class="bookshelf-toggle__count" aria-hidden="true">0</span>
</button>
<button id="specialBackButton" class="special-back-button" type="button" hidden>
<span class="special-back-button__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" focusable="false">
<circle cx="12" cy="12" r="9.25"></circle>
<path d="M2.75 12h18.5M12 2.75a13.8 13.8 0 0 1 0 18.5M12 2.75a13.8 13.8 0 0 0 0 18.5"></path>
</svg>
</span>
<span class="special-back-button__label">返回全球视角</span>
</button>
<p class="drag-hint" aria-hidden="true">── 长按转动地球</p>
<div id="musicSignature" class="music-signature" aria-label="背景音乐">
<button id="musicToggle" class="music-signature__toggle" type="button" aria-label="播放背景音乐">
<svg class="music-signature__icon music-signature__icon--sound" viewBox="0 0 24 24" focusable="false" aria-hidden="true">
<path class="music-signature__speaker" d="M4.9 10.1v3.8h3.2l4.8 4.2V5.9l-4.8 4.2H4.9Z"></path>
<path class="music-signature__wave music-signature__wave--soft" d="M15.8 9.5c.58.68.92 1.54.92 2.5s-.34 1.82-.92 2.5"></path>
<path class="music-signature__wave music-signature__wave--full" d="M18 7.7c1.02 1.12 1.6 2.58 1.6 4.3s-.58 3.18-1.6 4.3"></path>
<path class="music-signature__mute-line" d="M7 7.15 16.55 16.85"></path>
</svg>
</button>
<p class="music-signature__credit" aria-live="polite">
<span id="musicTitle">Car 24</span>
<span class="music-signature__separator"> - </span>
<span id="musicArtist">菅野よう子</span>
</p>
<span id="musicVolume" class="music-signature__volume" aria-hidden="true">24%</span>
</div>
<audio id="musicLight" src="public/audio/car24.mp3" preload="metadata" loop></audio>
<audio id="musicDark" src="public/audio/road-to-the-west.mp3" preload="metadata" loop></audio>
<svg id="mapSvg" class="map-svg" viewBox="0 0 1440 920" preserveAspectRatio="xMidYMid slice" role="img" aria-label="世界球体地图">
<defs>
<radialGradient id="globeWash" cx="34%" cy="28%" r="74%">
<stop class="ocean-stop-a" offset="0%" stop-opacity="1" />
<stop class="ocean-stop-b" offset="48%" stop-opacity="0.96" />
<stop class="ocean-stop-c" offset="100%" stop-opacity="1" />
</radialGradient>
<pattern id="oceanWaves" width="224" height="224" patternUnits="userSpaceOnUse">
<image id="oceanWaveImage" href="public/textures/ocean-wave-lines-alpha.png" width="224" height="224" preserveAspectRatio="none" />
</pattern>
<pattern id="landTexture" width="260" height="260" patternUnits="userSpaceOnUse">
<image id="landTextureImage" href="public/textures/land-soft-halftone-dots.png" width="260" height="260" preserveAspectRatio="none" />
</pattern>
<filter id="cityMapDarkLandMultiply" color-interpolation-filters="sRGB">
<feColorMatrix in="SourceGraphic" type="saturate" values="0" result="gray" />
<feComponentTransfer in="gray" result="softGray">
<feFuncR type="linear" slope="1" intercept="0.012" />
<feFuncG type="linear" slope="1" intercept="0.012" />
<feFuncB type="linear" slope="1" intercept="0.012" />
</feComponentTransfer>
<feFlood flood-color="#548482" flood-opacity="0.66" result="landTint" />
<feBlend in="softGray" in2="landTint" mode="multiply" result="tintedLand" />
<feComposite in="tintedLand" in2="SourceAlpha" operator="in" />
</filter>
</defs>
<g id="globeLayer"></g>
<g id="worldLayer"></g>
<g id="highlightLayer"></g>
<g id="cityLayer"></g>
</svg>
<div id="cityLabelLayer" class="city-label-layer" aria-hidden="true"></div>
<svg id="specialOverlaySvg" class="special-overlay-svg" aria-hidden="true"></svg>
<div id="specialLabelLayer" class="special-label-layer" aria-label="城市特辑入口"></div>
<div id="specialBookLayer" class="special-book-layer" aria-label="城市特辑书籍"></div>
<aside id="cityTooltip" class="book-card is-ticket" aria-live="polite" hidden>
<section class="book-card__ticket-view" aria-label="书票卡片">
<button class="book-card__close book-card__close--float" type="button" aria-label="关闭书籍卡片">×</button>
<article class="book-ticket">
<div class="book-ticket__cover" aria-hidden="true">
<img alt="" />
<span class="book-card__cover-fallback">BOOK</span>
</div>
<div class="book-ticket__body">
<p class="book-card__location-zh"></p>
<p class="book-card__location-en"></p>
<h2 class="book-card__title-zh"></h2>
<p class="book-card__title-original"></p>
<p class="book-card__meta"></p>
<p class="book-card__shareline"></p>
<div class="book-card__ticket-actions">
<button class="book-card__action book-card__save" type="button">
<svg class="book-card__action-icon" viewBox="0 0 24 24" focusable="false" aria-hidden="true">
<path d="M20.2 5.8c-1.9-1.9-5-1.8-6.8.2L12 7.5 10.6 6c-1.8-2-4.9-2.1-6.8-.2-2 2-2.1 5.2-.1 7.3L12 21l8.3-7.9c2-2.1 1.9-5.3-.1-7.3Z" />
</svg>
<span class="book-card__action-label">收藏</span>
</button>
<button class="book-card__action book-card__share" type="button">
<svg class="book-card__action-icon" viewBox="0 0 24 24" focusable="false" aria-hidden="true">
<path d="M8.2 12.9 15.8 17" />
<path d="M15.8 7 8.2 11.1" />
<circle cx="6" cy="12" r="2.4" />
<circle cx="18" cy="6" r="2.4" />
<circle cx="18" cy="18" r="2.4" />
</svg>
<span class="book-card__action-label">分享</span>
</button>
<button class="book-card__action book-card__detail" type="button">
<svg class="book-card__action-icon" viewBox="0 0 24 24" focusable="false" aria-hidden="true">
<path d="M4.5 5.5c2.5-.9 5-.5 7.5 1.2 2.5-1.7 5-2.1 7.5-1.2v13c-2.5-.8-5-.4-7.5 1.2-2.5-1.6-5-2-7.5-1.2v-13Z" />
<path d="M12 6.7v13" />
</svg>
<span class="book-card__action-label">详情</span>
</button>
</div>
</div>
</article>
</section>
<section class="book-card__detail-view" aria-label="藏书卡详情">
<button class="book-card__close book-card__close--detail" type="button" aria-label="关闭书籍卡片">×</button>
<div class="book-card__detail-cover" aria-hidden="true">
<img alt="" />
<span class="book-card__cover-fallback">BOOK</span>
</div>
<div class="book-card__detail-body">
<div class="book-card__detail-top">
<div>
<p class="book-card__location-zh"></p>
<p class="book-card__location-en"></p>
</div>
</div>
<h2 class="book-card__title-zh"></h2>
<p class="book-card__title-original"></p>
<p class="book-card__meta"></p>
<div class="book-card__intro"></div>
<div class="book-card__detail-footer">
<div class="book-card__explore">
<button class="book-card__city-page book-card__city-page--prev" type="button" aria-label="上一座城市">«</button>
<div class="book-card__pager" hidden>
<button class="book-card__page book-card__page--prev" type="button" aria-label="上一本书"></button>
<span class="book-card__counter">1 / 1</span>
<button class="book-card__page book-card__page--next" type="button" aria-label="下一本书"></button>
</div>
<button class="book-card__city-page book-card__city-page--next" type="button" aria-label="下一座城市">»</button>
</div>
<div class="book-card__detail-actions">
<button class="book-card__action book-card__save" type="button">
<svg class="book-card__action-icon" viewBox="0 0 24 24" focusable="false" aria-hidden="true">
<path d="M20.2 5.8c-1.9-1.9-5-1.8-6.8.2L12 7.5 10.6 6c-1.8-2-4.9-2.1-6.8-.2-2 2-2.1 5.2-.1 7.3L12 21l8.3-7.9c2-2.1 1.9-5.3-.1-7.3Z" />
</svg>
<span class="book-card__action-label">收藏</span>
</button>
<button class="book-card__action book-card__share" type="button">
<svg class="book-card__action-icon" viewBox="0 0 24 24" focusable="false" aria-hidden="true">
<path d="M8.2 12.9 15.8 17" />
<path d="M15.8 7 8.2 11.1" />
<circle cx="6" cy="12" r="2.4" />
<circle cx="18" cy="6" r="2.4" />
<circle cx="18" cy="18" r="2.4" />
</svg>
<span class="book-card__action-label">分享</span>
</button>
</div>
</div>
</div>
</section>
</aside>
<div id="sharePreview" class="share-preview" hidden>
<section class="share-preview__canvas" aria-label="分享书票预览">
<div class="share-preview__topbar">
<p class="share-preview__eyebrow">分享书票预览</p>
<button class="share-preview__close" type="button" aria-label="关闭分享预览">×</button>
</div>
<div class="share-ticket-shell">
<article class="share-ticket">
<div class="share-ticket__cover" aria-hidden="true">
<img alt="" />
<span class="book-card__cover-fallback">BOOK</span>
</div>
<div class="share-ticket__body">
<p class="book-card__location-zh"></p>
<p class="book-card__location-en"></p>
<h2 class="book-card__title-zh"></h2>
<p class="book-card__title-original"></p>
<p class="book-card__meta"></p>
<blockquote class="book-card__quote"></blockquote>
<div class="share-ticket__stamp">
<span class="share-ticket__brand">World Citybook</span>
<img class="share-ticket__seal" src="public/assets/stamps/city-routebook-seal.png" alt="" />
</div>
</div>
</article>
</div>
<button class="share-preview__page share-preview__page--prev" type="button" aria-label="上一张分享书票">‹‹</button>
<button class="share-preview__page share-preview__page--next" type="button" aria-label="下一张分享书票">››</button>
<div class="share-preview__actions">
<button class="share-preview__save" type="button">保存藏书票</button>
</div>
</section>
</div>
<section id="bookshelfView" class="bookshelf-view" aria-label="我的书架" hidden>
<button id="bookshelfClose" class="special-back-button bookshelf-back-button" type="button" aria-label="返回全球视角">
<span class="special-back-button__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" focusable="false">
<circle cx="12" cy="12" r="9.25"></circle>
<path d="M2.75 12h18.5M12 2.75a13.8 13.8 0 0 1 0 18.5M12 2.75a13.8 13.8 0 0 0 0 18.5"></path>
</svg>
</span>
<span class="special-back-button__label">返回全球视角</span>
</button>
<div class="bookshelf-view__stage">
<div id="bookshelfGrid" class="bookshelf-grid" aria-live="polite"></div>
<p id="bookshelfEmpty" class="bookshelf-empty">收藏一本城市之书,它会出现在这里。</p>
</div>
<div id="bookshelfPager" class="bookshelf-pager" aria-label="书架翻页" hidden>
<button id="bookshelfPrev" class="book-card__page book-card__page--prev bookshelf-pager__button" type="button" aria-label="上一页"></button>
<span id="bookshelfPageLabel" class="book-card__counter bookshelf-pager__label">1 / 1</span>
<button id="bookshelfNext" class="book-card__page book-card__page--next bookshelf-pager__button" type="button" aria-label="下一页"></button>
</div>
</section>
</section>
</main>
<script>
window.CITYBOOK_MAP_CONFIG = {
cityTileProvider: "cartoLight",
defaultMapStyleId: "light",
mapboxStyleId: "mapbox/light-v11",
mapboxAccessToken: "",
retinaTiles: true,
};
</script>
<script src="public/vendor/d3-array-3.2.4.min.js?v=20260714-predeploy-010"></script>
<script src="public/vendor/d3-geo-3.1.1.min.js?v=20260714-predeploy-010"></script>
<script type="module" src="src/app.js?v=20260714-predeploy-010"></script>
</body>
</html>