mirror of
https://github.com/NetworkCats/rustyip.git
synced 2026-11-13 16:17:46 +00:00
feat: add skeleton loading state for alt-IP section when primary IP is IPv6
Show a shimmer skeleton placeholder while fetching the local IPv4 address via the IPv4-only domain. When the primary IP is already IPv4, no loading state is displayed and the alt section fades in directly.
This commit is contained in:
+41
-5
@@ -272,10 +272,37 @@ function initCopyIp(wrap){
|
||||
return html;
|
||||
}
|
||||
|
||||
function showAltIp(ip,info){
|
||||
section.innerHTML=buildBlock(ip,info);
|
||||
function buildSkeleton(){
|
||||
var html='<div class="skeleton-block">';
|
||||
html+='<div class="skeleton-bone skeleton-ip"></div>';
|
||||
html+='</div>';
|
||||
html+='<div class="skeleton-table">';
|
||||
for(var i=0;i<8;i++){
|
||||
html+='<div class="skeleton-row">';
|
||||
html+='<div class="skeleton-row-label"><div class="skeleton-bone"></div></div>';
|
||||
html+='<div class="skeleton-row-value"><div class="skeleton-bone"></div></div>';
|
||||
html+='</div>';
|
||||
}
|
||||
html+='</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
function showSkeleton(){
|
||||
section.innerHTML=buildSkeleton();
|
||||
section.hidden=false;
|
||||
initCopyIp(section.querySelector(".ip-copy-wrap"));
|
||||
section.classList.add("alt-visible");
|
||||
}
|
||||
|
||||
function showAltIp(ip,info){
|
||||
section.classList.remove("alt-visible");
|
||||
setTimeout(function(){
|
||||
section.innerHTML=buildBlock(ip,info);
|
||||
initCopyIp(section.querySelector(".ip-copy-wrap"));
|
||||
section.hidden=false;
|
||||
// Force reflow before adding the visible class for transition
|
||||
void section.offsetHeight;
|
||||
section.classList.add("alt-visible");
|
||||
},primaryIsIPv6?300:0);
|
||||
}
|
||||
|
||||
function fetchJson(ip){
|
||||
@@ -285,8 +312,17 @@ function initCopyIp(wrap){
|
||||
});
|
||||
}
|
||||
|
||||
function hideSkeleton(){
|
||||
section.classList.remove("alt-visible");
|
||||
setTimeout(function(){
|
||||
section.innerHTML="";
|
||||
section.hidden=true;
|
||||
},300);
|
||||
}
|
||||
|
||||
function detectAltIp(){
|
||||
if(primaryIsIPv6&&ipv4Domain){
|
||||
showSkeleton();
|
||||
var controller=new AbortController();
|
||||
var timeout=setTimeout(function(){controller.abort();},5000);
|
||||
fetch("https://"+ipv4Domain+"/",{signal:controller.signal})
|
||||
@@ -297,12 +333,12 @@ function initCopyIp(wrap){
|
||||
})
|
||||
.then(function(text){
|
||||
var ip=text.trim();
|
||||
if(!ip||ip.indexOf(":")!==-1)return;
|
||||
if(!ip||ip.indexOf(":")!==-1){hideSkeleton();return;}
|
||||
return fetchJson(ip).then(function(info){
|
||||
showAltIp(ip,info);
|
||||
});
|
||||
})
|
||||
.catch(function(){});
|
||||
.catch(function(){hideSkeleton();});
|
||||
}else if(!primaryIsIPv6){
|
||||
fetch("/ip")
|
||||
.then(function(r){
|
||||
|
||||
@@ -477,6 +477,82 @@ main {
|
||||
padding: 6px 10px 6px 28px;
|
||||
}
|
||||
|
||||
#alt-ip-section {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
#alt-ip-section.alt-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.skeleton-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.skeleton-bone {
|
||||
background: var(--color-gray5);
|
||||
border-radius: 6px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.skeleton-bone::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
var(--color-bg-tertiary) 50%,
|
||||
transparent 100%
|
||||
);
|
||||
animation: skeleton-shimmer 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes skeleton-shimmer {
|
||||
0% { translate: -100% 0; }
|
||||
100% { translate: 100% 0; }
|
||||
}
|
||||
|
||||
.skeleton-ip {
|
||||
inline-size: 260px;
|
||||
block-size: 42px;
|
||||
margin-block: 28px 20px;
|
||||
}
|
||||
|
||||
.skeleton-table {
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
.skeleton-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-block: 10px;
|
||||
border-block-start: 1px solid var(--color-separator);
|
||||
}
|
||||
|
||||
.skeleton-row:last-child {
|
||||
border-block-end: 1px solid var(--color-separator);
|
||||
}
|
||||
|
||||
.skeleton-row-label {
|
||||
inline-size: 42%;
|
||||
padding-inline: 35px 32px;
|
||||
}
|
||||
|
||||
.skeleton-row-label .skeleton-bone {
|
||||
inline-size: 60px;
|
||||
block-size: 15px;
|
||||
}
|
||||
|
||||
.skeleton-row-value .skeleton-bone {
|
||||
inline-size: 100px;
|
||||
block-size: 15px;
|
||||
}
|
||||
|
||||
@media (width <= 480px) {
|
||||
main {
|
||||
margin-block-start: 40px;
|
||||
|
||||
Reference in New Issue
Block a user