修复改为hexagon实现后遮挡背景图的问题

This commit is contained in:
jimleerx
2025-11-12 00:08:32 +08:00
parent cf36b71990
commit dcc5654603
6 changed files with 201 additions and 97 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -190,6 +190,7 @@ const viewHeight = rawHeight / sizeScale
const viewMinX = centerX - viewWidth / 2
const viewMinY = centerY - viewHeight / 2
const viewBox = `${viewMinX} ${viewMinY} ${viewWidth} ${viewHeight}`
const iconClipId = 'hexIconClip'
const cells = baseCells.map((cell) => ({
...cell,
@@ -198,7 +199,7 @@ const cells = baseCells.map((cell) => ({
---
<svg
class="hex-grid"
class="hex-grid hex-grid--polygons"
width="100%"
height="100%"
viewBox={viewBox}
@@ -206,82 +207,94 @@ const cells = baseCells.map((cell) => ({
preserveAspectRatio="xMidYMid slice"
>
<g class="hex-grid__group">
{cells.map(({ link, center, showContent }, index) => {
{cells.map(({ link, center }, index) => {
const isGhost = !link
return (
<polygon
class={`hexagon-bg ${isGhost ? 'hexagon-bg--ghost' : ''}`}
points={hexagonPoints}
fill="transparent"
stroke="#252525"
stroke-width={BORDER_WIDTH}
transform={`translate(${center.x}, ${center.y})`}
data-index={index}
/>
)
})}
</g>
</svg>
<svg
class="hex-grid hex-grid--icons"
width="100%"
height="100%"
viewBox={viewBox}
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMidYMid slice"
>
<defs>
<clipPath id={iconClipId} clipPathUnits="userSpaceOnUse">
<circle cx="0" cy="0" r={circleRadius} />
</clipPath>
</defs>
<g class="hex-grid__group">
{cells.map(({ link, center, showContent }, index) => {
if (!link || !showContent) return null
return (
<g
class={`hexagon-wrapper ${isGhost ? 'hexagon-wrapper--ghost' : ''}`}
class="hexagon-wrapper"
transform={`translate(${center.x}, ${center.y})`}
data-index={index}
>
{link ? (
<a
href={link.href}
target="_blank"
rel="noopener noreferrer"
aria-label={link.label}
title={link.title}
>
<polygon
points={hexagonPoints}
class="hexagon-bg"
fill="transparent"
stroke="#252525"
stroke-width={BORDER_WIDTH}
<a
href={link.href}
target="_blank"
rel="noopener noreferrer"
aria-label={link.label}
>
<title>{link.title}</title>
<g class="icon-group">
<circle
r={circleRadius}
fill="hsl(var(--secondary))"
fill-opacity="0.45"
stroke="hsl(var(--border))"
stroke-width={Math.max(4, BORDER_WIDTH * 0.32)}
class="icon-circle z-10"
/>
{
showContent && (
<g class="icon-group">
<circle
r={circleRadius}
fill="hsl(var(--secondary))"
fill-opacity="0.45"
stroke="hsl(var(--primary))"
stroke-width={Math.max(4, BORDER_WIDTH * 0.32)}
class="icon-circle"
{link.icon.startsWith('mdi:') ? (
<foreignObject
x={-(layout.size.x * 0.7)}
y={-(layout.size.y * 0.7)}
width={layout.size.x * 1.4}
height={layout.size.y * 1.4}
clip-path={`url(#${iconClipId})`}
class="icon-foreign"
>
<div class="icon-container">
<Icon
name={link.icon}
class="hexagon-icon"
style="color: rgb(233, 211, 182);"
aria-hidden="true"
/>
{link.icon.startsWith('mdi:') ? (
<foreignObject
x={-(layout.size.x * 0.7)}
y={-(layout.size.y * 0.7)}
width={layout.size.x * 1.4}
height={layout.size.y * 1.4}
class="icon-foreign"
>
<div class="icon-container">
<Icon
name={link.icon}
class="hexagon-icon"
style="color: rgb(233, 211, 182);"
aria-hidden="true"
/>
</div>
</foreignObject>
) : (
<image
href={link.icon}
x={-layout.size.x * 0.6}
y={-layout.size.y * 0.6}
width={layout.size.x * 1.2}
height={layout.size.y * 1.2}
class="z-[1] size-1/2 size-8 sm:size-8"
/>
)}
</g>
)
}
</a>
) : (
<polygon
points={hexagonPoints}
class="hexagon-bg hexagon-bg--ghost"
fill="transparent"
stroke="#252525"
stroke-width={BORDER_WIDTH}
/>
)}
</div>
</foreignObject>
) : (
<image
href={link.icon}
x={-layout.size.x * 0.3}
y={-layout.size.y * 0.3}
width={layout.size.x * 0.6}
height={layout.size.y * 0.6}
clip-path={`url(#${iconClipId})`}
class="hexagon-image"
/>
)}
</g>
</a>
</g>
)
})}
@@ -294,16 +307,41 @@ const cells = baseCells.map((cell) => ({
inset: 0;
width: 100%;
height: 100%;
z-index: 10;
pointer-events: none;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
.hex-grid--polygons {
z-index: 1;
}
.hex-grid--icons {
z-index: 20;
}
.hex-grid__group {
transform-origin: center;
transform: translateX(-114px) translateY(60px) scale(1.08)
transform: translateX(-114px) translateY(60px) scale(1.08);
}
.hexagon-wrapper {
cursor: pointer;
pointer-events: auto;
user-select: none;
-webkit-user-select: none;
-webkit-tap-highlight-color: transparent;
}
.hexagon-wrapper a {
outline: none;
-webkit-tap-highlight-color: transparent;
pointer-events: auto;
cursor: pointer;
}
.hexagon-wrapper a title {
pointer-events: none;
}
.hexagon-bg,
@@ -322,13 +360,9 @@ const cells = baseCells.map((cell) => ({
filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.45));
}
.hexagon-wrapper:hover .hexagon-bg {
stroke: #252525;
stroke-width: 16;
}
.hexagon-wrapper:hover .icon-circle {
fill-opacity: 0.85;
stroke: hsl(var(--primary));
stroke-width: 4px;
transform: scale(1.08);
}
@@ -338,11 +372,6 @@ const cells = baseCells.map((cell) => ({
transform-origin: center;
}
.hexagon-wrapper--ghost {
cursor: default;
pointer-events: none;
}
.hexagon-bg--ghost {
stroke-dasharray: none;
}
@@ -359,8 +388,8 @@ const cells = baseCells.map((cell) => ({
.hexagon-icon {
width: 100% !important;
height: 100% !important;
max-width: 68px;
max-height: 68px;
max-width: 88px;
max-height: 88px;
}
.hexagon-image {

View File

@@ -15,8 +15,8 @@ import logo from '../../public/static/logo.webp'
>
<Container>
<div class="flex flex-wrap items-center justify-between gap-4 py-4 ">
<Link href="/">
<Image src={logo} alt="Logo" class="size-8 -scale-x-100 border-2 border-[color:rgba(241,140,110,0.4)] shadow-[4px_4px_0_rgba(0,0,0,0.2)]" />
<Link href="/" class="logo-link">
<Image src={logo} alt="Logo" class="size-8 -scale-x-100 border-2 border-[color:rgba(241,140,110,0.4)] shadow-[4px_4px_0_rgba(0,0,0,0.2)] transition-all duration-300" />
</Link>
<div class="flex items-center gap-2 sm:gap-4">
<nav class="hidden items-center gap-2 text-base sm:flex sm:gap-3">
@@ -38,3 +38,31 @@ import logo from '../../public/static/logo.webp'
</div>
</Container>
</header>
<style>
.logo-link:hover img {
border-color: hsl(var(--primary));
box-shadow:
0 0 12px rgba(241, 140, 110, 0.6),
0 0 24px rgba(241, 140, 110, 0.4),
0 0 36px rgba(241, 140, 110, 0.2),
4px 4px 0 rgba(0, 0, 0, 0.2);
transform: scale(1.05);
}
nav :global(.pixel-button:hover) {
box-shadow:
0 0 12px rgba(241, 140, 110, 0.5),
0 0 24px rgba(241, 140, 110, 0.3),
0 0 36px rgba(241, 140, 110, 0.15),
4px 4px 0 rgba(0, 0, 0, 0.2) !important;
}
.dark nav :global(.pixel-button:hover) {
box-shadow:
0 0 12px rgba(241, 140, 110, 0.5),
0 0 24px rgba(241, 140, 110, 0.3),
0 0 36px rgba(241, 140, 110, 0.15),
4px 4px 0 rgba(0, 0, 0, 0.4) !important;
}
</style>

View File

@@ -54,10 +54,10 @@ export const DEV_LINKS: DevLink[] = [
icon: 'mdi:git',
},
{
href: 'https://maven.2ha.me',
href: 'https://img.2ha.me',
label: 'Nexus',
title: 'Maven仓库',
icon: 'mdi:chart-doughnut-variant',
title: '图床',
icon: 'mdi:image-multiple',
},
{
href: 'https://dms.2ha.me',
@@ -69,13 +69,13 @@ export const DEV_LINKS: DevLink[] = [
href: 'https://p.2ha.me',
label: 'Zfile',
title: '网盘',
icon: 'mdi:cloud-arrow-up',
icon: 'mdi:harddisk',
},
{
href: 'https://photo.2ha.me',
label: 'immich',
title: '相册',
icon: 'mdi:camera',
href: 'https://tz.2ha.me',
label: 'VPS Monitor',
title: '探针',
icon: 'mdi:chart-areaspline',
},
{
href: 'https://f.2ha.me',
@@ -83,7 +83,12 @@ export const DEV_LINKS: DevLink[] = [
title: '文件服务器',
icon: 'mdi:file-arrow-up-down-outline',
},
{ href: 'https://v.2ha.me', label: 'Emby', title: 'Emby', icon: 'mdi:emby' },
{
href: 'https://status.2ha.me',
label: 'Domain Status',
title: '站点检测',
icon: 'mdi:cloud-check'
},
{
href: 'https://in.2ha.me',
label: '2ha.me statistics',
@@ -95,6 +100,7 @@ export const DEV_LINKS: DevLink[] = [
label: '妙妙屋',
title: '个人Clash订阅管理工具',
icon: '/static/mmw.svg',
// icon: 'mdi:cat',
},
{
href: 'https://1ms.cc',

View File

@@ -48,8 +48,8 @@ const latestPost = await getCollection('blog').then((posts: any[]) =>
aria-label="Developer Stack Shortcuts"
>
<img
class="overlay absolute no-repeat w-full max-w-fit justify-center object-cover z-9"
src="/static/images/shortcuts-bg.png"
class="overlay absolute bottom-0 right-0 no-repeat max-w-[28%] object-contain z-[100]"
src="/static/images/shortcuts-bg-mini.png"
/>
<!-- <DevStackIconsCloud client:load/> -->
<!-- <DevShortCuts /> -->
@@ -65,7 +65,7 @@ const latestPost = await getCollection('blog').then((posts: any[]) =>
style="grid-template-rows: 9fr 1fr; "
>
<div
class="overlay absolute inset-0 size-full rounded-3xl bg-[url('/static/images/lastblogbg-sm.webp')] bg-cover bg-center bg-no-repeat transition-opacity duration-200 sm:bg-[url('/static/images/lastblogbg.webp')] xl:opacity-100"
class="overlay absolute inset-0 size-full rounded-3xl bg-[url('/static/images/lastblogbg-sm.webp')] bg-cover bg-no-repeat transition-opacity duration-200 sm:bg-[url('/static/images/lastblogbg.webp')] xl:opacity-100"
>
</div>
{
@@ -171,3 +171,21 @@ const latestPost = await getCollection('blog').then((posts: any[]) =>
</div>
</section>
</Layout>
<style>
section > div:hover {
box-shadow:
0 0 16px rgba(241, 140, 110, 0.5),
0 0 32px rgba(241, 140, 110, 0.3),
0 0 48px rgba(241, 140, 110, 0.15),
6px 6px 0 rgba(0, 0, 0, 0.26) !important;
}
.dark section > div:hover {
box-shadow:
0 0 16px rgba(241, 140, 110, 0.5),
0 0 32px rgba(241, 140, 110, 0.3),
0 0 48px rgba(241, 140, 110, 0.15),
6px 6px 0 rgba(0, 0, 0, 0.75) !important;
}
</style>

View File

@@ -486,7 +486,30 @@
@apply border-border;
}
/* Prevent text selection cursor on interactive elements */
/* Prevent text selection cursor on all elements by default */
* {
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-webkit-tap-highlight-color: transparent;
cursor: default;
}
/* Allow text selection in content areas */
article,
article *,
.prose,
.prose *,
input,
textarea,
[contenteditable="true"] {
user-select: text;
-webkit-user-select: text;
cursor: text;
}
/* Ensure proper cursor on interactive elements */
button,
a,
div,