diff --git a/src/styles/editor.scss b/src/styles/editor.scss new file mode 100644 index 0000000..9d97781 --- /dev/null +++ b/src/styles/editor.scss @@ -0,0 +1,68 @@ +/** + * Editor-only styles for the Filtered Image block. + * + * The swatch grid and inspector panel live here — they only need to render + * inside the editor canvas. + * + * @package ImageFilters + */ + +.ksolo-image-filter-panel { + .components-base-control { + margin-bottom: 16px; + } +} + +.ksolo-image-filter-presets { + display: grid; + grid-template-columns: repeat( 4, 1fr ); + gap: 8px; + margin-bottom: 16px; +} + +.ksolo-image-filter-preset { + display: flex; + flex-direction: column; + align-items: center; + padding: 8px; + border: 1px solid #ddd; + border-radius: 4px; + background: #fff; + cursor: pointer; + font-size: 11px; + text-align: center; + transition: border-color 0.15s ease, box-shadow 0.15s ease; + + &:hover { + border-color: #999; + } + + &[aria-pressed='true'] { + border-color: #007cba; + box-shadow: 0 0 0 1px #007cba; + } + + &:focus-visible { + outline: 2px solid #007cba; + outline-offset: 2px; + } +} + +.ksolo-image-filter-preset__swatch { + width: 32px; + height: 32px; + border-radius: 4px; + border: 1px solid rgba(0, 0, 0, 0.1); + margin-bottom: 4px; +} + +.ksolo-image-filter-preview { + text-align: center; + + img { + max-width: 100%; + height: auto; + display: block; + margin: 0 auto; + } +} \ No newline at end of file diff --git a/src/styles/style.scss b/src/styles/style.scss new file mode 100644 index 0000000..fc58727 --- /dev/null +++ b/src/styles/style.scss @@ -0,0 +1,70 @@ +/** + * Filtered Image block — front-end and editor styles. + * + * The .has-filter- classes below MUST stay in sync with PRESETS in + * src/presets.js. The cssFilter value in presets.js is the source of truth; + * the rules below reproduce it. If they diverge, treat it as a bug. + * + * @package ImageFilters + */ + +.wp-block-ksolo-image-filter { + --filter-intensity: 1; + display: inline-block; + margin: 0; + + img { + filter: none; + max-width: 100%; + height: auto; + } +} + +// Intensity scaling via CSS custom property. +// Each filter value is split into calc(...) expressions where the literal +// numbers are replaced with (value * var(--filter-intensity)). For "none" +// (normal preset) there is nothing to scale — the image stays unfiltered. +.wp-block-ksolo-image-filter { + .has-filter-warm img { + filter: saturate( calc( 1.25 * var(--filter-intensity) ) ) + sepia( calc( 0.18 * var(--filter-intensity) ) ) + brightness( calc( 0.05 + 1 * var(--filter-intensity) ) ) + contrast( calc( 0.05 + 1 * var(--filter-intensity) ) ); + } + + .has-filter-cool img { + filter: saturate( calc( 0.05 + 0.95 * var(--filter-intensity) ) ) + hue-rotate( calc( -10deg * var(--filter-intensity) ) ) + brightness( calc( 0.02 + 1 * var(--filter-intensity) ) ) + contrast( calc( 0.05 + 1 * var(--filter-intensity) ) ); + } + + .has-filter-vivid img { + filter: saturate( calc( 0.6 * var(--filter-intensity) ) ) + contrast( calc( 0.15 + 1 * var(--filter-intensity) ) ) + brightness( calc( 0.03 + 1 * var(--filter-intensity) ) ); + } + + .has-filter-fade img { + filter: saturate( calc( 0.15 + 0.85 * var(--filter-intensity) ) ) + contrast( calc( 0.1 + 0.9 * var(--filter-intensity) ) ) + brightness( calc( 0.08 + 1 * var(--filter-intensity) ) ) + sepia( calc( 0.08 * var(--filter-intensity) ) ); + } + + .has-filter-mono img { + filter: grayscale( var(--filter-intensity) ) contrast( calc( 0.05 + 1 * var(--filter-intensity) ) ); + } + + .has-filter-dramatic img { + filter: contrast( calc( 0.35 + 1 * var(--filter-intensity) ) ) + saturate( calc( 0.15 + 1 * var(--filter-intensity) ) ) + brightness( calc( 1 - 0.08 * var(--filter-intensity) ) ); + } + + .has-filter-sepia img { + filter: sepia( calc( 0.85 * var(--filter-intensity) ) ) + saturate( calc( 0.1 + 1 * var(--filter-intensity) ) ) + contrast( calc( 0.05 + 1 * var(--filter-intensity) ) ); + } +} \ No newline at end of file