|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Neon Portal</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
<style> |
|
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700;900&display=swap'); |
|
|
|
:root { |
|
--neon-blue: #05d9e8; |
|
--neon-pink: #ff2a6d; |
|
--neon-purple: #d300c5; |
|
--dark-bg: #05010e; |
|
--darker-bg: #0d0221; |
|
--nav-dark: #12092a; |
|
} |
|
|
|
body { |
|
font-family: 'Orbitron', sans-serif; |
|
background-color: var(--dark-bg); |
|
color: white; |
|
min-height: 100vh; |
|
background-image: var(--bg-image, none); |
|
background-size: cover; |
|
background-attachment: fixed; |
|
background-position: center; |
|
} |
|
|
|
.glitch-effect { |
|
position: relative; |
|
color: white; |
|
} |
|
|
|
.glitch-effect::before, .glitch-effect::after { |
|
content: attr(data-text); |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
opacity: 0.8; |
|
} |
|
|
|
.glitch-effect::before { |
|
color: var(--neon-blue); |
|
z-index: -1; |
|
animation: glitch-effect 3s infinite; |
|
} |
|
|
|
.glitch-effect::after { |
|
color: var(--neon-pink); |
|
z-index: -2; |
|
animation: glitch-effect 2s infinite reverse; |
|
} |
|
|
|
@keyframes glitch-effect { |
|
0% { transform: translate(0); } |
|
20% { transform: translate(-3px, 3px); } |
|
40% { transform: translate(-3px, -3px); } |
|
60% { transform: translate(3px, 3px); } |
|
80% { transform: translate(3px, -3px); } |
|
100% { transform: translate(0); } |
|
} |
|
|
|
.neon-text-blue { |
|
color: var(--neon-blue); |
|
text-shadow: 0 0 5px var(--neon-blue), 0 0 10px var(--neon-blue), 0 0 20px var(--neon-blue); |
|
} |
|
|
|
.neon-text-pink { |
|
color: var(--neon-pink); |
|
text-shadow: 0 0 5px var(--neon-pink), 0 0 10px var(--neon-pink), 0 0 20px var(--neon-pink); |
|
} |
|
|
|
.neon-text-purple { |
|
color: var(--neon-purple); |
|
text-shadow: 0 0 5px var(--neon-purple), 0 0 10px var(--neon-purple), 0 0 20px var(--neon-purple); |
|
} |
|
|
|
.neon-border-blue { |
|
border: 1px solid var(--neon-blue); |
|
box-shadow: 0 0 5px var(--neon-blue), inset 0 0 5px var(--neon-blue), 0 0 20px var(--neon-blue); |
|
} |
|
|
|
.neon-border-pink { |
|
border: 1px solid var(--neon-pink); |
|
box-shadow: 0 0 5px var(--neon-pink), inset 0 0 5px var(--neon-pink), 0 0 20px var(--neon-pink); |
|
} |
|
|
|
.neon-hover:hover { |
|
text-shadow: 0 0 10px currentColor, 0 0 20px currentColor, 0 0 30px currentColor; |
|
transition: text-shadow 0.3s ease; |
|
} |
|
|
|
.nav-item:hover { |
|
transform: translateY(-2px); |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.dropdown { |
|
display: none; |
|
background: var(--nav-dark); |
|
border: 1px solid var(--neon-blue); |
|
box-shadow: 0 0 20px var(--neon-blue); |
|
transition: all 0.3s ease; |
|
z-index: 100; |
|
} |
|
|
|
.group:hover .dropdown { |
|
display: block; |
|
} |
|
|
|
.portal-card { |
|
transition: all 0.3s ease; |
|
backdrop-filter: blur(10px); |
|
perspective: 1000px; |
|
transform-style: preserve-3d; |
|
} |
|
|
|
.portal-card:hover { |
|
transform: translateY(-5px) scale(1.05); |
|
box-shadow: 0 0 20px currentColor; |
|
} |
|
|
|
.portal-card-inner { |
|
transition: transform 0.6s; |
|
transform-style: preserve-3d; |
|
} |
|
|
|
.portal-card:hover .portal-card-inner { |
|
transform: rotateY(15deg) rotateX(10deg); |
|
} |
|
|
|
.modal-overlay { |
|
background: rgba(5, 1, 14, 0.9); |
|
backdrop-filter: blur(5px); |
|
animation: fadeIn 0.3s ease; |
|
} |
|
|
|
.modal-content { |
|
animation: slideIn 0.3s ease; |
|
background: var(--darker-bg); |
|
} |
|
|
|
@keyframes fadeIn { |
|
from { opacity: 0; } |
|
to { opacity: 1; } |
|
} |
|
|
|
@keyframes slideIn { |
|
from { transform: translateY(-50px); opacity: 0; } |
|
to { transform: translateY(0); opacity: 1; } |
|
} |
|
|
|
.color-option { |
|
width: 30px; |
|
height: 30px; |
|
border-radius: 50%; |
|
display: inline-block; |
|
margin: 5px; |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
position: relative; |
|
} |
|
|
|
.color-option:hover { |
|
transform: scale(1.1); |
|
} |
|
|
|
.color-option.selected::after { |
|
content: "✓"; |
|
position: absolute; |
|
top: 50%; |
|
left: 50%; |
|
transform: translate(-50%, -50%); |
|
color: white; |
|
font-weight: bold; |
|
} |
|
|
|
.custom-color-toggle { |
|
padding: 8px; |
|
cursor: pointer; |
|
border-radius: 5px; |
|
margin-top: 10px; |
|
text-align: center; |
|
border: 1px dashed var(--neon-blue); |
|
} |
|
|
|
.custom-color-toggle:hover { |
|
background: rgba(5, 217, 232, 0.1); |
|
} |
|
|
|
.custom-color-input { |
|
width: 100%; |
|
height: 30px; |
|
border: none; |
|
background: transparent; |
|
cursor: pointer; |
|
margin-top: 10px; |
|
} |
|
|
|
.bg-preview, .icon-preview { |
|
max-width: 100%; |
|
height: auto; |
|
margin-top: 10px; |
|
border-radius: 5px; |
|
display: none; |
|
} |
|
|
|
.grid-lines { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
width: 100%; |
|
height: 100%; |
|
background-image: linear-gradient(to right, rgba(5, 217, 232, 0.05) 1px, transparent 1px), |
|
linear-gradient(to bottom, rgba(5, 217, 232, 0.05) 1px, transparent 1px); |
|
background-size: 30px 30px; |
|
z-index: -1; |
|
pointer-events: none; |
|
} |
|
|
|
.neon-underline { |
|
position: relative; |
|
display: inline-block; |
|
} |
|
|
|
.neon-underline::after { |
|
content: ''; |
|
position: absolute; |
|
bottom: -5px; |
|
left: 0; |
|
width: 100%; |
|
height: 2px; |
|
background: linear-gradient(to right, var(--neon-blue), var(--neon-pink)); |
|
transform: scaleX(0); |
|
transform-origin: bottom right; |
|
transition: transform 0.5s ease-out; |
|
} |
|
|
|
.neon-underline:hover::after { |
|
transform: scaleX(1); |
|
transform-origin: bottom left; |
|
} |
|
|
|
|
|
.holographic-effect { |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.holographic-effect::before { |
|
content: ''; |
|
position: absolute; |
|
top: -50%; |
|
left: -50%; |
|
width: 200%; |
|
height: 200%; |
|
background: linear-gradient( |
|
to bottom right, |
|
rgba(255, 255, 255, 0) 45%, |
|
rgba(5, 217, 232, 0.2) 50%, |
|
rgba(255, 255, 255, 0) 55% |
|
); |
|
transform: rotate(30deg); |
|
animation: holographic 6s linear infinite; |
|
} |
|
|
|
@keyframes holographic { |
|
0% { transform: translateY(-100%) rotate(30deg); } |
|
100% { transform: translateY(100%) rotate(30deg); } |
|
} |
|
</style> |
|
</head> |
|
<body class="min-h-screen relative"> |
|
|
|
<div class="grid-lines"></div> |
|
|
|
|
|
<nav class="navbar fixed top-0 left-0 right-0 z-50 bg-[#05010e]/90 backdrop-blur-md border-b border-[#12092a]"> |
|
<div class="container mx-auto px-4"> |
|
<div class="flex justify-between items-center h-16"> |
|
|
|
<div class="flex items-center"> |
|
<div class="neon-border-pink rounded-full p-2"> |
|
<i class="fas fa-terminal text-xl neon-text-pink"></i> |
|
</div> |
|
<span class="ml-3 font-bold text-xl neon-text-blue">NEON PORTAL</span> |
|
</div> |
|
|
|
|
|
<div class="hidden md:flex items-center space-x-6"> |
|
<div class="nav-item relative group"> |
|
<button class="flex items-center space-x-1 neon-text-blue neon-underline"> |
|
<i class="fas fa-cog"></i> |
|
<span>Settings</span> |
|
<i class="fas fa-chevron-down text-xs"></i> |
|
</button> |
|
<div class="dropdown absolute right-0 mt-2 w-80 rounded-lg dropdown-content p-4"> |
|
<h3 class="text-sm neon-text-pink mb-3 uppercase tracking-wider">Portal Management</h3> |
|
<button onclick="showAddLinkModal()" |
|
class="w-full py-2 neon-border-blue rounded flex items-center justify-center mb-3 hover:bg-[#05d9e8] hover:text-[#0d0221] transition-all"> |
|
<i class="fas fa-plus mr-2"></i>Add New Portal |
|
</button> |
|
|
|
<h3 class="text-sm neon-text-blue mt-4 mb-3 uppercase tracking-wider">Customization</h3> |
|
<div class="space-y-4"> |
|
<div> |
|
<label for="bg-image" class="block mb-2 text-xs uppercase tracking-wider">Background Image URL</label> |
|
<div class="flex"> |
|
<input type="url" id="bg-image" class="flex-grow p-2 rounded-l-lg bg-[#12092a]" |
|
placeholder="https://example.com/image.jpg"> |
|
<button onclick="setBackgroundImage()" |
|
class="px-3 py-2 bg-[#05d9e8] text-[#0d0221] rounded-r-lg hover:bg-[#00c4d2] transition-all"> |
|
<i class="fas fa-check"></i> |
|
</button> |
|
</div> |
|
<div class="bg-upload-container"> |
|
<label class="block mt-2 text-xs uppercase tracking-wider">Upload Background</label> |
|
<input type="file" id="bg-upload" class="w-full mt-1" accept="image/*"> |
|
<img id="bg-preview" class="bg-preview" src="#" alt="Background Preview"> |
|
<button onclick="applyUploadedBackground()" |
|
class="mt-2 px-3 py-1 rounded border border-[#ff2a6d] hover:bg-[#ff2a6d]/20 transition-all text-xs"> |
|
Apply Uploaded Image |
|
</button> |
|
</div> |
|
<button onclick="resetBackgroundImage()" |
|
class="mt-2 text-xs px-3 py-1 rounded border border-[#ff2a6d] hover:bg-[#ff2a6d]/20 transition-all"> |
|
Reset Background |
|
</button> |
|
</div> |
|
|
|
<div> |
|
<label class="block mb-2 text-xs uppercase tracking-wider">Theme Color</label> |
|
<div class="color-picker-container neon-border-blue rounded-lg p-4"> |
|
<div class="color-option selected" style="background-color: #05d9e8;" |
|
onclick="selectThemeColor('#05d9e8', this)"></div> |
|
<div class="color-option" style="background-color: #ff2a6d;" |
|
onclick="selectThemeColor('#ff2a6d', this)"></div> |
|
<div class="color-option" style="background-color: #d300c5;" |
|
onclick="selectThemeColor('#d300c5', this)"></div> |
|
<div class="color-option" style="background-color: #00ff9d;" |
|
onclick="selectThemeColor('#00ff9d', this)"></div> |
|
<div class="color-option" style="background-color: #ffcc00;" |
|
onclick="selectThemeColor('#ffcc00', this)"></div> |
|
<div class="color-option" style="background-color: #ff3333;" |
|
onclick="selectThemeColor('#ff3333', this)"></div> |
|
<div class="color-option" style="background-color: #4267B2;" |
|
onclick="selectThemeColor('#4267B2', this)"></div> |
|
<div class="color-option" style="background-color: #9147ff;" |
|
onclick="selectThemeColor('#9147ff', this)"></div> |
|
<div class="color-option" style="background-color: #25F4EE;" |
|
onclick="selectThemeColor('#25F4EE', this)"></div> |
|
<div class="custom-color-toggle w-full" onclick="toggleCustomColorInput()"> |
|
Custom Color |
|
</div> |
|
<div id="custom-color-wrapper" class="custom-color-option" style="display: none;"> |
|
<input type="color" id="custom-color" class="custom-color-input"> |
|
<button class="custom-color-confirm mt-2 px-3 py-1 rounded border border-[#05d9e8] hover:bg-[#05d9e8]/20 transition-all" onclick="confirmCustomColor()">OK</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<h3 class="text-sm neon-text-blue mt-4 mb-3 uppercase tracking-wider">System Info</h3> |
|
<div class="text-xs space-y-2"> |
|
<div class="flex justify-between"> |
|
<span>Version</span> |
|
<span class="text-[#05d9e8]">v2.3.5</span> |
|
</div> |
|
<div class="flex justify-between"> |
|
<span>Portals</span> |
|
<span id="portal-count" class="text-[#ff2a6d]">0</span> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="nav-item relative group"> |
|
<button class="flex items-center space-x-1 neon-text-blue neon-underline"> |
|
<i class="fas fa-address-card"></i> |
|
<span>Contact</span> |
|
<i class="fas fa-chevron-down text-xs"></i> |
|
</button> |
|
<div class="dropdown absolute right-0 mt-2 w-72 rounded-lg dropdown-content p-4"> |
|
<h3 class="text-sm neon-text-pink mb-3 uppercase tracking-wider">Connection Channels</h3> |
|
<div class="space-y-3"> |
|
<div class="contact-card p-3 rounded border border-[#05d9e8] hover:bg-[#05d9e8]/10 transition-all"> |
|
<div class="flex items-center"> |
|
<i class="fas fa-envelope text-lg text-[#05d9e8] mr-3"></i> |
|
<div> |
|
<h4 class="font-bold">Encrypted Mail</h4> |
|
<a href="mailto:" |
|
class="text-sm hover:underline block">daisuke at duck.com</a> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="contact-card p-3 rounded border border-[#ff2a6d] hover:bg-[#ff2a6d]/10 transition-all"> |
|
<div class="flex items-center"> |
|
<i class="fab fa-discord text-lg text-[#5865F2] mr-3"></i> |
|
<div> |
|
<h4 class="font-bold">Discord</h4> |
|
<span class="text-sm">NeonPortal#0001</span> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="contact-card p-3 rounded border border-[#25F4EE] hover:bg-[#25F4EE]/10 transition-all"> |
|
<div class="flex items-center"> |
|
<i class="fab fa-twitter text-lg text-[#1DA1F2] mr-3"></i> |
|
<div> |
|
<h4 class="font-bold">Twitter</h4> |
|
<a href="https://twitter.com/daisuke" target="_blank" class="text-sm hover:underline block">@daisuke</a> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="contact-card p-3 rounded border border-[#9147ff] hover:bg-[#9147ff]/10 transition-all"> |
|
<div class="flex items-center"> |
|
<i class="fab fa-patreon text-lg text-[#FF424D] mr-3"></i> |
|
<div> |
|
<h4 class="font-bold">Support</h4> |
|
<a href="https://patreon.com/neonportal" target="_blank" class="text-sm hover:underline block">Patreon</a> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="md:hidden"> |
|
<button id="mobile-menu-button" class="neon-text-pink text-2xl focus:outline-none"> |
|
<i class="fas fa-bars"></i> |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="mobile-menu" class="md:hidden hidden bg-[#05010e] border-t border-[#ff2a6d]"> |
|
<div class="px-2 py-3 space-y-1"> |
|
<button onclick="showAddLinkModal()" class="block px-3 py-2 rounded-md neon-text-blue w-full text-left hover:bg-[#05d9e8]/20"> |
|
<i class="fas fa-plus mr-2"></i>Add New Portal |
|
</button> |
|
<button class="block px-3 py-2 rounded-md neon-text-blue w-full text-left hover:bg-[#05d9e8]/20"> |
|
<i class="fas fa-cog mr-2"></i>Settings |
|
</button> |
|
<button class="block px-3 py-2 rounded-md neon-text-blue w-full text-left hover:bg-[#05d9e8]/20"> |
|
<i class="fas fa-address-card mr-2"></i>Contact |
|
</button> |
|
<div class="px-3 py-2"> |
|
<label class="block text-xs neon-text-blue mb-1">Background Image</label> |
|
<div class="flex mb-2"> |
|
<input type="url" id="bg-image-mobile" class="flex-grow p-2 rounded-l-lg bg-[#12092a]" |
|
placeholder="Image URL"> |
|
<button onclick="setBackgroundImage()" |
|
class="px-3 py-2 bg-[#05d9e8] text-[#0d0221] rounded-r-lg hover:bg-[#00c4d2] transition-all"> |
|
<i class="fas fa-check"></i> |
|
</button> |
|
</div> |
|
<button onclick="resetBackgroundImage()" |
|
class="w-full px-3 py-1.5 text-xs rounded border border-[#ff2a6d] hover:bg-[#ff2a6d]/20 transition-all"> |
|
Reset Background |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</nav> |
|
|
|
|
|
<div class="container mx-auto px-4 py-8 relative z-10 mt-20"> |
|
|
|
<header class="text-center mb-12"> |
|
<div class="relative inline-block"> |
|
<h1 class="glitch-effect text-5xl md:text-7xl font-bold mb-4" data-text="NEON PORTAL">NEON PORTAL</h1> |
|
<span |
|
class="absolute -bottom-3 left-1/2 transform -translate-x-1/2 w-48 h-1 bg-gradient-to-r from-transparent via-[#05d9e8] to-transparent"></span> |
|
<span |
|
class="absolute -bottom-5 left-1/2 transform -translate-x-1/2 w-32 h-1 bg-gradient-to-r from-transparent via-[#ff2a6d] to-transparent"></span> |
|
</div> |
|
<p class="text-xl neon-text-purple uppercase tracking-wider mt-8">Your gateway to the digital neonverse</p> |
|
</header> |
|
|
|
|
|
<div class="flex justify-center mb-12"> |
|
<div class="neon-border-blue rounded-lg p-4 text-center backdrop-blur-sm bg-[#0d0221]/50 holographic-effect"> |
|
<div id="time" class="text-3xl font-bold neon-text-blue">00:00:00</div> |
|
<div id="date" class="text-lg uppercase tracking-wider mt-1">Loading...</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-6 mb-12" id="portals-grid"> |
|
|
|
</div> |
|
</div> |
|
|
|
|
|
<div id="add-portal-modal" class="fixed inset-0 flex items-center justify-center z-50 hidden modal-overlay"> |
|
<div class="modal-content neon-border-blue rounded-xl p-8 max-w-md w-full mx-4 relative"> |
|
<button id="close-portal-modal" |
|
class="absolute top-4 right-4 text-xl hover:text-[#ff2a6d] transition-all">×</button> |
|
<h2 class="text-2xl neon-text-pink mb-6 uppercase tracking-wider">Create New Portal</h2> |
|
|
|
<form id="portal-form" class="space-y-6"> |
|
<div> |
|
<label for="portal-name" class="block mb-2 neon-text-blue uppercase text-sm tracking-wider">Portal Name</label> |
|
<input type="text" id="portal-name" class="w-full p-3 rounded-lg bg-[#12092a] focus:outline-none focus:border focus:border-[#05d9e8]" required> |
|
</div> |
|
|
|
<div> |
|
<label for="portal-url" |
|
class="block mb-2 neon-text-blue uppercase text-sm tracking-wider">Destination URL</label> |
|
<input type="url" id="portal-url" class="w-full p-3 rounded-lg bg-[#12092a] focus:outline-none focus:border focus:border-[#05d9e8]" placeholder="https://" |
|
required> |
|
</div> |
|
|
|
<div> |
|
<label class="block mb-2 neon-text-blue uppercase text-sm tracking-wider">Icon</label> |
|
<select id="portal-icon" class="w-full p-3 rounded-lg bg-[#0d0221] border border-[#05d9e8] focus:outline-none focus:border focus:border-[#ff2a6d]"> |
|
<option value="fab fa-youtube">YouTube</option> |
|
<option value="fab fa-twitter">Twitter</option> |
|
<option value="fab fa-github">GitHub</option> |
|
<option value="fab fa-reddit">Reddit</option> |
|
<option value="fab fa-discord">Discord</option> |
|
<option value="fab fa-facebook">Facebook</option> |
|
<option value="fab fa-google-drive">Drive</option> |
|
<option value="fas fa-envelope">Mail</option> |
|
<option value="fas fa-music">Music</option> |
|
<option value="fas fa-gamepad">Games</option> |
|
<option value="fas fa-film">Movies</option> |
|
<option value="fas fa-newspaper">News</option> |
|
<option value="fas fa-shopping-cart">Shop</option> |
|
<option value="custom-icon">Custom Icon</option> |
|
</select> |
|
|
|
<div id="custom-icon-options" class="custom-icon-option mt-3" style="display: none;"> |
|
<div class="flex space-x-4"> |
|
<div class="flex-1"> |
|
<label class="block mb-2 text-xs uppercase tracking-wider">Upload Icon</label> |
|
<input type="file" id="icon-upload" class="w-full" accept="image/*"> |
|
</div> |
|
<div class="flex-1"> |
|
<label class="block mb-2 text-xs uppercase tracking-wider">Icon URL</label> |
|
<input type="url" id="icon-url" class="w-full p-2 rounded bg-[#0d0221]" |
|
placeholder="https://example.com/icon.png"> |
|
</div> |
|
</div> |
|
<img id="icon-preview" class="icon-preview" src="#" alt="Icon Preview"> |
|
</div> |
|
</div> |
|
|
|
<div> |
|
<label class="block mb-2 neon-text-blue uppercase text-sm tracking-wider">Color</label> |
|
<div class="color-picker-container neon-border-blue rounded-lg p-4"> |
|
<div class="color-option" style="background-color: #ff2a6d;" |
|
onclick="selectPortalColor('#ff2a6d', this)"></div> |
|
<div class="color-option selected" style="background-color: #05d9e8;" |
|
onclick="selectPortalColor('#05d9e8', this)"></div> |
|
<div class="color-option" style="background-color: #d300c5;" |
|
onclick="selectPortalColor('#d300c5', this)"></div> |
|
<div class="color-option" style="background-color: #00ff9d;" |
|
onclick="selectPortalColor('#00ff9d', this)"></div> |
|
<div class="color-option" style="background-color: #ffcc00;" |
|
onclick="selectPortalColor('#ffcc00', this)"></div> |
|
<div class="color-option" style="background-color: #ffffff;" |
|
onclick="selectPortalColor('#ffffff', this)"></div> |
|
<div class="color-option" style="background-color: #4267B2;" |
|
onclick="selectPortalColor('#4267B2', this)"></div> |
|
<div class="color-option" style="background-color: #9147ff;" |
|
onclick="selectPortalColor('#9147ff', this)"></div> |
|
<div class="custom-color-toggle w-full" onclick="togglePortalCustomColorInput()"> |
|
Custom Color |
|
</div> |
|
<input type="color" id="portal-custom-color" class="custom-color-input" |
|
onchange="applyCustomPortalColor(this.value)"> |
|
</div> |
|
<input type="hidden" id="portal-color" value="#05d9e8"> |
|
</div> |
|
|
|
<div class="flex justify-end space-x-3"> |
|
<button type="button" onclick="document.getElementById('add-portal-modal').classList.add('hidden')" |
|
class="px-4 py-2 rounded-lg border border-[#ff2a6d] hover:bg-[#ff2a6d] hover:text-white transition-all"> |
|
Cancel |
|
</button> |
|
<button type="submit" |
|
class="px-6 py-2 neon-border-blue rounded-lg hover:bg-[#05d9e8] hover:text-[#0d0221] transition-all font-bold"> |
|
Create Portal |
|
</button> |
|
</div> |
|
</form> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
|
|
const defaultPortals = [ |
|
{ name: 'YouTube', url: 'https://youtube.com', icon: 'fab fa-youtube', color: '#ff0000' }, |
|
{ name: 'Twitter', url: 'https://twitter.com', icon: 'fab fa-twitter', color: '#1DA1F2' }, |
|
{ name: 'GitHub', url: 'https://github.com', icon: 'fab fa-github', color: '#ffffff' }, |
|
{ name: 'Reddit', url: 'https://reddit.com', icon: 'fab fa-reddit', color: '#FF5700' }, |
|
{ name: 'Discord', url: 'https://discord.com', icon: 'fab fa-discord', color: '#5865F2' }, |
|
{ name: 'Google Drive', url: 'https://drive.google.com', icon: 'fab fa-google-drive', color: '#34A853' }, |
|
{ name: 'Gmail', url: 'https://mail.google.com', icon: 'fas fa-envelope', color: '#EA4335' }, |
|
{ name: 'Spotify', url: 'https://open.spotify.com', icon: 'fas fa-music', color: '#1DB954' } |
|
]; |
|
|
|
|
|
const portalsGrid = document.getElementById('portals-grid'); |
|
const portalForm = document.getElementById('portal-form'); |
|
const portalCount = document.getElementById('portal-count'); |
|
const mobileMenuButton = document.getElementById('mobile-menu-button'); |
|
const mobileMenu = document.getElementById('mobile-menu'); |
|
const timeDisplay = document.getElementById('time'); |
|
const dateDisplay = document.getElementById('date'); |
|
const portalIconSelect = document.getElementById('portal-icon'); |
|
const customIconOptions = document.getElementById('custom-icon-options'); |
|
const bgUpload = document.getElementById('bg-upload'); |
|
const bgPreview = document.getElementById('bg-preview'); |
|
const iconUpload = document.getElementById('icon-upload'); |
|
const iconPreview = document.getElementById('icon-preview'); |
|
|
|
|
|
let portals = JSON.parse(localStorage.getItem('portals')) || defaultPortals; |
|
let currentThemeColor = '#05d9e8'; |
|
let currentBgImage = localStorage.getItem('bgImage') || ''; |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
renderPortals(); |
|
updateTime(); |
|
setInterval(updateTime, 1000); |
|
loadBackgroundImage(); |
|
|
|
|
|
mobileMenuButton.addEventListener('click', function() { |
|
mobileMenu.classList.toggle('hidden'); |
|
}); |
|
|
|
|
|
portalForm.addEventListener('submit', handlePortalFormSubmit); |
|
|
|
|
|
portalIconSelect.addEventListener('change', function() { |
|
if (this.value === 'custom-icon') { |
|
customIconOptions.style.display = 'block'; |
|
} else { |
|
customIconOptions.style.display = 'none'; |
|
} |
|
}); |
|
|
|
|
|
bgUpload.addEventListener('change', function(e) { |
|
const file = e.target.files[0]; |
|
if (file) { |
|
const reader = new FileReader(); |
|
reader.onload = function(event) { |
|
bgPreview.src = event.target.result; |
|
bgPreview.style.display = 'block'; |
|
}; |
|
reader.readAsDataURL(file); |
|
} |
|
}); |
|
|
|
|
|
iconUpload.addEventListener('change', function(e) { |
|
const file = e.target.files[0]; |
|
if (file) { |
|
const reader = new FileReader(); |
|
reader.onload = function(event) { |
|
iconPreview.src = event.target.result; |
|
iconPreview.style.display = 'block'; |
|
}; |
|
reader.readAsDataURL(file); |
|
} |
|
}); |
|
}); |
|
|
|
|
|
function renderPortals() { |
|
portalsGrid.innerHTML = ''; |
|
|
|
portals.forEach((portal, index) => { |
|
const portalElement = document.createElement('div'); |
|
|
|
|
|
const textColorStyle = `color: ${portal.color}; text-shadow: 0 0 5px ${portal.color}, 0 0 10px ${portal.color};`; |
|
const borderStyle = `border: 1px solid ${portal.color}; box-shadow: 0 0 5px ${portal.color}, inset 0 0 5px ${portal.color}, 0 0 20px ${portal.color};`; |
|
|
|
portalElement.innerHTML = ` |
|
<div class="portal-card h-full" style="${borderStyle}"> |
|
<a href="${portal.url}" target="_blank" class="block h-full p-6 rounded-lg text-center relative overflow-hidden backdrop-blur-sm bg-[#0d0221]/50 transition-all duration-300"> |
|
<div class="portal-card-inner"> |
|
${portal.icon.startsWith('http') ? |
|
`<img src="${portal.icon}" class="mx-auto h-12 w-12 mb-4" alt="${portal.name} icon">` : |
|
`<i class="${portal.icon} text-4xl mb-4" style="${textColorStyle}"></i>`} |
|
<h3 class="font-bold uppercase tracking-wider" style="${textColorStyle}">${portal.name}</h3> |
|
</div> |
|
<button onclick="deletePortal(${index}); event.preventDefault();" |
|
class="absolute top-1 right-1 text-xs text-red-500 hover:text-red-400"> |
|
<i class="fas fa-times"></i> |
|
</button> |
|
</a> |
|
</div> |
|
`; |
|
|
|
portalsGrid.appendChild(portalElement); |
|
}); |
|
|
|
|
|
portalCount.textContent = portals.length; |
|
} |
|
|
|
|
|
function handlePortalFormSubmit(e) { |
|
e.preventDefault(); |
|
|
|
const name = document.getElementById('portal-name').value; |
|
const url = document.getElementById('portal-url').value; |
|
let icon = document.getElementById('portal-icon').value; |
|
const color = document.getElementById('portal-color').value; |
|
|
|
|
|
if (icon === 'custom-icon') { |
|
const iconUrl = document.getElementById('icon-url').value; |
|
const iconFile = document.getElementById('icon-upload').files[0]; |
|
|
|
if (iconUrl) { |
|
icon = iconUrl; |
|
} else if (iconFile) { |
|
const reader = new FileReader(); |
|
reader.onload = function(e) { |
|
|
|
icon = e.target.result; |
|
addPortalToArray(name, url, icon, color); |
|
}; |
|
reader.readAsDataURL(iconFile); |
|
return; |
|
} else { |
|
alert('Please provide an icon URL or upload an icon'); |
|
return; |
|
} |
|
} |
|
|
|
addPortalToArray(name, url, icon, color); |
|
} |
|
|
|
|
|
function addPortalToArray(name, url, icon, color) { |
|
const newPortal = { |
|
name: name, |
|
url: url, |
|
icon: icon, |
|
color: color |
|
}; |
|
|
|
portals.push(newPortal); |
|
savePortals(); |
|
renderPortals(); |
|
document.getElementById('add-portal-modal').classList.add('hidden'); |
|
resetPortalForm(); |
|
} |
|
|
|
|
|
function deletePortal(index) { |
|
if (confirm('Are you sure you want to delete this portal?')) { |
|
portals.splice(index, 1); |
|
savePortals(); |
|
renderPortals(); |
|
} |
|
} |
|
|
|
|
|
function resetPortalForm() { |
|
document.getElementById('portal-form').reset(); |
|
customIconOptions.style.display = 'none'; |
|
iconPreview.style.display = 'none'; |
|
document.getElementById('portal-color').value = '#05d9e8'; |
|
} |
|
|
|
|
|
function savePortals() { |
|
localStorage.setItem('portals', JSON.stringify(portals)); |
|
} |
|
|
|
|
|
function showAddLinkModal() { |
|
document.getElementById('add-portal-modal').classList.remove('hidden'); |
|
mobileMenu.classList.add('hidden'); |
|
} |
|
|
|
|
|
function updateTime() { |
|
const now = new Date(); |
|
const timeString = now.toLocaleTimeString(); |
|
const dateString = now.toLocaleDateString(undefined, { |
|
weekday: 'long', |
|
year: 'numeric', |
|
month: 'long', |
|
day: 'numeric' |
|
}); |
|
|
|
timeDisplay.textContent = timeString; |
|
dateDisplay.textContent = dateString; |
|
} |
|
|
|
|
|
function selectPortalColor(color, element) { |
|
|
|
document.querySelectorAll('.color-picker-container .color-option').forEach(el => { |
|
el.classList.remove('selected'); |
|
}); |
|
|
|
|
|
element.classList.add('selected'); |
|
|
|
|
|
document.getElementById('portal-color').value = color; |
|
} |
|
|
|
|
|
function selectThemeColor(color, element) { |
|
|
|
document.querySelectorAll('.dropdown .color-option').forEach(el => { |
|
el.classList.remove('selected'); |
|
}); |
|
|
|
|
|
element.classList.add('selected'); |
|
|
|
|
|
currentThemeColor = color; |
|
updateThemeColor(color); |
|
} |
|
|
|
|
|
function updateThemeColor(color) { |
|
|
|
document.documentElement.style.setProperty('--neon-blue', color); |
|
|
|
|
|
|
|
const neonElements = document.querySelectorAll('.neon-text-blue, .neon-border-blue'); |
|
neonElements.forEach(el => { |
|
if (el.classList.contains('neon-text-blue')) { |
|
el.style.color = color; |
|
el.style.textShadow = `0 0 5px ${color}, 0 0 10px ${color}, 0 0 20px ${color}`; |
|
} |
|
if (el.classList.contains('neon-border-blue')) { |
|
el.style.borderColor = color; |
|
el.style.boxShadow = `0 0 5px ${color}, inset 0 0 5px ${color}, 0 0 20px ${color}`; |
|
} |
|
}); |
|
} |
|
|
|
|
|
function toggleCustomColorInput() { |
|
const wrapper = document.getElementById('custom-color-wrapper'); |
|
wrapper.style.display = wrapper.style.display === 'none' ? 'block' : 'none'; |
|
} |
|
|
|
|
|
function togglePortalCustomColorInput() { |
|
const input = document.getElementById('portal-custom-color'); |
|
input.style.display = input.style.display === 'none' ? 'block' : 'none'; |
|
} |
|
|
|
|
|
function applyCustomPortalColor(color) { |
|
selectPortalColor(color, document.querySelector('.portal-form .color-option.selected')); |
|
} |
|
|
|
|
|
function confirmCustomColor() { |
|
const customColor = document.getElementById('custom-color').value; |
|
selectThemeColor(customColor, document.querySelector('.dropdown .color-option.selected')); |
|
document.getElementById('custom-color-wrapper').style.display = 'none'; |
|
} |
|
|
|
|
|
function setBackgroundImage() { |
|
|
|
const bgUrlInput = document.getElementById('bg-image-mobile') || document.getElementById('bg-image'); |
|
|
|
if (bgUrlInput && bgUrlInput.value) { |
|
currentBgImage = bgUrlInput.value; |
|
localStorage.setItem('bgImage', currentBgImage); |
|
document.body.style.backgroundImage = `url('${currentBgImage}')`; |
|
} |
|
} |
|
|
|
|
|
function applyUploadedBackground() { |
|
if (bgPreview.src && bgPreview.src !== '#') { |
|
currentBgImage = bgPreview.src; |
|
localStorage.setItem('bgImage', currentBgImage); |
|
document.body.style.backgroundImage = `url('${currentBgImage}')`; |
|
} |
|
} |
|
|
|
|
|
function loadBackgroundImage() { |
|
if (currentBgImage) { |
|
document.body.style.backgroundImage = `url('${currentBgImage}')`; |
|
document.body.style.backgroundSize = 'cover'; |
|
document.body.style.backgroundAttachment = 'fixed'; |
|
document.body.style.backgroundColor = 'transparent'; |
|
} |
|
} |
|
|
|
|
|
function resetBackgroundImage() { |
|
currentBgImage = ''; |
|
localStorage.removeItem('bgImage'); |
|
document.body.style.backgroundImage = 'none'; |
|
document.body.style.backgroundColor = '#05010e'; |
|
|
|
|
|
const bgInputs = document.querySelectorAll('[id^=bg-image]'); |
|
bgInputs.forEach(input => input.value = ''); |
|
|
|
if (bgPreview) bgPreview.style.display = 'none'; |
|
} |
|
</script> |
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=Shiroaki085/hubv2" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p><p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=dai/dai" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
</html> |