AdminLTE3
203
.history/public/css/enhanced-animations_20251026210710.css
Normal file
@@ -0,0 +1,203 @@
|
||||
/* Enhanced Animations for SmartSolTech */
|
||||
|
||||
/* Gradient Animation */
|
||||
@keyframes gradient-x {
|
||||
0%, 100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-gradient-x {
|
||||
background-size: 200% 200%;
|
||||
animation: gradient-x 4s ease infinite;
|
||||
}
|
||||
|
||||
/* Enhanced Blob Animation */
|
||||
@keyframes blob {
|
||||
0% {
|
||||
transform: translate(0px, 0px) scale(1);
|
||||
}
|
||||
33% {
|
||||
transform: translate(30px, -50px) scale(1.1);
|
||||
}
|
||||
66% {
|
||||
transform: translate(-20px, 20px) scale(0.9);
|
||||
}
|
||||
100% {
|
||||
transform: translate(0px, 0px) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-blob {
|
||||
animation: blob 7s infinite;
|
||||
}
|
||||
|
||||
.animation-delay-2000 {
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
.animation-delay-4000 {
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
.animation-delay-6000 {
|
||||
animation-delay: 6s;
|
||||
}
|
||||
|
||||
/* Pulse Animation with Delay */
|
||||
@keyframes pulse-delayed {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-pulse-delayed {
|
||||
animation: pulse-delayed 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
/* Floating Animation */
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-float {
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Card Hover Effects */
|
||||
.card-hover {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.card-hover:hover {
|
||||
transform: translateY(-8px);
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
/* Background Pattern */
|
||||
.bg-pattern {
|
||||
background-image: radial-gradient(circle at 1px 1px, rgba(59, 130, 246, 0.15) 1px, transparent 0);
|
||||
background-size: 20px 20px;
|
||||
}
|
||||
|
||||
/* Glowing Effect */
|
||||
.glow {
|
||||
box-shadow: 0 0 20px rgba(59, 130, 246, 0.5);
|
||||
}
|
||||
|
||||
.glow-purple {
|
||||
box-shadow: 0 0 20px rgba(139, 92, 246, 0.5);
|
||||
}
|
||||
|
||||
.glow-green {
|
||||
box-shadow: 0 0 20px rgba(16, 185, 129, 0.5);
|
||||
}
|
||||
|
||||
.glow-orange {
|
||||
box-shadow: 0 0 20px rgba(251, 146, 60, 0.5);
|
||||
}
|
||||
|
||||
/* Hero Section Specific */
|
||||
.hero-section {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background:
|
||||
radial-gradient(1200px 600px at 10% -10%, rgba(99, 102, 241, 0.35), transparent 60%),
|
||||
radial-gradient(1000px 500px at 110% 10%, rgba(168, 85, 247, 0.35), transparent 60%);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Glass Effect */
|
||||
.glass-effect {
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
/* Smooth Transitions */
|
||||
.smooth-transition {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Text Shimmer Effect */
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -200% center;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% center;
|
||||
}
|
||||
}
|
||||
|
||||
.text-shimmer {
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.8), transparent);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 2s infinite;
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
}
|
||||
|
||||
/* Button Hover Effects */
|
||||
.btn-enhanced {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-enhanced::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.btn-enhanced:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
/* Responsive Adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.animate-blob {
|
||||
animation-duration: 10s;
|
||||
}
|
||||
|
||||
.card-hover:hover {
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark Mode Adjustments */
|
||||
.dark .glass-effect {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.dark .bg-pattern {
|
||||
background-image: radial-gradient(circle at 1px 1px, rgba(59, 130, 246, 0.1) 1px, transparent 0);
|
||||
}
|
||||
203
.history/public/css/enhanced-animations_20251026210722.css
Normal file
@@ -0,0 +1,203 @@
|
||||
/* Enhanced Animations for SmartSolTech */
|
||||
|
||||
/* Gradient Animation */
|
||||
@keyframes gradient-x {
|
||||
0%, 100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-gradient-x {
|
||||
background-size: 200% 200%;
|
||||
animation: gradient-x 4s ease infinite;
|
||||
}
|
||||
|
||||
/* Enhanced Blob Animation */
|
||||
@keyframes blob {
|
||||
0% {
|
||||
transform: translate(0px, 0px) scale(1);
|
||||
}
|
||||
33% {
|
||||
transform: translate(30px, -50px) scale(1.1);
|
||||
}
|
||||
66% {
|
||||
transform: translate(-20px, 20px) scale(0.9);
|
||||
}
|
||||
100% {
|
||||
transform: translate(0px, 0px) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-blob {
|
||||
animation: blob 7s infinite;
|
||||
}
|
||||
|
||||
.animation-delay-2000 {
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
.animation-delay-4000 {
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
.animation-delay-6000 {
|
||||
animation-delay: 6s;
|
||||
}
|
||||
|
||||
/* Pulse Animation with Delay */
|
||||
@keyframes pulse-delayed {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-pulse-delayed {
|
||||
animation: pulse-delayed 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
/* Floating Animation */
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-float {
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Card Hover Effects */
|
||||
.card-hover {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.card-hover:hover {
|
||||
transform: translateY(-8px);
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
/* Background Pattern */
|
||||
.bg-pattern {
|
||||
background-image: radial-gradient(circle at 1px 1px, rgba(59, 130, 246, 0.15) 1px, transparent 0);
|
||||
background-size: 20px 20px;
|
||||
}
|
||||
|
||||
/* Glowing Effect */
|
||||
.glow {
|
||||
box-shadow: 0 0 20px rgba(59, 130, 246, 0.5);
|
||||
}
|
||||
|
||||
.glow-purple {
|
||||
box-shadow: 0 0 20px rgba(139, 92, 246, 0.5);
|
||||
}
|
||||
|
||||
.glow-green {
|
||||
box-shadow: 0 0 20px rgba(16, 185, 129, 0.5);
|
||||
}
|
||||
|
||||
.glow-orange {
|
||||
box-shadow: 0 0 20px rgba(251, 146, 60, 0.5);
|
||||
}
|
||||
|
||||
/* Hero Section Specific */
|
||||
.hero-section {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background:
|
||||
radial-gradient(1200px 600px at 10% -10%, rgba(99, 102, 241, 0.35), transparent 60%),
|
||||
radial-gradient(1000px 500px at 110% 10%, rgba(168, 85, 247, 0.35), transparent 60%);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Glass Effect */
|
||||
.glass-effect {
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
/* Smooth Transitions */
|
||||
.smooth-transition {
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Text Shimmer Effect */
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -200% center;
|
||||
}
|
||||
100% {
|
||||
background-position: 200% center;
|
||||
}
|
||||
}
|
||||
|
||||
.text-shimmer {
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.8), transparent);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 2s infinite;
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
}
|
||||
|
||||
/* Button Hover Effects */
|
||||
.btn-enhanced {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-enhanced::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.btn-enhanced:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
/* Responsive Adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.animate-blob {
|
||||
animation-duration: 10s;
|
||||
}
|
||||
|
||||
.card-hover:hover {
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark Mode Adjustments */
|
||||
.dark .glass-effect {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.dark .bg-pattern {
|
||||
background-image: radial-gradient(circle at 1px 1px, rgba(59, 130, 246, 0.1) 1px, transparent 0);
|
||||
}
|
||||
55
.history/public/images/services/branding_20251026180829.svg
Normal file
@@ -0,0 +1,55 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Logo design canvas -->
|
||||
<rect x="60" y="50" width="80" height="80" rx="8" fill="rgba(255,255,255,0.9)" stroke="rgba(255,255,255,0.3)" stroke-width="2"/>
|
||||
|
||||
<!-- Logo elements - abstract brand symbol -->
|
||||
<circle cx="100" cy="90" r="20" fill="none" stroke="rgba(59,130,246,0.6)" stroke-width="3"/>
|
||||
<path d="M85 90 Q100 75 115 90 Q100 105 85 90" fill="rgba(139,92,246,0.5)"/>
|
||||
<circle cx="100" cy="90" r="8" fill="rgba(245,158,11,0.7)"/>
|
||||
|
||||
<!-- Brand typography -->
|
||||
<rect x="70" y="115" width="60" height="8" rx="4" fill="rgba(59,130,246,0.3)"/>
|
||||
|
||||
<!-- Color swatches -->
|
||||
<rect x="20" y="30" width="15" height="15" rx="3" fill="rgba(59,130,246,0.8)"/>
|
||||
<rect x="20" y="50" width="15" height="15" rx="3" fill="rgba(139,92,246,0.8)"/>
|
||||
<rect x="20" y="70" width="15" height="15" rx="3" fill="rgba(245,158,11,0.8)"/>
|
||||
<rect x="20" y="90" width="15" height="15" rx="3" fill="rgba(34,197,94,0.8)"/>
|
||||
<rect x="20" y="110" width="15" height="15" rx="3" fill="rgba(239,68,68,0.8)"/>
|
||||
|
||||
<!-- Business cards -->
|
||||
<rect x="150" y="40" width="30" height="20" rx="3" fill="rgba(255,255,255,0.8)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
<rect x="152" y="45" width="8" height="3" rx="1.5" fill="rgba(59,130,246,0.5)"/>
|
||||
<rect x="152" y="50" width="12" height="2" rx="1" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="152" y="54" width="10" height="2" rx="1" fill="rgba(245,158,11,0.3)"/>
|
||||
|
||||
<!-- Brand guidelines -->
|
||||
<rect x="25" y="140" width="40" height="30" rx="4" fill="rgba(255,255,255,0.7)" stroke="rgba(255,255,255,0.3)" stroke-width="1"/>
|
||||
<rect x="30" y="150" width="30" height="3" rx="1.5" fill="rgba(59,130,246,0.4)"/>
|
||||
<rect x="30" y="157" width="20" height="2" rx="1" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="30" y="162" width="25" height="2" rx="1" fill="rgba(245,158,11,0.3)"/>
|
||||
|
||||
<!-- Letterhead -->
|
||||
<rect x="140" y="140" width="35" height="45" rx="4" fill="rgba(255,255,255,0.8)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
<circle cx="157" cy="155" r="6" fill="rgba(59,130,246,0.3)" stroke="rgba(59,130,246,0.5)" stroke-width="1"/>
|
||||
<rect x="145" y="165" width="20" height="2" rx="1" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="145" y="170" width="15" height="2" rx="1" fill="rgba(245,158,11,0.3)"/>
|
||||
<rect x="145" y="175" width="18" height="2" rx="1" fill="rgba(34,197,94,0.3)"/>
|
||||
|
||||
<!-- Pencil/Design tool -->
|
||||
<rect x="160" y="15" width="4" height="25" rx="2" fill="rgba(245,158,11,0.7)"/>
|
||||
<path d="M160 40 L164 40 L162 45 Z" fill="rgba(139,92,246,0.6)"/>
|
||||
<circle cx="162" cy="12" r="3" fill="rgba(236,72,153,0.6)"/>
|
||||
|
||||
<!-- Typography samples -->
|
||||
<text x="75" y="180" fill="rgba(255,255,255,0.5)" font-family="serif" font-size="12" font-weight="bold">Aa</text>
|
||||
<text x="95" y="180" fill="rgba(255,255,255,0.4)" font-family="sans-serif" font-size="10">Brand</text>
|
||||
<text x="125" y="180" fill="rgba(255,255,255,0.3)" font-family="monospace" font-size="8">123</text>
|
||||
|
||||
<!-- Copyright symbol -->
|
||||
<circle cx="175" cy="100" r="8" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
<text x="171" y="105" fill="rgba(255,255,255,0.4)" font-family="serif" font-size="10" font-weight="bold">©</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
55
.history/public/images/services/branding_20251026181004.svg
Normal file
@@ -0,0 +1,55 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Logo design canvas -->
|
||||
<rect x="60" y="50" width="80" height="80" rx="8" fill="rgba(255,255,255,0.9)" stroke="rgba(255,255,255,0.3)" stroke-width="2"/>
|
||||
|
||||
<!-- Logo elements - abstract brand symbol -->
|
||||
<circle cx="100" cy="90" r="20" fill="none" stroke="rgba(59,130,246,0.6)" stroke-width="3"/>
|
||||
<path d="M85 90 Q100 75 115 90 Q100 105 85 90" fill="rgba(139,92,246,0.5)"/>
|
||||
<circle cx="100" cy="90" r="8" fill="rgba(245,158,11,0.7)"/>
|
||||
|
||||
<!-- Brand typography -->
|
||||
<rect x="70" y="115" width="60" height="8" rx="4" fill="rgba(59,130,246,0.3)"/>
|
||||
|
||||
<!-- Color swatches -->
|
||||
<rect x="20" y="30" width="15" height="15" rx="3" fill="rgba(59,130,246,0.8)"/>
|
||||
<rect x="20" y="50" width="15" height="15" rx="3" fill="rgba(139,92,246,0.8)"/>
|
||||
<rect x="20" y="70" width="15" height="15" rx="3" fill="rgba(245,158,11,0.8)"/>
|
||||
<rect x="20" y="90" width="15" height="15" rx="3" fill="rgba(34,197,94,0.8)"/>
|
||||
<rect x="20" y="110" width="15" height="15" rx="3" fill="rgba(239,68,68,0.8)"/>
|
||||
|
||||
<!-- Business cards -->
|
||||
<rect x="150" y="40" width="30" height="20" rx="3" fill="rgba(255,255,255,0.8)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
<rect x="152" y="45" width="8" height="3" rx="1.5" fill="rgba(59,130,246,0.5)"/>
|
||||
<rect x="152" y="50" width="12" height="2" rx="1" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="152" y="54" width="10" height="2" rx="1" fill="rgba(245,158,11,0.3)"/>
|
||||
|
||||
<!-- Brand guidelines -->
|
||||
<rect x="25" y="140" width="40" height="30" rx="4" fill="rgba(255,255,255,0.7)" stroke="rgba(255,255,255,0.3)" stroke-width="1"/>
|
||||
<rect x="30" y="150" width="30" height="3" rx="1.5" fill="rgba(59,130,246,0.4)"/>
|
||||
<rect x="30" y="157" width="20" height="2" rx="1" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="30" y="162" width="25" height="2" rx="1" fill="rgba(245,158,11,0.3)"/>
|
||||
|
||||
<!-- Letterhead -->
|
||||
<rect x="140" y="140" width="35" height="45" rx="4" fill="rgba(255,255,255,0.8)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
<circle cx="157" cy="155" r="6" fill="rgba(59,130,246,0.3)" stroke="rgba(59,130,246,0.5)" stroke-width="1"/>
|
||||
<rect x="145" y="165" width="20" height="2" rx="1" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="145" y="170" width="15" height="2" rx="1" fill="rgba(245,158,11,0.3)"/>
|
||||
<rect x="145" y="175" width="18" height="2" rx="1" fill="rgba(34,197,94,0.3)"/>
|
||||
|
||||
<!-- Pencil/Design tool -->
|
||||
<rect x="160" y="15" width="4" height="25" rx="2" fill="rgba(245,158,11,0.7)"/>
|
||||
<path d="M160 40 L164 40 L162 45 Z" fill="rgba(139,92,246,0.6)"/>
|
||||
<circle cx="162" cy="12" r="3" fill="rgba(236,72,153,0.6)"/>
|
||||
|
||||
<!-- Typography samples -->
|
||||
<text x="75" y="180" fill="rgba(255,255,255,0.5)" font-family="serif" font-size="12" font-weight="bold">Aa</text>
|
||||
<text x="95" y="180" fill="rgba(255,255,255,0.4)" font-family="sans-serif" font-size="10">Brand</text>
|
||||
<text x="125" y="180" fill="rgba(255,255,255,0.3)" font-family="monospace" font-size="8">123</text>
|
||||
|
||||
<!-- Copyright symbol -->
|
||||
<circle cx="175" cy="100" r="8" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
<text x="171" y="105" fill="rgba(255,255,255,0.4)" font-family="serif" font-size="10" font-weight="bold">©</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,69 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Light bulb -->
|
||||
<circle cx="100" cy="85" r="25" fill="rgba(245,158,11,0.2)" stroke="rgba(245,158,11,0.6)" stroke-width="3"/>
|
||||
<rect x="95" y="105" width="10" height="8" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
<rect x="93" y="113" width="14" height="4" rx="2" fill="rgba(255,255,255,0.8)"/>
|
||||
|
||||
<!-- Light rays -->
|
||||
<path d="M75 60 L80 65" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M125 60 L120 65" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M60 85 L65 85" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M140 85 L135 85" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M75 110 L80 105" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M125 110 L120 105" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
|
||||
<!-- Filament inside bulb -->
|
||||
<path d="M90 75 Q100 70 110 75 Q100 80 90 75" stroke="rgba(245,158,11,0.8)" stroke-width="2" fill="none"/>
|
||||
<path d="M90 85 Q100 90 110 85 Q100 95 90 85" stroke="rgba(245,158,11,0.8)" stroke-width="2" fill="none"/>
|
||||
|
||||
<!-- Gears -->
|
||||
<circle cx="50" cy="140" r="12" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2"/>
|
||||
<circle cx="50" cy="140" r="8" fill="rgba(59,130,246,0.3)"/>
|
||||
<rect x="46" y="132" width="8" height="3" rx="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
<rect x="46" y="145" width="8" height="3" rx="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
<rect x="42" y="138" width="3" height="8" rx="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
<rect x="55" y="138" width="3" height="8" rx="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
|
||||
<circle cx="150" cy="50" r="10" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
<circle cx="150" cy="50" r="6" fill="rgba(34,197,94,0.3)"/>
|
||||
<rect x="147" y="43" width="6" height="2" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="147" y="55" width="6" height="2" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="144" y="48" width="2" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="154" y="48" width="2" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
|
||||
<!-- Charts/Analytics -->
|
||||
<rect x="130" y="130" width="50" height="30" rx="4" fill="rgba(255,255,255,0.8)"/>
|
||||
<rect x="135" y="145" width="6" height="12" fill="rgba(59,130,246,0.6)"/>
|
||||
<rect x="143" y="140" width="6" height="17" fill="rgba(34,197,94,0.6)"/>
|
||||
<rect x="151" y="148" width="6" height="9" fill="rgba(245,158,11,0.6)"/>
|
||||
<rect x="159" y="142" width="6" height="15" fill="rgba(139,92,246,0.6)"/>
|
||||
<rect x="167" y="146" width="6" height="11" fill="rgba(236,72,153,0.6)"/>
|
||||
|
||||
<!-- Puzzle pieces -->
|
||||
<path d="M20 40 L35 40 Q40 35 45 40 L60 40 L60 55 Q55 60 60 65 L60 80 L45 80 Q40 75 35 80 L20 80 Z"
|
||||
fill="rgba(255,255,255,0.6)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
<circle cx="40" cy="60" r="3" fill="rgba(59,130,246,0.5)"/>
|
||||
|
||||
<!-- Arrow pointing up (growth) -->
|
||||
<path d="M170 140 L170 120" stroke="rgba(34,197,94,0.8)" stroke-width="3"/>
|
||||
<path d="M165 125 L170 120 L175 125" stroke="rgba(34,197,94,0.8)" stroke-width="3" fill="none"/>
|
||||
|
||||
<!-- Document/Report -->
|
||||
<rect x="25" y="160" width="20" height="25" rx="2" fill="rgba(255,255,255,0.8)"/>
|
||||
<rect x="28" y="165" width="14" height="2" rx="1" fill="rgba(59,130,246,0.4)"/>
|
||||
<rect x="28" y="170" width="10" height="1.5" rx="0.75" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="28" y="174" width="12" height="1.5" rx="0.75" fill="rgba(245,158,11,0.3)"/>
|
||||
<rect x="28" y="178" width="8" height="1.5" rx="0.75" fill="rgba(34,197,94,0.3)"/>
|
||||
|
||||
<!-- Clock/Time -->
|
||||
<circle cx="170" cy="170" r="8" fill="rgba(255,255,255,0.7)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
<path d="M170 165 L170 170 L175 170" stroke="rgba(59,130,246,0.8)" stroke-width="2" fill="none"/>
|
||||
|
||||
<!-- Target/Goals -->
|
||||
<circle cx="30" cy="30" r="8" fill="none" stroke="rgba(239,68,68,0.5)" stroke-width="2"/>
|
||||
<circle cx="30" cy="30" r="5" fill="none" stroke="rgba(239,68,68,0.6)" stroke-width="1"/>
|
||||
<circle cx="30" cy="30" r="2" fill="rgba(239,68,68,0.7)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,69 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Light bulb -->
|
||||
<circle cx="100" cy="85" r="25" fill="rgba(245,158,11,0.2)" stroke="rgba(245,158,11,0.6)" stroke-width="3"/>
|
||||
<rect x="95" y="105" width="10" height="8" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
<rect x="93" y="113" width="14" height="4" rx="2" fill="rgba(255,255,255,0.8)"/>
|
||||
|
||||
<!-- Light rays -->
|
||||
<path d="M75 60 L80 65" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M125 60 L120 65" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M60 85 L65 85" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M140 85 L135 85" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M75 110 L80 105" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
<path d="M125 110 L120 105" stroke="rgba(245,158,11,0.6)" stroke-width="2"/>
|
||||
|
||||
<!-- Filament inside bulb -->
|
||||
<path d="M90 75 Q100 70 110 75 Q100 80 90 75" stroke="rgba(245,158,11,0.8)" stroke-width="2" fill="none"/>
|
||||
<path d="M90 85 Q100 90 110 85 Q100 95 90 85" stroke="rgba(245,158,11,0.8)" stroke-width="2" fill="none"/>
|
||||
|
||||
<!-- Gears -->
|
||||
<circle cx="50" cy="140" r="12" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2"/>
|
||||
<circle cx="50" cy="140" r="8" fill="rgba(59,130,246,0.3)"/>
|
||||
<rect x="46" y="132" width="8" height="3" rx="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
<rect x="46" y="145" width="8" height="3" rx="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
<rect x="42" y="138" width="3" height="8" rx="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
<rect x="55" y="138" width="3" height="8" rx="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
|
||||
<circle cx="150" cy="50" r="10" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
<circle cx="150" cy="50" r="6" fill="rgba(34,197,94,0.3)"/>
|
||||
<rect x="147" y="43" width="6" height="2" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="147" y="55" width="6" height="2" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="144" y="48" width="2" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="154" y="48" width="2" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
|
||||
<!-- Charts/Analytics -->
|
||||
<rect x="130" y="130" width="50" height="30" rx="4" fill="rgba(255,255,255,0.8)"/>
|
||||
<rect x="135" y="145" width="6" height="12" fill="rgba(59,130,246,0.6)"/>
|
||||
<rect x="143" y="140" width="6" height="17" fill="rgba(34,197,94,0.6)"/>
|
||||
<rect x="151" y="148" width="6" height="9" fill="rgba(245,158,11,0.6)"/>
|
||||
<rect x="159" y="142" width="6" height="15" fill="rgba(139,92,246,0.6)"/>
|
||||
<rect x="167" y="146" width="6" height="11" fill="rgba(236,72,153,0.6)"/>
|
||||
|
||||
<!-- Puzzle pieces -->
|
||||
<path d="M20 40 L35 40 Q40 35 45 40 L60 40 L60 55 Q55 60 60 65 L60 80 L45 80 Q40 75 35 80 L20 80 Z"
|
||||
fill="rgba(255,255,255,0.6)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
<circle cx="40" cy="60" r="3" fill="rgba(59,130,246,0.5)"/>
|
||||
|
||||
<!-- Arrow pointing up (growth) -->
|
||||
<path d="M170 140 L170 120" stroke="rgba(34,197,94,0.8)" stroke-width="3"/>
|
||||
<path d="M165 125 L170 120 L175 125" stroke="rgba(34,197,94,0.8)" stroke-width="3" fill="none"/>
|
||||
|
||||
<!-- Document/Report -->
|
||||
<rect x="25" y="160" width="20" height="25" rx="2" fill="rgba(255,255,255,0.8)"/>
|
||||
<rect x="28" y="165" width="14" height="2" rx="1" fill="rgba(59,130,246,0.4)"/>
|
||||
<rect x="28" y="170" width="10" height="1.5" rx="0.75" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="28" y="174" width="12" height="1.5" rx="0.75" fill="rgba(245,158,11,0.3)"/>
|
||||
<rect x="28" y="178" width="8" height="1.5" rx="0.75" fill="rgba(34,197,94,0.3)"/>
|
||||
|
||||
<!-- Clock/Time -->
|
||||
<circle cx="170" cy="170" r="8" fill="rgba(255,255,255,0.7)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
<path d="M170 165 L170 170 L175 170" stroke="rgba(59,130,246,0.8)" stroke-width="2" fill="none"/>
|
||||
|
||||
<!-- Target/Goals -->
|
||||
<circle cx="30" cy="30" r="8" fill="none" stroke="rgba(239,68,68,0.5)" stroke-width="2"/>
|
||||
<circle cx="30" cy="30" r="5" fill="none" stroke="rgba(239,68,68,0.6)" stroke-width="1"/>
|
||||
<circle cx="30" cy="30" r="2" fill="rgba(239,68,68,0.7)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
52
.history/public/images/services/default_20251026180915.svg
Normal file
@@ -0,0 +1,52 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Main gear -->
|
||||
<circle cx="100" cy="100" r="30" fill="none" stroke="rgba(255,255,255,0.6)" stroke-width="4"/>
|
||||
<circle cx="100" cy="100" r="20" fill="rgba(59,130,246,0.3)"/>
|
||||
|
||||
<!-- Gear teeth -->
|
||||
<rect x="95" y="65" width="10" height="8" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
<rect x="95" y="127" width="10" height="8" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
<rect x="65" y="95" width="8" height="10" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
<rect x="127" y="95" width="8" height="10" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
|
||||
<!-- Diagonal gear teeth -->
|
||||
<rect x="80" y="75" width="8" height="8" rx="2" fill="rgba(255,255,255,0.6)" transform="rotate(45 84 79)"/>
|
||||
<rect x="112" y="75" width="8" height="8" rx="2" fill="rgba(255,255,255,0.6)" transform="rotate(-45 116 79)"/>
|
||||
<rect x="80" y="117" width="8" height="8" rx="2" fill="rgba(255,255,255,0.6)" transform="rotate(-45 84 121)"/>
|
||||
<rect x="112" y="117" width="8" height="8" rx="2" fill="rgba(255,255,255,0.6)" transform="rotate(45 116 121)"/>
|
||||
|
||||
<!-- Center circle -->
|
||||
<circle cx="100" cy="100" r="8" fill="rgba(255,255,255,0.8)"/>
|
||||
|
||||
<!-- Smaller gears -->
|
||||
<circle cx="60" cy="60" r="15" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
<circle cx="60" cy="60" r="10" fill="rgba(34,197,94,0.3)"/>
|
||||
<rect x="57" y="48" width="6" height="4" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="57" y="68" width="6" height="4" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="48" y="57" width="4" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="68" y="57" width="4" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
|
||||
<circle cx="140" cy="140" r="15" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
<circle cx="140" cy="140" r="10" fill="rgba(245,158,11,0.3)"/>
|
||||
<rect x="137" y="128" width="6" height="4" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="137" y="148" width="6" height="4" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="128" y="137" width="4" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="148" y="137" width="4" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
|
||||
<!-- Connecting lines -->
|
||||
<path d="M70 70 L90 90" stroke="rgba(255,255,255,0.3)" stroke-width="2" stroke-dasharray="4,4"/>
|
||||
<path d="M130 130 L110 110" stroke="rgba(255,255,255,0.3)" stroke-width="2" stroke-dasharray="4,4"/>
|
||||
|
||||
<!-- Decorative elements -->
|
||||
<circle cx="30" cy="170" r="4" fill="rgba(255,255,255,0.2)"/>
|
||||
<circle cx="170" cy="30" r="4" fill="rgba(255,255,255,0.2)"/>
|
||||
|
||||
<!-- Tool icons -->
|
||||
<rect x="20" y="25" width="15" height="3" rx="1.5" fill="rgba(255,255,255,0.4)"/>
|
||||
<circle cx="22" cy="26.5" r="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
|
||||
<path d="M165 165 L175 175 M170 160 L180 170" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
52
.history/public/images/services/default_20251026181004.svg
Normal file
@@ -0,0 +1,52 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Main gear -->
|
||||
<circle cx="100" cy="100" r="30" fill="none" stroke="rgba(255,255,255,0.6)" stroke-width="4"/>
|
||||
<circle cx="100" cy="100" r="20" fill="rgba(59,130,246,0.3)"/>
|
||||
|
||||
<!-- Gear teeth -->
|
||||
<rect x="95" y="65" width="10" height="8" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
<rect x="95" y="127" width="10" height="8" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
<rect x="65" y="95" width="8" height="10" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
<rect x="127" y="95" width="8" height="10" rx="2" fill="rgba(255,255,255,0.7)"/>
|
||||
|
||||
<!-- Diagonal gear teeth -->
|
||||
<rect x="80" y="75" width="8" height="8" rx="2" fill="rgba(255,255,255,0.6)" transform="rotate(45 84 79)"/>
|
||||
<rect x="112" y="75" width="8" height="8" rx="2" fill="rgba(255,255,255,0.6)" transform="rotate(-45 116 79)"/>
|
||||
<rect x="80" y="117" width="8" height="8" rx="2" fill="rgba(255,255,255,0.6)" transform="rotate(-45 84 121)"/>
|
||||
<rect x="112" y="117" width="8" height="8" rx="2" fill="rgba(255,255,255,0.6)" transform="rotate(45 116 121)"/>
|
||||
|
||||
<!-- Center circle -->
|
||||
<circle cx="100" cy="100" r="8" fill="rgba(255,255,255,0.8)"/>
|
||||
|
||||
<!-- Smaller gears -->
|
||||
<circle cx="60" cy="60" r="15" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
<circle cx="60" cy="60" r="10" fill="rgba(34,197,94,0.3)"/>
|
||||
<rect x="57" y="48" width="6" height="4" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="57" y="68" width="6" height="4" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="48" y="57" width="4" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="68" y="57" width="4" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
|
||||
<circle cx="140" cy="140" r="15" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
<circle cx="140" cy="140" r="10" fill="rgba(245,158,11,0.3)"/>
|
||||
<rect x="137" y="128" width="6" height="4" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="137" y="148" width="6" height="4" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="128" y="137" width="4" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
<rect x="148" y="137" width="4" height="6" rx="1" fill="rgba(255,255,255,0.5)"/>
|
||||
|
||||
<!-- Connecting lines -->
|
||||
<path d="M70 70 L90 90" stroke="rgba(255,255,255,0.3)" stroke-width="2" stroke-dasharray="4,4"/>
|
||||
<path d="M130 130 L110 110" stroke="rgba(255,255,255,0.3)" stroke-width="2" stroke-dasharray="4,4"/>
|
||||
|
||||
<!-- Decorative elements -->
|
||||
<circle cx="30" cy="170" r="4" fill="rgba(255,255,255,0.2)"/>
|
||||
<circle cx="170" cy="30" r="4" fill="rgba(255,255,255,0.2)"/>
|
||||
|
||||
<!-- Tool icons -->
|
||||
<rect x="20" y="25" width="15" height="3" rx="1.5" fill="rgba(255,255,255,0.4)"/>
|
||||
<circle cx="22" cy="26.5" r="1.5" fill="rgba(255,255,255,0.6)"/>
|
||||
|
||||
<path d="M165 165 L175 175 M170 160 L180 170" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,56 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Chart/Graph -->
|
||||
<rect x="40" y="60" width="120" height="80" rx="8" fill="rgba(255,255,255,0.9)"/>
|
||||
|
||||
<!-- Chart bars -->
|
||||
<rect x="55" y="100" width="12" height="30" fill="rgba(34,197,94,0.7)"/>
|
||||
<rect x="72" y="85" width="12" height="45" fill="rgba(59,130,246,0.7)"/>
|
||||
<rect x="89" y="95" width="12" height="35" fill="rgba(245,158,11,0.7)"/>
|
||||
<rect x="106" y="75" width="12" height="55" fill="rgba(239,68,68,0.7)"/>
|
||||
<rect x="123" y="90" width="12" height="40" fill="rgba(139,92,246,0.7)"/>
|
||||
|
||||
<!-- Trend line -->
|
||||
<path d="M55 110 L72 95 L89 105 L106 85 L123 100" stroke="rgba(236,72,153,0.8)" stroke-width="3" fill="none"/>
|
||||
|
||||
<!-- Chart dots -->
|
||||
<circle cx="61" cy="110" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
<circle cx="78" cy="95" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
<circle cx="95" cy="105" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
<circle cx="112" cy="85" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
<circle cx="129" cy="100" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
|
||||
<!-- Megaphone/Speaker -->
|
||||
<path d="M20 120 L35 115 L35 125 Z" fill="rgba(255,255,255,0.8)"/>
|
||||
<rect x="35" y="117" width="15" height="6" rx="3" fill="rgba(255,255,255,0.8)"/>
|
||||
<path d="M50 115 Q60 115 60 120 Q60 125 50 125" stroke="rgba(255,255,255,0.6)" stroke-width="2" fill="none"/>
|
||||
|
||||
<!-- Social media icons -->
|
||||
<circle cx="170" cy="40" r="8" fill="rgba(59,130,246,0.7)"/>
|
||||
<text x="166" y="45" fill="white" font-family="sans-serif" font-size="8" font-weight="bold">f</text>
|
||||
|
||||
<circle cx="170" cy="60" r="8" fill="rgba(29,161,242,0.7)"/>
|
||||
<text x="167" y="65" fill="white" font-family="sans-serif" font-size="8" font-weight="bold">t</text>
|
||||
|
||||
<circle cx="170" cy="80" r="8" fill="rgba(225,48,108,0.7)"/>
|
||||
<text x="167" y="85" fill="white" font-family="sans-serif" font-size="8" font-weight="bold">i</text>
|
||||
|
||||
<!-- Target/Bullseye -->
|
||||
<circle cx="30" cy="170" r="12" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2"/>
|
||||
<circle cx="30" cy="170" r="8" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2"/>
|
||||
<circle cx="30" cy="170" r="4" fill="rgba(239,68,68,0.7)"/>
|
||||
|
||||
<!-- SEO elements -->
|
||||
<text x="140" y="170" fill="rgba(255,255,255,0.5)" font-family="sans-serif" font-size="12" font-weight="bold">SEO</text>
|
||||
|
||||
<!-- Growth arrow -->
|
||||
<path d="M140 110 L155 95" stroke="rgba(34,197,94,0.8)" stroke-width="3" fill="none"/>
|
||||
<path d="M150 95 L155 95 L155 100" stroke="rgba(34,197,94,0.8)" stroke-width="3" fill="none"/>
|
||||
|
||||
<!-- Analytics symbols -->
|
||||
<circle cx="60" cy="40" r="3" fill="rgba(255,255,255,0.4)"/>
|
||||
<circle cx="75" cy="35" r="4" fill="rgba(255,255,255,0.3)"/>
|
||||
<circle cx="90" cy="45" r="2" fill="rgba(255,255,255,0.4)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,56 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Chart/Graph -->
|
||||
<rect x="40" y="60" width="120" height="80" rx="8" fill="rgba(255,255,255,0.9)"/>
|
||||
|
||||
<!-- Chart bars -->
|
||||
<rect x="55" y="100" width="12" height="30" fill="rgba(34,197,94,0.7)"/>
|
||||
<rect x="72" y="85" width="12" height="45" fill="rgba(59,130,246,0.7)"/>
|
||||
<rect x="89" y="95" width="12" height="35" fill="rgba(245,158,11,0.7)"/>
|
||||
<rect x="106" y="75" width="12" height="55" fill="rgba(239,68,68,0.7)"/>
|
||||
<rect x="123" y="90" width="12" height="40" fill="rgba(139,92,246,0.7)"/>
|
||||
|
||||
<!-- Trend line -->
|
||||
<path d="M55 110 L72 95 L89 105 L106 85 L123 100" stroke="rgba(236,72,153,0.8)" stroke-width="3" fill="none"/>
|
||||
|
||||
<!-- Chart dots -->
|
||||
<circle cx="61" cy="110" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
<circle cx="78" cy="95" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
<circle cx="95" cy="105" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
<circle cx="112" cy="85" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
<circle cx="129" cy="100" r="3" fill="rgba(236,72,153,0.8)"/>
|
||||
|
||||
<!-- Megaphone/Speaker -->
|
||||
<path d="M20 120 L35 115 L35 125 Z" fill="rgba(255,255,255,0.8)"/>
|
||||
<rect x="35" y="117" width="15" height="6" rx="3" fill="rgba(255,255,255,0.8)"/>
|
||||
<path d="M50 115 Q60 115 60 120 Q60 125 50 125" stroke="rgba(255,255,255,0.6)" stroke-width="2" fill="none"/>
|
||||
|
||||
<!-- Social media icons -->
|
||||
<circle cx="170" cy="40" r="8" fill="rgba(59,130,246,0.7)"/>
|
||||
<text x="166" y="45" fill="white" font-family="sans-serif" font-size="8" font-weight="bold">f</text>
|
||||
|
||||
<circle cx="170" cy="60" r="8" fill="rgba(29,161,242,0.7)"/>
|
||||
<text x="167" y="65" fill="white" font-family="sans-serif" font-size="8" font-weight="bold">t</text>
|
||||
|
||||
<circle cx="170" cy="80" r="8" fill="rgba(225,48,108,0.7)"/>
|
||||
<text x="167" y="85" fill="white" font-family="sans-serif" font-size="8" font-weight="bold">i</text>
|
||||
|
||||
<!-- Target/Bullseye -->
|
||||
<circle cx="30" cy="170" r="12" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2"/>
|
||||
<circle cx="30" cy="170" r="8" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="2"/>
|
||||
<circle cx="30" cy="170" r="4" fill="rgba(239,68,68,0.7)"/>
|
||||
|
||||
<!-- SEO elements -->
|
||||
<text x="140" y="170" fill="rgba(255,255,255,0.5)" font-family="sans-serif" font-size="12" font-weight="bold">SEO</text>
|
||||
|
||||
<!-- Growth arrow -->
|
||||
<path d="M140 110 L155 95" stroke="rgba(34,197,94,0.8)" stroke-width="3" fill="none"/>
|
||||
<path d="M150 95 L155 95 L155 100" stroke="rgba(34,197,94,0.8)" stroke-width="3" fill="none"/>
|
||||
|
||||
<!-- Analytics symbols -->
|
||||
<circle cx="60" cy="40" r="3" fill="rgba(255,255,255,0.4)"/>
|
||||
<circle cx="75" cy="35" r="4" fill="rgba(255,255,255,0.3)"/>
|
||||
<circle cx="90" cy="45" r="2" fill="rgba(255,255,255,0.4)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,43 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Main phone -->
|
||||
<rect x="70" y="40" width="60" height="120" rx="12" fill="rgba(255,255,255,0.95)" stroke="rgba(255,255,255,0.3)" stroke-width="2"/>
|
||||
|
||||
<!-- Screen -->
|
||||
<rect x="75" y="55" width="50" height="90" rx="6" fill="rgba(34,197,94,0.2)"/>
|
||||
|
||||
<!-- Status bar -->
|
||||
<rect x="78" y="58" width="44" height="8" fill="rgba(34,197,94,0.4)"/>
|
||||
|
||||
<!-- App icons grid -->
|
||||
<rect x="80" y="75" width="12" height="12" rx="3" fill="rgba(59,130,246,0.7)"/>
|
||||
<rect x="95" y="75" width="12" height="12" rx="3" fill="rgba(239,68,68,0.7)"/>
|
||||
<rect x="110" y="75" width="12" height="12" rx="3" fill="rgba(245,158,11,0.7)"/>
|
||||
|
||||
<rect x="80" y="92" width="12" height="12" rx="3" fill="rgba(139,92,246,0.7)"/>
|
||||
<rect x="95" y="92" width="12" height="12" rx="3" fill="rgba(16,185,129,0.7)"/>
|
||||
<rect x="110" y="92" width="12" height="12" rx="3" fill="rgba(236,72,153,0.7)"/>
|
||||
|
||||
<!-- Navigation bar -->
|
||||
<circle cx="100" cy="130" r="8" fill="rgba(255,255,255,0.8)" stroke="rgba(34,197,94,0.3)" stroke-width="2"/>
|
||||
|
||||
<!-- Home button -->
|
||||
<circle cx="100" cy="150" r="4" fill="rgba(255,255,255,0.6)"/>
|
||||
|
||||
<!-- Secondary phones -->
|
||||
<rect x="35" y="80" width="25" height="45" rx="6" fill="rgba(255,255,255,0.7)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
<rect x="38" y="88" width="19" height="25" fill="rgba(34,197,94,0.3)"/>
|
||||
|
||||
<rect x="140" y="90" width="25" height="45" rx="6" fill="rgba(255,255,255,0.7)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
<rect x="143" y="98" width="19" height="25" fill="rgba(34,197,94,0.3)"/>
|
||||
|
||||
<!-- Decorative elements -->
|
||||
<circle cx="50" cy="50" r="4" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
<circle cx="150" cy="160" r="6" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
|
||||
<!-- WiFi and signal indicators -->
|
||||
<path d="M25 25 L35 25 M30 20 L30 30 M27 23 L33 23" stroke="rgba(255,255,255,0.3)" stroke-width="2" fill="none"/>
|
||||
<path d="M165 25 Q175 25 175 35 Q175 45 165 45" stroke="rgba(255,255,255,0.3)" stroke-width="2" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,43 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Main phone -->
|
||||
<rect x="70" y="40" width="60" height="120" rx="12" fill="rgba(255,255,255,0.95)" stroke="rgba(255,255,255,0.3)" stroke-width="2"/>
|
||||
|
||||
<!-- Screen -->
|
||||
<rect x="75" y="55" width="50" height="90" rx="6" fill="rgba(34,197,94,0.2)"/>
|
||||
|
||||
<!-- Status bar -->
|
||||
<rect x="78" y="58" width="44" height="8" fill="rgba(34,197,94,0.4)"/>
|
||||
|
||||
<!-- App icons grid -->
|
||||
<rect x="80" y="75" width="12" height="12" rx="3" fill="rgba(59,130,246,0.7)"/>
|
||||
<rect x="95" y="75" width="12" height="12" rx="3" fill="rgba(239,68,68,0.7)"/>
|
||||
<rect x="110" y="75" width="12" height="12" rx="3" fill="rgba(245,158,11,0.7)"/>
|
||||
|
||||
<rect x="80" y="92" width="12" height="12" rx="3" fill="rgba(139,92,246,0.7)"/>
|
||||
<rect x="95" y="92" width="12" height="12" rx="3" fill="rgba(16,185,129,0.7)"/>
|
||||
<rect x="110" y="92" width="12" height="12" rx="3" fill="rgba(236,72,153,0.7)"/>
|
||||
|
||||
<!-- Navigation bar -->
|
||||
<circle cx="100" cy="130" r="8" fill="rgba(255,255,255,0.8)" stroke="rgba(34,197,94,0.3)" stroke-width="2"/>
|
||||
|
||||
<!-- Home button -->
|
||||
<circle cx="100" cy="150" r="4" fill="rgba(255,255,255,0.6)"/>
|
||||
|
||||
<!-- Secondary phones -->
|
||||
<rect x="35" y="80" width="25" height="45" rx="6" fill="rgba(255,255,255,0.7)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
<rect x="38" y="88" width="19" height="25" fill="rgba(34,197,94,0.3)"/>
|
||||
|
||||
<rect x="140" y="90" width="25" height="45" rx="6" fill="rgba(255,255,255,0.7)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
<rect x="143" y="98" width="19" height="25" fill="rgba(34,197,94,0.3)"/>
|
||||
|
||||
<!-- Decorative elements -->
|
||||
<circle cx="50" cy="50" r="4" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
<circle cx="150" cy="160" r="6" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
|
||||
<!-- WiFi and signal indicators -->
|
||||
<path d="M25 25 L35 25 M30 20 L30 30 M27 23 L33 23" stroke="rgba(255,255,255,0.3)" stroke-width="2" fill="none"/>
|
||||
<path d="M165 25 Q175 25 175 35 Q175 45 165 45" stroke="rgba(255,255,255,0.3)" stroke-width="2" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,47 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Design canvas/artboard -->
|
||||
<rect x="50" y="50" width="100" height="80" rx="8" fill="rgba(255,255,255,0.9)" stroke="rgba(255,255,255,0.3)" stroke-width="2"/>
|
||||
|
||||
<!-- Design elements - wireframe -->
|
||||
<rect x="60" y="65" width="80" height="8" rx="4" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="60" y="80" width="50" height="6" rx="3" fill="rgba(236,72,153,0.4)"/>
|
||||
<rect x="60" y="92" width="70" height="6" rx="3" fill="rgba(59,130,246,0.4)"/>
|
||||
|
||||
<!-- Button mockups -->
|
||||
<rect x="60" y="105" width="25" height="12" rx="6" fill="rgba(34,197,94,0.6)"/>
|
||||
<rect x="90" y="105" width="25" height="12" rx="6" fill="rgba(239,68,68,0.3)" stroke="rgba(239,68,68,0.5)" stroke-width="1"/>
|
||||
|
||||
<!-- Color palette -->
|
||||
<circle cx="170" cy="60" r="8" fill="rgba(59,130,246,0.8)"/>
|
||||
<circle cx="170" cy="80" r="8" fill="rgba(34,197,94,0.8)"/>
|
||||
<circle cx="170" cy="100" r="8" fill="rgba(245,158,11,0.8)"/>
|
||||
<circle cx="170" cy="120" r="8" fill="rgba(236,72,153,0.8)"/>
|
||||
|
||||
<!-- Design tools -->
|
||||
<rect x="20" y="30" width="40" height="6" rx="3" fill="rgba(255,255,255,0.7)"/>
|
||||
<circle cx="25" cy="33" r="2" fill="rgba(59,130,246,0.7)"/>
|
||||
<circle cx="32" cy="33" r="2" fill="rgba(34,197,94,0.7)"/>
|
||||
<circle cx="39" cy="33" r="2" fill="rgba(239,68,68,0.7)"/>
|
||||
|
||||
<!-- Cursor/pointer -->
|
||||
<path d="M25 160 L35 170 L30 175 L20 170 Z" fill="rgba(255,255,255,0.8)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
|
||||
<!-- Grid lines -->
|
||||
<defs>
|
||||
<pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse">
|
||||
<path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect x="50" y="50" width="100" height="80" fill="url(#grid)"/>
|
||||
|
||||
<!-- Floating design elements -->
|
||||
<rect x="160" y="140" width="20" height="12" rx="6" fill="rgba(255,255,255,0.5)" stroke="rgba(255,255,255,0.3)" stroke-width="1"/>
|
||||
<circle cx="30" cy="140" r="6" fill="rgba(255,255,255,0.3)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
|
||||
<!-- Typography indicator -->
|
||||
<text x="25" y="180" fill="rgba(255,255,255,0.4)" font-family="serif" font-size="16" font-weight="bold">Aa</text>
|
||||
<text x="150" y="180" fill="rgba(255,255,255,0.4)" font-family="sans-serif" font-size="12">UI/UX</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,47 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Design canvas/artboard -->
|
||||
<rect x="50" y="50" width="100" height="80" rx="8" fill="rgba(255,255,255,0.9)" stroke="rgba(255,255,255,0.3)" stroke-width="2"/>
|
||||
|
||||
<!-- Design elements - wireframe -->
|
||||
<rect x="60" y="65" width="80" height="8" rx="4" fill="rgba(139,92,246,0.3)"/>
|
||||
<rect x="60" y="80" width="50" height="6" rx="3" fill="rgba(236,72,153,0.4)"/>
|
||||
<rect x="60" y="92" width="70" height="6" rx="3" fill="rgba(59,130,246,0.4)"/>
|
||||
|
||||
<!-- Button mockups -->
|
||||
<rect x="60" y="105" width="25" height="12" rx="6" fill="rgba(34,197,94,0.6)"/>
|
||||
<rect x="90" y="105" width="25" height="12" rx="6" fill="rgba(239,68,68,0.3)" stroke="rgba(239,68,68,0.5)" stroke-width="1"/>
|
||||
|
||||
<!-- Color palette -->
|
||||
<circle cx="170" cy="60" r="8" fill="rgba(59,130,246,0.8)"/>
|
||||
<circle cx="170" cy="80" r="8" fill="rgba(34,197,94,0.8)"/>
|
||||
<circle cx="170" cy="100" r="8" fill="rgba(245,158,11,0.8)"/>
|
||||
<circle cx="170" cy="120" r="8" fill="rgba(236,72,153,0.8)"/>
|
||||
|
||||
<!-- Design tools -->
|
||||
<rect x="20" y="30" width="40" height="6" rx="3" fill="rgba(255,255,255,0.7)"/>
|
||||
<circle cx="25" cy="33" r="2" fill="rgba(59,130,246,0.7)"/>
|
||||
<circle cx="32" cy="33" r="2" fill="rgba(34,197,94,0.7)"/>
|
||||
<circle cx="39" cy="33" r="2" fill="rgba(239,68,68,0.7)"/>
|
||||
|
||||
<!-- Cursor/pointer -->
|
||||
<path d="M25 160 L35 170 L30 175 L20 170 Z" fill="rgba(255,255,255,0.8)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
|
||||
|
||||
<!-- Grid lines -->
|
||||
<defs>
|
||||
<pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse">
|
||||
<path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect x="50" y="50" width="100" height="80" fill="url(#grid)"/>
|
||||
|
||||
<!-- Floating design elements -->
|
||||
<rect x="160" y="140" width="20" height="12" rx="6" fill="rgba(255,255,255,0.5)" stroke="rgba(255,255,255,0.3)" stroke-width="1"/>
|
||||
<circle cx="30" cy="140" r="6" fill="rgba(255,255,255,0.3)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
|
||||
<!-- Typography indicator -->
|
||||
<text x="25" y="180" fill="rgba(255,255,255,0.4)" font-family="serif" font-size="16" font-weight="bold">Aa</text>
|
||||
<text x="150" y="180" fill="rgba(255,255,255,0.4)" font-family="sans-serif" font-size="12">UI/UX</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,34 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Browser window -->
|
||||
<rect x="40" y="60" width="120" height="80" rx="8" fill="rgba(255,255,255,0.9)"/>
|
||||
|
||||
<!-- Browser header -->
|
||||
<rect x="40" y="60" width="120" height="20" rx="8" fill="rgba(59,130,246,0.8)"/>
|
||||
|
||||
<!-- Browser dots -->
|
||||
<circle cx="50" cy="70" r="3" fill="rgba(239,68,68,0.8)"/>
|
||||
<circle cx="60" cy="70" r="3" fill="rgba(245,158,11,0.8)"/>
|
||||
<circle cx="70" cy="70" r="3" fill="rgba(34,197,94,0.8)"/>
|
||||
|
||||
<!-- Code lines -->
|
||||
<rect x="50" y="90" width="60" height="3" rx="1.5" fill="rgba(59,130,246,0.6)"/>
|
||||
<rect x="50" y="100" width="40" height="3" rx="1.5" fill="rgba(16,185,129,0.6)"/>
|
||||
<rect x="50" y="110" width="80" height="3" rx="1.5" fill="rgba(139,92,246,0.6)"/>
|
||||
<rect x="50" y="120" width="30" height="3" rx="1.5" fill="rgba(245,158,11,0.6)"/>
|
||||
|
||||
<!-- Mobile phone -->
|
||||
<rect x="130" y="110" width="25" height="40" rx="4" fill="rgba(255,255,255,0.9)" stroke="rgba(255,255,255,0.3)" stroke-width="1"/>
|
||||
<rect x="132" y="115" width="21" height="25" fill="rgba(59,130,246,0.3)"/>
|
||||
<circle cx="142.5" cy="145" r="2" fill="rgba(255,255,255,0.7)"/>
|
||||
|
||||
<!-- Decorative elements -->
|
||||
<circle cx="170" cy="80" r="8" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
<circle cx="30" cy="120" r="6" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
|
||||
<!-- Code brackets -->
|
||||
<text x="20" y="50" fill="rgba(255,255,255,0.4)" font-family="monospace" font-size="20" font-weight="bold"></></text>
|
||||
<text x="160" y="170" fill="rgba(255,255,255,0.4)" font-family="monospace" font-size="16" font-weight="bold">{}</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,34 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||
<!-- Background circle -->
|
||||
<circle cx="100" cy="100" r="90" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="2"/>
|
||||
|
||||
<!-- Browser window -->
|
||||
<rect x="40" y="60" width="120" height="80" rx="8" fill="rgba(255,255,255,0.9)"/>
|
||||
|
||||
<!-- Browser header -->
|
||||
<rect x="40" y="60" width="120" height="20" rx="8" fill="rgba(59,130,246,0.8)"/>
|
||||
|
||||
<!-- Browser dots -->
|
||||
<circle cx="50" cy="70" r="3" fill="rgba(239,68,68,0.8)"/>
|
||||
<circle cx="60" cy="70" r="3" fill="rgba(245,158,11,0.8)"/>
|
||||
<circle cx="70" cy="70" r="3" fill="rgba(34,197,94,0.8)"/>
|
||||
|
||||
<!-- Code lines -->
|
||||
<rect x="50" y="90" width="60" height="3" rx="1.5" fill="rgba(59,130,246,0.6)"/>
|
||||
<rect x="50" y="100" width="40" height="3" rx="1.5" fill="rgba(16,185,129,0.6)"/>
|
||||
<rect x="50" y="110" width="80" height="3" rx="1.5" fill="rgba(139,92,246,0.6)"/>
|
||||
<rect x="50" y="120" width="30" height="3" rx="1.5" fill="rgba(245,158,11,0.6)"/>
|
||||
|
||||
<!-- Mobile phone -->
|
||||
<rect x="130" y="110" width="25" height="40" rx="4" fill="rgba(255,255,255,0.9)" stroke="rgba(255,255,255,0.3)" stroke-width="1"/>
|
||||
<rect x="132" y="115" width="21" height="25" fill="rgba(59,130,246,0.3)"/>
|
||||
<circle cx="142.5" cy="145" r="2" fill="rgba(255,255,255,0.7)"/>
|
||||
|
||||
<!-- Decorative elements -->
|
||||
<circle cx="170" cy="80" r="8" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
<circle cx="30" cy="120" r="6" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.2)" stroke-width="1"/>
|
||||
|
||||
<!-- Code brackets -->
|
||||
<text x="20" y="50" fill="rgba(255,255,255,0.4)" font-family="monospace" font-size="20" font-weight="bold"></></text>
|
||||
<text x="160" y="170" fill="rgba(255,255,255,0.4)" font-family="monospace" font-size="16" font-weight="bold">{}</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
414
.history/public/sw_20251026215851.js
Normal file
@@ -0,0 +1,414 @@
|
||||
// Service Worker for SmartSolTech PWA
|
||||
const CACHE_NAME = 'smartsoltech-v1.0.2';
|
||||
const STATIC_CACHE_NAME = 'smartsoltech-static-v1.0.2';
|
||||
const DYNAMIC_CACHE_NAME = 'smartsoltech-dynamic-v1.0.2';
|
||||
|
||||
// Files to cache immediately
|
||||
const STATIC_FILES = [
|
||||
'/',
|
||||
'/css/main.css',
|
||||
'/css/fixes.css',
|
||||
'/css/dark-theme.css',
|
||||
'/js/main.js',
|
||||
'/vendor/jquery/jquery-3.6.0.min.js',
|
||||
'/vendor/bootstrap/bootstrap.bundle.min.js',
|
||||
'/vendor/bootstrap/bootstrap.min.css',
|
||||
'/vendor/adminlte/adminlte.min.js',
|
||||
'/vendor/adminlte/adminlte.min.css',
|
||||
'/vendor/adminlte/fontawesome.min.css',
|
||||
'/images/logo.png',
|
||||
'/images/icon-192x192.png',
|
||||
'/images/icon-144x144.png',
|
||||
'/manifest.json',
|
||||
'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap',
|
||||
'https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap',
|
||||
'https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css',
|
||||
'https://unpkg.com/aos@2.3.1/dist/aos.css',
|
||||
'https://unpkg.com/aos@2.3.1/dist/aos.js'
|
||||
];
|
||||
|
||||
// Routes to cache dynamically
|
||||
const DYNAMIC_ROUTES = [
|
||||
'/about',
|
||||
'/services',
|
||||
'/portfolio',
|
||||
'/calculator',
|
||||
'/contact'
|
||||
];
|
||||
|
||||
// API endpoints to cache
|
||||
const API_CACHE_PATTERNS = [
|
||||
/^\/api\/portfolio/,
|
||||
/^\/api\/services/,
|
||||
/^\/api\/calculator\/services/
|
||||
];
|
||||
|
||||
// Install event - cache static files
|
||||
self.addEventListener('install', event => {
|
||||
console.log('Service Worker: Installing...');
|
||||
|
||||
event.waitUntil(
|
||||
caches.open(STATIC_CACHE_NAME)
|
||||
.then(cache => {
|
||||
console.log('Service Worker: Caching static files');
|
||||
return cache.addAll(STATIC_FILES);
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Service Worker: Static files cached');
|
||||
return self.skipWaiting();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Service Worker: Error caching static files', error);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Activate event - clean up old caches
|
||||
self.addEventListener('activate', event => {
|
||||
console.log('Service Worker: Activating...');
|
||||
|
||||
event.waitUntil(
|
||||
caches.keys()
|
||||
.then(cacheNames => {
|
||||
return Promise.all(
|
||||
cacheNames.map(cacheName => {
|
||||
if (cacheName !== STATIC_CACHE_NAME &&
|
||||
cacheName !== DYNAMIC_CACHE_NAME) {
|
||||
console.log('Service Worker: Deleting old cache', cacheName);
|
||||
return caches.delete(cacheName);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Service Worker: Activated');
|
||||
return self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Fetch event - serve cached files or fetch from network
|
||||
self.addEventListener('fetch', event => {
|
||||
const request = event.request;
|
||||
const url = new URL(request.url);
|
||||
|
||||
// Skip non-GET requests
|
||||
if (request.method !== 'GET') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip Chrome extension requests
|
||||
if (url.protocol === 'chrome-extension:') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle different types of requests
|
||||
if (isStaticFile(request.url)) {
|
||||
event.respondWith(cacheFirst(request));
|
||||
} else if (isAPIRequest(request.url)) {
|
||||
event.respondWith(networkFirst(request));
|
||||
} else if (isDynamicRoute(request.url) || url.pathname === '/') {
|
||||
// For main pages, always check network first to ensure language consistency
|
||||
event.respondWith(networkFirst(request));
|
||||
} else {
|
||||
event.respondWith(networkFirst(request));
|
||||
}
|
||||
});
|
||||
|
||||
// Cache strategies
|
||||
async function cacheFirst(request) {
|
||||
try {
|
||||
const cachedResponse = await caches.match(request);
|
||||
if (cachedResponse) {
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
const networkResponse = await fetch(request);
|
||||
const cache = await caches.open(STATIC_CACHE_NAME);
|
||||
cache.put(request, networkResponse.clone());
|
||||
return networkResponse;
|
||||
} catch (error) {
|
||||
console.error('Cache first strategy failed:', error);
|
||||
return new Response('Offline', { status: 503 });
|
||||
}
|
||||
}
|
||||
|
||||
async function networkFirst(request) {
|
||||
try {
|
||||
const networkResponse = await fetch(request);
|
||||
|
||||
// Cache successful responses
|
||||
if (networkResponse.ok) {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
cache.put(request, networkResponse.clone());
|
||||
}
|
||||
|
||||
return networkResponse;
|
||||
} catch (error) {
|
||||
console.log('Network first: Falling back to cache for', request.url);
|
||||
|
||||
const cachedResponse = await caches.match(request);
|
||||
if (cachedResponse) {
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
// Return offline page for navigation requests
|
||||
if (request.mode === 'navigate') {
|
||||
return caches.match('/offline.html') || new Response('Offline', {
|
||||
status: 503,
|
||||
headers: { 'Content-Type': 'text/html' }
|
||||
});
|
||||
}
|
||||
|
||||
return new Response('Network Error', { status: 503 });
|
||||
}
|
||||
}
|
||||
|
||||
async function staleWhileRevalidate(request) {
|
||||
try {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
const cachedResponse = await cache.match(request);
|
||||
|
||||
const fetchPromise = fetch(request).then(networkResponse => {
|
||||
if (networkResponse && networkResponse.ok) {
|
||||
cache.put(request, networkResponse.clone());
|
||||
}
|
||||
return networkResponse;
|
||||
}).catch(error => {
|
||||
console.log('staleWhileRevalidate fetch failed:', error);
|
||||
return null;
|
||||
});
|
||||
|
||||
return cachedResponse || fetchPromise || new Response('Not available', { status: 503 });
|
||||
} catch (error) {
|
||||
console.error('staleWhileRevalidate error:', error);
|
||||
return new Response('Service unavailable', { status: 503 });
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
function isStaticFile(url) {
|
||||
return url.includes('/css/') ||
|
||||
url.includes('/js/') ||
|
||||
url.includes('/images/') ||
|
||||
url.includes('/fonts/') ||
|
||||
url.includes('googleapis.com') ||
|
||||
url.includes('cdnjs.cloudflare.com');
|
||||
}
|
||||
|
||||
function isAPIRequest(url) {
|
||||
return url.includes('/api/') ||
|
||||
API_CACHE_PATTERNS.some(pattern => pattern.test(url));
|
||||
}
|
||||
|
||||
function isDynamicRoute(url) {
|
||||
const pathname = new URL(url).pathname;
|
||||
return DYNAMIC_ROUTES.includes(pathname) ||
|
||||
pathname.startsWith('/portfolio/') ||
|
||||
pathname.startsWith('/services/');
|
||||
}
|
||||
|
||||
// Background sync for form submissions
|
||||
self.addEventListener('sync', event => {
|
||||
console.log('Service Worker: Background sync triggered', event.tag);
|
||||
|
||||
if (event.tag === 'contact-form-sync') {
|
||||
event.waitUntil(syncContactForms());
|
||||
}
|
||||
});
|
||||
|
||||
async function syncContactForms() {
|
||||
try {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
const requests = await cache.keys();
|
||||
|
||||
const contactRequests = requests.filter(request =>
|
||||
request.url.includes('/api/contact/submit')
|
||||
);
|
||||
|
||||
for (const request of contactRequests) {
|
||||
try {
|
||||
await fetch(request);
|
||||
await cache.delete(request);
|
||||
console.log('Contact form synced successfully');
|
||||
} catch (error) {
|
||||
console.error('Failed to sync contact form:', error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Background sync failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Push notification handling
|
||||
self.addEventListener('push', event => {
|
||||
console.log('Service Worker: Push received', event);
|
||||
|
||||
let data = {};
|
||||
if (event.data) {
|
||||
data = event.data.json();
|
||||
}
|
||||
|
||||
const title = data.title || 'SmartSolTech';
|
||||
const options = {
|
||||
body: data.body || 'You have a new notification',
|
||||
icon: '/images/icon-192x192.png',
|
||||
badge: '/images/icon-72x72.png',
|
||||
tag: data.tag || 'default',
|
||||
data: data.url || '/',
|
||||
actions: [
|
||||
{
|
||||
action: 'open',
|
||||
title: '열기',
|
||||
icon: '/images/icon-open.png'
|
||||
},
|
||||
{
|
||||
action: 'close',
|
||||
title: '닫기',
|
||||
icon: '/images/icon-close.png'
|
||||
}
|
||||
],
|
||||
requireInteraction: data.requireInteraction || false,
|
||||
silent: data.silent || false,
|
||||
vibrate: data.vibrate || [200, 100, 200]
|
||||
};
|
||||
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(title, options)
|
||||
);
|
||||
});
|
||||
|
||||
// Notification click handling
|
||||
self.addEventListener('notificationclick', event => {
|
||||
console.log('Service Worker: Notification clicked', event);
|
||||
|
||||
event.notification.close();
|
||||
|
||||
if (event.action === 'close') {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = event.notification.data || '/';
|
||||
|
||||
event.waitUntil(
|
||||
clients.matchAll({ type: 'window' }).then(clientList => {
|
||||
// Check if window is already open
|
||||
for (const client of clientList) {
|
||||
if (client.url === url && 'focus' in client) {
|
||||
return client.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// Open new window
|
||||
if (clients.openWindow) {
|
||||
return clients.openWindow(url);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Handle messages from main thread
|
||||
self.addEventListener('message', event => {
|
||||
console.log('Service Worker: Message received', event.data);
|
||||
|
||||
if (event.data && event.data.type === 'SKIP_WAITING') {
|
||||
self.skipWaiting();
|
||||
}
|
||||
|
||||
if (event.data && event.data.type === 'CACHE_URLS') {
|
||||
cacheUrls(event.data.urls);
|
||||
}
|
||||
});
|
||||
|
||||
async function cacheUrls(urls) {
|
||||
try {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
await cache.addAll(urls);
|
||||
console.log('URLs cached successfully:', urls);
|
||||
} catch (error) {
|
||||
console.error('Failed to cache URLs:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Periodic background sync (if supported)
|
||||
self.addEventListener('periodicsync', event => {
|
||||
console.log('Service Worker: Periodic sync triggered', event.tag);
|
||||
|
||||
if (event.tag === 'content-sync') {
|
||||
event.waitUntil(syncContent());
|
||||
}
|
||||
});
|
||||
|
||||
async function syncContent() {
|
||||
try {
|
||||
// Fetch fresh portfolio and services data
|
||||
const portfolioResponse = await fetch('/api/portfolio?featured=true');
|
||||
const servicesResponse = await fetch('/api/services?featured=true');
|
||||
|
||||
if (portfolioResponse.ok && servicesResponse.ok) {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
cache.put('/api/portfolio?featured=true', portfolioResponse.clone());
|
||||
cache.put('/api/services?featured=true', servicesResponse.clone());
|
||||
console.log('Content synced successfully');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Content sync failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache management utilities
|
||||
async function cleanupCaches() {
|
||||
const cacheNames = await caches.keys();
|
||||
const currentCaches = [STATIC_CACHE_NAME, DYNAMIC_CACHE_NAME];
|
||||
|
||||
return Promise.all(
|
||||
cacheNames.map(cacheName => {
|
||||
if (!currentCaches.includes(cacheName)) {
|
||||
console.log('Deleting old cache:', cacheName);
|
||||
return caches.delete(cacheName);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Limit cache size
|
||||
async function limitCacheSize(cacheName, maxItems) {
|
||||
const cache = await caches.open(cacheName);
|
||||
const keys = await cache.keys();
|
||||
|
||||
if (keys.length > maxItems) {
|
||||
const keysToDelete = keys.slice(0, keys.length - maxItems);
|
||||
return Promise.all(keysToDelete.map(key => cache.delete(key)));
|
||||
}
|
||||
}
|
||||
|
||||
// Performance monitoring
|
||||
self.addEventListener('fetch', event => {
|
||||
if (event.request.url.includes('/api/')) {
|
||||
const start = performance.now();
|
||||
|
||||
event.respondWith(
|
||||
fetch(event.request).then(response => {
|
||||
const duration = performance.now() - start;
|
||||
|
||||
// Log slow API requests
|
||||
if (duration > 2000) {
|
||||
console.warn('Slow API request:', event.request.url, duration + 'ms');
|
||||
}
|
||||
|
||||
return response;
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Error tracking
|
||||
self.addEventListener('error', event => {
|
||||
console.error('Service Worker error:', event.error);
|
||||
// Could send to analytics service
|
||||
});
|
||||
|
||||
self.addEventListener('unhandledrejection', event => {
|
||||
console.error('Service Worker unhandled rejection:', event.reason);
|
||||
// Could send to analytics service
|
||||
});
|
||||
414
.history/public/sw_20251026215934.js
Normal file
@@ -0,0 +1,414 @@
|
||||
// Service Worker for SmartSolTech PWA
|
||||
const CACHE_NAME = 'smartsoltech-v1.0.2';
|
||||
const STATIC_CACHE_NAME = 'smartsoltech-static-v1.0.2';
|
||||
const DYNAMIC_CACHE_NAME = 'smartsoltech-dynamic-v1.0.2';
|
||||
|
||||
// Files to cache immediately
|
||||
const STATIC_FILES = [
|
||||
'/',
|
||||
'/css/main.css',
|
||||
'/css/fixes.css',
|
||||
'/css/dark-theme.css',
|
||||
'/js/main.js',
|
||||
'/vendor/jquery/jquery-3.6.0.min.js',
|
||||
'/vendor/bootstrap/bootstrap.bundle.min.js',
|
||||
'/vendor/bootstrap/bootstrap.min.css',
|
||||
'/vendor/adminlte/adminlte.min.js',
|
||||
'/vendor/adminlte/adminlte.min.css',
|
||||
'/vendor/adminlte/fontawesome.min.css',
|
||||
'/images/logo.png',
|
||||
'/images/icon-192x192.png',
|
||||
'/images/icon-144x144.png',
|
||||
'/manifest.json',
|
||||
'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap',
|
||||
'https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap',
|
||||
'https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css',
|
||||
'https://unpkg.com/aos@2.3.1/dist/aos.css',
|
||||
'https://unpkg.com/aos@2.3.1/dist/aos.js'
|
||||
];
|
||||
|
||||
// Routes to cache dynamically
|
||||
const DYNAMIC_ROUTES = [
|
||||
'/about',
|
||||
'/services',
|
||||
'/portfolio',
|
||||
'/calculator',
|
||||
'/contact'
|
||||
];
|
||||
|
||||
// API endpoints to cache
|
||||
const API_CACHE_PATTERNS = [
|
||||
/^\/api\/portfolio/,
|
||||
/^\/api\/services/,
|
||||
/^\/api\/calculator\/services/
|
||||
];
|
||||
|
||||
// Install event - cache static files
|
||||
self.addEventListener('install', event => {
|
||||
console.log('Service Worker: Installing...');
|
||||
|
||||
event.waitUntil(
|
||||
caches.open(STATIC_CACHE_NAME)
|
||||
.then(cache => {
|
||||
console.log('Service Worker: Caching static files');
|
||||
return cache.addAll(STATIC_FILES);
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Service Worker: Static files cached');
|
||||
return self.skipWaiting();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Service Worker: Error caching static files', error);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Activate event - clean up old caches
|
||||
self.addEventListener('activate', event => {
|
||||
console.log('Service Worker: Activating...');
|
||||
|
||||
event.waitUntil(
|
||||
caches.keys()
|
||||
.then(cacheNames => {
|
||||
return Promise.all(
|
||||
cacheNames.map(cacheName => {
|
||||
if (cacheName !== STATIC_CACHE_NAME &&
|
||||
cacheName !== DYNAMIC_CACHE_NAME) {
|
||||
console.log('Service Worker: Deleting old cache', cacheName);
|
||||
return caches.delete(cacheName);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Service Worker: Activated');
|
||||
return self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Fetch event - serve cached files or fetch from network
|
||||
self.addEventListener('fetch', event => {
|
||||
const request = event.request;
|
||||
const url = new URL(request.url);
|
||||
|
||||
// Skip non-GET requests
|
||||
if (request.method !== 'GET') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip Chrome extension requests
|
||||
if (url.protocol === 'chrome-extension:') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle different types of requests
|
||||
if (isStaticFile(request.url)) {
|
||||
event.respondWith(cacheFirst(request));
|
||||
} else if (isAPIRequest(request.url)) {
|
||||
event.respondWith(networkFirst(request));
|
||||
} else if (isDynamicRoute(request.url) || url.pathname === '/') {
|
||||
// For main pages, always check network first to ensure language consistency
|
||||
event.respondWith(networkFirst(request));
|
||||
} else {
|
||||
event.respondWith(networkFirst(request));
|
||||
}
|
||||
});
|
||||
|
||||
// Cache strategies
|
||||
async function cacheFirst(request) {
|
||||
try {
|
||||
const cachedResponse = await caches.match(request);
|
||||
if (cachedResponse) {
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
const networkResponse = await fetch(request);
|
||||
const cache = await caches.open(STATIC_CACHE_NAME);
|
||||
cache.put(request, networkResponse.clone());
|
||||
return networkResponse;
|
||||
} catch (error) {
|
||||
console.error('Cache first strategy failed:', error);
|
||||
return new Response('Offline', { status: 503 });
|
||||
}
|
||||
}
|
||||
|
||||
async function networkFirst(request) {
|
||||
try {
|
||||
const networkResponse = await fetch(request);
|
||||
|
||||
// Cache successful responses
|
||||
if (networkResponse.ok) {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
cache.put(request, networkResponse.clone());
|
||||
}
|
||||
|
||||
return networkResponse;
|
||||
} catch (error) {
|
||||
console.log('Network first: Falling back to cache for', request.url);
|
||||
|
||||
const cachedResponse = await caches.match(request);
|
||||
if (cachedResponse) {
|
||||
return cachedResponse;
|
||||
}
|
||||
|
||||
// Return offline page for navigation requests
|
||||
if (request.mode === 'navigate') {
|
||||
return caches.match('/offline.html') || new Response('Offline', {
|
||||
status: 503,
|
||||
headers: { 'Content-Type': 'text/html' }
|
||||
});
|
||||
}
|
||||
|
||||
return new Response('Network Error', { status: 503 });
|
||||
}
|
||||
}
|
||||
|
||||
async function staleWhileRevalidate(request) {
|
||||
try {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
const cachedResponse = await cache.match(request);
|
||||
|
||||
const fetchPromise = fetch(request).then(networkResponse => {
|
||||
if (networkResponse && networkResponse.ok) {
|
||||
cache.put(request, networkResponse.clone());
|
||||
}
|
||||
return networkResponse;
|
||||
}).catch(error => {
|
||||
console.log('staleWhileRevalidate fetch failed:', error);
|
||||
return null;
|
||||
});
|
||||
|
||||
return cachedResponse || fetchPromise || new Response('Not available', { status: 503 });
|
||||
} catch (error) {
|
||||
console.error('staleWhileRevalidate error:', error);
|
||||
return new Response('Service unavailable', { status: 503 });
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
function isStaticFile(url) {
|
||||
return url.includes('/css/') ||
|
||||
url.includes('/js/') ||
|
||||
url.includes('/images/') ||
|
||||
url.includes('/fonts/') ||
|
||||
url.includes('googleapis.com') ||
|
||||
url.includes('cdnjs.cloudflare.com');
|
||||
}
|
||||
|
||||
function isAPIRequest(url) {
|
||||
return url.includes('/api/') ||
|
||||
API_CACHE_PATTERNS.some(pattern => pattern.test(url));
|
||||
}
|
||||
|
||||
function isDynamicRoute(url) {
|
||||
const pathname = new URL(url).pathname;
|
||||
return DYNAMIC_ROUTES.includes(pathname) ||
|
||||
pathname.startsWith('/portfolio/') ||
|
||||
pathname.startsWith('/services/');
|
||||
}
|
||||
|
||||
// Background sync for form submissions
|
||||
self.addEventListener('sync', event => {
|
||||
console.log('Service Worker: Background sync triggered', event.tag);
|
||||
|
||||
if (event.tag === 'contact-form-sync') {
|
||||
event.waitUntil(syncContactForms());
|
||||
}
|
||||
});
|
||||
|
||||
async function syncContactForms() {
|
||||
try {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
const requests = await cache.keys();
|
||||
|
||||
const contactRequests = requests.filter(request =>
|
||||
request.url.includes('/api/contact/submit')
|
||||
);
|
||||
|
||||
for (const request of contactRequests) {
|
||||
try {
|
||||
await fetch(request);
|
||||
await cache.delete(request);
|
||||
console.log('Contact form synced successfully');
|
||||
} catch (error) {
|
||||
console.error('Failed to sync contact form:', error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Background sync failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Push notification handling
|
||||
self.addEventListener('push', event => {
|
||||
console.log('Service Worker: Push received', event);
|
||||
|
||||
let data = {};
|
||||
if (event.data) {
|
||||
data = event.data.json();
|
||||
}
|
||||
|
||||
const title = data.title || 'SmartSolTech';
|
||||
const options = {
|
||||
body: data.body || 'You have a new notification',
|
||||
icon: '/images/icon-192x192.png',
|
||||
badge: '/images/icon-72x72.png',
|
||||
tag: data.tag || 'default',
|
||||
data: data.url || '/',
|
||||
actions: [
|
||||
{
|
||||
action: 'open',
|
||||
title: '열기',
|
||||
icon: '/images/icon-open.png'
|
||||
},
|
||||
{
|
||||
action: 'close',
|
||||
title: '닫기',
|
||||
icon: '/images/icon-close.png'
|
||||
}
|
||||
],
|
||||
requireInteraction: data.requireInteraction || false,
|
||||
silent: data.silent || false,
|
||||
vibrate: data.vibrate || [200, 100, 200]
|
||||
};
|
||||
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(title, options)
|
||||
);
|
||||
});
|
||||
|
||||
// Notification click handling
|
||||
self.addEventListener('notificationclick', event => {
|
||||
console.log('Service Worker: Notification clicked', event);
|
||||
|
||||
event.notification.close();
|
||||
|
||||
if (event.action === 'close') {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = event.notification.data || '/';
|
||||
|
||||
event.waitUntil(
|
||||
clients.matchAll({ type: 'window' }).then(clientList => {
|
||||
// Check if window is already open
|
||||
for (const client of clientList) {
|
||||
if (client.url === url && 'focus' in client) {
|
||||
return client.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// Open new window
|
||||
if (clients.openWindow) {
|
||||
return clients.openWindow(url);
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Handle messages from main thread
|
||||
self.addEventListener('message', event => {
|
||||
console.log('Service Worker: Message received', event.data);
|
||||
|
||||
if (event.data && event.data.type === 'SKIP_WAITING') {
|
||||
self.skipWaiting();
|
||||
}
|
||||
|
||||
if (event.data && event.data.type === 'CACHE_URLS') {
|
||||
cacheUrls(event.data.urls);
|
||||
}
|
||||
});
|
||||
|
||||
async function cacheUrls(urls) {
|
||||
try {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
await cache.addAll(urls);
|
||||
console.log('URLs cached successfully:', urls);
|
||||
} catch (error) {
|
||||
console.error('Failed to cache URLs:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Periodic background sync (if supported)
|
||||
self.addEventListener('periodicsync', event => {
|
||||
console.log('Service Worker: Periodic sync triggered', event.tag);
|
||||
|
||||
if (event.tag === 'content-sync') {
|
||||
event.waitUntil(syncContent());
|
||||
}
|
||||
});
|
||||
|
||||
async function syncContent() {
|
||||
try {
|
||||
// Fetch fresh portfolio and services data
|
||||
const portfolioResponse = await fetch('/api/portfolio?featured=true');
|
||||
const servicesResponse = await fetch('/api/services?featured=true');
|
||||
|
||||
if (portfolioResponse.ok && servicesResponse.ok) {
|
||||
const cache = await caches.open(DYNAMIC_CACHE_NAME);
|
||||
cache.put('/api/portfolio?featured=true', portfolioResponse.clone());
|
||||
cache.put('/api/services?featured=true', servicesResponse.clone());
|
||||
console.log('Content synced successfully');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Content sync failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache management utilities
|
||||
async function cleanupCaches() {
|
||||
const cacheNames = await caches.keys();
|
||||
const currentCaches = [STATIC_CACHE_NAME, DYNAMIC_CACHE_NAME];
|
||||
|
||||
return Promise.all(
|
||||
cacheNames.map(cacheName => {
|
||||
if (!currentCaches.includes(cacheName)) {
|
||||
console.log('Deleting old cache:', cacheName);
|
||||
return caches.delete(cacheName);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Limit cache size
|
||||
async function limitCacheSize(cacheName, maxItems) {
|
||||
const cache = await caches.open(cacheName);
|
||||
const keys = await cache.keys();
|
||||
|
||||
if (keys.length > maxItems) {
|
||||
const keysToDelete = keys.slice(0, keys.length - maxItems);
|
||||
return Promise.all(keysToDelete.map(key => cache.delete(key)));
|
||||
}
|
||||
}
|
||||
|
||||
// Performance monitoring
|
||||
self.addEventListener('fetch', event => {
|
||||
if (event.request.url.includes('/api/')) {
|
||||
const start = performance.now();
|
||||
|
||||
event.respondWith(
|
||||
fetch(event.request).then(response => {
|
||||
const duration = performance.now() - start;
|
||||
|
||||
// Log slow API requests
|
||||
if (duration > 2000) {
|
||||
console.warn('Slow API request:', event.request.url, duration + 'ms');
|
||||
}
|
||||
|
||||
return response;
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Error tracking
|
||||
self.addEventListener('error', event => {
|
||||
console.error('Service Worker error:', event.error);
|
||||
// Could send to analytics service
|
||||
});
|
||||
|
||||
self.addEventListener('unhandledrejection', event => {
|
||||
console.error('Service Worker unhandled rejection:', event.reason);
|
||||
// Could send to analytics service
|
||||
});
|
||||