2026-02-20 21:28:00 -05:00
|
|
|
|
<?php
|
|
|
|
|
|
/**
|
2026-02-20 22:06:53 -05:00
|
|
|
|
* Theme Settings - Custom admin page for configuring colours, fonts,
|
2026-02-20 21:28:00 -05:00
|
|
|
|
* spacing, and border-radius design tokens.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Appearance → Theme Design Settings
|
|
|
|
|
|
*
|
|
|
|
|
|
* @package OTS_Theme
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
|
|
|
|
exit;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Register the admin page ───────────────────────────────────── */
|
|
|
|
|
|
add_action( 'admin_menu', function () {
|
|
|
|
|
|
add_theme_page(
|
|
|
|
|
|
__( 'Theme Design Settings', 'ots-theme' ),
|
|
|
|
|
|
__( 'Theme Design', 'ots-theme' ),
|
|
|
|
|
|
'edit_theme_options',
|
|
|
|
|
|
'oribi-theme-settings',
|
|
|
|
|
|
'oribi_render_settings_page'
|
|
|
|
|
|
);
|
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Enqueue admin-only assets ─────────────────────────────────── */
|
|
|
|
|
|
add_action( 'admin_enqueue_scripts', function ( $hook ) {
|
|
|
|
|
|
|
|
|
|
|
|
if ( 'appearance_page_oribi-theme-settings' !== $hook ) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// WordPress colour picker.
|
|
|
|
|
|
wp_enqueue_style( 'wp-color-picker' );
|
|
|
|
|
|
wp_enqueue_script( 'wp-color-picker' );
|
|
|
|
|
|
|
|
|
|
|
|
// Google Fonts for preview.
|
|
|
|
|
|
wp_enqueue_style(
|
|
|
|
|
|
'oribi-admin-google-fonts',
|
|
|
|
|
|
'https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Roboto:wght@400;700&family=Open+Sans:wght@400;700&family=Poppins:wght@400;600;700&family=Lato:wght@400;700&family=Montserrat:wght@400;600;700&family=Source+Sans+3:wght@400;600;700&family=Nunito:wght@400;600;700&family=Raleway:wght@400;600;700&family=DM+Sans:wght@400;500;700&family=Work+Sans:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap',
|
|
|
|
|
|
[],
|
|
|
|
|
|
null
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// Inline CSS + JS for the settings page.
|
|
|
|
|
|
wp_add_inline_style( 'wp-color-picker', oribi_admin_inline_css() );
|
|
|
|
|
|
wp_add_inline_script( 'wp-color-picker', oribi_admin_inline_js(), 'after' );
|
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Handle form submission ────────────────────────────────────── */
|
|
|
|
|
|
add_action( 'admin_init', function () {
|
|
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
! isset( $_POST['oribi_settings_nonce'] ) ||
|
|
|
|
|
|
! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['oribi_settings_nonce'] ) ), 'oribi_save_settings' )
|
|
|
|
|
|
) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$defaults = oribi_get_theme_defaults();
|
|
|
|
|
|
|
2026-02-20 22:06:53 -05:00
|
|
|
|
// Determine action - save or reset.
|
2026-02-20 21:28:00 -05:00
|
|
|
|
$action = isset( $_POST['oribi_action'] ) ? sanitize_text_field( wp_unslash( $_POST['oribi_action'] ) ) : 'save';
|
|
|
|
|
|
|
|
|
|
|
|
if ( 'reset' === $action ) {
|
|
|
|
|
|
foreach ( $defaults as $key => $value ) {
|
|
|
|
|
|
set_theme_mod( 'oribi_' . $key, $value );
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Sanitize & save each setting.
|
|
|
|
|
|
foreach ( $defaults as $key => $default ) {
|
|
|
|
|
|
$posted = isset( $_POST[ 'oribi_' . $key ] )
|
|
|
|
|
|
? wp_unslash( $_POST[ 'oribi_' . $key ] ) // phpcs:ignore
|
|
|
|
|
|
: $default;
|
|
|
|
|
|
|
|
|
|
|
|
// Determine sanitisation method by key prefix/type.
|
|
|
|
|
|
if ( strpos( $key, 'color_' ) === 0 || strpos( $key, 'dark_' ) === 0 ) {
|
|
|
|
|
|
// Colour values (hex or rgba).
|
|
|
|
|
|
$posted = oribi_sanitize_color( $posted );
|
|
|
|
|
|
} elseif ( strpos( $key, 'font_' ) === 0 ) {
|
|
|
|
|
|
$posted = sanitize_text_field( $posted );
|
|
|
|
|
|
} elseif ( strpos( $key, 'radius_' ) === 0 || strpos( $key, 'container_' ) === 0 || $key === 'wide_size' ) {
|
|
|
|
|
|
$posted = sanitize_text_field( $posted );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$posted = sanitize_text_field( $posted );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
set_theme_mod( 'oribi_' . $key, $posted );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Regenerate CSS.
|
|
|
|
|
|
$result = oribi_write_generated_css();
|
|
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
|
|
|
|
add_settings_error( 'oribi_settings', 'css_error', $result->get_error_message(), 'error' );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$msg = 'reset' === $action
|
|
|
|
|
|
? __( 'Settings reset to defaults. CSS regenerated.', 'ots-theme' )
|
|
|
|
|
|
: __( 'Settings saved. CSS regenerated.', 'ots-theme' );
|
|
|
|
|
|
add_settings_error( 'oribi_settings', 'saved', $msg, 'success' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Store errors/notices in transient so they survive the redirect.
|
|
|
|
|
|
set_transient( 'oribi_settings_notices', get_settings_errors( 'oribi_settings' ), 30 );
|
|
|
|
|
|
|
|
|
|
|
|
// PRG redirect.
|
|
|
|
|
|
wp_safe_redirect( admin_url( 'themes.php?page=oribi-theme-settings' ) );
|
|
|
|
|
|
exit;
|
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Sanitize a colour value (hex or rgba).
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $value Raw colour value.
|
|
|
|
|
|
* @return string Sanitized colour.
|
|
|
|
|
|
*/
|
|
|
|
|
|
function oribi_sanitize_color( $value ) {
|
|
|
|
|
|
$value = trim( $value );
|
|
|
|
|
|
|
|
|
|
|
|
// Allow rgba(...) values (used for dark mode light tints).
|
|
|
|
|
|
if ( preg_match( '/^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(,\s*[\d.]+\s*)?\)$/', $value ) ) {
|
|
|
|
|
|
return $value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Standard hex.
|
|
|
|
|
|
return sanitize_hex_color( $value ) ?? '#000000';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Render the settings page ──────────────────────────────────── */
|
|
|
|
|
|
function oribi_render_settings_page() {
|
|
|
|
|
|
|
|
|
|
|
|
// Seed defaults on first visit.
|
|
|
|
|
|
oribi_maybe_seed_defaults();
|
|
|
|
|
|
|
|
|
|
|
|
// Show any saved notices.
|
|
|
|
|
|
$notices = get_transient( 'oribi_settings_notices' );
|
|
|
|
|
|
if ( $notices ) {
|
|
|
|
|
|
delete_transient( 'oribi_settings_notices' );
|
|
|
|
|
|
foreach ( $notices as $notice ) {
|
|
|
|
|
|
printf(
|
|
|
|
|
|
'<div class="notice notice-%s is-dismissible"><p>%s</p></div>',
|
|
|
|
|
|
esc_attr( $notice['type'] ),
|
|
|
|
|
|
esc_html( $notice['message'] )
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$s = 'oribi_get_setting';
|
|
|
|
|
|
$fonts = oribi_get_available_fonts();
|
|
|
|
|
|
|
|
|
|
|
|
?>
|
|
|
|
|
|
<div class="wrap oribi-settings-wrap">
|
|
|
|
|
|
<h1><?php esc_html_e( 'Theme Design Settings', 'ots-theme' ); ?></h1>
|
|
|
|
|
|
<p class="description" style="margin-bottom:24px;">
|
|
|
|
|
|
<?php esc_html_e( 'Customise colours, typography, spacing, and border radii. Changes are applied site-wide via a generated CSS file.', 'ots-theme' ); ?>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<form method="post" id="oribi-settings-form">
|
|
|
|
|
|
<?php wp_nonce_field( 'oribi_save_settings', 'oribi_settings_nonce' ); ?>
|
|
|
|
|
|
<input type="hidden" name="oribi_action" id="oribi-action-field" value="save" />
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Tabs -->
|
|
|
|
|
|
<nav class="oribi-tabs" role="tablist">
|
|
|
|
|
|
<button type="button" class="oribi-tab active" data-tab="colors" role="tab"><?php esc_html_e( 'Colours', 'ots-theme' ); ?></button>
|
|
|
|
|
|
<button type="button" class="oribi-tab" data-tab="dark" role="tab"><?php esc_html_e( 'Dark Mode', 'ots-theme' ); ?></button>
|
|
|
|
|
|
<button type="button" class="oribi-tab" data-tab="typography" role="tab"><?php esc_html_e( 'Typography', 'ots-theme' ); ?></button>
|
|
|
|
|
|
<button type="button" class="oribi-tab" data-tab="spacing" role="tab"><?php esc_html_e( 'Spacing & Layout', 'ots-theme' ); ?></button>
|
|
|
|
|
|
<button type="button" class="oribi-tab" data-tab="radius" role="tab"><?php esc_html_e( 'Border Radius', 'ots-theme' ); ?></button>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="oribi-panels-wrap">
|
|
|
|
|
|
<div class="oribi-panels">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ═══ COLOURS ══════════════════════════════════════ -->
|
|
|
|
|
|
<div class="oribi-panel active" data-panel="colors">
|
|
|
|
|
|
<h2><?php esc_html_e( 'Light Mode Colour Palette', 'ots-theme' ); ?></h2>
|
|
|
|
|
|
<p class="description"><?php esc_html_e( 'These colours apply when dark mode is off.', 'ots-theme' ); ?></p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="oribi-color-grid">
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$light_colors = [
|
|
|
|
|
|
'color_primary' => __( 'Primary', 'ots-theme' ),
|
|
|
|
|
|
'color_primary_dk' => __( 'Primary Dark', 'ots-theme' ),
|
|
|
|
|
|
'color_primary_lt' => __( 'Primary Light', 'ots-theme' ),
|
|
|
|
|
|
'color_accent' => __( 'Accent', 'ots-theme' ),
|
|
|
|
|
|
'color_accent_dk' => __( 'Accent Dark', 'ots-theme' ),
|
|
|
|
|
|
'color_accent_lt' => __( 'Accent Light', 'ots-theme' ),
|
|
|
|
|
|
'color_dark' => __( 'Dark', 'ots-theme' ),
|
|
|
|
|
|
'color_dark_2' => __( 'Dark 2', 'ots-theme' ),
|
|
|
|
|
|
'color_text' => __( 'Text', 'ots-theme' ),
|
|
|
|
|
|
'color_text_muted' => __( 'Text Muted', 'ots-theme' ),
|
|
|
|
|
|
'color_border' => __( 'Border', 'ots-theme' ),
|
|
|
|
|
|
'color_bg' => __( 'Background', 'ots-theme' ),
|
|
|
|
|
|
'color_bg_alt' => __( 'Background Alt', 'ots-theme' ),
|
|
|
|
|
|
];
|
|
|
|
|
|
foreach ( $light_colors as $key => $label ) :
|
|
|
|
|
|
$val = $s( $key );
|
|
|
|
|
|
?>
|
|
|
|
|
|
<div class="oribi-color-field">
|
|
|
|
|
|
<label for="oribi_<?php echo esc_attr( $key ); ?>">
|
|
|
|
|
|
<?php echo esc_html( $label ); ?>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="oribi_<?php echo esc_attr( $key ); ?>"
|
|
|
|
|
|
name="oribi_<?php echo esc_attr( $key ); ?>"
|
|
|
|
|
|
value="<?php echo esc_attr( $val ); ?>"
|
|
|
|
|
|
class="oribi-color-picker"
|
|
|
|
|
|
data-default-color="<?php echo esc_attr( oribi_get_theme_defaults()[ $key ] ); ?>"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ═══ DARK MODE ════════════════════════════════════ -->
|
|
|
|
|
|
<div class="oribi-panel" data-panel="dark">
|
|
|
|
|
|
<h2><?php esc_html_e( 'Dark Mode Colour Palette', 'ots-theme' ); ?></h2>
|
|
|
|
|
|
<p class="description"><?php esc_html_e( 'These colours apply when dark mode is active. Some values support rgba() notation.', 'ots-theme' ); ?></p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="oribi-color-grid">
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$dark_colors = [
|
|
|
|
|
|
'dark_primary' => __( 'Primary', 'ots-theme' ),
|
|
|
|
|
|
'dark_primary_dk' => __( 'Primary Dark', 'ots-theme' ),
|
|
|
|
|
|
'dark_primary_lt' => __( 'Primary Light', 'ots-theme' ),
|
|
|
|
|
|
'dark_accent' => __( 'Accent', 'ots-theme' ),
|
|
|
|
|
|
'dark_accent_dk' => __( 'Accent Dark', 'ots-theme' ),
|
|
|
|
|
|
'dark_accent_lt' => __( 'Accent Light', 'ots-theme' ),
|
|
|
|
|
|
'dark_dark' => __( 'Dark (Text)', 'ots-theme' ),
|
|
|
|
|
|
'dark_dark_2' => __( 'Dark 2 (Text)', 'ots-theme' ),
|
|
|
|
|
|
'dark_text' => __( 'Body Text', 'ots-theme' ),
|
|
|
|
|
|
'dark_text_muted' => __( 'Text Muted', 'ots-theme' ),
|
|
|
|
|
|
'dark_border' => __( 'Border', 'ots-theme' ),
|
|
|
|
|
|
'dark_bg' => __( 'Background', 'ots-theme' ),
|
|
|
|
|
|
'dark_bg_alt' => __( 'Background Alt', 'ots-theme' ),
|
|
|
|
|
|
'dark_bg_dark' => __( 'Background Darker', 'ots-theme' ),
|
|
|
|
|
|
'dark_heading' => __( 'Heading', 'ots-theme' ),
|
|
|
|
|
|
'dark_card_bg' => __( 'Card Background', 'ots-theme' ),
|
|
|
|
|
|
];
|
|
|
|
|
|
foreach ( $dark_colors as $key => $label ) :
|
|
|
|
|
|
$val = $s( $key );
|
|
|
|
|
|
$is_rgba = ( strpos( $val, 'rgba' ) !== false );
|
|
|
|
|
|
?>
|
|
|
|
|
|
<div class="oribi-color-field">
|
|
|
|
|
|
<label for="oribi_<?php echo esc_attr( $key ); ?>">
|
|
|
|
|
|
<?php echo esc_html( $label ); ?>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<?php if ( $is_rgba ) : ?>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="oribi_<?php echo esc_attr( $key ); ?>"
|
|
|
|
|
|
name="oribi_<?php echo esc_attr( $key ); ?>"
|
|
|
|
|
|
value="<?php echo esc_attr( $val ); ?>"
|
|
|
|
|
|
class="regular-text oribi-rgba-input"
|
|
|
|
|
|
placeholder="rgba(r,g,b,a)"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span class="oribi-color-swatch" style="background:<?php echo esc_attr( $val ); ?>;"></span>
|
|
|
|
|
|
<?php else : ?>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
id="oribi_<?php echo esc_attr( $key ); ?>"
|
|
|
|
|
|
name="oribi_<?php echo esc_attr( $key ); ?>"
|
|
|
|
|
|
value="<?php echo esc_attr( $val ); ?>"
|
|
|
|
|
|
class="oribi-color-picker"
|
|
|
|
|
|
data-default-color="<?php echo esc_attr( oribi_get_theme_defaults()[ $key ] ); ?>"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ═══ TYPOGRAPHY ═══════════════════════════════════ -->
|
|
|
|
|
|
<div class="oribi-panel" data-panel="typography">
|
|
|
|
|
|
<h2><?php esc_html_e( 'Typography', 'ots-theme' ); ?></h2>
|
|
|
|
|
|
<p class="description">
|
|
|
|
|
|
<?php
|
|
|
|
|
|
printf(
|
|
|
|
|
|
/* translators: %s = link to Font Library */
|
|
|
|
|
|
esc_html__( 'Select from available fonts below. To add more fonts, use the %s in the Site Editor.', 'ots-theme' ),
|
|
|
|
|
|
'<a href="' . esc_url( admin_url( 'site-editor.php' ) ) . '">' . esc_html__( 'Font Library', 'ots-theme' ) . '</a>'
|
|
|
|
|
|
);
|
|
|
|
|
|
?>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<table class="form-table" role="presentation">
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th scope="row">
|
|
|
|
|
|
<label for="oribi_font_family"><?php esc_html_e( 'Body Font', 'ots-theme' ); ?></label>
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<select id="oribi_font_family" name="oribi_font_family" class="oribi-font-select">
|
|
|
|
|
|
<?php foreach ( $fonts as $f ) : ?>
|
|
|
|
|
|
<option
|
|
|
|
|
|
value="<?php echo esc_attr( $f['slug'] ); ?>"
|
|
|
|
|
|
data-font-family="<?php echo esc_attr( $f['fontFamily'] ); ?>"
|
|
|
|
|
|
<?php selected( $s( 'font_family' ), $f['slug'] ); ?>
|
|
|
|
|
|
>
|
|
|
|
|
|
<?php echo esc_html( $f['name'] ); ?>
|
|
|
|
|
|
</option>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<p class="description"><?php esc_html_e( 'Applied to body text, paragraphs, and UI elements.', 'ots-theme' ); ?></p>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th scope="row">
|
|
|
|
|
|
<label for="oribi_font_heading"><?php esc_html_e( 'Heading Font', 'ots-theme' ); ?></label>
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<select id="oribi_font_heading" name="oribi_font_heading" class="oribi-font-select">
|
2026-02-20 22:06:53 -05:00
|
|
|
|
<option value=""><?php esc_html_e( '- Same as body font -', 'ots-theme' ); ?></option>
|
2026-02-20 21:28:00 -05:00
|
|
|
|
<?php foreach ( $fonts as $f ) : ?>
|
|
|
|
|
|
<option
|
|
|
|
|
|
value="<?php echo esc_attr( $f['slug'] ); ?>"
|
|
|
|
|
|
data-font-family="<?php echo esc_attr( $f['fontFamily'] ); ?>"
|
|
|
|
|
|
<?php selected( $s( 'font_heading' ), $f['slug'] ); ?>
|
|
|
|
|
|
>
|
|
|
|
|
|
<?php echo esc_html( $f['name'] ); ?>
|
|
|
|
|
|
</option>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<p class="description"><?php esc_html_e( 'Applied to h1–h6 headings. Leave blank to use the body font.', 'ots-theme' ); ?></p>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Font preview -->
|
|
|
|
|
|
<div class="oribi-font-preview" id="oribi-font-preview">
|
|
|
|
|
|
<h3 style="margin:0 0 8px;"><?php esc_html_e( 'Font Preview', 'ots-theme' ); ?></h3>
|
|
|
|
|
|
<div class="oribi-font-preview-heading" id="oribi-preview-heading">
|
|
|
|
|
|
The quick brown fox jumps over the lazy dog
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="oribi-font-preview-body" id="oribi-preview-body">
|
|
|
|
|
|
The quick brown fox jumps over the lazy dog. 0123456789
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ═══ SPACING & LAYOUT ═════════════════════════════ -->
|
|
|
|
|
|
<div class="oribi-panel" data-panel="spacing">
|
|
|
|
|
|
<h2><?php esc_html_e( 'Spacing & Layout', 'ots-theme' ); ?></h2>
|
|
|
|
|
|
|
|
|
|
|
|
<table class="form-table" role="presentation">
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th scope="row">
|
|
|
|
|
|
<label for="oribi_container_max"><?php esc_html_e( 'Container Max Width (px)', 'ots-theme' ); ?></label>
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<input type="number" id="oribi_container_max" name="oribi_container_max"
|
|
|
|
|
|
value="<?php echo esc_attr( $s( 'container_max' ) ); ?>"
|
|
|
|
|
|
min="600" max="2400" step="10" class="small-text" />
|
|
|
|
|
|
<p class="description"><?php esc_html_e( 'Maximum width of the main content area (default: 1200).', 'ots-theme' ); ?></p>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th scope="row">
|
|
|
|
|
|
<label for="oribi_wide_size"><?php esc_html_e( 'Wide Block Width (px)', 'ots-theme' ); ?></label>
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<input type="number" id="oribi_wide_size" name="oribi_wide_size"
|
|
|
|
|
|
value="<?php echo esc_attr( $s( 'wide_size' ) ); ?>"
|
|
|
|
|
|
min="800" max="3000" step="10" class="small-text" />
|
|
|
|
|
|
<p class="description"><?php esc_html_e( 'Width of "wide" aligned blocks (default: 1536).', 'ots-theme' ); ?></p>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th scope="row"><?php esc_html_e( 'Horizontal Padding', 'ots-theme' ); ?></th>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<label>
|
|
|
|
|
|
<?php esc_html_e( 'Min:', 'ots-theme' ); ?>
|
|
|
|
|
|
<input type="number" name="oribi_container_pad_min"
|
|
|
|
|
|
value="<?php echo esc_attr( $s( 'container_pad_min' ) ); ?>"
|
|
|
|
|
|
min="0" max="10" step="0.25" class="small-text" /> rem
|
|
|
|
|
|
</label>
|
|
|
|
|
|
|
|
|
|
|
|
<label>
|
|
|
|
|
|
<?php esc_html_e( 'Max:', 'ots-theme' ); ?>
|
|
|
|
|
|
<input type="number" name="oribi_container_pad_max"
|
|
|
|
|
|
value="<?php echo esc_attr( $s( 'container_pad_max' ) ); ?>"
|
|
|
|
|
|
min="0" max="10" step="0.25" class="small-text" /> rem
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<p class="description"><?php esc_html_e( 'Responsive horizontal padding using clamp(min, 5vw, max). Default: 1rem – 2rem.', 'ots-theme' ); ?></p>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ═══ BORDER RADIUS ════════════════════════════════ -->
|
|
|
|
|
|
<div class="oribi-panel" data-panel="radius">
|
|
|
|
|
|
<h2><?php esc_html_e( 'Border Radius', 'ots-theme' ); ?></h2>
|
|
|
|
|
|
<p class="description"><?php esc_html_e( 'Four preset sizes used across all blocks. Values in pixels.', 'ots-theme' ); ?></p>
|
|
|
|
|
|
|
|
|
|
|
|
<table class="form-table" role="presentation">
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$radii = [
|
|
|
|
|
|
'radius_sm' => [ 'SM', __( 'Buttons, badges, small elements', 'ots-theme' ) ],
|
|
|
|
|
|
'radius_md' => [ 'MD', __( 'Cards, inputs, mid-size components', 'ots-theme' ) ],
|
|
|
|
|
|
'radius_lg' => [ 'LG', __( 'Sections, larger surfaces', 'ots-theme' ) ],
|
|
|
|
|
|
'radius_xl' => [ 'XL', __( 'Pills, fully rounded elements', 'ots-theme' ) ],
|
|
|
|
|
|
];
|
|
|
|
|
|
foreach ( $radii as $key => $info ) :
|
|
|
|
|
|
?>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th scope="row">
|
|
|
|
|
|
<label for="oribi_<?php echo esc_attr( $key ); ?>">
|
|
|
|
|
|
<?php echo esc_html( $info[0] ); ?>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<td>
|
|
|
|
|
|
<input type="number" id="oribi_<?php echo esc_attr( $key ); ?>"
|
|
|
|
|
|
name="oribi_<?php echo esc_attr( $key ); ?>"
|
|
|
|
|
|
value="<?php echo esc_attr( $s( $key ) ); ?>"
|
|
|
|
|
|
min="0" max="100" step="1" class="small-text" /> px
|
|
|
|
|
|
<span class="oribi-radius-preview" style="border-radius:<?php echo esc_attr( $s( $key ) ); ?>px;"></span>
|
|
|
|
|
|
<p class="description"><?php echo esc_html( $info[1] ); ?></p>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div><!-- .oribi-panels -->
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ═══ LIVE PREVIEW SIDEBAR ═════════════════════════ -->
|
|
|
|
|
|
<aside class="oribi-preview-sidebar" id="oribi-preview-sidebar">
|
|
|
|
|
|
<h3><?php esc_html_e( 'Preview', 'ots-theme' ); ?></h3>
|
|
|
|
|
|
<div class="oribi-preview-card" id="oribi-preview-card">
|
|
|
|
|
|
<div class="oribi-preview-hero" id="preview-hero">
|
|
|
|
|
|
<h2 id="preview-hero-title"><?php esc_html_e( 'Hero Heading', 'ots-theme' ); ?></h2>
|
|
|
|
|
|
<p id="preview-hero-text"><?php esc_html_e( 'Body text preview. The quick brown fox jumps over the lazy dog.', 'ots-theme' ); ?></p>
|
|
|
|
|
|
<button id="preview-btn-primary"><?php esc_html_e( 'Primary Button', 'ots-theme' ); ?></button>
|
|
|
|
|
|
<button id="preview-btn-accent"><?php esc_html_e( 'Accent Button', 'ots-theme' ); ?></button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="oribi-preview-section" id="preview-card-section">
|
|
|
|
|
|
<div class="oribi-prev-card" id="preview-card-1">
|
|
|
|
|
|
<h4><?php esc_html_e( 'Card Title', 'ots-theme' ); ?></h4>
|
|
|
|
|
|
<p><?php esc_html_e( 'Card body text with muted small text below.', 'ots-theme' ); ?></p>
|
|
|
|
|
|
<small><?php esc_html_e( 'Muted text', 'ots-theme' ); ?></small>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</aside>
|
|
|
|
|
|
</div><!-- .oribi-panels-wrap -->
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Actions -->
|
|
|
|
|
|
<div class="oribi-actions">
|
|
|
|
|
|
<?php submit_button( __( 'Save Changes', 'ots-theme' ), 'primary', 'submit', false ); ?>
|
|
|
|
|
|
<button type="button" id="oribi-reset-btn" class="button button-secondary">
|
|
|
|
|
|
<?php esc_html_e( 'Reset to Defaults', 'ots-theme' ); ?>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Inline CSS for the admin page ─────────────────────────────── */
|
|
|
|
|
|
function oribi_admin_inline_css() {
|
|
|
|
|
|
return <<<'CSS'
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Settings page layout ── */
|
|
|
|
|
|
.oribi-settings-wrap { max-width: 1400px; }
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Tabs ── */
|
|
|
|
|
|
.oribi-tabs {
|
|
|
|
|
|
display: flex; gap: 0; border-bottom: 2px solid #c3c4c7;
|
|
|
|
|
|
margin-bottom: 0; background: #f0f0f1;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-tab {
|
|
|
|
|
|
padding: 12px 20px; border: none; background: transparent;
|
|
|
|
|
|
cursor: pointer; font-size: 14px; font-weight: 500;
|
|
|
|
|
|
border-bottom: 2px solid transparent; margin-bottom: -2px;
|
|
|
|
|
|
color: #50575e; transition: all .15s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-tab:hover { color: #1d2327; background: #fff; }
|
|
|
|
|
|
.oribi-tab.active {
|
|
|
|
|
|
color: #1d2327; background: #fff;
|
|
|
|
|
|
border-bottom-color: #2271b1; font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Panels + Preview sidebar ── */
|
|
|
|
|
|
.oribi-panels-wrap {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 1fr 320px;
|
|
|
|
|
|
gap: 24px;
|
|
|
|
|
|
margin-top: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
@media (max-width: 1100px) {
|
|
|
|
|
|
.oribi-panels-wrap { grid-template-columns: 1fr; }
|
|
|
|
|
|
.oribi-preview-sidebar { order: -1; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.oribi-panel { display: none; padding: 24px; background: #fff; border: 1px solid #c3c4c7; border-top: none; }
|
|
|
|
|
|
.oribi-panel.active { display: block; }
|
|
|
|
|
|
.oribi-panel h2 { margin-top: 0; }
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Colour grid ── */
|
|
|
|
|
|
.oribi-color-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
|
|
|
|
|
gap: 16px; margin-top: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-color-field { display: flex; flex-direction: column; gap: 4px; }
|
|
|
|
|
|
.oribi-color-field label { font-weight: 500; font-size: 13px; }
|
|
|
|
|
|
.oribi-rgba-input { font-family: monospace; font-size: 13px; }
|
|
|
|
|
|
.oribi-color-swatch {
|
|
|
|
|
|
display: inline-block; width: 28px; height: 28px;
|
|
|
|
|
|
border: 1px solid #ddd; border-radius: 4px; margin-top: 4px;
|
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Font preview ── */
|
|
|
|
|
|
.oribi-font-preview {
|
|
|
|
|
|
margin-top: 24px; padding: 20px;
|
|
|
|
|
|
background: #f9f9f9; border: 1px solid #ddd; border-radius: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-font-preview-heading {
|
|
|
|
|
|
font-size: 28px; font-weight: 700; line-height: 1.3; margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-font-preview-body {
|
|
|
|
|
|
font-size: 16px; line-height: 1.65; color: #555;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Radius preview ── */
|
|
|
|
|
|
.oribi-radius-preview {
|
|
|
|
|
|
display: inline-block; width: 40px; height: 40px;
|
|
|
|
|
|
background: #2271b1; vertical-align: middle; margin-left: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Preview sidebar ── */
|
|
|
|
|
|
.oribi-preview-sidebar {
|
|
|
|
|
|
position: sticky; top: 32px; align-self: start;
|
|
|
|
|
|
padding: 20px; background: #fff; border: 1px solid #c3c4c7;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-preview-sidebar h3 { margin-top: 0; }
|
|
|
|
|
|
.oribi-preview-card { border-radius: 8px; overflow: hidden; }
|
|
|
|
|
|
.oribi-preview-hero {
|
|
|
|
|
|
padding: 24px 16px; text-align: center;
|
|
|
|
|
|
transition: all .2s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-preview-hero h2 { margin: 0 0 8px; font-size: 22px; }
|
|
|
|
|
|
.oribi-preview-hero p { font-size: 14px; margin: 0 0 16px; }
|
|
|
|
|
|
.oribi-preview-hero button {
|
|
|
|
|
|
padding: 8px 16px; border: none; color: #fff;
|
|
|
|
|
|
border-radius: 6px; cursor: default; margin: 4px;
|
|
|
|
|
|
font-size: 13px; font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-preview-section {
|
|
|
|
|
|
padding: 16px; transition: all .2s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-prev-card {
|
|
|
|
|
|
padding: 16px; border: 1px solid #e2e8f0;
|
|
|
|
|
|
transition: all .2s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-prev-card h4 { margin: 0 0 6px; font-size: 15px; }
|
|
|
|
|
|
.oribi-prev-card p { margin: 0 0 4px; font-size: 13px; }
|
|
|
|
|
|
.oribi-prev-card small { font-size: 12px; }
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Actions bar ── */
|
|
|
|
|
|
.oribi-actions {
|
|
|
|
|
|
display: flex; align-items: center; gap: 12px;
|
|
|
|
|
|
margin-top: 24px; padding-top: 16px;
|
|
|
|
|
|
border-top: 1px solid #c3c4c7;
|
|
|
|
|
|
}
|
|
|
|
|
|
.oribi-actions .button-primary { margin: 0 !important; }
|
|
|
|
|
|
|
|
|
|
|
|
CSS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Inline JS for the admin page ──────────────────────────────── */
|
|
|
|
|
|
function oribi_admin_inline_js() {
|
|
|
|
|
|
return <<<'JS'
|
|
|
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Tabs ── */
|
|
|
|
|
|
document.querySelectorAll('.oribi-tab').forEach(function(tab) {
|
|
|
|
|
|
tab.addEventListener('click', function() {
|
|
|
|
|
|
document.querySelectorAll('.oribi-tab').forEach(function(t) { t.classList.remove('active'); });
|
|
|
|
|
|
document.querySelectorAll('.oribi-panel').forEach(function(p) { p.classList.remove('active'); });
|
|
|
|
|
|
tab.classList.add('active');
|
|
|
|
|
|
var panel = document.querySelector('[data-panel="' + tab.dataset.tab + '"]');
|
|
|
|
|
|
if (panel) panel.classList.add('active');
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Colour pickers ── */
|
|
|
|
|
|
if (typeof jQuery !== 'undefined' && jQuery.fn.wpColorPicker) {
|
|
|
|
|
|
jQuery('.oribi-color-picker').wpColorPicker({
|
|
|
|
|
|
change: debounce(updatePreview, 150),
|
|
|
|
|
|
clear: debounce(updatePreview, 150)
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Font preview ── */
|
|
|
|
|
|
document.querySelectorAll('.oribi-font-select').forEach(function(sel) {
|
|
|
|
|
|
sel.addEventListener('change', updateFontPreview);
|
|
|
|
|
|
});
|
|
|
|
|
|
updateFontPreview();
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Reset button ── */
|
|
|
|
|
|
document.getElementById('oribi-reset-btn').addEventListener('click', function() {
|
|
|
|
|
|
if (confirm('Reset all settings to factory defaults? This cannot be undone.')) {
|
|
|
|
|
|
document.getElementById('oribi-action-field').value = 'reset';
|
|
|
|
|
|
document.getElementById('oribi-settings-form').submit();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/* ── Live preview updater ── */
|
|
|
|
|
|
function updatePreview() {
|
|
|
|
|
|
var get = function(id) {
|
|
|
|
|
|
var el = document.getElementById(id);
|
|
|
|
|
|
if (!el) return '';
|
|
|
|
|
|
// wpColorPicker stores hex in the text input
|
|
|
|
|
|
return el.value || '';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var hero = document.getElementById('preview-hero');
|
|
|
|
|
|
var card = document.getElementById('preview-card-1');
|
|
|
|
|
|
var section = document.getElementById('preview-card-section');
|
|
|
|
|
|
var btnP = document.getElementById('preview-btn-primary');
|
|
|
|
|
|
var btnA = document.getElementById('preview-btn-accent');
|
|
|
|
|
|
var heroTitle = document.getElementById('preview-hero-title');
|
|
|
|
|
|
var heroText = document.getElementById('preview-hero-text');
|
|
|
|
|
|
|
|
|
|
|
|
if (hero) {
|
2026-02-20 22:06:53 -05:00
|
|
|
|
hero.style.backgroundColor = get('oribi_color_dark') || '#111111';
|
2026-02-20 21:28:00 -05:00
|
|
|
|
if (heroTitle) heroTitle.style.color = '#fff';
|
|
|
|
|
|
if (heroText) heroText.style.color = 'rgba(255,255,255,.8)';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (btnP) {
|
2026-02-20 22:06:53 -05:00
|
|
|
|
btnP.style.backgroundColor = get('oribi_color_primary') || '#004225';
|
2026-02-20 21:28:00 -05:00
|
|
|
|
btnP.style.borderRadius = (get('oribi_radius_sm') || '6') + 'px';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (btnA) {
|
2026-02-20 22:06:53 -05:00
|
|
|
|
btnA.style.backgroundColor = get('oribi_color_accent') || '#4CAF50';
|
2026-02-20 21:28:00 -05:00
|
|
|
|
btnA.style.borderRadius = (get('oribi_radius_sm') || '6') + 'px';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (section) {
|
2026-02-20 22:06:53 -05:00
|
|
|
|
section.style.backgroundColor = get('oribi_color_bg_alt') || '#F5F5F5';
|
2026-02-20 21:28:00 -05:00
|
|
|
|
}
|
|
|
|
|
|
if (card) {
|
|
|
|
|
|
card.style.backgroundColor = get('oribi_color_bg') || '#fff';
|
2026-02-20 22:06:53 -05:00
|
|
|
|
card.style.borderColor = get('oribi_color_border') || '#E0E0E0';
|
|
|
|
|
|
card.style.borderRadius = (get('oribi_radius_md') || '10') + 'px';
|
2026-02-20 21:28:00 -05:00
|
|
|
|
var h4 = card.querySelector('h4');
|
2026-02-20 22:06:53 -05:00
|
|
|
|
if (h4) h4.style.color = get('oribi_color_dark') || '#111111';
|
2026-02-20 21:28:00 -05:00
|
|
|
|
var p = card.querySelector('p');
|
2026-02-20 22:06:53 -05:00
|
|
|
|
if (p) p.style.color = get('oribi_color_text') || '#333333';
|
2026-02-20 21:28:00 -05:00
|
|
|
|
var sm = card.querySelector('small');
|
2026-02-20 22:06:53 -05:00
|
|
|
|
if (sm) sm.style.color = get('oribi_color_text_muted') || '#666666';
|
2026-02-20 21:28:00 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Radius previews.
|
|
|
|
|
|
document.querySelectorAll('.oribi-radius-preview').forEach(function(el) {
|
|
|
|
|
|
var inp = el.parentElement.querySelector('input[type="number"]');
|
|
|
|
|
|
if (inp) el.style.borderRadius = inp.value + 'px';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function updateFontPreview() {
|
|
|
|
|
|
var bodySelect = document.getElementById('oribi_font_family');
|
|
|
|
|
|
var headSelect = document.getElementById('oribi_font_heading');
|
|
|
|
|
|
var previewHead = document.getElementById('oribi-preview-heading');
|
|
|
|
|
|
var previewBody = document.getElementById('oribi-preview-body');
|
|
|
|
|
|
|
|
|
|
|
|
if (bodySelect && previewBody) {
|
|
|
|
|
|
var opt = bodySelect.options[bodySelect.selectedIndex];
|
|
|
|
|
|
previewBody.style.fontFamily = opt.dataset.fontFamily || 'system-ui';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (headSelect && previewHead) {
|
|
|
|
|
|
var hOpt = headSelect.options[headSelect.selectedIndex];
|
|
|
|
|
|
if (hOpt.value) {
|
|
|
|
|
|
previewHead.style.fontFamily = hOpt.dataset.fontFamily || 'system-ui';
|
|
|
|
|
|
} else if (bodySelect) {
|
|
|
|
|
|
var bOpt = bodySelect.options[bodySelect.selectedIndex];
|
|
|
|
|
|
previewHead.style.fontFamily = bOpt.dataset.fontFamily || 'system-ui';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Also update preview sidebar heading/body fonts.
|
|
|
|
|
|
var heroTitle = document.getElementById('preview-hero-title');
|
|
|
|
|
|
var heroText = document.getElementById('preview-hero-text');
|
|
|
|
|
|
var cardH4 = document.querySelector('.oribi-prev-card h4');
|
|
|
|
|
|
var cardP = document.querySelector('.oribi-prev-card p');
|
|
|
|
|
|
|
|
|
|
|
|
if (headSelect) {
|
|
|
|
|
|
var hf = headSelect.options[headSelect.selectedIndex];
|
|
|
|
|
|
var headingFont = hf.value
|
|
|
|
|
|
? (hf.dataset.fontFamily || 'system-ui')
|
|
|
|
|
|
: (bodySelect ? bodySelect.options[bodySelect.selectedIndex].dataset.fontFamily : 'system-ui');
|
|
|
|
|
|
if (heroTitle) heroTitle.style.fontFamily = headingFont;
|
|
|
|
|
|
if (cardH4) cardH4.style.fontFamily = headingFont;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (bodySelect) {
|
|
|
|
|
|
var bf = bodySelect.options[bodySelect.selectedIndex];
|
|
|
|
|
|
var bodyFont = bf.dataset.fontFamily || 'system-ui';
|
|
|
|
|
|
if (heroText) heroText.style.fontFamily = bodyFont;
|
|
|
|
|
|
if (cardP) cardP.style.fontFamily = bodyFont;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function debounce(fn, ms) {
|
|
|
|
|
|
var timer;
|
|
|
|
|
|
return function() {
|
|
|
|
|
|
clearTimeout(timer);
|
|
|
|
|
|
timer = setTimeout(fn, ms);
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Initial preview render.
|
|
|
|
|
|
updatePreview();
|
|
|
|
|
|
|
|
|
|
|
|
// Attach change listeners to all inputs for live preview.
|
|
|
|
|
|
document.querySelectorAll('input[type="number"]').forEach(function(inp) {
|
|
|
|
|
|
inp.addEventListener('input', debounce(updatePreview, 100));
|
|
|
|
|
|
});
|
|
|
|
|
|
document.querySelectorAll('.oribi-rgba-input').forEach(function(inp) {
|
|
|
|
|
|
inp.addEventListener('input', debounce(updatePreview, 200));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
JS;
|
|
|
|
|
|
}
|