@tanstack/devtools
Version:
TanStack Devtools is a set of tools for building advanced devtools for your application.
1,553 lines (1,486 loc) • 42.8 kB
text/typescript
import * as goober from 'goober'
import { createEffect, createSignal } from 'solid-js'
import { useTheme } from '../context/use-devtools-context'
import { tokens } from './tokens'
import type { TanStackDevtoolsConfig } from '../context/devtools-context'
import type { Accessor } from 'solid-js'
import type { DevtoolsStore } from '../context/devtools-store'
const mSecondsToCssSeconds = (mSeconds: number) =>
`${(mSeconds / 1000).toFixed(2)}s`
const fadeIn = goober.keyframes`
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
`
const slideInRight = goober.keyframes`
from {
transform: translateX(100%);
}
to {
transform: translateX(0);
}
`
const slideUp = goober.keyframes`
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
`
const statusFadeIn = goober.keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`
const iconPop = goober.keyframes`
0% {
transform: scale(0);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
`
const spin = goober.keyframes`
to {
transform: rotate(360deg);
}
`
const sparkle = goober.keyframes`
0%,
100% {
opacity: 1;
transform: scale(1) rotate(0deg);
}
50% {
opacity: 0.6;
transform: scale(1.1) rotate(10deg);
}
`
const stylesFactory = (theme: DevtoolsStore['settings']['theme']) => {
const { colors, font, size, border } = tokens
const { fontFamily, size: fontSize } = font
const css = goober.css
const t = (light: string, dark: string) => (theme === 'light' ? light : dark)
return {
seoTabContainer: css`
padding: 0;
margin: 0 auto;
background: ${t(colors.white, colors.darkGray[700])};
border-radius: 8px;
box-shadow: none;
overflow-y: auto;
height: 100%;
display: flex;
flex-direction: column;
gap: 0;
width: 100%;
overflow-y: auto;
`,
seoTabTitle: css`
font-size: 1.25rem;
font-weight: 600;
color: ${t(colors.gray[900], colors.gray[100])};
margin: 0;
padding: 1rem 1.5rem 0.5rem 1.5rem;
text-align: left;
border-bottom: 1px solid ${t(colors.gray[200], colors.gray[800])};
`,
seoTabSection: css`
padding: 1.5rem;
background: ${t(colors.gray[50], colors.darkGray[800])};
border: 1px solid ${t(colors.gray[200], colors.gray[800])};
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 2rem;
border-radius: 0.75rem;
`,
seoSubNav: css`
display: flex;
flex-direction: row;
gap: 0;
margin-bottom: 1rem;
border-bottom: 1px solid ${t(colors.gray[200], colors.gray[800])};
`,
seoSubNavLabel: css`
padding: 0.5rem 1rem;
font-size: 0.875rem;
font-weight: 500;
color: ${t(colors.gray[600], colors.gray[400])};
background: none;
border: none;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
cursor: pointer;
font-family: inherit;
&:hover {
color: ${t(colors.gray[800], colors.gray[200])};
}
`,
seoSubNavLabelActive: css`
color: ${t(colors.gray[900], colors.gray[100])};
border-bottom-color: ${t(colors.gray[900], colors.gray[100])};
`,
seoPreviewSection: css`
display: flex;
flex-direction: row;
gap: 16px;
margin-bottom: 0;
justify-content: flex-start;
align-items: flex-start;
overflow-x: auto;
flex-wrap: wrap;
padding-bottom: 0.5rem;
`,
seoPreviewCard: css`
border: 1px solid ${t(colors.gray[200], colors.gray[800])};
border-radius: 8px;
padding: 12px 10px;
background: ${t(colors.white, colors.darkGray[900])};
margin-bottom: 0;
box-shadow: 0 1px 3px ${t('rgba(0,0,0,0.05)', 'rgba(0,0,0,0.1)')};
display: flex;
flex-direction: column;
align-items: flex-start;
min-width: 200px;
max-width: 240px;
font-size: 0.95rem;
gap: 4px;
`,
seoPreviewHeader: css`
font-size: 0.875rem;
font-weight: 600;
margin-bottom: 0;
color: ${t(colors.gray[700], colors.gray[300])};
`,
seoPreviewImage: css`
max-width: 100%;
border-radius: 6px;
margin-bottom: 6px;
box-shadow: 0 1px 2px ${t('rgba(0,0,0,0.03)', 'rgba(0,0,0,0.06)')};
height: 160px;
object-fit: cover;
`,
seoPreviewTitle: css`
font-size: 0.9rem;
font-weight: 600;
margin-bottom: 4px;
color: ${t(colors.gray[900], colors.gray[100])};
`,
seoPreviewDesc: css`
color: ${t(colors.gray[600], colors.gray[400])};
margin-bottom: 4px;
font-size: 0.8rem;
`,
seoPreviewUrl: css`
color: ${t(colors.gray[500], colors.gray[500])};
font-size: 0.75rem;
margin-bottom: 0;
word-break: break-all;
`,
seoMissingTagsSection: css`
margin-top: 4px;
font-size: 0.875rem;
color: ${t(colors.red[500], colors.red[400])};
`,
seoMissingTagsList: css`
margin: 4px 0 0 0;
padding: 0;
list-style: none;
display: flex;
flex-wrap: wrap;
gap: 4px;
max-width: 240px;
`,
seoMissingTag: css`
background: ${t(colors.red[100], colors.red[500] + '22')};
color: ${t(colors.red[700], colors.red[500])};
border-radius: 3px;
padding: 2px 6px;
font-size: 0.75rem;
font-weight: 500;
`,
seoAllTagsFound: css`
color: ${t(colors.green[700], colors.green[500])};
font-weight: 500;
margin-left: 0;
padding: 0 10px 8px 10px;
font-size: 0.875rem;
`,
serpPreviewBlock: css`
margin-bottom: 1.5rem;
border: 1px solid ${t(colors.gray[200], colors.gray[700])};
border-radius: 10px;
padding: 1rem;
`,
serpPreviewLabel: css`
font-size: 0.875rem;
font-weight: 600;
margin-bottom: 0.5rem;
color: ${t(colors.gray[700], colors.gray[300])};
`,
serpSnippet: css`
border: 1px solid ${t(colors.gray[100], colors.gray[800])};
border-radius: 8px;
padding: 1rem 1.25rem;
background: ${t(colors.white, colors.darkGray[900])};
max-width: 600px;
font-family: ${fontFamily.sans};
box-shadow: 0 1px 2px ${t('rgba(0,0,0,0.04)', 'rgba(0,0,0,0.08)')};
`,
serpSnippetMobile: css`
border: 1px solid ${t(colors.gray[100], colors.gray[800])};
border-radius: 8px;
padding: 1rem 1.25rem;
background: ${t(colors.white, colors.darkGray[900])};
max-width: 380px;
font-family: ${fontFamily.sans};
box-shadow: 0 1px 2px ${t('rgba(0,0,0,0.04)', 'rgba(0,0,0,0.08)')};
`,
serpSnippetDescMobile: css`
font-size: 0.875rem;
color: ${t(colors.gray[700], colors.gray[300])};
margin: 0;
line-height: 1.5;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
`,
serpSnippetTopRow: css`
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
`,
serpSnippetFavicon: css`
width: 28px;
height: 28px;
border-radius: 50%;
flex-shrink: 0;
object-fit: contain;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
`,
serpSnippetDefaultFavicon: css`
width: 28px;
height: 28px;
background-color: ${t(colors.gray[200], colors.gray[800])};
border-radius: 50%;
flex-shrink: 0;
object-fit: contain;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
`,
serpSnippetSiteColumn: css`
display: flex;
flex-direction: column;
gap: 0;
min-width: 0;
`,
serpSnippetSiteName: css`
font-size: 0.875rem;
color: ${t(colors.gray[900], colors.gray[100])};
line-height: 1.4;
margin: 0;
`,
serpSnippetSiteUrl: css`
font-size: 0.75rem;
color: ${t(colors.gray[500], colors.gray[500])};
line-height: 1.4;
margin: 0;
`,
serpSnippetTitle: css`
font-size: 1.25rem;
font-weight: 400;
color: ${t('#1a0dab', '#8ab4f8')};
margin: 0 0 4px 0;
line-height: 1.3;
`,
serpSnippetDesc: css`
font-size: 0.875rem;
color: ${t(colors.gray[700], colors.gray[300])};
margin: 0;
line-height: 1.5;
`,
serpMeasureHidden: css`
position: absolute;
left: -9999px;
top: 0;
visibility: hidden;
pointer-events: none;
box-sizing: border-box;
`,
serpMeasureHiddenMobile: css`
position: absolute;
left: -9999px;
top: 0;
width: 340px;
visibility: hidden;
pointer-events: none;
font-size: 0.875rem;
line-height: 1.5;
`,
serpReportSection: css`
margin-top: 1rem;
font-size: 0.875rem;
color: ${t(colors.gray[700], colors.gray[300])};
`,
serpErrorList: css`
margin: 4px 0 0 0;
padding-left: 1.25rem;
list-style-type: disc;
`,
serpReportItem: css`
margin-top: 0.25rem;
color: ${t(colors.red[700], colors.red[400])};
font-size: 0.875rem;
`,
devtoolsPanelContainer: (
panelLocation: TanStackDevtoolsConfig['panelLocation'],
isDetached: boolean,
) => css`
direction: ltr;
position: fixed;
overflow-y: hidden;
overflow-x: hidden;
${panelLocation}: 0;
right: 0;
z-index: 99999;
width: 100%;
${isDetached ? '' : 'max-height: 90%;'}
border-top: 1px solid ${t(colors.gray[200], colors.gray[800])};
transform-origin: top;
`,
devtoolsPanelContainerVisibility: (isOpen: boolean) => {
return css`
visibility: ${isOpen ? 'visible' : 'hidden'};
height: ${isOpen ? 'auto' : '0'};
`
},
devtoolsPanelContainerResizing: (isResizing: Accessor<boolean>) => {
if (isResizing()) {
return css`
transition: none;
`
}
return css`
transition: all 0.4s ease;
`
},
devtoolsPanelContainerAnimation: (
isOpen: boolean,
height: number,
panelLocation: TanStackDevtoolsConfig['panelLocation'],
) => {
if (isOpen) {
return css`
pointer-events: auto;
transform: translateY(0);
`
}
return css`
pointer-events: none;
transform: translateY(${panelLocation === 'top' ? -height : height}px);
`
},
devtoolsPanel: css`
display: flex;
font-size: ${fontSize.sm};
font-family: ${fontFamily.sans};
background-color: ${t(colors.white, colors.darkGray[700])};
color: ${t(colors.gray[900], colors.gray[300])};
width: w-screen;
flex-direction: row;
overflow-x: hidden;
overflow-y: hidden;
height: 100%;
`,
dragHandle: (panelLocation: TanStackDevtoolsConfig['panelLocation']) => css`
position: absolute;
left: 0;
${panelLocation === 'bottom' ? 'top' : 'bottom'}: 0;
width: 100%;
height: 4px;
cursor: row-resize;
user-select: none;
z-index: 100000;
&:hover {
background-color: ${t(colors.gray[400], colors.gray[500])};
}
`,
mainCloseBtn: css`
background: transparent;
position: fixed;
z-index: 99999;
display: inline-flex;
width: fit-content;
cursor: pointer;
appearance: none;
border: 0;
align-items: center;
padding: 0;
font-size: ${font.size.xs};
cursor: pointer;
transition: all 0.25s ease-out;
& > img {
width: 56px;
height: 56px;
transition: all 0.3s ease;
outline-offset: 2px;
border-radius: ${border.radius.full};
outline: 2px solid transparent;
}
&:hide-until-hover {
opacity: 0;
pointer-events: none;
visibility: hidden;
}
&:hide-until-hover:hover {
opacity: 1;
pointer-events: auto;
visibility: visible;
}
& > img:focus-visible,
img:hover {
outline: 2px solid ${t(colors.black, colors.black)};
}
`,
mainCloseBtnPosition: (position: TanStackDevtoolsConfig['position']) => {
const base = css`
${position === 'top-left' ? `top: ${size[2]}; left: ${size[2]};` : ''}
${position === 'top-right' ? `top: ${size[2]}; right: ${size[2]};` : ''}
${position === 'middle-left'
? `top: 50%; left: ${size[2]}; transform: translateY(-50%);`
: ''}
${position === 'middle-right'
? `top: 50%; right: ${size[2]}; transform: translateY(-50%);`
: ''}
${position === 'bottom-left'
? `bottom: ${size[2]}; left: ${size[2]};`
: ''}
${position === 'bottom-right'
? `bottom: ${size[2]}; right: ${size[2]};`
: ''}
`
return base
},
mainCloseBtnAnimation: (isOpen: boolean, hideUntilHover: boolean) => {
if (!isOpen) {
return hideUntilHover
? css`
opacity: 0;
&:hover {
opacity: 1;
pointer-events: auto;
visibility: visible;
}
`
: css`
opacity: 1;
pointer-events: auto;
visibility: visible;
`
}
return css`
opacity: 0;
pointer-events: none;
visibility: hidden;
`
},
tabContainer: css`
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
height: 100%;
background-color: ${t(colors.gray[50], colors.darkGray[900])};
border-right: 1px solid ${t(colors.gray[200], colors.gray[800])};
box-shadow: none;
position: relative;
width: ${size[10]};
`,
tab: css`
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: ${size[10]};
cursor: pointer;
font-size: ${fontSize.sm};
font-family: ${fontFamily.sans};
color: ${t(colors.gray[600], colors.gray[400])};
background-color: transparent;
border: none;
transition: all 0.15s ease;
border-left: 2px solid transparent;
&:hover:not(.close):not(.active):not(.detach) {
background-color: ${t(colors.gray[100], colors.gray[800])};
color: ${t(colors.gray[900], colors.gray[100])};
border-left: 2px solid ${t(colors.gray[900], colors.gray[100])};
}
&.active {
background-color: ${t(colors.gray[100], colors.gray[800])};
color: ${t(colors.gray[900], colors.gray[100])};
border-left: 2px solid ${t(colors.gray[900], colors.gray[100])};
}
&.detach {
&:hover {
background-color: ${t(colors.gray[100], colors.gray[800])};
}
&:hover {
color: ${t(colors.green[700], colors.green[500])};
}
}
&.close {
margin-top: auto;
&:hover {
background-color: ${t(colors.gray[100], colors.gray[800])};
}
&:hover {
color: ${t(colors.red[700], colors.red[500])};
}
}
&.disabled {
cursor: not-allowed;
opacity: 0.2;
pointer-events: none;
}
&.disabled:hover {
background-color: transparent;
color: ${colors.gray[300]};
}
& > svg {
flex-shrink: 0;
}
`,
tabContent: css`
transition: all 0.2s ease-in-out;
width: 100%;
height: 100%;
`,
pluginsTabPanel: css`
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
overflow: hidden;
`,
pluginsTabDraw: (isExpanded: boolean) => css`
width: ${isExpanded ? size[48] : 0};
height: 100%;
background-color: ${t(colors.white, colors.darkGray[900])};
box-shadow: none;
${isExpanded
? `border-right: 1px solid ${t(colors.gray[200], colors.gray[800])};`
: ''}
`,
pluginsTabDrawExpanded: css`
width: ${size[48]};
border-right: 1px solid ${t(colors.gray[200], colors.gray[800])};
`,
pluginsTabDrawTransition: (mSeconds: number) => {
return css`
transition: width ${mSecondsToCssSeconds(mSeconds)} ease;
`
},
pluginsTabSidebar: (isExpanded: boolean) => css`
width: ${size[48]};
overflow-y: auto;
transform: ${isExpanded ? 'translateX(0)' : 'translateX(-100%)'};
display: flex;
flex-direction: column;
`,
pluginsTabSidebarTransition: (mSeconds: number) => {
return css`
transition: transform ${mSecondsToCssSeconds(mSeconds)} ease;
`
},
pluginsList: css`
flex: 1;
overflow-y: auto;
`,
pluginName: css`
font-size: ${fontSize.xs};
font-family: ${fontFamily.sans};
color: ${t(colors.gray[600], colors.gray[400])};
padding: ${size[2]};
cursor: pointer;
text-align: center;
transition: all 0.15s ease;
border-left: 2px solid transparent;
&:hover {
background-color: ${t(colors.gray[100], colors.gray[800])};
color: ${t(colors.gray[900], colors.gray[100])};
padding: ${size[2]};
}
&.active {
background-color: ${t(colors.gray[100], colors.gray[800])};
color: ${t(colors.gray[900], colors.gray[100])};
border-left: 2px solid ${t(colors.gray[900], colors.gray[100])};
}
&.active:hover {
background-color: ${t(colors.gray[200], colors.gray[700])};
}
`,
pluginsTabContent: css`
width: 100%;
height: 100%;
min-width: 0;
min-height: 0;
& > * {
min-width: 0;
min-height: 0;
width: 100%;
height: 100%;
}
& > * > * {
min-width: 0;
min-height: 0;
width: 100%;
height: 100%;
}
&:not(:last-child) {
border-right: 5px solid ${t(colors.purple[200], colors.purple[800])};
}
`,
settingsGroup: css`
display: flex;
flex-direction: column;
gap: 0.75rem;
`,
conditionalSetting: css`
margin-left: 1.5rem;
padding-left: 1rem;
border-left: 2px solid ${t(colors.gray[300], colors.gray[600])};
background-color: ${t(colors.gray[50], colors.darkGray[900])};
padding: 0.75rem;
border-radius: 0.375rem;
margin-top: 0.5rem;
`,
settingRow: css`
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
@media (max-width: 768px) {
grid-template-columns: 1fr;
}
`,
settingsModifiers: css`
display: flex;
gap: 0.5rem;
`,
settingsStack: css`
display: flex;
flex-direction: column;
gap: 1rem;
`,
// No Plugins Fallback Styles
noPluginsFallback: css`
display: flex;
align-items: center;
justify-content: center;
min-height: 400px;
padding: 2rem;
background: ${t(colors.gray[50], colors.darkGray[700])};
width: 100%;
height: 100%;
`,
noPluginsFallbackContent: css`
max-width: 600px;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
`,
noPluginsFallbackIcon: css`
width: 64px;
height: 64px;
color: ${t(colors.gray[400], colors.gray[600])};
margin-bottom: 0.5rem;
svg {
width: 100%;
height: 100%;
}
`,
noPluginsFallbackTitle: css`
font-size: 1.5rem;
font-weight: 600;
color: ${t(colors.gray[900], colors.gray[100])};
margin: 0;
`,
noPluginsFallbackDescription: css`
font-size: 0.95rem;
color: ${t(colors.gray[600], colors.gray[400])};
line-height: 1.5;
margin: 0;
`,
noPluginsSuggestions: css`
width: 100%;
margin-top: 1.5rem;
padding: 1.5rem;
background: ${t(colors.white, colors.darkGray[800])};
border: 1px solid ${t(colors.gray[200], colors.gray[700])};
border-radius: 0.5rem;
`,
noPluginsSuggestionsTitle: css`
font-size: 1.125rem;
font-weight: 600;
color: ${t(colors.gray[900], colors.gray[100])};
margin: 0 0 0.5rem 0;
`,
noPluginsSuggestionsDesc: css`
font-size: 0.875rem;
color: ${t(colors.gray[600], colors.gray[400])};
margin: 0 0 1rem 0;
`,
noPluginsSuggestionsList: css`
display: flex;
flex-direction: column;
gap: 0.75rem;
`,
noPluginsSuggestionCard: css`
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem;
background: ${t(colors.gray[50], colors.darkGray[900])};
border: 1px solid ${t(colors.gray[200], colors.gray[700])};
border-radius: 0.375rem;
transition: all 0.15s ease;
&:hover {
border-color: ${t(colors.gray[300], colors.gray[600])};
background: ${t(colors.gray[100], colors.darkGray[800])};
}
`,
noPluginsSuggestionInfo: css`
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0.25rem;
flex: 1;
`,
noPluginsSuggestionPackage: css`
font-size: 0.95rem;
font-weight: 600;
color: ${t(colors.gray[900], colors.gray[100])};
margin: 0;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
`,
noPluginsSuggestionSource: css`
font-size: 0.8rem;
color: ${t(colors.gray[500], colors.gray[500])};
margin: 0;
`,
noPluginsSuggestionStatus: css`
display: flex;
align-items: center;
gap: 0.5rem;
color: ${t(colors.green[600], colors.green[400])};
svg {
width: 18px;
height: 18px;
}
`,
noPluginsSuggestionStatusText: css`
font-size: 0.875rem;
font-weight: 500;
`,
noPluginsSuggestionStatusTextError: css`
font-size: 0.875rem;
font-weight: 500;
color: ${t(colors.red[600], colors.red[400])};
`,
noPluginsEmptyState: css`
margin-top: 1.5rem;
padding: 1.5rem;
background: ${t(colors.white, colors.darkGray[800])};
border: 1px solid ${t(colors.gray[200], colors.gray[700])};
border-radius: 0.5rem;
`,
noPluginsEmptyStateText: css`
font-size: 0.875rem;
color: ${t(colors.gray[600], colors.gray[400])};
margin: 0;
line-height: 1.5;
`,
noPluginsFallbackLinks: css`
display: flex;
align-items: center;
gap: 0.75rem;
margin-top: 1.5rem;
`,
noPluginsFallbackLink: css`
font-size: 0.875rem;
color: ${t(colors.gray[700], colors.gray[300])};
text-decoration: none;
transition: color 0.15s ease;
&:hover {
color: ${t(colors.gray[900], colors.gray[100])};
text-decoration: underline;
}
`,
noPluginsFallbackLinkSeparator: css`
color: ${t(colors.gray[400], colors.gray[600])};
`,
// Plugin Marketplace Styles (for "Add More" tab)
pluginMarketplace: css`
width: 100%;
overflow-y: auto;
padding: 2rem;
background: ${t(
'linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%)',
'linear-gradient(135deg, #1a1d23 0%, #13161a 100%)',
)};
animation: ${fadeIn} 0.3s ease;
`,
pluginMarketplaceHeader: css`
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 2px solid ${t(colors.gray[200], colors.gray[700])};
`,
pluginMarketplaceTitleRow: css`
display: flex;
align-items: center;
justify-content: space-between;
gap: 2rem;
margin-bottom: 0.5rem;
`,
pluginMarketplaceTitle: css`
font-size: 1.5rem;
font-weight: 700;
color: ${t(colors.gray[900], colors.gray[100])};
margin: 0;
letter-spacing: -0.02em;
`,
pluginMarketplaceDescription: css`
font-size: 0.95rem;
color: ${t(colors.gray[600], colors.gray[400])};
margin: 0 0 1rem 0;
line-height: 1.5;
`,
pluginMarketplaceSearchWrapper: css`
position: relative;
display: flex;
align-items: center;
max-width: 400px;
flex-shrink: 0;
svg {
position: absolute;
left: 1rem;
color: ${t(colors.gray[400], colors.gray[500])};
pointer-events: none;
}
`,
pluginMarketplaceSearch: css`
width: 100%;
padding: 0.75rem 1rem 0.75rem 2.75rem;
background: ${t(colors.gray[50], colors.darkGray[900])};
border: 2px solid ${t(colors.gray[200], colors.gray[700])};
border-radius: 0.5rem;
color: ${t(colors.gray[900], colors.gray[100])};
font-size: 0.875rem;
font-family: ${fontFamily.sans};
transition: all 0.2s ease;
&::placeholder {
color: ${t(colors.gray[400], colors.gray[500])};
}
&:focus {
outline: none;
border-color: ${t(colors.blue[500], colors.blue[400])};
background: ${t(colors.white, colors.darkGray[800])};
box-shadow: 0 0 0 3px
${t('rgba(59, 130, 246, 0.1)', 'rgba(96, 165, 250, 0.1)')};
}
`,
pluginMarketplaceFilters: css`
margin-top: 1.5rem;
padding-top: 1rem;
`,
pluginMarketplaceTagsContainer: css`
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 1.5rem;
padding: 1rem;
background: ${t(colors.gray[50], colors.darkGray[800])};
border: 1px solid ${t(colors.gray[200], colors.gray[700])};
border-radius: 0.5rem;
`,
pluginMarketplaceTagButton: css`
padding: 0.5rem 1rem;
font-size: 0.875rem;
font-weight: 500;
background: ${t(colors.white, colors.darkGray[700])};
border: 2px solid ${t(colors.gray[300], colors.gray[600])};
border-radius: 0.375rem;
color: ${t(colors.gray[700], colors.gray[300])};
cursor: pointer;
transition: all 0.15s ease;
&:hover {
background: ${t(colors.gray[100], colors.darkGray[600])};
border-color: ${t(colors.gray[400], colors.gray[500])};
color: ${t(colors.gray[900], colors.gray[100])};
}
`,
pluginMarketplaceTagButtonActive: css`
background: ${t(
'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)',
'linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%)',
)} ;
border-color: ${t('#2563eb', '#3b82f6')} ;
color: white ;
&:hover {
background: ${t(
'linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%)',
'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)',
)} ;
border-color: ${t('#1d4ed8', '#2563eb')} ;
}
`,
pluginMarketplaceSettingsButton: css`
display: flex;
align-items: center;
justify-content: center;
padding: 0.75rem;
background: ${t(colors.gray[100], colors.darkGray[800])};
border: 2px solid ${t(colors.gray[200], colors.gray[700])};
border-radius: 0.5rem;
color: ${t(colors.gray[700], colors.gray[300])};
cursor: pointer;
transition: all 0.2s ease;
margin-left: 0.5rem;
&:hover {
background: ${t(colors.gray[200], colors.darkGray[700])};
border-color: ${t(colors.gray[300], colors.gray[600])};
color: ${t(colors.gray[900], colors.gray[100])};
}
&:active {
transform: scale(0.95);
}
`,
pluginMarketplaceSettingsPanel: css`
position: fixed;
top: 0;
right: 0;
bottom: 0;
width: 350px;
background: ${t(colors.white, colors.darkGray[800])};
border-left: 1px solid ${t(colors.gray[200], colors.gray[700])};
box-shadow: -4px 0 12px ${t('rgba(0, 0, 0, 0.1)', 'rgba(0, 0, 0, 0.4)')};
z-index: 1000;
display: flex;
flex-direction: column;
animation: ${slideInRight} 0.3s ease;
`,
pluginMarketplaceSettingsPanelHeader: css`
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.5rem;
border-bottom: 1px solid ${t(colors.gray[200], colors.gray[700])};
`,
pluginMarketplaceSettingsPanelTitle: css`
font-size: 1.125rem;
font-weight: 600;
color: ${t(colors.gray[900], colors.gray[100])};
margin: 0;
`,
pluginMarketplaceSettingsPanelClose: css`
display: flex;
align-items: center;
justify-content: center;
padding: 0.5rem;
background: transparent;
border: none;
color: ${t(colors.gray[600], colors.gray[400])};
cursor: pointer;
border-radius: 0.375rem;
transition: all 0.15s ease;
&:hover {
background: ${t(colors.gray[100], colors.darkGray[700])};
color: ${t(colors.gray[900], colors.gray[100])};
}
`,
pluginMarketplaceSettingsPanelContent: css`
flex: 1;
padding: 1.5rem;
overflow-y: auto;
`,
pluginMarketplaceGrid: css`
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.25rem;
animation: ${slideUp} 0.4s ease;
`,
pluginMarketplaceCard: css`
background: ${t(colors.white, colors.darkGray[800])};
border: 2px solid ${t(colors.gray[200], colors.gray[700])};
border-radius: 0.75rem;
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1rem;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: ${t(
'linear-gradient(90deg, #3b82f6 0%, #8b5cf6 100%)',
'linear-gradient(90deg, #60a5fa 0%, #a78bfa 100%)',
)};
transform: scaleX(0);
transform-origin: left;
transition: transform 0.25s ease;
}
&:hover {
border-color: ${t(colors.gray[400], colors.gray[500])};
box-shadow: 0 8px 24px ${t('rgba(0,0,0,0.1)', 'rgba(0,0,0,0.4)')};
transform: translateY(-4px);
&::before {
transform: scaleX(1);
}
}
`,
pluginMarketplaceCardIcon: css`
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: ${t(
'linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%)',
'linear-gradient(135deg, #60a5fa 0%, #a78bfa 100%)',
)};
border-radius: 0.5rem;
color: white;
transition: transform 0.25s ease;
svg {
width: 20px;
height: 20px;
}
&.custom-logo {
}
`,
pluginMarketplaceCardHeader: css`
flex: 1;
`,
pluginMarketplaceCardTitle: css`
font-size: 0.95rem;
font-weight: 600;
color: ${t(colors.gray[900], colors.gray[100])};
margin: 0 0 0.5rem 0;
line-height: 1.4;
`,
pluginMarketplaceCardDescription: css`
font-size: 0.8rem;
color: ${t(colors.gray[500], colors.gray[500])};
margin: 0;
padding: 0;
background: transparent;
border-radius: 0.375rem;
display: block;
font-weight: 500;
`,
pluginMarketplaceCardPackageBadge: css`
margin-top: 4px;
margin-bottom: 8px;
font-size: 0.6875rem;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
opacity: 0.6;
padding: 4px 8px;
padding-left: 0;
background-color: var(--bg-tertiary);
border-radius: 4px;
word-break: break-all;
display: inline-block;
`,
pluginMarketplaceCardDescriptionText: css`
line-height: 1.5;
margin-top: 0;
`,
pluginMarketplaceCardVersionInfo: css`
margin-top: 8px;
font-size: 0.6875rem;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
`,
pluginMarketplaceCardVersionSatisfied: css`
color: ${t(colors.green[600], colors.green[400])};
`,
pluginMarketplaceCardVersionUnsatisfied: css`
color: ${t(colors.red[600], colors.red[400])};
`,
pluginMarketplaceCardDocsLink: css`
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.75rem;
color: ${t(colors.blue[600], colors.blue[400])};
text-decoration: none;
margin-top: 0.5rem;
transition: color 0.15s ease;
&:hover {
color: ${t(colors.blue[700], colors.blue[300])};
text-decoration: underline;
}
svg {
width: 12px;
height: 12px;
}
`,
pluginMarketplaceCardTags: css`
display: flex;
flex-wrap: wrap;
gap: 0.375rem;
margin-top: 0.75rem;
`,
pluginMarketplaceCardTag: css`
font-size: 0.6875rem;
font-weight: 500;
padding: 0.25rem 0.5rem;
background: ${t(colors.gray[100], colors.darkGray[700])};
border: 1px solid ${t(colors.gray[300], colors.gray[600])};
border-radius: 0.25rem;
color: ${t(colors.gray[700], colors.gray[300])};
`,
pluginMarketplaceCardImage: css`
width: 28px;
height: 28px;
object-fit: contain;
`,
pluginMarketplaceNewBanner: css`
position: absolute;
top: 12px;
right: -35px;
background-color: ${t(colors.green[500], colors.green[500])};
color: white;
padding: 4px 40px;
font-size: 0.6875rem;
font-weight: bold;
text-transform: uppercase;
transform: rotate(45deg);
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.5);
z-index: 10;
letter-spacing: 0.5px;
`,
pluginMarketplaceCardFeatured: css`
border-color: ${t(colors.blue[500], colors.blue[400])};
border-width: 2px;
`,
pluginMarketplaceCardActive: css`
border-color: ${t(colors.green[500], colors.green[600])};
border-width: 2px;
&:hover {
border-color: ${t(colors.green[500], colors.green[600])};
box-shadow: none;
transform: none;
&::before {
transform: scaleX(0);
}
}
`,
pluginMarketplaceCardStatus: css`
display: flex;
align-items: center;
gap: 0.5rem;
color: ${t(colors.green[600], colors.green[400])};
animation: ${statusFadeIn} 0.3s ease;
svg {
width: 18px;
height: 18px;
animation: ${iconPop} 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
`,
pluginMarketplaceCardSpinner: css`
width: 18px;
height: 18px;
border: 2px solid ${t(colors.gray[200], colors.gray[700])};
border-top-color: ${t(colors.blue[600], colors.blue[400])};
border-radius: 50%;
animation: ${spin} 0.8s linear infinite;
`,
pluginMarketplaceCardStatusText: css`
font-size: 0.875rem;
font-weight: 600;
`,
pluginMarketplaceCardStatusTextError: css`
font-size: 0.875rem;
font-weight: 600;
color: ${t(colors.red[600], colors.red[400])};
`,
pluginMarketplaceEmpty: css`
padding: 3rem 2rem;
text-align: center;
background: ${t(colors.white, colors.darkGray[800])};
border: 2px dashed ${t(colors.gray[300], colors.gray[700])};
border-radius: 0.75rem;
animation: ${fadeIn} 0.3s ease;
`,
pluginMarketplaceEmptyText: css`
font-size: 0.95rem;
color: ${t(colors.gray[600], colors.gray[400])};
margin: 0;
line-height: 1.6;
`,
// Framework sections
pluginMarketplaceSection: css`
margin-bottom: 2.5rem;
&:last-child {
margin-bottom: 0;
}
`,
pluginMarketplaceSectionHeader: css`
margin-bottom: 1rem;
padding: 1rem 1.25rem;
display: flex;
align-items: center;
gap: 0.75rem;
cursor: pointer;
user-select: none;
background: ${t(colors.gray[50], colors.darkGray[800])};
border: 1px solid ${t(colors.gray[200], colors.gray[700])};
border-radius: 0.5rem;
transition: all 0.15s ease;
&:hover {
background: ${t(colors.gray[100], colors.darkGray[700])};
border-color: ${t(colors.gray[300], colors.gray[600])};
}
`,
pluginMarketplaceSectionHeaderLeft: css`
display: flex;
align-items: center;
gap: 0.5rem;
`,
pluginMarketplaceSectionChevron: css`
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: ${t(colors.gray[700], colors.gray[300])};
transition: transform 0.2s ease;
`,
pluginMarketplaceSectionChevronCollapsed: css`
transform: rotate(-90deg);
`,
pluginMarketplaceSectionTitle: css`
font-size: 1.25rem;
font-weight: 700;
color: ${t(colors.gray[900], colors.gray[50])};
margin: 0;
display: flex;
align-items: center;
gap: 0.5rem;
`,
pluginMarketplaceSectionBadge: css`
font-size: 0.75rem;
font-weight: 600;
padding: 0.25rem 0.5rem;
background: ${t(
'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)',
'linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%)',
)};
color: white;
border-radius: 0.25rem;
text-transform: uppercase;
letter-spacing: 0.05em;
`,
pluginMarketplaceFeatureBanner: css`
margin-top: 1rem;
padding: 1.25rem 1.5rem;
background: ${t(
'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)',
'linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%)',
)};
border-radius: 0.75rem;
border: 1px solid ${t(colors.blue[400], colors.blue[800])};
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06);
`,
pluginMarketplaceFeatureBannerContent: css`
display: flex;
flex-direction: column;
gap: 0.75rem;
`,
pluginMarketplaceFeatureBannerTitle: css`
font-size: 1.125rem;
font-weight: 700;
color: white;
margin: 0;
display: flex;
align-items: center;
gap: 0.5rem;
`,
pluginMarketplaceFeatureBannerIcon: css`
width: 24px;
height: 24px;
display: inline-flex;
`,
pluginMarketplaceFeatureBannerText: css`
font-size: 0.95rem;
color: ${t('rgba(255, 255, 255, 0.95)', 'rgba(255, 255, 255, 0.9)')};
line-height: 1.5;
margin: 0;
`,
pluginMarketplaceFeatureBannerButton: css`
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.625rem 1.25rem;
background: white;
color: ${colors.blue[600]};
font-weight: 600;
font-size: 0.95rem;
border-radius: 0.5rem;
border: none;
cursor: pointer;
transition: all 0.2s ease;
text-decoration: none;
align-self: flex-start;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
&:hover {
background: ${t(colors.gray[50], colors.gray[100])};
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
&:active {
transform: translateY(0);
}
`,
pluginMarketplaceFeatureBannerButtonIcon: css`
width: 18px;
height: 18px;
`,
pluginMarketplaceCardDisabled: css`
opacity: 0.6;
filter: grayscale(0.3);
cursor: not-allowed;
&:hover {
transform: none;
box-shadow: none;
}
`,
// Card state badges
pluginMarketplaceCardBadge: css`
position: absolute;
top: 1rem;
right: 1rem;
padding: 0.25rem 0.5rem;
font-size: 0.65rem;
font-weight: 600;
text-transform: uppercase;
border-radius: 0.25rem;
letter-spacing: 0.05em;
`,
pluginMarketplaceCardBadgeInstall: css`
background: ${t(colors.green[100], colors.green[900])};
color: ${t(colors.green[700], colors.green[300])};
`,
pluginMarketplaceCardBadgeAdd: css`
background: ${t(colors.blue[100], colors.blue[900])};
color: ${t(colors.blue[700], colors.blue[300])};
`,
pluginMarketplaceCardBadgeRequires: css`
background: ${t(colors.gray[100], colors.gray[800])};
color: ${t(colors.gray[600], colors.gray[400])};
`,
// Button style for already installed plugins
pluginMarketplaceButtonInstalled: css`
opacity: 0.5;
`,
// Add More Tab Style (visually distinct from regular plugins)
pluginNameAddMore: css`
font-size: ${fontSize.xs};
font-family: ${fontFamily.sans};
color: ${t(colors.gray[600], colors.gray[400])};
padding: ${size[3]} ${size[2]};
cursor: pointer;
text-align: center;
transition: all 0.15s ease;
border-left: 2px solid transparent;
background: ${t(
'linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%)',
'linear-gradient(135deg, #1f2937 0%, #111827 100%)',
)};
font-weight: 600;
position: relative;
margin-top: auto;
h3 {
margin: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 0.25rem;
&::before {
content: '✨';
font-size: 0.875rem;
animation: ${sparkle} 2s ease-in-out infinite;
}
}
&:hover {
background: ${t(
'linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%)',
'linear-gradient(135deg, #374151 0%, #1f2937 100%)',
)};
color: ${t(colors.gray[900], colors.gray[100])};
border-left-color: ${t(colors.blue[500], colors.blue[400])};
h3::before {
animation: ${sparkle} 0.5s ease-in-out infinite;
}
}
&.active {
background: ${t(
'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)',
'linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%)',
)};
color: ${t(colors.white, colors.white)};
border-left: 2px solid ${t(colors.blue[600], colors.blue[300])};
box-shadow: 0 4px 12px
${t('rgba(59, 130, 246, 0.3)', 'rgba(96, 165, 250, 0.3)')};
h3::before {
filter: brightness(0) invert(1);
}
}
&.active:hover {
background: ${t(
'linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%)',
'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)',
)};
}
`,
}
}
export function useStyles() {
const { theme } = useTheme()
const [styles, setStyles] = createSignal(stylesFactory(theme()))
createEffect(() => {
setStyles(stylesFactory(theme()))
})
return styles
}