Team Ai
Apppublic

katira/function-gemma

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
colored_dropdown.py291 linesDownload Raw Back to components
1import gradio as gr2 3 4class ColoredDropdown(gr.HTML):5    def __init__(6        self,7        choices: list[str] | None = None,8        *,9        placeholder: str = "Select...",10        value: str | None = None,11        colors: list[str] | None = None,12        label: str | None = None,13        **kwargs,14    ):15        html_template = """16        <div class="colored-dropdown-container">17            ${label ? `<span class="dropdown-label">${label}</span>` : ''}18            <div class="dropdown-wrapper">19                <button type="button" class="dropdown-trigger">20                    <span class="selected-display">21                        ${value ? `<span class="color-dot" style="background: ${colors[choices.indexOf(value)]};"></span>${value}` : `<span class="placeholder">${placeholder}</span>`}22                    </span>23                    <svg class="dropdown-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">24                        <polyline points="6 9 12 15 18 9"></polyline>25                    </svg>26                </button>27                <div class="dropdown-menu">28                    ${choices.map((choice, i) => `29                        <div class="dropdown-item ${value === choice ? 'selected' : ''}" data-value="${choice}" data-color="${colors[i]}">30                            <span class="color-dot" style="background: ${colors[i]};"></span>31                            <span class="item-text">${choice}</span>32                        </div>33                    `).join('')}34                </div>35            </div>36        </div>37        """38 39        css_template = """40        .colored-dropdown-container {41            display: flex;42            flex-direction: column;43            gap: var(--spacing-sm);44            overflow: visible;45        }46        .dropdown-label {47            color: var(--block-title-text-color);48            font-size: var(--text-sm);49            font-weight: 500;50        }51        .dropdown-wrapper {52            position: relative;53            z-index: 1;54        }55        .dropdown-trigger {56            width: 100%;57            display: flex;58            align-items: center;59            justify-content: space-between;60            padding: 8px 12px;61            border: 1px solid var(--border-color-primary);62            border-radius: var(--radius-md);63            background: var(--input-background-fill);64            color: var(--body-text-color);65            cursor: pointer;66            font-size: var(--text-md);67            text-align: left;68            transition: border-color 0.15s ease;69        }70        .dropdown-trigger:hover {71            border-color: var(--border-color-accent);72        }73        .dropdown-trigger:focus {74            outline: none;75            border-color: var(--color-accent);76            box-shadow: 0 0 0 2px var(--color-accent-soft);77        }78        .selected-display {79            display: flex;80            align-items: center;81            gap: 8px;82            flex: 1;83            overflow: hidden;84            text-overflow: ellipsis;85            white-space: nowrap;86        }87        .placeholder {88            color: var(--input-placeholder-color);89        }90        .dropdown-arrow {91            width: 16px;92            height: 16px;93            flex-shrink: 0;94            transition: transform 0.2s ease;95        }96        .dropdown-wrapper.open .dropdown-arrow {97            transform: rotate(180deg);98        }99        .dropdown-menu {100            position: fixed;101            max-height: 240px;102            overflow-y: auto;103            background: var(--background-fill-primary);104            border: 1px solid var(--border-color-primary);105            border-radius: var(--radius-md);106            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);107            z-index: 9999;108            display: none;109        }110        .dropdown-wrapper.open .dropdown-menu {111            display: block;112        }113        .dropdown-item {114            display: flex;115            align-items: center;116            gap: 8px;117            padding: 8px 12px;118            cursor: pointer;119            transition: background 0.1s ease;120        }121        .dropdown-item:hover {122            background: var(--background-fill-secondary);123        }124        .dropdown-item.selected {125            background: var(--color-accent-soft);126        }127        .item-text {128            overflow: hidden;129            text-overflow: ellipsis;130            white-space: nowrap;131        }132        .color-dot {133            width: 10px;134            height: 10px;135            border-radius: 50%;136            flex-shrink: 0;137        }138        """139 140        js_on_load = """141        const wrapper = element.querySelector('.dropdown-wrapper');142        const triggerButton = element.querySelector('.dropdown-trigger');143        const menu = element.querySelector('.dropdown-menu');144        const selectedDisplay = element.querySelector('.selected-display');145        146        function positionMenu() {147            const rect = triggerButton.getBoundingClientRect();148            menu.style.position = 'fixed';149            menu.style.top = (rect.bottom + 4) + 'px';150            menu.style.left = rect.left + 'px';151            menu.style.width = rect.width + 'px';152            menu.style.right = 'auto';153        }154        155        triggerButton.addEventListener('click', (e) => {156            e.stopPropagation();157            wrapper.classList.toggle('open');158            if (wrapper.classList.contains('open')) {159                positionMenu();160            }161        });162        163        menu.addEventListener('click', (e) => {164            const item = e.target.closest('.dropdown-item');165            if (!item) return;166            167            const value = item.dataset.value;168            const color = item.dataset.color;169            170            menu.querySelectorAll('.dropdown-item').forEach(el => el.classList.remove('selected'));171            item.classList.add('selected');172            173            selectedDisplay.innerHTML = `<span class="color-dot" style="background: ${color};"></span>${value}`;174            175            props.value = value;176            trigger('input');177            178            wrapper.classList.remove('open');179        });180        181        document.addEventListener('click', (e) => {182            if (!element.contains(e.target)) {183                wrapper.classList.remove('open');184            }185        });186        187        window.addEventListener('resize', () => {188            if (wrapper.classList.contains('open')) {189                positionMenu();190            }191        });192        193        window.addEventListener('scroll', () => {194            if (wrapper.classList.contains('open')) {195                positionMenu();196            }197        }, true);198        199        triggerButton.addEventListener('keydown', (e) => {200            if (e.key === 'Enter' || e.key === ' ') {201                e.preventDefault();202                wrapper.classList.toggle('open');203                if (wrapper.classList.contains('open')) {204                    positionMenu();205                }206            } else if (e.key === 'Escape') {207                wrapper.classList.remove('open');208            }209        });210        """211 212        super().__init__(213            value=value,214            html_template=html_template,215            css_template=css_template,216            js_on_load=js_on_load,217            choices=choices,218            colors=colors,219            label=label,220            placeholder=placeholder,221            **kwargs,222        )223 224    def api_info(self):225        return {226            "enum": self.props["choices"],227            "title": "Dropdown",228            "type": "string",229        }230 231 232if __name__ == "__main__":233 234    def generate_color_variants(color: str, count: int):235        if color.startswith("rgb"):236            rgb_values = (237                color.replace("rgba", "").replace("rgb", "").strip("()").split(",")238            )239            r, g, b = (240                int(float(rgb_values[0])),241                int(float(rgb_values[1])),242                int(float(rgb_values[2])),243            )244        else:245            r = int(color[1:3], 16)246            g = int(color[3:5], 16)247            b = int(color[5:7], 16)248 249        colors = []250        for i in range(count):251            factor = 0.3 + (0.7 * i / max(count - 1, 1))252            nr = int(r * factor + (255 - r * factor) * (1 - factor) * 0.3)253            ng = int(g * factor + (255 - g * factor) * (1 - factor) * 0.3)254            nb = int(b * factor + (255 - b * factor) * (1 - factor) * 0.3)255            nr, ng, nb = min(255, nr), min(255, ng), min(255, nb)256            colors.append(f"#{nr:02x}{ng:02x}{nb:02x}")257        return colors258 259    def update_dropdown(color: str, s: int):260        items = [f"Item {i + 1} ({s + 1})" for i in range(12)]261        colors = generate_color_variants(color, len(items))262        return ColoredDropdown(263            choices=items,264            colors=colors,265            label=f"Select Item ({s + 1})",266        ), s + 1267 268    with gr.Blocks() as demo:269        s = gr.State(0)270        with gr.Row():271            with gr.Column():272                cp = gr.ColorPicker(value="#FF0000", label="Base Color")273            with gr.Column(scale=2):274                items = [f"Item {i + 1}" for i in range(15)]275                colors = generate_color_variants("#FF0000", len(items))276                dropdown = ColoredDropdown(277                    choices=items,278                    colors=colors,279                    label="Select Item",280                    value=items[0],281                )282                output = gr.Textbox(label="Selected Value")283                dropdown.input(lambda x: x, inputs=dropdown, outputs=output)284        cp.change(285            update_dropdown,286            inputs=[cp, s],287            outputs=[dropdown, s],288            show_progress="hidden",289        )290    demo.launch()291