From bb35f20e27e44c8315627ae7b58fdbffc9b5726f Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Wed, 19 Aug 2026 14:31:06 +0900 Subject: [PATCH 1/2] improve website style --- .vitepress/theme/components/CustomLayout.vue | 100 +++++++++++-------- .vitepress/theme/components/FutureStar.vue | 52 ++++++++-- .vitepress/theme/style.css | 94 +++++++++++++++++ 3 files changed, 194 insertions(+), 52 deletions(-) diff --git a/.vitepress/theme/components/CustomLayout.vue b/.vitepress/theme/components/CustomLayout.vue index fd376a60..c8bda0e3 100644 --- a/.vitepress/theme/components/CustomLayout.vue +++ b/.vitepress/theme/components/CustomLayout.vue @@ -9,57 +9,74 @@ const enableTransitions = () => "startViewTransition" in document && window.matchMedia("(prefers-reduced-motion: no-preference)").matches; -provide("toggle-appearance", async () => { +provide("toggle-appearance", async (event) => { if (!enableTransitions()) { isDark.value = !isDark.value; return; } - const innerWidth = window.innerWidth + 10; - const innerHeight = window.innerHeight + 10; + const x = event?.clientX ?? window.innerWidth / 2; + const y = event?.clientY ?? 0; - const vw = innerWidth / 100; - const vh = innerHeight / 100; + // 星の凹み(内側頂点)が画面の最遠隅より外に出れば全面を覆える + const innerRate = 0.45; + const maxRadius = + (Math.hypot( + Math.max(x, window.innerWidth - x), + Math.max(y, window.innerHeight - y), + ) / + 0.38) * + 1.05; - const maskImage = - `url('data:image/svg+xml, - - - - - - - ')`.replace(/\s+/gu, " "); + const star = (radius, rotate) => { + const points = []; + for (let i = 0; i < 10; i++) { + const r = i % 2 === 0 ? radius : radius * innerRate; + const a = (Math.PI / 5) * i + rotate; + points.push( + `${(x + r * Math.sin(a)).toFixed(1)}px ${(y - r * Math.cos(a)).toFixed(1)}px`, + ); + } + return `polygon(${points.join(",")})`; + }; - await document.startViewTransition(async () => { - isDark.value = !isDark.value; - await nextTick(); - }).ready; + // 回転を先行させ、半径は後から追いつかせて「ひねりながら開く」動きにする + const keyframes = [ + [0, 0], + [0.12, 0.4], + [0.35, 0.7], + [0.68, 0.9], + [1, 1], + ].map(([growth, spin]) => ({ + clipPath: star(maxRadius * growth, Math.PI * 0.8 * spin), + })); - const maskPosition = [ - `${100 * vw}px -${5 * vh}px`, - `-${100 * vw}px -${5 * vh}px`, - ]; - const maskSize = `${220 * vw}px ${110 * vh}px`; + let starAnimation; + try { + const transition = document.startViewTransition(async () => { + isDark.value = !isDark.value; + await nextTick(); + }); + await transition.ready; - document.documentElement.animate( - { - maskImage: [maskImage, maskImage], - maskPosition: isDark.value ? maskPosition.reverse() : maskPosition, - maskSize: [maskSize, maskSize], - }, - { - duration: 300, - easing: "ease-in", - fill: "forwards", - pseudoElement: `::view-transition-${isDark.value ? "old" : "new"}(root)`, - }, - ); + starAnimation = document.documentElement.animate( + isDark.value ? keyframes.reverse() : keyframes, + { + duration: 500, + easing: "ease-in-out", + fill: "forwards", + pseudoElement: `::view-transition-${isDark.value ? "old" : "new"}(root)`, + }, + ); + await transition.finished; + } catch { + // ページ遷移などでトランジションが破棄された場合。テーマ自体は切り替え済み + } finally { + // fill: forwards のアニメーションはトランジション終了後も残留し、 + // 次回のトグルで同名の擬似要素が再生成された瞬間に前回の最終状態 + // (全面表示のクリップ)が再適用されて画面が一瞬素通しになるため、必ず破棄する + starAnimation?.cancel(); + } }); @@ -72,7 +89,6 @@ provide("toggle-appearance", async () => { ::view-transition-new(root) { animation: none; mix-blend-mode: normal; - mask-repeat: no-repeat; } ::view-transition-old(root), diff --git a/.vitepress/theme/components/FutureStar.vue b/.vitepress/theme/components/FutureStar.vue index a285da5b..9635c520 100644 --- a/.vitepress/theme/components/FutureStar.vue +++ b/.vitepress/theme/components/FutureStar.vue @@ -29,10 +29,10 @@ const starPath = `path("M 0 ${starSize / 2} l ${starSize * lengthRate} -${starSi left: v-bind(-starWidth + "px"); filter: blur(3px); transform-origin: left 50%; - opacity: 0.1; + opacity: 0.15; } .dark .future-star__container { - opacity: 0.2; + opacity: 0.3; } .future-star--kind-1 { transform: rotate(-6deg); @@ -42,29 +42,61 @@ const starPath = `path("M 0 ${starSize / 2} l ${starSize * lengthRate} -${starSi } .future-star { position: absolute; - background-color: #da0058; + /* 尾に向かって透明になるグラデーションで彗星らしい残像を出す */ + background: linear-gradient( + 90deg, + transparent, + #da0058 45%, + #ff4d88 90%, + #ffb3cd + ); height: v-bind(starSize + "px"); width: v-bind(starWidth + "px"); clip-path: v-bind(starPath); + transform-origin: right center; /* 先端(右)を基点に尾が伸縮する */ + opacity: 0; - animation-composition: add; - animation-name: slide-to-right; - animation-duration: 10s; + animation-name: star-streak; + animation-duration: 9s; animation-iteration-count: infinite; - animation-timing-function: linear; + /* 加速して飛び込み、減速して抜ける */ + animation-timing-function: cubic-bezier(0.45, 0, 0.4, 1); } .future-star--kind-2 .future-star { - animation-delay: 250ms; + /* 2本目はわずかに遅らせて並走させる(飛翔中に必ず2本同時に見えるずれ幅) */ + animation-delay: 150ms; } -@keyframes slide-to-right { +@keyframes star-streak { 0% { left: 0; + opacity: 0; + transform: scaleX(0.5); } - 50% { + 2% { + opacity: 1; + } + 8% { + /* 最高速付近で尾が伸びる */ + transform: scaleX(1.2); + } + 13% { + opacity: 1; + } + 15% { left: 100%; + opacity: 0; + transform: scaleX(0.6); } 100% { left: 100%; + opacity: 0; + } +} +@media (prefers-reduced-motion: reduce) { + .future-star { + animation: none; + left: 30%; + opacity: 0.6; } } diff --git a/.vitepress/theme/style.css b/.vitepress/theme/style.css index 042e3547..3b128e4f 100644 --- a/.vitepress/theme/style.css +++ b/.vitepress/theme/style.css @@ -1,5 +1,8 @@ :root { --vp-home-hero-name-color: transparent; + /* ヒーロー背景を漂うオーロラの色斑(ライトは朝焼け風の淡いトーン) */ + --hero-aurora-pink: rgba(229, 0, 79, 0.14); + --hero-aurora-blue: rgba(40, 70, 190, 0.12); --vp-home-hero-name-background: -webkit-linear-gradient( 120deg, #0a1561 30%, @@ -13,6 +16,9 @@ #fff 30%, #e5004f ); + /* ダークは夜空のオーロラ風に少し強める */ + --hero-aurora-pink: rgba(229, 0, 79, 0.26); + --hero-aurora-blue: rgba(110, 130, 255, 0.18); /* 背景が透過である画像が、ダークモードで視認性が下がるための対応 */ .img-bg-transparent img { filter: invert(1); @@ -51,6 +57,94 @@ white-space: nowrap; } +/* オーロラ背景: ブランドカラーの色斑がヒーロー背景をゆっくり漂う */ +.standards-home .VPHero { + position: relative; + /* 色斑のはみ出しを閉じ込め、擬似要素の z-index: -1 をヒーロー内に留める */ + overflow: hidden; + isolation: isolate; +} +.standards-home .VPHero::before, +.standards-home .VPHero::after { + content: ""; + position: absolute; + z-index: -1; + border-radius: 50%; + filter: blur(48px); + pointer-events: none; +} +.standards-home .VPHero::before { + width: 560px; + height: 360px; + left: 48%; + top: -80px; + background: radial-gradient( + circle at 45% 45%, + var(--hero-aurora-pink), + transparent 70% + ); +} +.standards-home .VPHero::after { + width: 480px; + height: 380px; + left: 4%; + top: 120px; + background: radial-gradient( + circle at 55% 50%, + var(--hero-aurora-blue), + transparent 70% + ); +} + +/* ヒーロー要素の登場アニメーション */ +@media (prefers-reduced-motion: no-preference) { + .standards-home .VPHero .name, + .standards-home .VPHero .tagline, + .standards-home .VPHero .actions { + animation: hero-rise 0.8s cubic-bezier(0.22, 1, 0.36, 1) both; + } + .standards-home .VPHero .tagline { + animation-delay: 0.15s; + } + .standards-home .VPHero .actions { + animation-delay: 0.3s; + } + + /* オーロラのドリフト(reduced-motion時は静止表示のまま) */ + .standards-home .VPHero::before { + animation: hero-aurora-a 13s ease-in-out infinite alternate; + } + .standards-home .VPHero::after { + animation: hero-aurora-b 17s ease-in-out infinite alternate; + } +} +@keyframes hero-aurora-a { + from { + transform: translate(0, 0) scale(1); + } + to { + transform: translate(-120px, 40px) scale(1.25); + } +} +@keyframes hero-aurora-b { + from { + transform: translate(0, 0) scale(1.1); + } + to { + transform: translate(140px, -30px) scale(0.9); + } +} +@keyframes hero-rise { + from { + opacity: 0; + transform: translateY(18px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + /* メインコンテンツの幅を広げます。最大1920pxまでを許可します。 */ #app .VPDoc.has-aside .content-container { max-width: 1280px; From 13b15aac5d4ff860dba14234bb49777b029091cc Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Wed, 19 Aug 2026 14:33:56 +0900 Subject: [PATCH 2/2] fix --- eslint.config.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eslint.config.mjs b/eslint.config.mjs index 01a6b73e..c5fda129 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -57,6 +57,8 @@ export default defineConfig([ ignoreUrls: [ // TODO なぜか Proxy環境で SocketError: other side closed となる。。。 "http://www.oracle.com/technetwork/java/codeconvtoc-136057.html", + // ログインなしではみられなくなった? + "https://github.com/future-architect/coding-standards/stargazers", // サイトは削除されているがドキュメントとしては残すリンク "https://www.acroquest.co.jp/webworkshop/javacordingrule/Acroquest_JavaCodingStandard_6_7.pdf", "http://www.fedict.belgium.be/sites/default/files/downloads/Java_J2EE_conventions_and_guidelines_EN.pdf",