Skip to content

Commit 3b16d7e

Browse files
committed
Use dialog element
1 parent 2d7e5a9 commit 3b16d7e

3 files changed

Lines changed: 148 additions & 171 deletions

File tree

index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
<link rel="image_src" href="https://s2v.app/static/preview.jpg">
1111
<link rel="preload" href="static/Manrope.woff2" as="font" type="font/woff2" crossorigin>
1212
<link rel="preconnect" href="https://api.github.com">
13-
<link rel="stylesheet" href="static/style.css?v=1760691590">
14-
<script src="static/main.js?v=1760691590" defer></script>
13+
<link rel="stylesheet" href="static/style.css?v=1770559932">
14+
<script src="static/main.js?v=1770559932" defer></script>
1515
<meta name="description" content="Browse VPK archives, view, extract, and decompile Source 2 assets. Supports CS2, Dota 2, Deadlock, Half-Life: Alyx, and more.">
1616
<meta property="og:description" content="Browse VPK archives, view, extract, and decompile Source 2 assets. Supports CS2, Dota 2, Deadlock, Half-Life: Alyx, and more.">
1717
<meta property="og:url" content="https://s2v.app/">

static/main.js

Lines changed: 49 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -168,96 +168,80 @@ fetch('https://api.github.com/repositories/42366054/releases?per_page=5', {
168168
});
169169

170170
function AdjustChangelog(changelogContainer) {
171-
// Handle images
172-
const images = changelogContainer.querySelectorAll('img');
173-
images.forEach(img => {
174-
// Remove parent link to prevent new-tab navigation
175-
const parentLink = img.closest('a');
176-
if (parentLink && parentLink.href === img.src) {
171+
const wrapMedia = (element, unwrapParent) => {
172+
if (unwrapParent) {
177173
const wrapper = document.createElement('div');
178-
wrapper.className = 'changelog-img-wrapper';
179-
parentLink.parentNode.insertBefore(wrapper, parentLink);
180-
wrapper.appendChild(img);
181-
parentLink.remove();
182-
} else if (!img.closest('.changelog-img-wrapper')) {
174+
wrapper.className = 'changelog-media-wrapper';
175+
unwrapParent.parentNode.insertBefore(wrapper, unwrapParent);
176+
wrapper.appendChild(element);
177+
unwrapParent.remove();
178+
} else if (!element.closest('.changelog-media-wrapper')) {
183179
const wrapper = document.createElement('div');
184-
wrapper.className = 'changelog-img-wrapper';
185-
img.parentNode.insertBefore(wrapper, img);
186-
wrapper.appendChild(img);
180+
wrapper.className = 'changelog-media-wrapper';
181+
element.parentNode.insertBefore(wrapper, element);
182+
wrapper.appendChild(element);
187183
}
184+
};
185+
186+
for (const img of changelogContainer.querySelectorAll('img')) {
187+
const parentLink = img.closest('a');
188+
wrapMedia(img, parentLink?.href === img.src ? parentLink : null);
188189

189-
// Add click handler for modal
190-
img.style.cursor = 'zoom-in';
191190
img.addEventListener('click', (e) => {
192191
e.preventDefault();
193-
OpenMediaModal(img.src, img.alt, 'image');
192+
OpenMediaModal(img.src, 'image');
194193
});
195-
});
194+
}
196195

197-
// Handle videos
198-
const videos = changelogContainer.querySelectorAll('video');
199-
videos.forEach(video => {
200-
// Remove outer details/summary wrapper if present
201-
const detailsParent = video.closest('details');
202-
if (detailsParent) {
203-
const wrapper = document.createElement('div');
204-
wrapper.className = 'changelog-video-wrapper';
205-
detailsParent.parentNode.insertBefore(wrapper, detailsParent);
206-
wrapper.appendChild(video);
207-
detailsParent.remove();
208-
} else if (!video.closest('.changelog-video-wrapper')) {
209-
const wrapper = document.createElement('div');
210-
wrapper.className = 'changelog-video-wrapper';
211-
video.parentNode.insertBefore(wrapper, video);
212-
wrapper.appendChild(video);
213-
}
196+
for (const video of changelogContainer.querySelectorAll('video')) {
197+
wrapMedia(video, video.closest('details'));
214198

215-
// Add click handler for modal
216-
video.style.cursor = 'zoom-in';
217199
video.addEventListener('click', (e) => {
218200
e.preventDefault();
219-
OpenMediaModal(video.src || video.querySelector('source')?.src, '', 'video');
201+
OpenMediaModal(video.src || video.querySelector('source')?.src, 'video');
220202
});
221-
});
203+
}
222204
}
223205

224-
// Media modal for changelog (images and videos)
225-
function OpenMediaModal(src, alt, type) {
206+
function OpenMediaModal(src, type) {
226207
let modal = document.getElementById('changelog-media-modal');
227208
if (!modal) {
228-
modal = document.createElement('div');
209+
modal = document.createElement('dialog');
229210
modal.id = 'changelog-media-modal';
230211
modal.className = 'changelog-modal';
231-
modal.innerHTML = `
232-
<div class="changelog-modal-backdrop">
233-
<button class="changelog-modal-close" aria-label="Close">&times;</button>
234-
<div class="changelog-modal-content"></div>
235-
</div>
236-
`;
237-
document.body.appendChild(modal);
238212

239-
const closeModal = () => {
240-
modal.classList.remove('active');
241-
const content = modal.querySelector('.changelog-modal-content');
242-
const video = content.querySelector('video');
213+
const closeBtn = document.createElement('button');
214+
closeBtn.className = 'changelog-modal-close';
215+
closeBtn.ariaLabel = 'Close';
216+
closeBtn.textContent = '\u00D7';
217+
closeBtn.onclick = () => modal.close();
218+
modal.appendChild(closeBtn);
219+
220+
modal.addEventListener('click', (e) => {
221+
if (e.target === modal) modal.close();
222+
});
223+
modal.addEventListener('close', () => {
224+
const video = modal.querySelector('video');
243225
if (video) video.pause();
244-
};
245-
modal.querySelector('.changelog-modal-close').onclick = closeModal;
246-
modal.querySelector('.changelog-modal-backdrop').onclick = (e) => {
247-
if (e.target.classList.contains('changelog-modal-backdrop')) closeModal();
248-
};
249-
document.addEventListener('keydown', (e) => {
250-
if (e.key === 'Escape' && modal.classList.contains('active')) closeModal();
251226
});
227+
228+
document.body.appendChild(modal);
252229
}
253230

254-
const content = modal.querySelector('.changelog-modal-content');
231+
const existing = modal.querySelector('img, video');
232+
if (existing) existing.remove();
233+
234+
const media = document.createElement(type === 'video' ? 'video' : 'img');
235+
media.className = 'changelog-modal-media';
236+
media.src = src;
255237
if (type === 'video') {
256-
content.innerHTML = `<video class="changelog-modal-video" src="${src}" controls autoplay loop></video>`;
257-
} else {
258-
content.innerHTML = `<img class="changelog-modal-img" src="${src}" alt="${alt || ''}">`;
238+
media.controls = true;
239+
media.autoplay = true;
240+
media.loop = true;
259241
}
260-
modal.classList.add('active');
242+
modal.appendChild(media);
243+
244+
modal.showModal();
261245
}
262246

263247
function LoadWorkshop() {

static/style.css

Lines changed: 97 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -927,134 +927,127 @@ a.hljs-built_in {
927927
}
928928
}
929929

930-
/* Changelog image optimization */
931-
.changelog-img-wrapper {
930+
.changelog-media-wrapper {
932931
display: block;
933932
max-width: var(--changelog-media-width);
934933
width: 100%;
935934
margin: 1rem auto;
936-
}
937-
938-
.changelog-img-wrapper img {
939-
width: 100%;
940-
height: auto;
941-
border-radius: 6px;
942-
border: 1px solid rgba(255, 255, 255, 0.08);
943-
transition: transform 0.2s ease, border-color 0.2s ease;
944-
}
945935

946-
.changelog-img-wrapper img:hover {
947-
border-color: var(--color-accent);
948-
transform: scale(1.02);
949-
}
950-
951-
/* Changelog video optimization */
952-
.changelog-video-wrapper {
953-
display: block;
954-
max-width: var(--changelog-media-width);
955-
width: 100%;
956-
margin: 1rem auto;
957-
}
936+
img,
937+
video {
938+
width: 100%;
939+
height: auto;
940+
border-radius: 6px;
941+
border: 1px solid rgba(255, 255, 255, 0.08);
942+
cursor: zoom-in;
943+
transition:
944+
transform 0.2s ease,
945+
border-color 0.2s ease;
958946

959-
.changelog-video-wrapper video {
960-
width: 100%;
961-
height: auto;
962-
border-radius: 6px;
963-
border: 1px solid rgba(255, 255, 255, 0.08);
964-
transition: transform 0.2s ease, border-color 0.2s ease;
947+
&:hover {
948+
border-color: var(--color-accent);
949+
transform: scale(1.02);
950+
}
951+
}
965952
}
966953

967-
.changelog-video-wrapper video:hover {
968-
border-color: var(--color-accent);
969-
transform: scale(1.02);
954+
html:has(dialog[open]) {
955+
overflow: hidden;
956+
scrollbar-gutter: stable;
970957
}
971958

972959
/* Media modal (images and videos) */
973960
.changelog-modal {
974-
display: none;
975-
position: fixed;
976-
inset: 0;
977-
z-index: 9999;
978-
animation: fadeIn 0.2s ease;
979-
}
980-
981-
.changelog-modal.active {
982-
display: block;
983-
}
984-
985-
.changelog-modal-backdrop {
986-
position: fixed;
987-
inset: 0;
988-
background: rgba(0, 0, 0, 0.92);
989-
display: flex;
961+
border: none;
962+
background: transparent;
963+
max-width: none;
964+
max-height: none;
965+
width: 100%;
966+
height: 100%;
990967
align-items: center;
991968
justify-content: center;
992969
padding: 2rem;
993-
backdrop-filter: blur(4px);
994-
}
970+
opacity: 0;
971+
transition:
972+
opacity 0.2s ease,
973+
overlay 0.2s ease allow-discrete,
974+
display 0.2s ease allow-discrete;
995975

996-
.changelog-modal-content {
997-
display: flex;
998-
align-items: center;
999-
justify-content: center;
1000-
}
976+
&[open] {
977+
display: flex;
978+
opacity: 1;
1001979

1002-
.changelog-modal-img,
1003-
.changelog-modal-video {
1004-
max-width: 100%;
1005-
max-height: 90vh;
1006-
width: auto;
1007-
height: auto;
1008-
border-radius: 8px;
1009-
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
1010-
object-fit: contain;
1011-
}
980+
@starting-style {
981+
opacity: 0;
982+
}
983+
}
1012984

1013-
.changelog-modal-close {
1014-
position: absolute;
1015-
top: 1.5rem;
1016-
right: 1.5rem;
1017-
background: rgba(255, 255, 255, 0.1);
1018-
border: none;
1019-
color: #fff;
1020-
font-size: 2rem;
1021-
line-height: 1;
1022-
width: 48px;
1023-
height: 48px;
1024-
border-radius: 50%;
1025-
cursor: pointer;
1026-
transition: background 0.2s ease;
1027-
z-index: 10000;
1028-
}
985+
&::backdrop {
986+
background: rgba(0, 0, 0, 0.92);
987+
backdrop-filter: blur(4px);
988+
opacity: 0;
989+
transition:
990+
opacity 0.2s ease,
991+
overlay 0.2s ease allow-discrete,
992+
display 0.2s ease allow-discrete;
993+
}
1029994

1030-
.changelog-modal-close:hover {
1031-
background: rgba(255, 255, 255, 0.2);
1032-
}
995+
&[open]::backdrop {
996+
opacity: 1;
1033997

1034-
@keyframes fadeIn {
1035-
from { opacity: 0; }
1036-
to { opacity: 1; }
1037-
}
998+
@starting-style {
999+
opacity: 0;
1000+
}
1001+
}
10381002

1039-
@media (max-width: 768px) {
1040-
.changelog-img-wrapper {
1041-
max-width: 100%;
1003+
.changelog-modal-media {
1004+
max-width: 90vw;
1005+
max-height: 90vh;
1006+
border-radius: 8px;
1007+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
1008+
object-fit: contain;
10421009
}
10431010

1044-
.changelog-modal-backdrop {
1045-
padding: 1rem;
1011+
.changelog-modal-close {
1012+
position: fixed;
1013+
top: 1.5rem;
1014+
right: 1.5rem;
1015+
background: rgba(255, 255, 255, 0.1);
1016+
border: none;
1017+
color: #fff;
1018+
font-size: 2rem;
1019+
line-height: 1;
1020+
width: 48px;
1021+
height: 48px;
1022+
border-radius: 50%;
1023+
cursor: pointer;
1024+
transition: background 0.2s ease;
1025+
z-index: 1;
1026+
1027+
&:hover {
1028+
background: rgba(255, 255, 255, 0.2);
1029+
}
10461030
}
1047-
1048-
.changelog-modal-img,
1049-
.changelog-modal-video {
1050-
max-height: 80vh;
1031+
1032+
@media (max-width: 768px) {
1033+
padding: 1rem;
1034+
1035+
.changelog-modal-media {
1036+
max-height: 80vh;
1037+
}
1038+
1039+
.changelog-modal-close {
1040+
top: 1rem;
1041+
right: 1rem;
1042+
width: 40px;
1043+
height: 40px;
1044+
font-size: 1.5rem;
1045+
}
10511046
}
1052-
1053-
.changelog-modal-close {
1054-
top: 1rem;
1055-
right: 1rem;
1056-
width: 40px;
1057-
height: 40px;
1058-
font-size: 1.5rem;
1047+
}
1048+
1049+
@media (max-width: 768px) {
1050+
.changelog-media-wrapper {
1051+
max-width: 100%;
10591052
}
10601053
}

0 commit comments

Comments
 (0)