stylist->current()->stylesheet(); if (! $this->stylist->current()->has($path)) { return new HtmlString(''); } return new HtmlString(''); } public function script(?string $path = null): HtmlString { $path ??= $this->stylist->current()->script(); if (! $this->stylist->current()->has($path)) { return new HtmlString(''); } return new HtmlString(''); } public function variables(): HtmlString { $theme = $this->stylist->current(); $default = $this->declarations($this->stylist->variables()); $rules = [':root{'.$default.'}']; foreach ($theme->appearances() as $name => $definition) { $vars = (array) data_get($definition, 'variables', []); if ($vars) { $rules[] = ':root[data-theme="'.$this->selector($name).'"]{'.$this->declarations($vars).'}'; } } foreach ($theme->accents() as $name => $definition) { $vars = (array) data_get($definition, 'variables', []); if ($vars) { $rules[] = ':root[data-accent="'.$this->selector($name).'"]{'.$this->declarations($vars).'}'; } } if ($theme->appearances() === [] && $theme->accents() === []) { return new HtmlString(''); } $appearance = json_encode($this->stylist->appearance(), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); $accent = json_encode($this->stylist->accent(), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); $themeKey = json_encode($theme->key(), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); $hasAppearances = $theme->appearances() !== [] ? 'true' : 'false'; $hasAccents = $theme->accents() !== [] ? 'true' : 'false'; $script = <<(function(){var d=document.documentElement,k={$themeKey},ha={$hasAppearances},hc={$hasAccents},a=ha?(localStorage.getItem('stylist:'+k+':appearance')||{$appearance}):'',c=hc?(localStorage.getItem('stylist:'+k+':accent')||{$accent}):'';function apply(){if(ha){var dark=a==='dark'||((a==='auto'||a==='system')&&matchMedia('(prefers-color-scheme: dark)').matches);d.dataset.theme=dark?'dark':'light';d.dataset.appearance=a;d.classList.toggle('dark',dark)}if(hc){d.dataset.accent=c}}apply();window.StylistTheme={setAppearance:function(v){if(!ha)return;a=v;localStorage.setItem('stylist:'+k+':appearance',v);apply()},setAccent:function(v){if(!hc)return;c=v;localStorage.setItem('stylist:'+k+':accent',v);apply()},appearance:function(){return a},accent:function(){return c}};if(ha){matchMedia('(prefers-color-scheme: dark)').addEventListener?.('change',function(){if(a==='auto'||a==='system')apply()})}document.dispatchEvent(new CustomEvent('stylist:ready',{detail:window.StylistTheme}))})(); JS; return new HtmlString(''.$script); } public function switcher(): HtmlString { $theme = $this->stylist->current(); $appearances = array_keys($theme->appearances()); $accents = array_keys($theme->accents()); if ($appearances === [] && $accents === []) { return new HtmlString(''); } $appearanceOptions = collect($appearances)->map(fn ($name) => '')->implode(''); $accentOptions = collect($accents)->map(fn ($name) => '')->implode(''); $appearanceSelect = $appearances ? '' : ''; $accentSelect = $accents ? '' : ''; return new HtmlString('
'.$appearanceSelect.$accentSelect.'
'); } private function declarations(array $variables): string { return collect($variables) ->filter(fn ($value, $key) => is_string($key) && (is_string($value) || is_numeric($value))) ->map(fn ($value, string $key) => '--'.ltrim($key, '-').': '.e((string) $value).';') ->implode(''); } private function selector(string $value): string { return preg_replace('/[^a-z0-9_-]/i', '', $value) ?: 'default'; } }