The Vault

build from scratch

OVERVIEW

Vault is a curated hub I built from scratch, showcasing AI-built products

& experiments by designers.

INTRODUCTION

OVERVIEW

The goal was to build a space where design meets AI showcasing creative experiments and ideas by designers.


Beyond just products, the focus was to humanize the experience, highlighting creators’ stories, process, and inspiration through features like LinkedIn integration and creator notes.


We also aimed to inspire learning with a Prompt Directory and improve performance through automation and lazy loading, fostering a growing AI design community.

MY ROLE

The goal was to build a space where design meets AI  showcasing creative experiments and ideas by designers.


As a designer and developer, I crafted the UI/UX in Figma and handled development in Framer, ensuring the experience felt seamless and intuitive.


I also wrote a Python script that created a data pipeline for embeds, allowing projects to be listed directly on pages from the script itself, automating what was once a manual process.

RESEARCH PHASE

Started with research

Started studying how designers showcase their products and noticed

4 common patterns in how designers share their AI projects online.

Tools used

A lot of designers talked about the tools behind their work, and it helped me understand how their AI ideas actually came together.

DESIGN PHASE

We prototyped multiple solutions

FIRST LIVE VERSION

After exploring multiple prototypes.

The final design took shape and went live

CONTINUING RESEARCH

After the launch : Understanding how users

are using this platform.

From a webinar where designers showcased their AI-made products,

I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section to share the process.

Simple changes that made the whole experience feel more human.

From a webinar where designers showcased their AI-made products,

I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section to share the process.

Simple changes that made the whole experience feel more human.

EXPLORATION OF TABS

Prototyped some solutions which from AI products to prompt directory

SOLVING PROBLEM

Heavy embeds were hard to manage,

but automation made it easy.

Embedding everything directly started slowing the site down — multiple embeds loaded at once, making the experience heavy and laggy.


To fix this, I built an automation script with ChatGPT and Cursor, creating a smooth pipeline that connects components automatically.


This streamlined the workflow, reduced manual effort, and made the overall system far more efficient to maintain and scale.

AUTOMATION SCRIPT

How data is flowing across the site

A glimpse of python script

from flask import Flask, request, render_template_string
import html
import requests
import os

app = Flask(__name__)

NOTION_TOKEN = os.getenv("NOTION_TOKEN", "secret_xyz123")
DATABASE_ID = os.getenv("NOTION_DATABASE_ID", "your_database_id")
NOTION_VERSION = "2022-06-28"

JS_SNIPPET = """
<script>
document.addEventListener("DOMContentLoaded", function () {
  const placeholders = document.querySelectorAll(".tweet-placeholder");
  const loadTweet = (el) => {
    const html = el.dataset.embed.replace(/'/g, "&#39;");
    el.innerHTML = html;
    if (!window.twttr) {
      let script = document.createElement("script");
      script.src = "https://platform.twitter.com/widgets.js";
      script.async = true;
      document.body.appendChild(script);
    } else {
      window.twttr.widgets.load(el);
    }
  };
  const observer = new IntersectionObserver((entries, obs) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        loadTweet(entry.target);
        obs.unobserve(entry.target);
      }
    });
  });
  placeholders.forEach(el => observer.observe(el));
});
</script>
"""

WIDTH = 500

def add_embed_to_notion(embed_html):
    url = "https://api.notion.com/v1/pages"
    headers = {
        "Authorization": f"Bearer {NOTION_TOKEN}",
        "Content-Type": "application/json",
        "Notion-Version": NOTION_VERSION,
    }
    data = {
        "parent": {"database_id": DATABASE_ID},
        "properties": {
            "Name": {
                "title": [
                    {
                        "text": {
                            "content": "Twitter Embed"
                        }
                    }
                ]
            },
            "EmbedCode": {
                "rich_text": [
                    {
                        "text": {
                            "content": embed_html
                        }
                    }
                ]
            }
        }
    }
    response = requests.post(url, headers=headers, json=data)
    response.raise_for_status()
    return response.json()

@app.route("/", methods=["GET", "POST"])
def index():
    transformed_embeds = []
    if request.method == "POST":
        raw_embeds = request.form.get("embeds", "")
        # Split embeds by double line break or add custom split logic as needed
        embed_list = [e.strip() for e in raw_embeds.split('\n\n') if e.strip()]
        
        for embed in embed_list:
            # Directly use the provided embed code (no parsing, since it's already valid HTML)
            # Escape single quotes for safe use in data-embed attribute
            escaped_html = html.escape(embed).replace("&#x27;", "&#39;")
            # Heuristic for reasonable height: 500->950px
            height = min(max(500, len(embed)), 950)

            transformed = f"""
<div style="width:{WIDTH}px; height:{height}px; overflow:hidden;"
     class="tweet-placeholder"
     data-embed='{escaped_html}'>
  <div style="color:#777; display:flex; align-items:center; justify-content:center; height:100%;">
    Loading Tweet…
  </div>
</div>
"""
            transformed_embeds.append(transformed)
            add_embed_to_notion(transformed)

        final_output = "\n".join(transformed_embeds) + JS_SNIPPET

        return render_template_string("""
            <html>
            <head><title>Transformed Embeds Output</title></head>
            <body style="background-color:#181818; color:#eee; font-family:sans-serif;">
                <h2>Transformed Embeds Output & Notion Upload Complete</h2>
                <p><a href="/">Back</a></p>
                <div>{{ output|safe }}</div>
            </body>
            </html>
        """, output=final_output)

    # GET = show textarea form
    return '''
    <html>
    <head><title>Embed Transformer</title></head>
    <body style="background-color:#181818; color:#eee; font-family:sans-serif;">
        <h1>Paste your Embed Codes</h1>
        <form method="post">
            <textarea name="embeds" rows="20" cols="80" placeholder="Paste embed codes here, separated by blank lines"></textarea><br><br>
            <button type="submit">Transform & Push to Notion</button>
        </form>
    </body>
    </html>

FINAL VERSION

Final Design that went live.

The Vault

build from scratch

OVERVIEW

Vault is a curated hub I built from scratch, showcasing AI-built products

& experiments by designers.

INTRODUCTION

OVERVIEW

The goal was to build a space where design meets AI showcasing creative experiments and ideas by designers.


Beyond just products, the focus was to humanize the experience, highlighting creators’ stories, process, and inspiration through features like LinkedIn integration and creator notes.


We also aimed to inspire learning with a Prompt Directory and improve performance through automation and lazy loading, fostering a growing AI design community.

MY ROLE

The goal was to build a space where design meets AI  showcasing creative experiments and ideas by designers.


As a designer and developer, I crafted the UI/UX in Figma and handled development in Framer, ensuring the experience felt seamless and intuitive.


I also wrote a Python script that created a data pipeline for embeds, allowing projects to be listed directly on pages from the script itself, automating what was once a manual process.

RESEARCH PHASE

Started with research

Started studying how designers showcase their products and noticed

4 common patterns in how designers share their AI projects online.

Tools used

A lot of designers talked about the tools behind their work, and it helped me understand how their AI ideas actually came together.

Tools used

A lot of designers talked about the tools behind their work, and it helped me understand how their AI ideas actually came together.

DESIGN PHASE

We prototyped multiple solutions

FIRST LIVE VERSION

After exploring multiple prototypes.

The final design took shape and went live

CONTINUING RESEARCH

After the launch : Understanding how users

are using this platform.

From a webinar where designers showcased their AI-made products,

I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section to share the process.

Simple changes that made the whole experience feel more human.

From a webinar where designers showcased their AI-made products,

I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section to share the process.

Simple changes that made the whole experience feel more human.

From a webinar where designers showcased their AI-made products,

I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section to share the process.

Simple changes that made the whole experience feel more human.

From a webinar where designers showcased their AI-made products,

I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section to share the process.

Simple changes that made the whole experience feel more human.

EXPLORATION OF TABS

Prototyped some solutions which switch from AI products to prompt directory

SOLVING PROBLEM

Heavy embeds were hard to manage,

but automation made it easy.

Embedding everything directly started slowing the site down — multiple embeds loaded at once, making the experience heavy and laggy.


To fix this, I built an automation script with ChatGPT and Cursor, creating a smooth pipeline that connects components automatically.


This streamlined the workflow, reduced manual effort, and made the overall system far more efficient to maintain and scale.

AUTOMATION SCRIPT

How data is flowing across the site

A glimpse of python script

from flask import Flask, request, render_template_string
import html
import requests
import os

app = Flask(__name__)

NOTION_TOKEN = os.getenv("NOTION_TOKEN", "secret_xyz123")
DATABASE_ID = os.getenv("NOTION_DATABASE_ID", "your_database_id")
NOTION_VERSION = "2022-06-28"

JS_SNIPPET = """
<script>
document.addEventListener("DOMContentLoaded", function () {
  const placeholders = document.querySelectorAll(".tweet-placeholder");
  const loadTweet = (el) => {
    const html = el.dataset.embed.replace(/'/g, "&#39;");
    el.innerHTML = html;
    if (!window.twttr) {
      let script = document.createElement("script");
      script.src = "https://platform.twitter.com/widgets.js";
      script.async = true;
      document.body.appendChild(script);
    } else {
      window.twttr.widgets.load(el);
    }
  };
  const observer = new IntersectionObserver((entries, obs) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        loadTweet(entry.target);
        obs.unobserve(entry.target);
      }
    });
  });
  placeholders.forEach(el => observer.observe(el));
});
</script>
"""

WIDTH = 500

def add_embed_to_notion(embed_html):
    url = "https://api.notion.com/v1/pages"
    headers = {
        "Authorization": f"Bearer {NOTION_TOKEN}",
        "Content-Type": "application/json",
        "Notion-Version": NOTION_VERSION,
    }
    data = {
        "parent": {"database_id": DATABASE_ID},
        "properties": {
            "Name": {
                "title": [
                    {
                        "text": {
                            "content": "Twitter Embed"
                        }
                    }
                ]
            },
            "EmbedCode": {
                "rich_text": [
                    {
                        "text": {
                            "content": embed_html
                        }
                    }
                ]
            }
        }
    }
    response = requests.post(url, headers=headers, json=data)
    response.raise_for_status()
    return response.json()

@app.route("/", methods=["GET", "POST"])
def index():
    transformed_embeds = []
    if request.method == "POST":
        raw_embeds = request.form.get("embeds", "")
        # Split embeds by double line break or add custom split logic as needed
        embed_list = [e.strip() for e in raw_embeds.split('\n\n') if e.strip()]
        
        for embed in embed_list:
            # Directly use the provided embed code (no parsing, since it's already valid HTML)
            # Escape single quotes for safe use in data-embed attribute
            escaped_html = html.escape(embed).replace("&#x27;", "&#39;")
            # Heuristic for reasonable height: 500->950px
            height = min(max(500, len(embed)), 950)

            transformed = f"""
<div style="width:{WIDTH}px; height:{height}px; overflow:hidden;"
     class="tweet-placeholder"
     data-embed='{escaped_html}'>
  <div style="color:#777; display:flex; align-items:center; justify-content:center; height:100%;">
    Loading Tweet…
  </div>
</div>
"""
            transformed_embeds.append(transformed)
            add_embed_to_notion(transformed)

        final_output = "\n".join(transformed_embeds) + JS_SNIPPET

        return render_template_string("""
            <html>
            <head><title>Transformed Embeds Output</title></head>
            <body style="background-color:#181818; color:#eee; font-family:sans-serif;">
                <h2>Transformed Embeds Output & Notion Upload Complete</h2>
                <p><a href="/">Back</a></p>
                <div>{{ output|safe }}</div>
            </body>
            </html>
        """, output=final_output)

    # GET = show textarea form
    return '''
    <html>
    <head><title>Embed Transformer</title></head>
    <body style="background-color:#181818; color:#eee; font-family:sans-serif;">
        <h1>Paste your Embed Codes</h1>
        <form method="post">
            <textarea name="embeds" rows="20" cols="80" placeholder="Paste embed codes here, separated by blank lines"></textarea><br><br>
            <button type="submit">Transform & Push to Notion</button>
        </form>
    </body>
    </html>

FINAL VERSION

Final Design that went live.

The Vault

build from scratch

OVERVIEW

Vault is a curated hub I built from scratch, showcasing AI-built products

& experiments by designers.

Introduction

OVERVIEW

The goal was to build a space where design meets AI showcasing creative experiments and ideas by designers.


Beyond just products, the focus was to humanize the experience, highlighting creators’ stories, process, and inspiration through features like LinkedIn integration and creator notes.


We also aimed to inspire learning with a Prompt Directory and improve performance through automation and lazy loading, fostering a growing AI design community.

MY ROLE

he goal was to build a space where design meets AI  showcasing creative experiments and ideas by designers.


As a designer and developer, I crafted the UI/UX in Figma and handled development in Framer, ensuring the experience felt seamless and intuitive.


I also wrote a Python script that created a data pipeline for embeds, allowing projects to be listed directly on pages from the script itself, automating what was once a manual process.

The goal was to build a space where design meets AI  showcasing creative experiments and ideas by designers.


As a designer and developer, I crafted the UI/UX in Figma and handled development in Framer, ensuring the experience felt seamless and intuitive.


I also wrote a Python script that created a data pipeline for embeds, allowing projects to be listed directly on pages from the script itself, automating what was once a manual process.

The goal was to build a space where design meets AI  showcasing creative experiments and ideas by designers.


As a designer and developer, I crafted the UI/UX in Figma and handled development in Framer, ensuring the experience felt seamless and intuitive.


I also wrote a Python script that created a data pipeline for embeds, allowing projects to be listed directly on pages from the script itself, automating what was once a manual process.

Research Phase

Started with research

Started studying how designers showcase their products and noticed

4 common patterns in how designers share their AI projects online.

Started with research

Started with research

Started studying how designers

showcase their products and noticed 4 common patterns in how designers share their AI projects online.

Started studying how designers

showcase their products and noticed 4 common patterns in how designers share their AI projects online.

  1. Tools used

A lot of designers talked about the tools behind their work, and it helped me understand how their AI ideas actually came together.

  1. Tools used

  1. Product type

A lot of designers talked about the tools behind their work, and it helped me understand how their AI ideas actually came together.

Designers frequently included the product type, targeting sector in industry like e-commerce, music or a plugin for figma

  1. Product type

  1. Description

Designers frequently included the product type, targeting sector in industry like e-commerce, music or a plugin for figma

Many designers shared a quick overview of their project a brief into what they built and why. Some of its features and how to use it also was mentioned

  1. Description

  1. Status

Many designers shared a quick overview of their project a brief into what they built and why. Some of its features and how to use it also was mentioned

They also shared whether their ideas currently exist as live, functioning products being used by real people, or if they are still in the prototype stage.

Tools used

A lot of designers talked about the tools behind their work, and it helped me understand how their AI ideas actually came together.

Product type

Designers frequently included the product type, targeting sector in industry like e-commerce, music or a plugin for figma

Description

Many designers shared a quick overview of their project a brief into what they built and why. Some of its features and how to use it also was mentioned

Status

They also shared whether their ideas currently exist as live, functioning products being used by real people, or if they are still in the prototype stage.

Design Phase

We prototyped multiple solutions

Started studying how designers showcase their products and noticed

4 common patterns in how designers share their AI projects online.

First Live Version

After exploring multiple prototypes.

The final design took shape and went live

Continuing research

After the launch : Understanding how users

are using this platform.

From a webinar where designers showcased their AI-made products, I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section

to share the process.

Simple changes that made the whole experience

feel more human.

From a webinar where designers showcased their AI-made products, I noticed that people wanted two things:


a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section

to share the process.

Simple changes that made the whole experience

feel more human.

From a webinar where designers showcased their AI-made products, I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section

to share the process.

Simple changes that made the whole experience

feel more human.

From a webinar where designers showcased their AI-made products,

I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section to share the process.

Simple changes that made the whole experience feel more human.

From a webinar where designers showcased their AI-made products,

I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section to share the process.

Simple changes that made the whole experience feel more human.

From a webinar where designers showcased their AI-made products,

I noticed that people wanted two things:

a way to connect with the creator and a glimpse into the story

behind that work. So we added a LinkedIn button for easy connection and a small creator notes section to share the process.

Simple changes that made the whole experience feel more human.

Exploration of tabs

Prototyped some solutions which switch from AI products to prompt directory

Solving Problems

Heavy embeds were hard to manage,

but automation made it easy.

Embedding everything directly started slowing the site down multiple embeds loaded at once, making the experience heavy and laggy.


To fix this, I built an automation script with ChatGPT and Cursor, creating a smooth pipeline that connects components automatically.


This streamlined the workflow, reduced manual effort, and made the overall system far more efficient to maintain and scale.

Embedding everything directly started slowing the site down multiple embeds loaded at once, making the experience heavy and laggy.


To fix this, I built an automation script with ChatGPT and Cursor, creating a smooth pipeline that connects components automatically.


This streamlined the workflow, reduced manual effort, and made the overall system far more efficient to maintain and scale.

AUTOMATION SCRIPT

How data is flowing across the site

A glimpse of python script

from flask import Flask, request, render_template_string
import html
import requests
import os

app = Flask(__name__)

NOTION_TOKEN = os.getenv("NOTION_TOKEN", "secret_xyz123")
DATABASE_ID = os.getenv("NOTION_DATABASE_ID", "your_database_id")
NOTION_VERSION = "2022-06-28"

JS_SNIPPET = """
<script>
document.addEventListener("DOMContentLoaded", function () {
  const placeholders = document.querySelectorAll(".tweet-placeholder");
  const loadTweet = (el) => {
    const html = el.dataset.embed.replace(/'/g, "&#39;");
    el.innerHTML = html;
    if (!window.twttr) {
      let script = document.createElement("script");
      script.src = "https://platform.twitter.com/widgets.js";
      script.async = true;
      document.body.appendChild(script);
    } else {
      window.twttr.widgets.load(el);
    }
  };
  const observer = new IntersectionObserver((entries, obs) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        loadTweet(entry.target);
        obs.unobserve(entry.target);
      }
    });
  });
  placeholders.forEach(el => observer.observe(el));
});
</script>
"""

WIDTH = 500

def add_embed_to_notion(embed_html):
    url = "https://api.notion.com/v1/pages"
    headers = {
        "Authorization": f"Bearer {NOTION_TOKEN}",
        "Content-Type": "application/json",
        "Notion-Version": NOTION_VERSION,
    }
    data = {
        "parent": {"database_id": DATABASE_ID},
        "properties": {
            "Name": {
                "title": [
                    {
                        "text": {
                            "content": "Twitter Embed"
                        }
                    }
                ]
            },
            "EmbedCode": {
                "rich_text": [
                    {
                        "text": {
                            "content": embed_html
                        }
                    }
                ]
            }
        }
    }
    response = requests.post(url, headers=headers, json=data)
    response.raise_for_status()
    return response.json()

@app.route("/", methods=["GET", "POST"])
def index():
    transformed_embeds = []
    if request.method == "POST":
        raw_embeds = request.form.get("embeds", "")
        # Split embeds by double line break or add custom split logic as needed
        embed_list = [e.strip() for e in raw_embeds.split('\n\n') if e.strip()]
        
        for embed in embed_list:
            # Directly use the provided embed code (no parsing, since it's already valid HTML)
            # Escape single quotes for safe use in data-embed attribute
            escaped_html = html.escape(embed).replace("&#x27;", "&#39;")
            # Heuristic for reasonable height: 500->950px
            height = min(max(500, len(embed)), 950)

            transformed = f"""
<div style="width:{WIDTH}px; height:{height}px; overflow:hidden;"
     class="tweet-placeholder"
     data-embed='{escaped_html}'>
  <div style="color:#777; display:flex; align-items:center; justify-content:center; height:100%;">
    Loading Tweet…
  </div>
</div>
"""
            transformed_embeds.append(transformed)
            add_embed_to_notion(transformed)

        final_output = "\n".join(transformed_embeds) + JS_SNIPPET

        return render_template_string("""
            <html>
            <head><title>Transformed Embeds Output</title></head>
            <body style="background-color:#181818; color:#eee; font-family:sans-serif;">
                <h2>Transformed Embeds Output & Notion Upload Complete</h2>
                <p><a href="/">Back</a></p>
                <div>{{ output|safe }}</div>
            </body>
            </html>
        """, output=final_output)

    # GET = show textarea form
    return '''
    <html>
    <head><title>Embed Transformer</title></head>
    <body style="background-color:#181818; color:#eee; font-family:sans-serif;">
        <h1>Paste your Embed Codes</h1>
        <form method="post">
            <textarea name="embeds" rows="20" cols="80" placeholder="Paste embed codes here, separated by blank lines"></textarea><br><br>
            <button type="submit">Transform & Push to Notion</button>
        </form>
    </body>
    </html>

from flask import Flask, request, render_template_string
import html
import requests
import os

app = Flask(__name__)

NOTION_TOKEN = os.getenv("NOTION_TOKEN", "secret_xyz123")
DATABASE_ID = os.getenv("NOTION_DATABASE_ID", "your_database_id")
NOTION_VERSION = "2022-06-28"

JS_SNIPPET = """
<script>
document.addEventListener("DOMContentLoaded", function () {
  const placeholders = document.querySelectorAll(".tweet-placeholder");
  const loadTweet = (el) => {
    const html = el.dataset.embed.replace(/'/g, "&#39;");
    el.innerHTML = html;
    if (!window.twttr) {
      let script = document.createElement("script");
      script.src = "https://platform.twitter.com/widgets.js";
      script.async = true;
      document.body.appendChild(script);
    } else {
      window.twttr.widgets.load(el);
    }
  };
  const observer = new IntersectionObserver((entries, obs) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        loadTweet(entry.target);
        obs.unobserve(entry.target);
      }
    });
  });
  placeholders.forEach(el => observer.observe(el));
});
</script>
"""

WIDTH = 500

def add_embed_to_notion(embed_html):
    url = "https://api.notion.com/v1/pages"
    headers = {
        "Authorization": f"Bearer {NOTION_TOKEN}",
        "Content-Type": "application/json",
        "Notion-Version": NOTION_VERSION,
    }
    data = {
        "parent": {"database_id": DATABASE_ID},
        "properties": {
            "Name": {
                "title": [
                    {
                        "text": {
                            "content": "Twitter Embed"
                        }
                    }
                ]
            },
            "EmbedCode": {
                "rich_text": [
                    {
                        "text": {
                            "content": embed_html
                        }
                    }
                ]
            }
        }
    }
    response = requests.post(url, headers=headers, json=data)
    response.raise_for_status()
    return response.json()

@app.route("/", methods=["GET", "POST"])
def index():
    transformed_embeds = []
    if request.method == "POST":
        raw_embeds = request.form.get("embeds", "")
        # Split embeds by double line break or add custom split logic as needed
        embed_list = [e.strip() for e in raw_embeds.split('\n\n') if e.strip()]
        
        for embed in embed_list:
            # Directly use the provided embed code (no parsing, since it's already valid HTML)
            # Escape single quotes for safe use in data-embed attribute
            escaped_html = html.escape(embed).replace("&#x27;", "&#39;")
            # Heuristic for reasonable height: 500->950px
            height = min(max(500, len(embed)), 950)

            transformed = f"""
<div style="width:{WIDTH}px; height:{height}px; overflow:hidden;"
     class="tweet-placeholder"
     data-embed='{escaped_html}'>
  <div style="color:#777; display:flex; align-items:center; justify-content:center; height:100%;">
    Loading Tweet…
  </div>
</div>
"""
            transformed_embeds.append(transformed)
            add_embed_to_notion(transformed)

        final_output = "\n".join(transformed_embeds) + JS_SNIPPET

        return render_template_string("""
            <html>
            <head><title>Transformed Embeds Output</title></head>
            <body style="background-color:#181818; color:#eee; font-family:sans-serif;">
                <h2>Transformed Embeds Output & Notion Upload Complete</h2>
                <p><a href="/">Back</a></p>
                <div>{{ output|safe }}</div>
            </body>
            </html>
        """, output=final_output)

    # GET = show textarea form
    return '''
    <html>
    <head><title>Embed Transformer</title></head>
    <body style="background-color:#181818; color:#eee; font-family:sans-serif;">
        <h1>Paste your Embed Codes</h1>
        <form method="post">
            <textarea name="embeds" rows="20" cols="80" placeholder="Paste embed codes here, separated by blank lines"></textarea><br><br>
            <button type="submit">Transform & Push to Notion</button>
        </form>
    </body>
    </html>

Final Version

Final Design that went live.

PC

PC