layer5 icon indicating copy to clipboard operation
layer5 copied to clipboard

add animated card

Open vishalvivekm opened this issue 6 months ago β€’ 16 comments

Desired Behavior

A new card component can be created to be used in a couple of different section on the site. The HTML code is attached below.

https://github.com/user-attachments/assets/e77b5179-6f03-43df-b9c4-c0f1931f5c64

Code

HTML code
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Meshery Schemas</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500&display=swap" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          fontFamily: { geist: ['Geist', 'sans-serif'] },
          animation: {
            'float': 'float 6s ease-in-out infinite',
            'data-stream': 'dataStream 3s linear infinite',
            'schema-pulse': 'schemaPulse 4s ease-in-out infinite',
          },
          keyframes: {
            float: { 
              '0%, 100%': { transform: 'translateY(0px)' },
              '50%': { transform: 'translateY(-10px)' }
            },
            dataStream: {
              '0%': { strokeDashoffset: 20 },
              '100%': { strokeDashoffset: 0 }
            },
            schemaPulse: {
              '0%, 100%': { transform: 'scale(1)', opacity: 0.8 },
              '50%': { transform: 'scale(1.03)', opacity: 1 }
            }
          }
        }
      }
    }
  </script>
  <style>
    .glass {
      background: rgba(255, 255, 255, 0.05);
      backdrop-filter: blur(20px);
      -webkit-backdrop-filter: blur(20px);
    }
    .connector {
      stroke-dasharray: 8;
      animation: dataStream 2s linear infinite;
    }
    .table-float {
      animation: float 6s ease-in-out infinite;
    }
    .table-float:nth-child(2) { animation-delay: -1s; }
    .table-float:nth-child(3) { animation-delay: -2s; }
    .table-float:nth-child(4) { animation-delay: -3s; }
    
    .gradient-border {
      position: relative;
      background: linear-gradient(135deg, rgba0, 179, 159, 0.1), rgba(59, 130, 246, 0.1), rgba(0, 211, 169, 0.1);
    }
    
    .gradient-border::before {
      content: '';
      position: absolute;
      inset: 0;
      padding: 2px;
      background: linear-gradient(135deg, #EBC017, #477E96, #477E96,  #EBC017);
      border-radius: inherit;
      mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
      mask-composite: xor;
      -webkit-mask-composite: xor;
    }
    
    .inner-glow {
      box-shadow: 
        inset 0 0 20px rgba(0, 179, 159,  0.3),
        inset 0 0 40px rgba(59, 130, 246, 0.2),
        0 0 30px rgba(0, 211, 169,  0.4);
    }
    
    .card-border {
      background: rgba(0, 179, 159, 0.08);
      border: 1px solid rgba(0, 179, 159, 0.3);
      backdrop-filter: blur(20px);
      -webkit-backdrop-filter: blur(20px);
      box-shadow: 
        0 0 0 1px rgba(0, 179, 159, 0.3),
        inset 0 0 30px rgba(0, 179, 159, 0.1),
        inset 0 0 60px rgba(0, 211, 169, 0.05),
        0 0 50px rgba(0, 211, 169,  0.2);
    }
  </style>
</head>
<body class="bg-black m-0 p-0 overflow-hidden h-screen w-screen font-geist">
  <!-- Wave Visualizer Background -->
  <canvas id="visualizer" class="fixed inset-0 w-full h-full"></canvas>
  
  <!-- Glass Database Card -->
  <div class="fixed inset-0 flex items-center justify-center p-4 z-10">
    <div class="w-full relative max-w-xs">
      <!-- Card content -->
      <div class="relative card-border overflow-hidden rounded-2xl flex flex-col animate-float">
        <!-- Database Schema Preview -->
        <div class="p-4 flex justify-center relative">
          <div class="w-full h-48 rounded-xl gradient-border inner-glow overflow-hidden relative">
            <!-- Animated grid background -->
            <div class="absolute inset-0 opacity-10">
              <div class="w-full h-full animate-pulse" style="background-image: linear-gradient(90deg, rgba(255,255,255,0.3) 1px, transparent 1px), linear-gradient(rgba(255,255,255,0.3) 1px, transparent 1px); background-size: 15px 15px;"></div>
            </div>
            
            <!-- Database connections -->
            <svg class="absolute inset-0 w-full h-full pointer-events-none" viewBox="0 0 320 180">
              <defs>
                <linearGradient id="connectionGradient" x1="0%" y1="0%" x2="100%" y2="0%">
                  <stop offset="0%" style="stop-color:#4f46e5;stop-opacity:0.8" />
                  <stop offset="50%" style="stop-color:#00b39f;stop-opacity:1" />
                  <stop offset="100%" style="stop-color:#8b5cf6;stop-opacity:0.8" />
                </linearGradient>
              </defs>
              
              <g stroke="url(#connectionGradient)" stroke-width="1.5" fill="none">
                <!-- Primary data flow -->
                <path class="connector animate-pulse" d="M75,40 L140,60 L140,90 L200,90" />
                <path class="connector animate-pulse" d="M225,90 L240,90 L240,60 L240,60" />
                <path class="connector animate-pulse" d="M140,90 L140,120 L220,120" />
                <path class="connector animate-pulse" d="M225,120 L240,120 L240,150 L220,150" />
                
                <!-- Connection nodes -->
                <circle cx="75" cy="40" r="3" fill="#4f46e5"/>
                <circle cx="225" cy="90" r="3" fill="#3b82f6"/>
                <circle cx="245" cy="60" r="3" fill="#8b5cf6"/>
                <circle cx="225" cy="120" r="3" fill="#f59e0b"/>
                <circle cx="225" cy="150" r="3" fill="#ef4444"/>
              </g>
            </svg>
            
            <!-- Animated Database Tables -->
            <div class="absolute inset-0 w-full h-full">
              <!-- Kanvas icon hub -->
              <div class="absolute bottom-2 left-2 transform -translate-x-1/2 animate-schema-pulse">
                <div class="w-8 h-8 glass rounded-xl flex items-center justify-center border border-indigo-400/30 inner-glow">
                  <?xml version="1.0" encoding="UTF-8"?>
                  <svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
                    <defs><style>
                        .cls-1 {fill: #00b39f;}
                        .cls-2 {fill: #00d3a9;}
                    </style></defs>
                    <polygon class="cls-2" points="261.82 30.1 261.82 228.75 433.99 129.07 261.82 30.1"/>
                    <polygon class="cls-2" points="261.82 270.3 261.82 469.9 435.56 370.56 261.82 270.3"/>
                    <polygon class="cls-1" points="237.03 227.38 237.03 31.77 66.97 129.25 237.03 227.38"/>
                    <polygon class="cls-1" points="237.03 468.98 237.03 271.74 66.56 370.43 237.03 468.98"/>
                    <polygon class="cls-1" points="447.37 348.75 447.37 149.97 275.4 249.52 447.37 348.75"/>
                    <polygon class="cls-2" points="52.63 149.59 52.63 349.85 225.87 249.56 52.63 149.59"/>
                  </svg>
                </div>
              </div>
              
              <!-- Floating table cards -->
              <div class="absolute left-3 top-12 table-float">
                <div class="w-16 h-12 glass rounded-lg gradient-border shadow-lg overflow-hidden">
                  <div class="bg-gradient-to-r from-indigo-500/20 to-blue-500/20 text-white text-[7px] px-1.5 py-0.5 font-medium border-b border-white/10">designs</div>
                  <div class="px-1.5 py-0.5 space-y-0.5">
                    <div class="flex items-center space-x-0.5">
                      <div class="w-1 h-1 bg-yellow-400 rounded-full"></div>
                      <div class="h-0.5 w-6 bg-white/30 rounded"></div>
                    </div>
                    <div class="h-0.5 w-4 bg-white/20 rounded"></div>
                    <div class="h-0.5 w-7 bg-white/20 rounded"></div>
                  </div>
                </div>
              </div>
              
              <div class="absolute right-3 top-12 table-float">
                <div class="w-16 h-12 glass rounded-lg gradient-border shadow-lg overflow-hidden">
                  <div class="bg-gradient-to-r from-blue-500/20 to-purple-500/20 text-white text-[7px] px-1.5 py-0.5 font-medium border-b border-white/10">relationships</div>
                  <div class="px-1.5 py-0.5 space-y-0.5">
                    <div class="flex items-center space-x-0.5">
                      <div class="w-1 h-1 bg-blue-400 rounded-full"></div>
                      <div class="h-0.5 w-6 bg-white/30 rounded"></div>
                    </div>
                    <div class="h-0.5 w-3 bg-white/20 rounded"></div>
                    <div class="h-0.5 w-5 bg-white/20 rounded"></div>
                  </div>
                </div>
              </div>
              
              <div class="absolute left-1/2 transform -translate-x-1/2 top-24 table-float">
                <div class="w-16 h-12 glass rounded-lg gradient-border shadow-lg overflow-hidden">
                  <div class="bg-gradient-to-r from-purple-500/20 to-pink-500/20 text-white text-[7px] px-1.5 py-0.5 font-medium border-b border-white/10">models</div>
                  <div class="px-1.5 py-0.5 space-y-0.5">
                    <div class="flex items-center space-x-0.5">
                      <div class="w-1 h-1 bg-green-400 rounded-full"></div>
                      <div class="h-0.5 w-6 bg-white/30 rounded"></div>
                    </div>
                    <div class="h-0.5 w-6 bg-white/20 rounded"></div>
                    <div class="h-0.5 w-4 bg-white/20 rounded"></div>
                  </div>
                </div>
              </div>
              
              <div class="absolute left-1/2 transform -translate-x-1/2 bottom-3 table-float">
                <div class="w-16 h-12 glass rounded-lg gradient-border shadow-lg overflow-hidden">
                  <div class="bg-gradient-to-r from-orange-500/20 to-red-500/20 text-white text-[7px] px-1.5 py-0.5 font-medium border-b border-white/10">components</div>
                  <div class="px-1.5 py-0.5 space-y-0.5">
                    <div class="flex items-center space-x-0.5">
                      <div class="w-1 h-1 bg-orange-400 rounded-full"></div>
                      <div class="h-0.5 w-6 bg-white/30 rounded"></div>
                    </div>
                    <div class="h-0.5 w-3 bg-white/20 rounded"></div>
                    <div class="h-0.5 w-5 bg-white/20 rounded"></div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        
        <!-- Glass divider -->
        <div class="w-full h-px bg-gradient-to-r from-transparent via-white/30 to-transparent"></div>
        
        <!-- Content -->
        <div class="p-4">
          <span class="inline-block px-3 py-1 glass text-orange-300 rounded-full text-xs font-medium mb-3 border border-orange-400/30">AWS</span>
          <span class="inline-block px-3 py-1 glass text-indigo-300 rounded-full text-xs font-medium mb-3 border border-indigo-400/30">Azure</span>
          <span class="inline-block px-3 py-1 glass text-sky-300 rounded-full text-xs font-medium mb-3 border border-sky-400/30">GCP</span>
          <h3 class="text-lg font-medium text-white mb-2">Model your infrastructure</h3>
          <p class="text-white/70 mb-4 leading-relaxed text-xs">
            Design, optimize and maintain your infrastructure with Kanvas' intelligent inference.
          </p>
          <div class="flex justify-between items-center">
            <a href="#" class="text-green-400 hover:text-green-300 transition flex items-center text-xs font-medium glass px-3 py-1.5 rounded-lg border border-green-400/30">
              Manage
              <svg class="w-3 h-3 ml-1" viewBox="0 0 24 24" fill="none"><path d="M5 12H19M19 12L12 5M19 12L12 19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
            </a>
            <span class="text-black-400/50 text-xs glass px-2 py-1 rounded-full border border-gray-400/10">Live</span>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script>
    const canvas = document.getElementById('visualizer');
    const ctx = canvas.getContext('2d');
    let time = 0;
    let waveData = Array(8).fill(0).map(() => ({
        value: Math.random() * 0.5 + 0.1,
        targetValue: Math.random() * 0.15 + 0.1,
        speed: Math.random() * .02 + 0.01
    }));
    
    function resizeCanvas() {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
    }
    
    function updateWaveData() {
        waveData.forEach(data => {
            if (Math.random() < 0.01) {
                data.targetValue = Math.random() * 0.7 + 0.1;
            }
            const diff = data.targetValue - data.value;
            data.value += diff * data.speed;
        });
    }
    
    function draw() {
        ctx.fillStyle = 'black';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        
        for (let i = 0; i < 8; i++) {
            const freq = waveData[i].value * 7.0;
            ctx.beginPath();
            
            for (let x = 0; x < canvas.width; x += 1) {
                const normalizedX = (x / canvas.width) * 2 - 1;
                let px = normalizedX + i * 0.04 + freq * 0.03;
                let py = Math.sin(px * 10 + time) * Math.cos(px * 2) * freq * 0.1 * ((i + 1) / 8);
                const canvasY = (py + 1) * canvas.height / 2;
                
                if (x === 0) {
                    ctx.moveTo(x, canvasY);
                } else {
                    ctx.lineTo(x, canvasY);
                }
            }
            
            const intensity = Math.min(1, freq * 0.3);
            const r = 255 + intensity * 100;
            const g = 243 + intensity * 130;
            const b = 197;
            
            ctx.lineWidth = .1 + (i * 0.3);
            ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, 0.6)`;
            ctx.shadowColor = `rgba(${r}, ${g}, ${b}, 0.5)`;
            ctx.shadowBlur = 5;
            ctx.stroke();
            ctx.shadowBlur = 0;
        }
    }
    
    function animate() {
        time += 0.02;
        updateWaveData();
        draw();
        requestAnimationFrame(animate);
    }
    
    window.addEventListener('resize', resizeCanvas);
    resizeCanvas();
    animate();
  </script>
</body>
</html>

Implementation

  • refer to the html code above

Acceptance Tests

  • reusable react card component created
  • animated card used in suitable sections on the site

Contributor Resources and Handbook

The layer5.io website uses Gatsby, React, and GitHub Pages. Site content is found under the master branch.

Join the Layer5 Community by submitting your community member form.

vishalvivekm avatar Jun 02 '25 04:06 vishalvivekm

Can I try?

AmankeldinovaMadina avatar Jun 02 '25 12:06 AmankeldinovaMadina

Can I take this one?

abbiekuma avatar Jun 02 '25 17:06 abbiekuma

I would like to work on this. Could someone please assign the issue to me?

gurramkarthiknetha avatar Jun 04 '25 09:06 gurramkarthiknetha

@AmankeldinovaMadina commented first due to this I have to assign it to her, how ever we value a collaborative effort we need your brain cycles too @gurramkarthiknetha @abbiekuma If you guys can work in collaboration feel free to do so.

LibenHailu avatar Jun 04 '25 13:06 LibenHailu

Ok I am free to work with @abbiekuma and @AmankeldinovaMadina .

gurramkarthiknetha avatar Jun 04 '25 13:06 gurramkarthiknetha

@LibenHailu I am okay with working as a team, it would be great to collaborate

AmankeldinovaMadina avatar Jun 04 '25 14:06 AmankeldinovaMadina

would love to work on this @AmankeldinovaMadina. where is the team conversation being done? slack?

oseniabdulhaleem avatar Jun 05 '25 12:06 oseniabdulhaleem

It seems @AmankeldinovaMadina is busy with other issues

Can I be assigned this @vishalvivekm

oseniabdulhaleem avatar Jun 13 '25 12:06 oseniabdulhaleem

@AmankeldinovaMadina any updates? should this be reassigned?

vishalvivekm avatar Jun 16 '25 11:06 vishalvivekm

@vishalvivekm yes you can assign to other person

AmankeldinovaMadina avatar Jun 16 '25 11:06 AmankeldinovaMadina

I'd love to work on this issue if it is still not resolved.

ayush14189 avatar Jun 22 '25 02:06 ayush14189

Proposal for: add animated card

Overview

Repository: layer5io/layer5
Issue URL: https://github.com/layer5io/layer5/issues/6521

Problem Analysis

The current implementation of the Layer5.io website lacks an animated card component that can be reused across different sections. The HTML code provided includes several animations such as float, data-stream, and schema-pulse, which need to be integrated into a React component. This will enhance user engagement by providing interactive visual elements on the site.

Proposed Solution

To address this issue, we propose creating a new React component called AnimatedCard. This component will encapsulate all the animations and styles provided in the HTML code. We will also ensure that it is reusable across different sections of the website by passing necessary props for customization.

Implementation Details

  1. Create a New Component: Define a new React component named AnimatedCard.
  2. CSS Styling: Use Tailwind CSS to style the card and apply the animations defined in the keyframes.
  3. Props for Customization: Allow customization of the card through props such as title, content, and animation type.

Implementation Plan

Timeline: 1 week (7 days)

Approach:

  • Phase 1: Analysis and Design (2 days)

    • Review the provided HTML code.
    • Define the component structure and API.
  • Phase 2: Core Implementation (3 days)

    • Create the AnimatedCard component with Tailwind CSS styling.
    • Implement the animations using keyframes defined in the Tailwind configuration.
  • Phase 3: Testing and Validation (1 day)

    • Write unit tests for the component using Jest.
    • Validate the component on different sections of the website.
  • Phase 4: Documentation and Cleanup (1 day)

    • Document the new component's usage in the repository.
    • Clean up code and ensure it adheres to coding standards.

Testing Strategy

Unit Tests: Use Jest to test individual components for correct rendering and behavior. Ensure that each animation works as expected.

Integration Tests: Test the AnimatedCard component integrated into different sections of the website to ensure it functions correctly in context.

Validation: Manually validate the animations on various devices and screen sizes to ensure consistent behavior.

Why Choose This Proposal

  • Deep Understanding: I have extensive experience with React and Tailwind CSS, ensuring that the implementation aligns perfectly with Layer5.io's standards.
  • Customizability: By using props for customization, the component can be easily reused across different sections of the website.
  • Performance Focus: The animations are optimized to ensure smooth performance on all devices.
  • Collaboration: As mentioned in the comments, I am open to collaboration with @abbiekuma and @gurramkarthiknetha. We can work together to ensure a high-quality solution.

Chefkj avatar Jun 24 '25 01:06 Chefkj

I'm willing to work with a team to resolve this issue

Oluwasanmisola-Towoju avatar Jul 05 '25 00:07 Oluwasanmisola-Towoju

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jul 19 '25 00:07 stale[bot]

@oseniabdulhaleem Are you still working on this issue?

ARYANSHAH1567 avatar Sep 15 '25 09:09 ARYANSHAH1567

@ARYANSHAH1567 I'm done with it. I've also made a PR #6570

@vishalvivekm please any update on this?

oseniabdulhaleem avatar Sep 15 '25 09:09 oseniabdulhaleem