Control ui adjsutments
This commit is contained in:
@@ -240,6 +240,6 @@ If `SLANG_ROOT` is not set, the workflow falls back to the repo-local default un
|
|||||||
- More comprehensive greenscreen shader
|
- More comprehensive greenscreen shader
|
||||||
- linear compositing?
|
- linear compositing?
|
||||||
- compute shaders or a small 1x1 or nx1 RGBA16f render target for abritary data store
|
- compute shaders or a small 1x1 or nx1 RGBA16f render target for abritary data store
|
||||||
- allow shaders to read other shaders data store based on name? or putput over OSC
|
- allow shaders to read other shaders data store based on name? or output over OSC
|
||||||
- Mipmappong needed?
|
- Mipmappong needed?
|
||||||
- unwrap a fish eyelens and mirror it and map it to equirectangulr for environmnet map purposes
|
- unwrap a fish eyelens and mirror it and map it to equirectangulr for environmnet map purposes
|
||||||
|
|||||||
14
ui/package-lock.json
generated
14
ui/package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@uiw/color-convert": "^2.10.1",
|
"@uiw/color-convert": "^2.10.1",
|
||||||
"@uiw/react-color-wheel": "^2.10.1",
|
"@uiw/react-color-wheel": "^2.10.1",
|
||||||
|
"fuse.js": "^7.3.0",
|
||||||
"lucide-react": "^0.511.0",
|
"lucide-react": "^0.511.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1"
|
"react-dom": "^18.3.1"
|
||||||
@@ -1429,6 +1430,19 @@
|
|||||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fuse.js": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-plz8RVjfcDedTGfVngWH1jmJvBvAwi1v2jecfDerbEnMcmOYUEEwKFTHbNoCiYyzaK2Ws8lABkTCcRSqCY1q4w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/krisk"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/gensync": {
|
"node_modules/gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@uiw/color-convert": "^2.10.1",
|
"@uiw/color-convert": "^2.10.1",
|
||||||
"@uiw/react-color-wheel": "^2.10.1",
|
"@uiw/react-color-wheel": "^2.10.1",
|
||||||
|
"fuse.js": "^7.3.0",
|
||||||
"lucide-react": "^0.511.0",
|
"lucide-react": "^0.511.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1"
|
"react-dom": "^18.3.1"
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ function AppFooter() {
|
|||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [appState, setAppState] = useRuntimeState();
|
const [appState, setAppState] = useRuntimeState();
|
||||||
const [pendingShaderId, setPendingShaderId] = useState("");
|
|
||||||
const [presetName, setPresetName] = useState("");
|
const [presetName, setPresetName] = useState("");
|
||||||
const [selectedPresetName, setSelectedPresetName] = useState("");
|
const [selectedPresetName, setSelectedPresetName] = useState("");
|
||||||
const [expandedLayerIds, setExpandedLayerIds] = useState([]);
|
const [expandedLayerIds, setExpandedLayerIds] = useState([]);
|
||||||
@@ -38,14 +37,6 @@ function App() {
|
|||||||
const app = appState?.app ?? {};
|
const app = appState?.app ?? {};
|
||||||
const stackPresets = appState?.stackPresets ?? [];
|
const stackPresets = appState?.stackPresets ?? [];
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!pendingShaderId && shaders.length > 0) {
|
|
||||||
setPendingShaderId(shaders[0].id);
|
|
||||||
} else if (pendingShaderId && !shaders.some((shader) => shader.id === pendingShaderId)) {
|
|
||||||
setPendingShaderId(shaders[0]?.id ?? "");
|
|
||||||
}
|
|
||||||
}, [pendingShaderId, shaders]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedPresetName && stackPresets.length > 0) {
|
if (!selectedPresetName && stackPresets.length > 0) {
|
||||||
setSelectedPresetName(stackPresets[0]);
|
setSelectedPresetName(stackPresets[0]);
|
||||||
@@ -123,12 +114,10 @@ function App() {
|
|||||||
dropTargetLayerId={dropTargetLayerId}
|
dropTargetLayerId={dropTargetLayerId}
|
||||||
expandedLayerIds={expandedLayerIds}
|
expandedLayerIds={expandedLayerIds}
|
||||||
layers={layers}
|
layers={layers}
|
||||||
pendingShaderId={pendingShaderId}
|
|
||||||
setAppState={setAppState}
|
setAppState={setAppState}
|
||||||
setDragLayerId={setDragLayerId}
|
setDragLayerId={setDragLayerId}
|
||||||
setDropTargetLayerId={setDropTargetLayerId}
|
setDropTargetLayerId={setDropTargetLayerId}
|
||||||
setExpandedLayerIds={setExpandedLayerIds}
|
setExpandedLayerIds={setExpandedLayerIds}
|
||||||
setPendingShaderId={setPendingShaderId}
|
|
||||||
shaders={shaders}
|
shaders={shaders}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { GripVertical, Trash2 } from "lucide-react";
|
import { EyeOff, GripVertical, RotateCcw, SlidersHorizontal, Trash2 } from "lucide-react";
|
||||||
|
|
||||||
import { postJson } from "../api/controlApi";
|
import { postJson } from "../api/controlApi";
|
||||||
import { ParameterField } from "./ParameterField";
|
import { ParameterField } from "./ParameterField";
|
||||||
@@ -71,11 +71,13 @@ export function LayerCard({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<EyeOff size={15} strokeWidth={1.8} aria-hidden="true" />
|
||||||
<span>Bypass</span>
|
<span>Bypass</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<button type="button" onClick={() => onToggleExpanded(layer.id)}>
|
<button type="button" className="button-with-icon" onClick={() => onToggleExpanded(layer.id)}>
|
||||||
{expanded ? "Hide" : "Controls"}
|
<SlidersHorizontal size={16} strokeWidth={1.9} aria-hidden="true" />
|
||||||
|
<span>{expanded ? "Hide" : "Controls"}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -116,10 +118,12 @@ export function LayerCard({
|
|||||||
<h3>Parameters</h3>
|
<h3>Parameters</h3>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
className="button-with-icon"
|
||||||
disabled={layer.parameters.length === 0}
|
disabled={layer.parameters.length === 0}
|
||||||
onClick={() => postJson("/api/layers/reset-parameters", { layerId: layer.id })}
|
onClick={() => postJson("/api/layers/reset-parameters", { layerId: layer.id })}
|
||||||
>
|
>
|
||||||
Reset
|
<RotateCcw size={16} strokeWidth={1.9} aria-hidden="true" />
|
||||||
|
<span>Reset</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ export function LayerStack({
|
|||||||
dropTargetLayerId,
|
dropTargetLayerId,
|
||||||
expandedLayerIds,
|
expandedLayerIds,
|
||||||
layers,
|
layers,
|
||||||
pendingShaderId,
|
|
||||||
setAppState,
|
setAppState,
|
||||||
setDragLayerId,
|
setDragLayerId,
|
||||||
setDropTargetLayerId,
|
setDropTargetLayerId,
|
||||||
setExpandedLayerIds,
|
setExpandedLayerIds,
|
||||||
setPendingShaderId,
|
|
||||||
shaders,
|
shaders,
|
||||||
}) {
|
}) {
|
||||||
const expandedSet = new Set(expandedLayerIds);
|
const expandedSet = new Set(expandedLayerIds);
|
||||||
@@ -118,27 +116,13 @@ export function LayerStack({
|
|||||||
<span className="layer-card__index">+</span>
|
<span className="layer-card__index">+</span>
|
||||||
<div className="layer-card__title layer-card__title--static">Add Layer</div>
|
<div className="layer-card__title layer-card__title--static">Add Layer</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="layer-card__actions">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
disabled={!pendingShaderId}
|
|
||||||
onClick={() => {
|
|
||||||
if (pendingShaderId) {
|
|
||||||
postJson("/api/layers/add", { shaderId: pendingShaderId });
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Add
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="layer-card__body">
|
<div className="layer-card__body">
|
||||||
<div className="layer-card__field">
|
<div className="layer-card__field">
|
||||||
<ShaderPicker
|
<ShaderPicker
|
||||||
id="add-layer"
|
id="add-layer"
|
||||||
shaders={shaders}
|
shaders={shaders}
|
||||||
value={pendingShaderId}
|
onAdd={(shaderId) => postJson("/api/layers/add", { shaderId })}
|
||||||
onChange={setPendingShaderId}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Wheel from "@uiw/react-color-wheel";
|
import Wheel from "@uiw/react-color-wheel";
|
||||||
import { hsvaToRgba, rgbaToHsva } from "@uiw/color-convert";
|
import { hsvaToRgba, rgbaToHsva } from "@uiw/color-convert";
|
||||||
import { Copy, RotateCcw } from "lucide-react";
|
import { Copy, RotateCcw, Zap } from "lucide-react";
|
||||||
|
|
||||||
import { useThrottledParameterValue } from "../hooks/useThrottledParameterValue";
|
import { useThrottledParameterValue } from "../hooks/useThrottledParameterValue";
|
||||||
import { ParameterValueDisplay } from "./ParameterValueDisplay";
|
import { ParameterValueDisplay } from "./ParameterValueDisplay";
|
||||||
@@ -325,10 +325,11 @@ export function ParameterField({ layer, parameter, onParameterChange }) {
|
|||||||
{header}
|
{header}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="parameter__trigger"
|
className="button-with-icon parameter__trigger"
|
||||||
onClick={() => sendValue(triggerCount + 1)}
|
onClick={() => sendValue(triggerCount + 1)}
|
||||||
>
|
>
|
||||||
Trigger
|
<Zap size={16} strokeWidth={1.9} aria-hidden="true" />
|
||||||
|
<span>Trigger</span>
|
||||||
</button>
|
</button>
|
||||||
<ParameterValueDisplay parameterType={parameter.type} value={appliedValue} pending={isPending} />
|
<ParameterValueDisplay parameterType={parameter.type} value={appliedValue} pending={isPending} />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { ChevronDown, Search } from "lucide-react";
|
import Fuse from "fuse.js";
|
||||||
|
import { Plus, Search } from "lucide-react";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
|
|
||||||
function matchesShader(shader, query) {
|
const shaderSearchOptions = {
|
||||||
const normalizedQuery = query.trim().toLowerCase();
|
threshold: 0.38,
|
||||||
if (!normalizedQuery) {
|
ignoreLocation: true,
|
||||||
return true;
|
minMatchCharLength: 2,
|
||||||
}
|
keys: [
|
||||||
|
{ name: "name", weight: 0.45 },
|
||||||
return [shader.name, shader.id, shader.category, shader.description, shader.error]
|
{ name: "id", weight: 0.25 },
|
||||||
.filter(Boolean)
|
{ name: "category", weight: 0.15 },
|
||||||
.some((value) => value.toLowerCase().includes(normalizedQuery));
|
{ name: "description", weight: 0.1 },
|
||||||
}
|
{ name: "error", weight: 0.05 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
function shaderSummary(shader) {
|
function shaderSummary(shader) {
|
||||||
if (!shader) {
|
if (!shader) {
|
||||||
@@ -37,46 +40,32 @@ function ShaderOptionContent({ shader }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ShaderPicker({ id, label = "Shader", shaders, value, onChange }) {
|
export function ShaderPicker({ id, label = "Shader", shaders, onAdd }) {
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
|
|
||||||
const filteredShaders = useMemo(
|
const shaderSearch = useMemo(
|
||||||
() => shaders.filter((shader) => matchesShader(shader, query)),
|
() => new Fuse(shaders, shaderSearchOptions),
|
||||||
[query, shaders],
|
[shaders],
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedShader = shaders.find((shader) => shader.id === value);
|
const filteredShaders = useMemo(
|
||||||
|
() => {
|
||||||
|
const normalizedQuery = query.trim();
|
||||||
|
if (!normalizedQuery) {
|
||||||
|
return shaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shaderSearch.search(normalizedQuery).map((result) => result.item);
|
||||||
|
},
|
||||||
|
[query, shaderSearch, shaders],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="shader-picker">
|
<div className="shader-picker">
|
||||||
<div className="shader-picker__topline">
|
<div className="shader-picker__topline">
|
||||||
<label id={`${id}-label`}>{label}</label>
|
<label id={`${id}-label`}>{label}</label>
|
||||||
{selectedShader ? <span className="shader-picker__selected">{selectedShader.name}</span> : null}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="shader-picker__trigger"
|
|
||||||
aria-labelledby={`${id}-label`}
|
|
||||||
aria-expanded={open}
|
|
||||||
onClick={() => setOpen((current) => !current)}
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<span className="shader-picker__option-head">
|
|
||||||
<span className="shader-picker__name">{selectedShader?.name ?? "Choose shader"}</span>
|
|
||||||
{selectedShader?.available === false ? (
|
|
||||||
<span className="shader-picker__category shader-picker__category--error">Error</span>
|
|
||||||
) : selectedShader?.category ? (
|
|
||||||
<span className="shader-picker__category">{selectedShader.category}</span>
|
|
||||||
) : null}
|
|
||||||
</span>
|
|
||||||
<span className="shader-picker__meta">{shaderSummary(selectedShader)}</span>
|
|
||||||
</span>
|
|
||||||
<ChevronDown size={16} strokeWidth={1.75} aria-hidden="true" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{open ? (
|
|
||||||
<div className="shader-picker__popover">
|
<div className="shader-picker__popover">
|
||||||
<div className="shader-picker__search">
|
<div className="shader-picker__search">
|
||||||
<Search size={16} strokeWidth={1.75} aria-hidden="true" />
|
<Search size={16} strokeWidth={1.75} aria-hidden="true" />
|
||||||
@@ -89,34 +78,40 @@ export function ShaderPicker({ id, label = "Shader", shaders, value, onChange })
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="shader-picker__list" role="listbox" aria-label={label}>
|
<div className="shader-picker__list" role="list" aria-labelledby={`${id}-label`}>
|
||||||
{filteredShaders.length > 0 ? (
|
{filteredShaders.length > 0 ? (
|
||||||
filteredShaders.map((shader) => (
|
filteredShaders.map((shader) => (
|
||||||
<button
|
<div
|
||||||
key={shader.id}
|
key={shader.id}
|
||||||
|
className={`shader-picker__option${shader.available === false ? " shader-picker__option--unavailable" : ""}`}
|
||||||
|
role="listitem"
|
||||||
|
>
|
||||||
|
<span className="shader-picker__option-copy">
|
||||||
|
<ShaderOptionContent shader={shader} />
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`shader-picker__option${shader.id === value ? " shader-picker__option--selected" : ""}${shader.available === false ? " shader-picker__option--unavailable" : ""}`}
|
className="icon-button shader-picker__add"
|
||||||
role="option"
|
title={`Add ${shader.name}`}
|
||||||
aria-selected={shader.id === value}
|
aria-label={`Add ${shader.name}`}
|
||||||
disabled={shader.available === false}
|
disabled={shader.available === false}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (shader.available === false) {
|
if (shader.available === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onChange(shader.id);
|
onAdd(shader.id);
|
||||||
setOpen(false);
|
|
||||||
setQuery("");
|
setQuery("");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ShaderOptionContent shader={shader} />
|
<Plus size={16} strokeWidth={1.9} />
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<div className="shader-picker__empty">No shaders found</div>
|
<div className="shader-picker__empty">No shaders found</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { FolderOpen, RefreshCw, Save } from "lucide-react";
|
||||||
|
|
||||||
import { postJson } from "../api/controlApi";
|
import { postJson } from "../api/controlApi";
|
||||||
|
|
||||||
export function StackPresetToolbar({
|
export function StackPresetToolbar({
|
||||||
@@ -14,8 +16,13 @@ export function StackPresetToolbar({
|
|||||||
<h3>Stack presets</h3>
|
<h3>Stack presets</h3>
|
||||||
<p className="muted">Save or recall the current layer chain.</p>
|
<p className="muted">Save or recall the current layer chain.</p>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" className="stack-panel__reload" onClick={() => postJson("/api/reload", {})}>
|
<button
|
||||||
Reload shader
|
type="button"
|
||||||
|
className="button-with-icon stack-panel__reload"
|
||||||
|
onClick={() => postJson("/api/reload", {})}
|
||||||
|
>
|
||||||
|
<RefreshCw size={16} strokeWidth={1.9} aria-hidden="true" />
|
||||||
|
<span>Reload shader</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -32,6 +39,7 @@ export function StackPresetToolbar({
|
|||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
className="button-with-icon"
|
||||||
disabled={!presetName.trim()}
|
disabled={!presetName.trim()}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const trimmedName = presetName.trim();
|
const trimmedName = presetName.trim();
|
||||||
@@ -44,7 +52,8 @@ export function StackPresetToolbar({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Save
|
<Save size={16} strokeWidth={1.9} aria-hidden="true" />
|
||||||
|
<span>Save</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,6 +75,7 @@ export function StackPresetToolbar({
|
|||||||
</select>
|
</select>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
className="button-with-icon"
|
||||||
disabled={!selectedPresetName}
|
disabled={!selectedPresetName}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (selectedPresetName) {
|
if (selectedPresetName) {
|
||||||
@@ -73,7 +83,8 @@ export function StackPresetToolbar({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Recall
|
<FolderOpen size={16} strokeWidth={1.9} aria-hidden="true" />
|
||||||
|
<span>Recall</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -156,6 +156,17 @@ button:active:not(:disabled) {
|
|||||||
transform: translateY(1px);
|
transform: translateY(1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-with-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-with-icon svg {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
button:disabled,
|
button:disabled,
|
||||||
input:disabled,
|
input:disabled,
|
||||||
select:disabled {
|
select:disabled {
|
||||||
@@ -746,7 +757,7 @@ pre {
|
|||||||
.shader-picker__list {
|
.shader-picker__list {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.45rem;
|
gap: 0.45rem;
|
||||||
max-height: 250px;
|
max-height: min(52vh, 520px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
border: 1px solid var(--app-border);
|
border: 1px solid var(--app-border);
|
||||||
@@ -754,22 +765,22 @@ pre {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.shader-picker__option {
|
.shader-picker__option {
|
||||||
width: 100%;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
|
align-items: center;
|
||||||
min-height: 4.25rem;
|
min-height: 4.25rem;
|
||||||
padding: 0.65rem 0.75rem;
|
padding: 0.65rem 0.75rem;
|
||||||
|
border: 1px solid var(--app-border);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background: #182232;
|
background: #182232;
|
||||||
border-color: var(--app-border);
|
|
||||||
align-content: start;
|
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shader-picker__option--selected {
|
.shader-picker__option-copy {
|
||||||
background: #203b54;
|
display: grid;
|
||||||
border-color: var(--app-primary);
|
gap: 0.25rem;
|
||||||
box-shadow: inset 0 0 0 1px var(--app-primary-soft);
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shader-picker__option--unavailable {
|
.shader-picker__option--unavailable {
|
||||||
@@ -778,16 +789,16 @@ pre {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shader-picker__option:disabled {
|
|
||||||
cursor: not-allowed;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shader-picker__option--unavailable .shader-picker__name,
|
.shader-picker__option--unavailable .shader-picker__name,
|
||||||
.shader-picker__option--unavailable .shader-picker__meta {
|
.shader-picker__option--unavailable .shader-picker__meta {
|
||||||
color: #ffd0cf;
|
color: #ffd0cf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shader-picker__add {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.shader-picker__name,
|
.shader-picker__name,
|
||||||
.shader-picker__meta {
|
.shader-picker__meta {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
@@ -1040,6 +1051,11 @@ pre {
|
|||||||
min-height: 36px;
|
min-height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toggle svg {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
color: var(--app-muted);
|
||||||
|
}
|
||||||
|
|
||||||
.toggle--compact {
|
.toggle--compact {
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user