o
    i6                     @  s   d Z ddlmZ ddlZddlmZ dZdZdZdZ	d	Z
d
ZdZdZdZdZ			d:d;ddZd<d=ddZd>d?d#d$Z	%	%	%d@dAd)d*ZdBd-d.ZdCd1d2ZdDdEd8d9ZdS )Fz
Shared UI utilities for FastMCP HTML pages.

This module provides reusable HTML/CSS components for OAuth callbacks,
consent pages, and other user-facing interfaces.
    )annotationsNHTMLResponsez0https://gofastmcp.com/assets/brand/blue-logo.pnga  
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }

    body {
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
        margin: 0;
        padding: 0;
        min-height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        background: #f9fafb;
        color: #0a0a0a;
    }

    .container {
        background: #ffffff;
        border: 1px solid #e5e7eb;
        padding: 3rem 2.5rem;
        border-radius: 1rem;
        box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        text-align: center;
        max-width: 36rem;
        margin: 1rem;
        width: 100%;
    }

    @media (max-width: 640px) {
        .container {
            padding: 2rem 1.5rem;
            margin: 0.5rem;
        }
    }

    .logo {
        width: 64px;
        height: auto;
        margin-bottom: 1.5rem;
        display: block;
        margin-left: auto;
        margin-right: auto;
    }

    h1 {
        font-size: 1.5rem;
        font-weight: 600;
        margin-bottom: 1.5rem;
        color: #111827;
    }
a  
    .button-group {
        display: flex;
        gap: 0.75rem;
        margin-top: 1.5rem;
        justify-content: center;
    }

    button {
        padding: 0.75rem 2rem;
        font-size: 0.9375rem;
        font-weight: 500;
        border-radius: 0.5rem;
        border: none;
        cursor: pointer;
        transition: all 0.15s;
        font-family: inherit;
    }

    button:hover {
        transform: translateY(-1px);
        box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
    }

    .btn-approve, .btn-primary {
        background: #10b981;
        color: #ffffff;
        min-width: 120px;
    }

    .btn-deny, .btn-secondary {
        background: #6b7280;
        color: #ffffff;
        min-width: 120px;
    }
a  
    .info-box {
        background: #f0f9ff;
        border: 1px solid #bae6fd;
        border-radius: 0.5rem;
        padding: 1rem;
        margin-bottom: 1.5rem;
        text-align: left;
        font-size: 0.9375rem;
        line-height: 1.5;
        color: #374151;
    }

    .info-box p {
        margin-bottom: 0.5rem;
    }

    .info-box p:last-child {
        margin-bottom: 0;
    }

    .info-box.centered {
        text-align: center;
    }

    .info-box.error {
        background: #fef2f2;
        border-color: #fecaca;
        color: #991b1b;
    }

    .info-box strong {
        color: #0ea5e9;
        font-weight: 600;
    }

    .info-box .server-name-link {
        color: #0ea5e9;
        text-decoration: underline;
        font-weight: 600;
        cursor: pointer;
        transition: opacity 0.15s;
    }

    .info-box .server-name-link:hover {
        opacity: 0.8;
    }

    /* Monospace info box - gray styling with code font */
    .info-box-mono {
        background: #f9fafb;
        border: 1px solid #e5e7eb;
        border-radius: 0.5rem;
        padding: 0.875rem;
        margin: 1.25rem 0;
        font-size: 0.875rem;
        color: #6b7280;
        font-family: 'SF Mono', 'Monaco', 'Consolas', 'Courier New', monospace;
        text-align: left;
    }

    .info-box-mono.centered {
        text-align: center;
    }

    .info-box-mono.error {
        background: #fef2f2;
        border-color: #fecaca;
        color: #991b1b;
    }

    .info-box-mono strong {
        color: #111827;
        font-weight: 600;
    }

    .warning-box {
        background: #f0f9ff;
        border: 1px solid #bae6fd;
        border-radius: 0.5rem;
        padding: 1rem;
        margin-bottom: 1.5rem;
        text-align: center;
    }

    .warning-box p {
        margin-bottom: 0.5rem;
        line-height: 1.5;
        color: #6b7280;
        font-size: 0.9375rem;
    }

    .warning-box p:last-child {
        margin-bottom: 0;
    }

    .warning-box strong {
        color: #0ea5e9;
        font-weight: 600;
    }

    .warning-box a {
        color: #0ea5e9;
        text-decoration: underline;
        font-weight: 600;
    }

    .warning-box a:hover {
        color: #0284c7;
        text-decoration: underline;
    }
a  
    .status-message {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 0.75rem;
        margin-bottom: 1.5rem;
    }

    .status-icon {
        font-size: 1.5rem;
        line-height: 1;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 2rem;
        height: 2rem;
        border-radius: 0.5rem;
        flex-shrink: 0;
    }

    .status-icon.success {
        background: #10b98120;
    }

    .status-icon.error {
        background: #ef444420;
    }

    .message {
        font-size: 1.125rem;
        line-height: 1.75;
        color: #111827;
        font-weight: 600;
        text-align: left;
    }
a)  
    .detail-box {
        background: #f9fafb;
        border: 1px solid #e5e7eb;
        border-radius: 0.5rem;
        padding: 1rem;
        margin-bottom: 1.5rem;
        text-align: left;
    }

    .detail-row {
        display: flex;
        padding: 0.5rem 0;
        border-bottom: 1px solid #e5e7eb;
    }

    .detail-row:last-child {
        border-bottom: none;
    }

    .detail-label {
        font-weight: 600;
        min-width: 160px;
        color: #6b7280;
        font-size: 0.875rem;
        flex-shrink: 0;
        padding-right: 1rem;
    }

    .detail-value {
        flex: 1;
        font-family: 'SF Mono', 'Monaco', 'Consolas', 'Courier New', monospace;
        font-size: 0.75rem;
        color: #111827;
        word-break: break-all;
        overflow-wrap: break-word;
    }
aa  
    .redirect-section {
        background: #fffbeb;
        border: 1px solid #fcd34d;
        border-radius: 0.5rem;
        padding: 1rem;
        margin-bottom: 1.5rem;
        text-align: left;
    }

    .redirect-section .label {
        font-size: 0.875rem;
        color: #6b7280;
        font-weight: 600;
        margin-bottom: 0.5rem;
        display: block;
    }

    .redirect-section .value {
        font-family: 'SF Mono', 'Monaco', 'Consolas', 'Courier New', monospace;
        font-size: 0.875rem;
        color: #111827;
        word-break: break-all;
        margin-top: 0.25rem;
    }
u  
    details {
        margin-bottom: 1.5rem;
        text-align: left;
    }

    summary {
        cursor: pointer;
        font-size: 0.875rem;
        color: #6b7280;
        font-weight: 600;
        list-style: none;
        padding: 0.5rem;
        border-radius: 0.25rem;
    }

    summary:hover {
        background: #f9fafb;
    }

    summary::marker {
        display: none;
    }

    summary::before {
        content: "▶";
        display: inline-block;
        margin-right: 0.5rem;
        transition: transform 0.2s;
        font-size: 0.75rem;
    }

    details[open] summary::before {
        transform: rotate(90deg);
    }
z}
    .close-instruction, .help-text {
        font-size: 0.875rem;
        color: #6b7280;
        margin-top: 1.5rem;
    }
a.  
    .help-link-container {
        position: fixed;
        bottom: 1.5rem;
        right: 1.5rem;
        font-size: 0.875rem;
    }

    .help-link {
        color: #6b7280;
        text-decoration: none;
        cursor: help;
        position: relative;
        display: inline-block;
        border-bottom: 1px dotted #9ca3af;
    }

    @media (max-width: 640px) {
        .help-link {
            background: #ffffff;
            padding: 0.25rem 0.5rem;
            border-radius: 0.25rem;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
        }
    }

    .help-link:hover {
        color: #111827;
        border-bottom-color: #111827;
    }

    .help-link:hover .tooltip {
        opacity: 1;
        visibility: visible;
    }

    .tooltip {
        position: absolute;
        bottom: 100%;
        right: 0;
        left: auto;
        margin-bottom: 0.5rem;
        background: #1f2937;
        color: #ffffff;
        padding: 0.75rem 1rem;
        border-radius: 0.5rem;
        font-size: 0.8125rem;
        line-height: 1.5;
        width: 280px;
        max-width: calc(100vw - 3rem);
        opacity: 0;
        visibility: hidden;
        transition: opacity 0.2s, visibility 0.2s;
        box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
        text-align: left;
    }

    .tooltip::after {
        content: '';
        position: absolute;
        top: 100%;
        right: 1rem;
        border: 6px solid transparent;
        border-top-color: #1f2937;
    }

    .tooltip-link {
        color: #60a5fa;
        text-decoration: underline;
    }
FastMCP Tdefault-src 'none'; style-src 'unsafe-inline'; img-src https: data:; base-uri 'none'contentstrtitleadditional_styles
csp_policyreturnc                 C  s.   t |}d| dt d| d| d|  dS )a3  
    Create a complete HTML page with FastMCP styling.

    Args:
        content: HTML content to place inside the page
        title: Page title
        additional_styles: Extra CSS to include
        csp_policy: Content Security Policy header value

    Returns:
        Complete HTML page as string
    z
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>z%</title>
        <style>
            z
            zN
        </style>
        <meta http-equiv="Content-Security-Policy" content="z$" />
    </head>
    <body>
        z
    </body>
    </html>
    )htmlescapeBASE_STYLES)r   r
   r   r    r   Z/var/www/html/karishye-ai-python/venv/lib/python3.10/site-packages/fastmcp/utilities/ui.pycreate_page  s   
	r   icon_url
str | Nonealt_textc                 C  s*   | pt }t|}dt| d| dS )zCreate logo HTML.

    Args:
        icon_url: Optional custom icon URL. If not provided, uses the FastMCP logo.
        alt_text: Alt text for the logo image.

    Returns:
        HTML for logo image tag.
    z
<img src="z" alt="z" class="logo" />)FASTMCP_LOGO_URLr   r   )r   r   urlaltr   r   r   create_logo  s   

r   Tmessage
is_successboolc                 C  s:   t | } |r	dnd}|rdnd}d| d| d|  dS )	u   
    Create a status message with icon.

    Args:
        message: Status message text
        is_success: True for success (✓), False for error (✕)

    Returns:
        HTML for status message
    u   ✓u   ✕successerrorzK
        <div class="status-message">
            <span class="status-icon ">z)</span>
            <div class="message">z</div>
        </div>
    r   r   )r   r   icon
icon_classr   r   r   create_status_message  s   
r$   Fis_errorcentered	monospacec                 C  sT   t | } |r	dnd}|g}|r|d |r|d d|}d| d|  dS )	aG  
    Create an info box.

    Args:
        content: HTML content for the info box
        is_error: True for error styling, False for normal
        centered: True to center the text, False for left-aligned
        monospace: True to use gray monospace font styling instead of blue

    Returns:
        HTML for info box
    zinfo-box-monozinfo-boxr   r&    z<div class="r    </div>)r   r   appendjoin)r   r%   r&   r'   
base_classclasses	class_strr   r   r   create_info_box  s   



r/   rowslist[tuple[str, str]]c                 C      d dd | D }d| dS )z
    Create a detail box with key-value pairs.

    Args:
        rows: List of (label, value) tuples

    Returns:
        HTML for detail box
    
c                 s  s2    | ]\}}d t | dt | dV  qdS )zH
        <div class="detail-row">
            <div class="detail-label">z.:</div>
            <div class="detail-value">z</div>
        </div>
        Nr!   ).0labelvaluer   r   r   	<genexpr>9  s    
z$create_detail_box.<locals>.<genexpr>z<div class="detail-box">r)   r+   )r0   	rows_htmlr   r   r   create_detail_box/  s   


r:   buttonslist[tuple[str, str, str]]c                 C  r2   )z
    Create a group of buttons.

    Args:
        buttons: List of (text, value, css_class) tuples

    Returns:
        HTML for button group
    r3   c                 s  s.    | ]\}}}d | d| d| dV  qdS )z+<button type="submit" name="action" value="z	" class="r    z	</button>Nr   )r4   textr6   	css_classr   r   r   r7   P  s
    
z&create_button_group.<locals>.<genexpr>z<div class="button-group">r)   r8   )r;   buttons_htmlr   r   r   create_button_groupF  s   

r@      r   status_codeintr   c                 C  s   t | |ddidS )a'  
    Create an HTMLResponse with security headers.

    Adds X-Frame-Options: DENY to prevent clickjacking attacks per MCP security best practices.

    Args:
        html: HTML content to return
        status_code: HTTP status code

    Returns:
        HTMLResponse with security headers
    zX-Frame-OptionsDENY)r   rB   headersr   )r   rB   r   r   r   create_secure_html_responseX  s
   rF   )r   r   r   )
r   r	   r
   r	   r   r	   r   r	   r   r	   )Nr   )r   r   r   r	   r   r	   )T)r   r	   r   r   r   r	   )FFF)
r   r	   r%   r   r&   r   r'   r   r   r	   )r0   r1   r   r	   )r;   r<   r   r	   )rA   )r   r	   rB   rC   r   r   )__doc__
__future__r   r   starlette.responsesr   r   r   BUTTON_STYLESINFO_BOX_STYLESSTATUS_MESSAGE_STYLESDETAIL_BOX_STYLESREDIRECT_SECTION_STYLESDETAILS_STYLESHELPER_TEXT_STYLESTOOLTIP_STYLESr   r   r$   r/   r:   r@   rF   r   r   r   r   <module>   s6    8&r'(&	K'

