Spaces:
Paused
Paused
| <html> | |
| <head> | |
| <title>Plugin Details</title> | |
| <script type="module"> | |
| import { store } from "/plugins/_plugin_installer/webui/pluginInstallStore.js"; | |
| </script> | |
| </head> | |
| <body> | |
| <div x-data> | |
| <template x-if="$store.pluginInstallStore?.selectedPlugin"> | |
| <div class="pi-detail-container"> | |
| <div class="pi-hero"> | |
| <div class="pi-hero-thumb"> | |
| <template x-if="$store.pluginInstallStore.getDetailThumbnailUrl()"> | |
| <img :src="$store.pluginInstallStore.getDetailThumbnailUrl()" | |
| :alt="$store.pluginInstallStore.selectedPlugin.title" | |
| @error="$store.pluginInstallStore.detailThumbnailUrl = null"> | |
| </template> | |
| <template x-if="!$store.pluginInstallStore.getDetailThumbnailUrl()"> | |
| <span class="material-symbols-outlined pi-hero-placeholder">extension</span> | |
| </template> | |
| </div> | |
| <div class="pi-hero-info"> | |
| <div class="pi-hero-title-row"> | |
| <div class="pi-hero-main"> | |
| <h2 class="pi-hero-title" x-text="$store.pluginInstallStore.selectedPlugin.title || $store.pluginInstallStore.selectedPlugin.key"></h2> | |
| <div class="pi-status-badges"> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.suspended"> | |
| <span class="pi-card-suspended-pill"> | |
| <span class="material-symbols-outlined">priority_high</span> | |
| <span>Suspended</span> | |
| </span> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.installed"> | |
| <span class="pi-card-installed-pill">Installed</span> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.has_update"> | |
| <span class="pi-card-update-pill">New version</span> | |
| </template> | |
| </div> | |
| <div class="pi-hero-meta"> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.author"> | |
| <span class="pi-hero-author"> | |
| <span class="pi-hero-label">Author</span> | |
| <span x-text="$store.pluginInstallStore.selectedPlugin.author"></span> | |
| </span> | |
| </template> | |
| <span class="pi-hero-stars"> | |
| <span class="material-symbols-outlined">star</span> | |
| <span x-text="($store.pluginInstallStore.selectedPlugin.stars || 0)"></span> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.github"> | |
| <a :href="$store.pluginInstallStore.selectedPlugin.github" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| class="pi-dev-link"> | |
| Give a star | |
| </a> | |
| </template> | |
| </span> | |
| </div> | |
| <div class="pi-hero-tags" x-show="$store.pluginInstallStore.selectedPlugin.tags?.length"> | |
| <template x-for="tag in $store.pluginInstallStore.selectedPlugin.tags || []" :key="tag"> | |
| <span class="pi-tag" x-text="tag"></span> | |
| </template> | |
| </div> | |
| </div> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.installed && $store.pluginInstallStore.installedPluginInfo"> | |
| <div class="pi-hero-manage"> | |
| <template x-if="$store.pluginInstallStore.installedPluginInfo.has_main_screen"> | |
| <button type="button" class="button" | |
| @click="$store.pluginInstallStore.handleOpenPlugin()"> | |
| <span class="icon material-symbols-outlined">dashboard</span> Open | |
| </button> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.installedPluginInfo.has_config_screen"> | |
| <button type="button" class="button" | |
| @click="$store.pluginInstallStore.handleOpenConfig()"> | |
| <span class="icon material-symbols-outlined">settings</span> Config | |
| </button> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.installedPluginInfo.has_readme"> | |
| <button type="button" class="button" | |
| @click="$store.pluginInstallStore.handleOpenDoc('readme')"> | |
| <span class="icon material-symbols-outlined">description</span> README | |
| </button> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.installedPluginInfo.has_license"> | |
| <button type="button" class="button" | |
| @click="$store.pluginInstallStore.handleOpenDoc('license')"> | |
| <span class="icon material-symbols-outlined">gavel</span> License | |
| </button> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.installedPluginInfo.has_execute_script"> | |
| <button type="button" class="button" | |
| @click="$store.pluginInstallStore.handleOpenExecute()"> | |
| <span class="icon material-symbols-outlined">terminal</span> Script | |
| </button> | |
| </template> | |
| <button type="button" class="button" | |
| @click="$store.pluginInstallStore.handleOpenInfo()"> | |
| <span class="icon material-symbols-outlined">info</span> Info | |
| </button> | |
| </div> | |
| </template> | |
| </div> | |
| </div> | |
| </div> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.suspended"> | |
| <div class="pi-suspension-banner"> | |
| <span class="material-symbols-outlined">priority_high</span> | |
| <div class="pi-suspension-banner-copy"> | |
| <div class="pi-suspension-banner-title">Plugin has been suspended for the following reasons:</div> | |
| <div class="pi-suspension-banner-explanation" | |
| x-text="$store.pluginInstallStore.selectedPlugin.suspended"></div> | |
| </div> | |
| </div> | |
| </template> | |
| <div class="pi-description" x-text="$store.pluginInstallStore.selectedPlugin.description || 'No description available.'"></div> | |
| <div class="pi-screenshots-section" | |
| x-show="$store.pluginInstallStore.selectedPlugin.screenshots?.length"> | |
| <div class="pi-screenshots-header">Screenshots</div> | |
| <div class="pi-screenshots-grid"> | |
| <template x-for="(url, i) in ($store.pluginInstallStore.selectedPlugin.screenshots || [])" :key="i"> | |
| <img class="pi-screenshot-thumb" | |
| :src="url" | |
| :alt="$store.pluginInstallStore.selectedPlugin.title + ' screenshot ' + (i + 1)" | |
| @click="$store.pluginInstallStore.openScreenshot(url)"> | |
| </template> | |
| </div> | |
| </div> | |
| <div class="pi-actions-primary"> | |
| <template x-if="!$store.pluginInstallStore.selectedPlugin.installed"> | |
| <button class="pi-btn-install" | |
| @click="$store.pluginInstallStore.installFromIndex($store.pluginInstallStore.selectedPlugin)" | |
| :disabled="$store.pluginInstallStore.loading"> | |
| <template x-if="$store.pluginInstallStore.loading"> | |
| <span class="pi-btn-loading"> | |
| <span class="spinner"></span> | |
| <span x-text="$store.pluginInstallStore.loadingMessage || 'Installing...'"></span> | |
| </span> | |
| </template> | |
| <template x-if="!$store.pluginInstallStore.loading"> | |
| <span class="material-symbols-outlined">download</span> | |
| </template> | |
| <template x-if="!$store.pluginInstallStore.loading"> | |
| <span>Install</span> | |
| </template> | |
| </button> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.installed && $store.pluginInstallStore.installedPluginInfo?.is_custom && $store.pluginInstallStore.selectedPlugin.has_update"> | |
| <button type="button" class="pi-btn-install" | |
| @click="$store.pluginInstallStore.handleUpdatePlugin()" | |
| :disabled="$store.pluginInstallStore.loading"> | |
| <template x-if="$store.pluginInstallStore.loading"> | |
| <span class="pi-btn-loading"> | |
| <span class="spinner"></span> | |
| <span x-text="$store.pluginInstallStore.loadingMessage || 'Installing...'"></span> | |
| </span> | |
| </template> | |
| <template x-if="!$store.pluginInstallStore.loading"> | |
| <span class="material-symbols-outlined">system_update</span> | |
| </template> | |
| <template x-if="!$store.pluginInstallStore.loading"> | |
| <span>Update</span> | |
| </template> | |
| </button> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.installed && $store.pluginInstallStore.installedPluginInfo?.is_custom"> | |
| <button type="button" class="pi-btn-uninstall" | |
| @click="$confirmClick($event, () => $store.pluginInstallStore.handleDeletePlugin())" | |
| :disabled="$store.pluginInstallStore.loading"> | |
| <span class="pi-btn-loading" x-show="$store.pluginInstallStore.loading"> | |
| <span class="spinner"></span> | |
| <span x-text="$store.pluginInstallStore.loadingMessage || 'Uninstalling...'"></span> | |
| </span> | |
| <span x-show="!$store.pluginInstallStore.loading"> | |
| <span class="material-symbols-outlined">delete</span> | |
| </span> | |
| <span x-show="!$store.pluginInstallStore.loading"> | |
| <span>Uninstall</span> | |
| </span> | |
| </button> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.discussion"> | |
| <a :href="$store.pluginInstallStore.selectedPlugin.discussion" target="_blank" class="pi-btn-discussion"> | |
| <span class="material-symbols-outlined">forum</span> | |
| <span>Discussion</span> | |
| </a> | |
| </template> | |
| </div> | |
| <div class="pi-readme-section" x-show="$store.pluginInstallStore.readmeContent || $store.pluginInstallStore.readmeLoading"> | |
| <div class="pi-readme-header">Readme</div> | |
| <div x-show="$store.pluginInstallStore.readmeLoading" class="pi-loading-text"> | |
| Loading readme... | |
| </div> | |
| <div x-show="$store.pluginInstallStore.readmeContent && !$store.pluginInstallStore.readmeLoading" | |
| class="pi-readme-content" x-html="$store.pluginInstallStore.readmeContent"></div> | |
| </div> | |
| <div class="pi-version-section" | |
| x-show="$store.pluginInstallStore.getCurrentInstalledVersion() || $store.pluginInstallStore.getCurrentInstalledCommit() || $store.pluginInstallStore.getLatestPluginHubVersion() || $store.pluginInstallStore.getLatestPluginHubCommit()"> | |
| <div class="pi-version-header">Version</div> | |
| <div class="pi-version-grid"> | |
| <div class="pi-version-card" | |
| x-show="$store.pluginInstallStore.selectedPlugin.installed && ($store.pluginInstallStore.getCurrentInstalledVersion() || $store.pluginInstallStore.getCurrentInstalledCommit())"> | |
| <div class="pi-version-label">Current</div> | |
| <div class="pi-version-name" | |
| x-text="$store.pluginInstallStore.getCurrentInstalledVersion() || 'Unknown version'"></div> | |
| <template x-if="$store.pluginInstallStore.getCurrentInstalledCommit() && $store.pluginInstallStore.getRepoCommitUrl($store.pluginInstallStore.selectedPlugin, $store.pluginInstallStore.getCurrentInstalledCommit())"> | |
| <a class="pi-version-commit" | |
| :href="$store.pluginInstallStore.getRepoCommitUrl($store.pluginInstallStore.selectedPlugin, $store.pluginInstallStore.getCurrentInstalledCommit())" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| x-text="$store.pluginInstallStore.getCommitShortHash($store.pluginInstallStore.getCurrentInstalledCommit())"></a> | |
| </template> | |
| <template x-if="!($store.pluginInstallStore.getCurrentInstalledCommit() && $store.pluginInstallStore.getRepoCommitUrl($store.pluginInstallStore.selectedPlugin, $store.pluginInstallStore.getCurrentInstalledCommit()))"> | |
| <div class="pi-version-commit" | |
| x-text="$store.pluginInstallStore.getCommitShortHash($store.pluginInstallStore.getCurrentInstalledCommit()) || 'Unknown'"></div> | |
| </template> | |
| <div class="pi-version-time" | |
| x-text="$store.pluginInstallStore.formatUserLocaleDateTime($store.pluginInstallStore.getCurrentInstalledCommitTimestamp()) || 'Timestamp unavailable'"></div> | |
| </div> | |
| <div class="pi-version-card" | |
| x-show="$store.pluginInstallStore.getLatestPluginHubVersion() || $store.pluginInstallStore.getLatestPluginHubCommit()"> | |
| <div class="pi-version-label">Latest</div> | |
| <div class="pi-version-name" | |
| x-text="$store.pluginInstallStore.getLatestPluginHubVersion() || 'Unknown version'"></div> | |
| <template x-if="$store.pluginInstallStore.getLatestPluginHubCommit() && $store.pluginInstallStore.getRepoCommitUrl($store.pluginInstallStore.selectedPlugin, $store.pluginInstallStore.getLatestPluginHubCommit())"> | |
| <a class="pi-version-commit" | |
| :href="$store.pluginInstallStore.getRepoCommitUrl($store.pluginInstallStore.selectedPlugin, $store.pluginInstallStore.getLatestPluginHubCommit())" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| x-text="$store.pluginInstallStore.getCommitShortHash($store.pluginInstallStore.getLatestPluginHubCommit())"></a> | |
| </template> | |
| <template x-if="!($store.pluginInstallStore.getLatestPluginHubCommit() && $store.pluginInstallStore.getRepoCommitUrl($store.pluginInstallStore.selectedPlugin, $store.pluginInstallStore.getLatestPluginHubCommit()))"> | |
| <div class="pi-version-commit" | |
| x-text="$store.pluginInstallStore.getCommitShortHash($store.pluginInstallStore.getLatestPluginHubCommit()) || 'Unknown'"></div> | |
| </template> | |
| <div class="pi-version-time" | |
| x-text="$store.pluginInstallStore.formatUserLocaleDateTime($store.pluginInstallStore.getLatestPluginHubCommitTimestamp()) || 'Timestamp unavailable'"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="pi-developer-section"> | |
| <div class="pi-developer-header">Plugin Code</div> | |
| <div class="pi-developer-links"> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.github"> | |
| <a :href="$store.pluginInstallStore.selectedPlugin.github" target="_blank" class="pi-dev-link"> | |
| <span class="material-symbols-outlined">code</span> | |
| <span>GitHub Repository</span> | |
| </a> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.selectedPlugin.key"> | |
| <a :href="$store.pluginInstallStore.getIndexUrl($store.pluginInstallStore.selectedPlugin.key)" target="_blank" class="pi-dev-link"> | |
| <span class="material-symbols-outlined">inventory_2</span> | |
| <span>Plugin Index</span> | |
| </a> | |
| </template> | |
| <template x-if="$store.pluginInstallStore.getReportUrl($store.pluginInstallStore.selectedPlugin)"> | |
| <a :href="$store.pluginInstallStore.getReportUrl($store.pluginInstallStore.selectedPlugin)" target="_blank" class="pi-dev-link pi-report-link"> | |
| <span class="material-symbols-outlined">report</span> | |
| <span>Report malicious plugin</span> | |
| </a> | |
| </template> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| <template x-if="$store.pluginInstallStore?.selectedPlugin"> | |
| <div class="modal-footer pi-footer" data-modal-footer> | |
| <div class="buttons-container"> | |
| <div class="buttons-left"></div> | |
| <div class="buttons-right"> | |
| <button class="btn btn-cancel" @click="window.closeModal?.()">Close</button> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| </div> | |
| <style> | |
| .pi-detail-container { | |
| padding: 1rem; | |
| margin: 0 auto; | |
| } | |
| .pi-hero { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 1.5rem; | |
| margin-bottom: 1.25rem; | |
| } | |
| .pi-hero-thumb { | |
| width: 120px; | |
| height: 120px; | |
| border-radius: 12px; | |
| overflow: hidden; | |
| flex-shrink: 0; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: radial-gradient(circle at top, #6b728089, var(--color-panel)), | |
| var(--color-panel); | |
| border: 1px solid var(--color-border); | |
| } | |
| .pi-hero-thumb img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: contain; | |
| padding: 0.5rem; | |
| } | |
| .pi-hero-placeholder { | |
| font-size: 5rem; | |
| color: var(--color-text-muted); | |
| } | |
| .pi-hero-info { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .pi-hero-title-row { | |
| display: grid; | |
| grid-template-columns: minmax(0, 1fr) clamp(15rem, 42%, 28rem); | |
| align-items: flex-start; | |
| column-gap: 1rem; | |
| row-gap: 0.5rem; | |
| margin-bottom: 0.5rem; | |
| } | |
| .pi-hero-main { | |
| min-width: 0; | |
| width: 100%; | |
| row-gap: var(--spacing-xxs); | |
| } | |
| .pi-status-badges { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.85rem; | |
| margin: var(--spacing-xs) 0; | |
| } | |
| .pi-hero-title { | |
| margin: 0; | |
| font-size: 1.75rem; | |
| font-weight: 600; | |
| line-height: 1.2; | |
| color: var(--color-text-primary); | |
| min-width: 0; | |
| } | |
| .pi-hero-manage { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| flex-wrap: wrap; | |
| justify-content: flex-end; | |
| align-content: flex-start; | |
| width: 100%; | |
| } | |
| .pi-hero-manage .button { | |
| padding: 0.3rem 0.6rem; | |
| font-size: 0.9rem; | |
| } | |
| .pi-hero-manage .button .icon { | |
| font-size: 1.1rem; | |
| } | |
| .pi-hero-meta { | |
| display: flex; | |
| align-items: center; | |
| gap: 1rem; | |
| flex-wrap: wrap; | |
| margin-bottom: 0.5rem; | |
| } | |
| .pi-hero-label { | |
| font-size: 0.8rem; | |
| color: var(--color-text-muted); | |
| margin-right: 0.2rem; | |
| } | |
| .pi-hero-author { | |
| font-size: 1rem; | |
| color: var(--color-text-secondary); | |
| font-weight: 500; | |
| display: inline-flex; | |
| align-items: baseline; | |
| gap: 0.15rem; | |
| } | |
| .pi-hero-stars { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.3rem; | |
| font-size: 0.95rem; | |
| color: var(--color-text-secondary); | |
| flex-wrap: wrap; | |
| } | |
| .pi-hero-stars .material-symbols-outlined { | |
| font-size: 1.1rem; | |
| color: #fbbf24; | |
| } | |
| .pi-hero-tags { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.4rem; | |
| } | |
| .pi-card-installed-pill { | |
| display: inline-flex; | |
| padding: 0.24rem 0.5rem; | |
| border-radius: 0.5rem; | |
| background: rgba(34, 197, 94, 0.15); | |
| color: #4ade80; | |
| font-size: 0.72rem; | |
| font-weight: 700; | |
| } | |
| body.light-mode .pi-card-installed-pill { | |
| background: rgba(34, 197, 94, 0.22); | |
| color: #166534; | |
| } | |
| .pi-card-update-pill { | |
| display: inline-flex; | |
| padding: 0.24rem 0.5rem; | |
| border-radius: 0.5rem; | |
| background: rgba(59, 130, 246, 0.16); | |
| color: #60a5fa; | |
| font-size: 0.72rem; | |
| font-weight: 700; | |
| } | |
| body.light-mode .pi-card-update-pill { | |
| background: rgba(59, 130, 246, 0.2); | |
| color: #1d4ed8; | |
| } | |
| .pi-card-suspended-pill { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.3rem; | |
| padding: 0.24rem 0.5rem; | |
| border-radius: 0.5rem; | |
| background: rgba(245, 158, 11, 0.16); | |
| color: #f59e0b; | |
| font-size: 0.72rem; | |
| font-weight: 700; | |
| } | |
| .pi-card-suspended-pill .material-symbols-outlined { | |
| font-size: 0.95rem; | |
| } | |
| body.light-mode .pi-card-suspended-pill { | |
| background: rgba(245, 158, 11, 0.2); | |
| color: #b45309; | |
| } | |
| .pi-status-badges .pi-card-installed-pill { | |
| position: static; | |
| top: auto; | |
| right: auto; | |
| } | |
| .pi-status-badges .pi-card-update-pill { | |
| position: static; | |
| top: auto; | |
| right: auto; | |
| } | |
| .pi-status-badges .pi-card-suspended-pill { | |
| position: static; | |
| top: auto; | |
| right: auto; | |
| } | |
| .pi-tag { | |
| display: inline-flex; | |
| align-items: center; | |
| font-size: 0.8rem; | |
| padding: 0.25rem 0.6rem; | |
| border-radius: 4px; | |
| background: var(--color-panel); | |
| color: var(--color-text-secondary); | |
| border: 1px solid var(--color-border); | |
| font-weight: 500; | |
| } | |
| .pi-description { | |
| font-size: 1rem; | |
| line-height: 1.6; | |
| color: var(--color-text-primary); | |
| margin-bottom: 1.5rem; | |
| } | |
| .pi-suspension-banner { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 0.75rem; | |
| margin-bottom: 1rem; | |
| padding: 0.9rem 1rem; | |
| border: 1px solid rgba(245, 158, 11, 0.32); | |
| border-radius: 10px; | |
| background: rgba(245, 158, 11, 0.12); | |
| color: #f59e0b; | |
| } | |
| .pi-suspension-banner .material-symbols-outlined { | |
| font-size: 1.2rem; | |
| line-height: 1.2; | |
| flex-shrink: 0; | |
| } | |
| .pi-suspension-banner-copy { | |
| min-width: 0; | |
| } | |
| .pi-suspension-banner-title { | |
| font-size: 0.92rem; | |
| font-weight: 700; | |
| line-height: 1.45; | |
| } | |
| .pi-suspension-banner-explanation { | |
| margin-top: 0.2rem; | |
| font-size: 0.92rem; | |
| line-height: 1.55; | |
| white-space: pre-line; | |
| } | |
| body.light-mode .pi-suspension-banner { | |
| border-color: rgba(217, 119, 6, 0.28); | |
| background: rgba(245, 158, 11, 0.14); | |
| color: #b45309; | |
| } | |
| .pi-actions-primary { | |
| display: flex; | |
| gap: 0.75rem; | |
| margin-bottom: 1.5rem; | |
| flex-wrap: wrap; | |
| } | |
| .pi-btn-install { | |
| flex: 1; | |
| min-width: 200px; | |
| padding: 0.85rem 1.5rem; | |
| border: none; | |
| border-radius: 8px; | |
| background: var(--color-highlight); | |
| color: #fff; | |
| font-family: 'Rubik'; | |
| font-size: 1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 0.5rem; | |
| } | |
| .pi-btn-install:hover:not(:disabled) { | |
| opacity: 0.9; | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.15); | |
| } | |
| .pi-btn-install:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| } | |
| .pi-btn-install .material-symbols-outlined { | |
| font-size: 1.3rem; | |
| } | |
| .pi-btn-uninstall { | |
| flex: 1; | |
| min-width: 200px; | |
| padding: 0.85rem 1.5rem; | |
| border: 2px solid var(--color-accent); | |
| border-radius: 8px; | |
| background: transparent; | |
| color: var(--color-accent); | |
| font-family: 'Rubik'; | |
| font-size: 1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 0.5rem; | |
| } | |
| .pi-btn-uninstall:hover { | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.15); | |
| background: var(--color-accent); | |
| color: #fff; | |
| } | |
| .pi-btn-uninstall:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| } | |
| .pi-btn-uninstall .material-symbols-outlined { | |
| font-size: 1.3rem; | |
| } | |
| .pi-btn-discussion { | |
| flex: 1; | |
| min-width: 200px; | |
| padding: 0.85rem 1.5rem; | |
| border: 2px solid var(--color-primary); | |
| border-radius: 8px; | |
| background: transparent; | |
| color: var(--color-text); | |
| font-size: 1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 0.5rem; | |
| text-decoration: none; | |
| } | |
| .pi-btn-discussion:hover { | |
| background: var(--color-highlight); | |
| color: #fff; | |
| border: 2px solid var(--color-highlight); | |
| box-shadow: 0 4px 12px rgba(0,0,0,0.15); | |
| } | |
| .pi-btn-discussion .material-symbols-outlined { | |
| font-size: 1.3rem; | |
| } | |
| .pi-btn-loading { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.6rem; | |
| } | |
| .pi-loading-text { | |
| font-size: 0.9rem; | |
| color: var(--color-text-secondary); | |
| padding: 0.75rem 0; | |
| } | |
| .pi-screenshots-section { | |
| margin: var(--spacing-lg) 0; | |
| padding-top: var(--spacing-lg); | |
| border-top: 1px solid var(--color-border); | |
| } | |
| .pi-version-section { | |
| margin-bottom: 1.5rem; | |
| padding-top: 1.5rem; | |
| border-top: 1px solid var(--color-border); | |
| } | |
| .pi-version-header { | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| color: var(--color-text-muted); | |
| margin-bottom: 0.75rem; | |
| } | |
| .pi-version-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); | |
| gap: 0.75rem; | |
| } | |
| .pi-version-card { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.3rem; | |
| padding: 0.9rem 1rem; | |
| border: 1px solid var(--color-border); | |
| border-radius: 10px; | |
| } | |
| .pi-version-label { | |
| font-size: 0.78rem; | |
| font-weight: 700; | |
| letter-spacing: 0.04em; | |
| text-transform: uppercase; | |
| color: var(--color-text-muted); | |
| } | |
| .pi-version-name { | |
| font-size: 1rem; | |
| font-weight: 700; | |
| color: var(--color-text-primary); | |
| line-height: 1.35; | |
| } | |
| .pi-version-commit { | |
| font-size: 0.92rem; | |
| font-weight: 600; | |
| color: var(--color-text-secondary); | |
| text-decoration: none; | |
| } | |
| a.pi-version-commit:hover { | |
| color: var(--color-highlight); | |
| } | |
| .pi-version-time { | |
| font-size: 0.85rem; | |
| color: var(--color-text-secondary); | |
| line-height: 1.4; | |
| } | |
| .pi-screenshots-header { | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| color: var(--color-text-muted); | |
| margin-bottom: 0.75rem; | |
| } | |
| .pi-screenshots-grid { | |
| display: flex; | |
| gap: 0.75rem; | |
| flex-wrap: wrap; | |
| } | |
| .pi-screenshot-thumb { | |
| height: 120px; | |
| flex: 1; | |
| min-width: 0; | |
| object-fit: cover; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| border: 1px solid var(--color-border); | |
| transition: opacity 0.15s; | |
| } | |
| .pi-screenshot-thumb:hover { | |
| opacity: 0.8; | |
| } | |
| .pi-readme-section { | |
| margin-top: 2rem; | |
| padding-top: 1.5rem; | |
| border-top: 1px solid var(--color-border); | |
| } | |
| .pi-readme-header { | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| color: var(--color-text-muted); | |
| margin-bottom: 0.75rem; | |
| } | |
| .pi-readme-content { | |
| font-size: 0.95rem; | |
| line-height: 1.6; | |
| color: var(--color-text-primary); | |
| overflow-y: auto; | |
| padding-right: 0.5rem; | |
| scrollbar-width: none; | |
| -ms-overflow-style: none; | |
| } | |
| .pi-readme-content::-webkit-scrollbar { | |
| display: none; | |
| } | |
| .pi-readme-content h1, | |
| .pi-readme-content h2, | |
| .pi-readme-content h3, | |
| .pi-readme-content h4 { | |
| margin-top: 1rem; | |
| margin-bottom: 0.5rem; | |
| color: var(--color-text-primary); | |
| } | |
| .pi-readme-content h1 { font-size: 1.5rem; } | |
| .pi-readme-content h2 { font-size: 1.25rem; } | |
| .pi-readme-content h3 { font-size: 1.1rem; } | |
| .pi-readme-content h4 { font-size: 1rem; } | |
| .pi-readme-content p { | |
| margin-bottom: 0.75rem; | |
| } | |
| .pi-readme-content code { | |
| background: var(--color-panel); | |
| padding: 0.15rem 0.35rem; | |
| border-radius: 4px; | |
| font-family: var(--font-family-code); | |
| font-size: 0.85em; | |
| } | |
| .pi-readme-content pre { | |
| background: var(--color-panel); | |
| padding: 1rem; | |
| border-radius: 8px; | |
| overflow-x: auto; | |
| margin-bottom: 1rem; | |
| } | |
| .pi-readme-content pre code { | |
| background: none; | |
| padding: 0; | |
| } | |
| .pi-readme-content ul, | |
| .pi-readme-content ol { | |
| margin-bottom: 0.75rem; | |
| padding-left: 1.5rem; | |
| } | |
| .pi-readme-content li { | |
| margin-bottom: 0.25rem; | |
| } | |
| .pi-readme-content a { | |
| color: var(--color-highlight); | |
| text-decoration: none; | |
| } | |
| .pi-readme-content a:hover { | |
| text-decoration: underline; | |
| } | |
| .pi-readme-content img { | |
| max-width: 100%; | |
| border-radius: 8px; | |
| margin: 0.5rem 0; | |
| } | |
| .pi-readme-content blockquote { | |
| border-left: 3px solid var(--color-border); | |
| padding-left: 1rem; | |
| margin-left: 0; | |
| color: var(--color-text-secondary); | |
| } | |
| .pi-readme-content table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| margin-bottom: 1rem; | |
| } | |
| .pi-readme-content th, | |
| .pi-readme-content td { | |
| border: 1px solid var(--color-border); | |
| padding: 0.5rem; | |
| text-align: left; | |
| } | |
| .pi-readme-content th { | |
| background: var(--color-panel); | |
| } | |
| .pi-developer-section { | |
| margin-top: 2rem; | |
| padding-top: 1.5rem; | |
| border-top: 1px solid var(--color-border); | |
| } | |
| .pi-developer-header { | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| color: var(--color-text-muted); | |
| margin-bottom: 0.75rem; | |
| } | |
| .pi-developer-links { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| } | |
| .pi-dev-link { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| padding: 0.5rem 0; | |
| text-decoration: none; | |
| font-size: 0.8rem; | |
| color: var(--color-text-secondary); | |
| transition: color 0.15s; | |
| } | |
| .pi-dev-link:hover { | |
| color: var(--color-highlight); | |
| } | |
| .pi-dev-link .material-symbols-outlined { | |
| font-size: 1.1rem; | |
| color: var(--color-text-muted); | |
| } | |
| .pi-dev-link:hover .material-symbols-outlined { | |
| color: var(--color-highlight); | |
| } | |
| .pi-dev-link.pi-report-link, | |
| .pi-dev-link.pi-report-link:hover, | |
| .pi-dev-link.pi-report-link .material-symbols-outlined, | |
| .pi-dev-link.pi-report-link:hover .material-symbols-outlined { | |
| color: var(--color-error-text); | |
| } | |
| .pi-footer .buttons-container { | |
| width: 100%; | |
| } | |
| @media (max-width: 768px) { | |
| .pi-hero { | |
| flex-direction: column; | |
| align-items: center; | |
| text-align: center; | |
| } | |
| .pi-hero-thumb { | |
| width: 100px; | |
| height: 100px; | |
| } | |
| .pi-hero-title { | |
| font-size: 1.5rem; | |
| } | |
| .pi-hero-title-row { | |
| grid-template-columns: 1fr; | |
| justify-items: center; | |
| } | |
| .pi-hero-manage { | |
| justify-content: center; | |
| } | |
| .pi-hero-meta { | |
| justify-content: center; | |
| } | |
| .pi-hero-stars { | |
| flex-basis: 100%; | |
| justify-content: center; | |
| } | |
| .pi-hero-tags { | |
| justify-content: center; | |
| } | |
| .pi-card-installed-pill { | |
| position: absolute; | |
| top: unset; | |
| right: unset; | |
| margin: 0 auto var(--spacing-sm) auto; | |
| } | |
| .pi-actions-primary { | |
| flex-direction: column; | |
| } | |
| .pi-btn-install, | |
| .pi-btn-discussion { | |
| min-width: 100%; | |
| } | |
| } | |
| </style> | |
| </body> | |
| </html> | |