yoone-snow/yoone-snow.php

388 lines
30 KiB
PHP

<?php
/*
Plugin Name: Yoone Snow
Description: 首页 canvas 雪花效果
Version: 2.0.0
Author: Yoone
*/
if (!defined('ABSPATH')) { exit; }
function yoone_snow_is_enabled() {
$mode = get_option('yoone_snow_display_routes_mode', 'home');
if ($mode === 'all') { return true; }
if ($mode === 'match') {
$routes = get_option('yoone_snow_display_routes', array());
if (is_string($routes)) { $routes = array_filter(array_map('trim', explode("\n", $routes))); }
if (!is_array($routes)) { $routes = array(); }
$requestUri = isset($_SERVER['REQUEST_URI']) ? (string)$_SERVER['REQUEST_URI'] : '';
$path = parse_url($requestUri, PHP_URL_PATH);
$path = is_string($path) ? $path : '';
foreach ($routes as $rule) {
$r = trim((string)$rule);
if ($r === '') { continue; }
if (substr($r, -1) === '*') {
$prefix = substr($r, 0, -1);
if ($prefix === '' || strpos($path, $prefix) === 0) { return true; }
} else { if ($path === $r) { return true; } }
}
return false;
}
return function_exists('is_front_page') ? is_front_page() : false;
}
function yoone_snow_enqueue_assets() {
if (!yoone_snow_is_enabled()) { return; }
$style_handle = 'yoone-snow-style';
$style_src = plugins_url('dist/snow.css', dirname(__FILE__));
$style_ver = @filemtime(plugin_dir_path(dirname(__FILE__)) . 'dist/snow.css');
wp_register_style($style_handle, $style_src, array(), $style_ver ? (string)$style_ver : '2.0.0', 'all');
wp_enqueue_style($style_handle);
$script_handle = 'yoone-snow-script';
$script_src = plugins_url('dist/snow.js', dirname(__FILE__));
$script_ver = @filemtime(plugin_dir_path(dirname(__FILE__)) . 'dist/snow.js');
wp_register_script($script_handle, $script_src, array(), $script_ver ? (string)$script_ver : '2.0.0', true);
wp_enqueue_script($script_handle);
$mixed_items_option = get_option('yoone_snow_mixed_items', array('dot','flake'));
if (is_string($mixed_items_option)) { $mixed_items_option = array_filter(array_map('trim', explode(',', $mixed_items_option))); }
$allowed_shapes = array('dot','flake','yuanbao','coin','santa_hat','candy_cane','christmas_sock','christmas_tree','reindeer','christmas_berry');
$mixed_items_sanitized = array_values(array_unique(array_intersect($mixed_items_option, $allowed_shapes)));
if (empty($mixed_items_sanitized)) { $mixed_items_sanitized = array('dot','flake'); }
$media_ids = get_option('yoone_snow_media_items', array());
if (!is_array($media_ids)) { $media_ids = array(); }
$media_urls = array();
$media_weights_option = get_option('yoone_snow_media_weights', array());
if (!is_array($media_weights_option)) { $media_weights_option = array(); }
$media_weights_by_url = array();
foreach ($media_ids as $mid) {
$url = wp_get_attachment_url(intval($mid));
if ($url) {
$media_urls[] = $url;
$intKey = intval($mid);
$strKey = (string)$intKey;
$w = 1;
if (isset($media_weights_option[$intKey])) { $w = intval($media_weights_option[$intKey]); }
elseif (isset($media_weights_option[$strKey])) { $w = intval($media_weights_option[$strKey]); }
if ($w < 0) { $w = 0; }
$media_weights_by_url[$url] = $w;
}
}
$default_weights = array('dot'=>1,'flake'=>4,'yuanbao'=>1,'coin'=>1,'santa_hat'=>1,'candy_cane'=>1,'christmas_sock'=>1,'christmas_tree'=>1,'reindeer'=>1,'christmas_berry'=>1);
$saved_weights = get_option('yoone_snow_shape_weights', $default_weights);
if (!is_array($saved_weights)) { $saved_weights = array(); }
$shape_weights = array();
foreach ($default_weights as $k => $v) { $val = isset($saved_weights[$k]) ? intval($saved_weights[$k]) : intval($v); if ($val < 0) { $val = 0; } $shape_weights[$k] = $val; }
$size_group = get_option('yoone_snow_size', array('min' => 1.0, 'max' => 3.0));
$radius_min_val = isset($size_group['min']) ? floatval($size_group['min']) : floatval(get_option('yoone_snow_radius_min', 1.0));
$radius_max_val = isset($size_group['max']) ? floatval($size_group['max']) : floatval(get_option('yoone_snow_radius_max', 3.0));
if ($radius_min_val < 0) { $radius_min_val = 0.0; }
if ($radius_max_val < $radius_min_val) { $radius_max_val = $radius_min_val; }
wp_localize_script($script_handle, 'YooneSnowSettings', array(
'selectedShapes' => $mixed_items_sanitized,
'mediaItems' => $media_urls,
'displayDurationSeconds' => intval(get_option('yoone_snow_home_duration', 0)),
'maxCount' => intval(get_option('yoone_snow_max_count', 0)),
'maxCountSmall' => (function(){ $grp = get_option('yoone_snow_max_count_breakpoints', array('small' => 0, 'medium' => 0, 'large' => 0)); $val = isset($grp['small']) ? intval($grp['small']) : 0; return max(0, min(1000, $val)); })(),
'maxCountMedium' => (function(){ $grp = get_option('yoone_snow_max_count_breakpoints', array('small' => 0, 'medium' => 0, 'large' => 0)); $val = isset($grp['medium']) ? intval($grp['medium']) : 0; return max(0, min(1000, $val)); })(),
'maxCountLarge' => (function(){ $grp = get_option('yoone_snow_max_count_breakpoints', array('small' => 0, 'medium' => 0, 'large' => 0)); $val = isset($grp['large']) ? intval($grp['large']) : 0; return max(0, min(1000, $val)); })(),
'radiusMin' => $radius_min_val,
'radiusMax' => $radius_max_val,
'driftMin' => floatval(get_option('yoone_snow_drift_min', 0.4)),
'driftMax' => floatval(get_option('yoone_snow_drift_max', 1.0)),
'swingMin' => floatval(get_option('yoone_snow_swing_min', 0.2)),
'swingMax' => floatval(get_option('yoone_snow_swing_max', 1.0)),
'assetsMap' => array(
'santa_hat' => plugins_url('dist/assets/圣诞雪帽.svg', dirname(__FILE__)),
'candy_cane' => plugins_url('dist/assets/圣诞拐杖.svg', dirname(__FILE__)),
'christmas_sock' => plugins_url('dist/assets/圣诞袜子.svg', dirname(__FILE__)),
'christmas_tree' => plugins_url('dist/assets/圣诞树.svg', dirname(__FILE__)),
'reindeer' => plugins_url('dist/assets/圣诞麋鹿.svg', dirname(__FILE__)),
'christmas_berry' => plugins_url('dist/assets/圣诞果.svg', dirname(__FILE__)),
),
'shapeWeights' => $shape_weights,
'mediaWeights' => $media_weights_by_url,
'emojiItems' => (function(){ $items = get_option('yoone_snow_emoji_items', array()); if (!is_array($items)) { $items = array(); } $clean = array(); foreach ($items as $it) { $s = trim((string)$it); if ($s !== '') { $clean[] = $s; } } return $clean; })(),
'emojiWeights' => (function(){ $map = get_option('yoone_snow_emoji_weights', array()); if (!is_array($map)) { $map = array(); } $clean = array(); foreach ($map as $k => $v) { $key = trim((string)$k); $num = intval($v); if ($key !== '') { if ($num < 0) { $num = 0; } $clean[$key] = $num; } } return $clean; })(),
'textItems' => (function(){ $items = get_option('yoone_snow_text_items', array()); if (!is_array($items)) { $items = array(); } $clean = array(); foreach ($items as $it) { $s = trim((string)$it); if ($s !== '') { $clean[] = $s; } } return $clean; })(),
'textWeights' => (function(){ $map = get_option('yoone_snow_text_weights', array()); if (!is_array($map)) { $map = array(); } $clean = array(); foreach ($map as $k => $v) { $key = trim((string)$k); $num = intval($v); if ($key !== '') { if ($num < 0) { $num = 0; } $clean[$key] = $num; } } return $clean; })(),
));
}
function yoone_snow_admin_enqueue($hook) {
if ($hook !== 'settings_page_yoone_snow') { return; }
wp_enqueue_media();
$bundle_handle = 'yoone-snow-bundle';
$bundle_src = plugins_url('dist/snow.js', dirname(__FILE__));
$bundle_ver = @filemtime(plugin_dir_path(dirname(__FILE__)) . 'dist/snow.js');
wp_register_script($bundle_handle, $bundle_src, array(), $bundle_ver ? (string)$bundle_ver : '2.0.0', true);
wp_enqueue_script($bundle_handle);
wp_localize_script($bundle_handle, 'YooneSnowAdmin', array(
'assetsMap' => array(
'santa_hat' => plugins_url('dist/assets/圣诞雪帽.svg', dirname(__FILE__)),
'candy_cane' => plugins_url('dist/assets/圣诞拐杖.svg', dirname(__FILE__)),
'christmas_sock' => plugins_url('dist/assets/圣诞袜子.svg', dirname(__FILE__)),
'christmas_tree' => plugins_url('dist/assets/圣诞树.svg', dirname(__FILE__)),
'reindeer' => plugins_url('dist/assets/圣诞麋鹿.svg', dirname(__FILE__)),
'christmas_berry' => plugins_url('dist/assets/圣诞果.svg', dirname(__FILE__)),
),
'shapeLabels' => array(
'dot' => __('Dot', 'yoone-snow'),
'flake' => __('Snowflake', 'yoone-snow'),
'yuanbao' => __('Yuanbao', 'yoone-snow'),
'coin' => __('Coin', 'yoone-snow'),
'santa_hat' => __('Santa Hat', 'yoone-snow'),
'candy_cane' => __('Candy Cane', 'yoone-snow'),
'christmas_sock' => __('Christmas Sock', 'yoone-snow'),
'christmas_tree' => __('Christmas Tree', 'yoone-snow'),
'reindeer' => __('Reindeer', 'yoone-snow'),
'christmas_berry' => __('Christmas Berry', 'yoone-snow'),
),
'i18n' => array(
'cancel' => __('Cancel', 'yoone-snow'),
'remove' => __('Remove', 'yoone-snow'),
'select_images_or_svg' => __('Select images or SVG', 'yoone-snow'),
),
));
$admin_script_handle = 'yoone-snow-admin-media';
wp_register_script(
$admin_script_handle,
plugins_url('js/admin-media.js', dirname(__FILE__)),
array($bundle_handle),
(@filemtime(plugin_dir_path(dirname(__FILE__)) . 'js/admin-media.js') ? (string)@filemtime(plugin_dir_path(dirname(__FILE__)) . 'js/admin-media.js') : '2.0.0'),
true
);
wp_enqueue_script($admin_script_handle);
}
function yoone_snow_render_overlay() {
if (!yoone_snow_is_enabled()) { return; }
static $yoone_snow_rendered = false;
if ($yoone_snow_rendered) { return; }
$yoone_snow_rendered = true;
echo '<canvas id="effectiveAppsSnow" aria-hidden="true"></canvas>';
}
add_action('wp_enqueue_scripts', 'yoone_snow_enqueue_assets');
add_action('wp_body_open', 'yoone_snow_render_overlay');
add_action('wp_footer', 'yoone_snow_render_overlay', 100);
function yoone_snow_load_textdomain() { load_plugin_textdomain('yoone-snow', false, dirname(plugin_basename(__FILE__)) . '/languages'); }
add_action('plugins_loaded', 'yoone_snow_load_textdomain');
add_action('admin_enqueue_scripts', 'yoone_snow_admin_enqueue');
function yoone_snow_admin_menu() {
add_options_page(__('Yoone Snow', 'yoone-snow'), __('Yoone Snow', 'yoone-snow'), 'manage_options', 'yoone_snow', 'yoone_snow_render_settings_page');
}
add_action('admin_menu', 'yoone_snow_admin_menu');
function yoone_snow_render_settings_page() {
if (!current_user_can('manage_options')) { wp_die(__('Sorry, you are not allowed to access this page.')); }
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['yoone_snow_save_settings'])) {
check_admin_referer('yoone_snow_save_settings');
$mixed = isset($_POST['yoone_snow_mixed_items']) && is_array($_POST['yoone_snow_mixed_items']) ? array_values(array_filter(array_map('sanitize_text_field', $_POST['yoone_snow_mixed_items']))) : array();
update_option('yoone_snow_mixed_items', $mixed);
$shape_weights = isset($_POST['yoone_snow_shape_weights']) && is_array($_POST['yoone_snow_shape_weights']) ? array_map('intval', $_POST['yoone_snow_shape_weights']) : array();
foreach ($shape_weights as $k => $v) { if (!is_string($k)) { unset($shape_weights[$k]); } else { $shape_weights[$k] = max(0, intval($v)); } }
update_option('yoone_snow_shape_weights', $shape_weights);
$media_ids = isset($_POST['yoone_snow_media_items']) && is_array($_POST['yoone_snow_media_items']) ? array_map('intval', $_POST['yoone_snow_media_items']) : array();
update_option('yoone_snow_media_items', $media_ids);
$media_weights = isset($_POST['yoone_snow_media_weights']) && is_array($_POST['yoone_snow_media_weights']) ? array_map('intval', $_POST['yoone_snow_media_weights']) : array();
foreach ($media_weights as $k => $v) { $media_weights[$k] = max(0, intval($v)); }
update_option('yoone_snow_media_weights', $media_weights);
$emoji_items = isset($_POST['yoone_snow_emoji_items']) && is_array($_POST['yoone_snow_emoji_items']) ? array_values(array_filter(array_map('sanitize_text_field', $_POST['yoone_snow_emoji_items']))) : array();
update_option('yoone_snow_emoji_items', $emoji_items);
$emoji_weights = isset($_POST['yoone_snow_emoji_weights']) && is_array($_POST['yoone_snow_emoji_weights']) ? array_map('intval', $_POST['yoone_snow_emoji_weights']) : array();
foreach ($emoji_weights as $k => $v) { if (!is_string($k)) { unset($emoji_weights[$k]); } else { $emoji_weights[$k] = max(0, intval($v)); } }
update_option('yoone_snow_emoji_weights', $emoji_weights);
$text_items = isset($_POST['yoone_snow_text_items']) && is_array($_POST['yoone_snow_text_items']) ? array_values(array_filter(array_map('sanitize_text_field', $_POST['yoone_snow_text_items']))) : array();
update_option('yoone_snow_text_items', $text_items);
$text_weights = isset($_POST['yoone_snow_text_weights']) && is_array($_POST['yoone_snow_text_weights']) ? array_map('intval', $_POST['yoone_snow_text_weights']) : array();
foreach ($text_weights as $k => $v) { if (!is_string($k)) { unset($text_weights[$k]); } else { $text_weights[$k] = max(0, intval($v)); } }
update_option('yoone_snow_text_weights', $text_weights);
$display_duration = isset($_POST['yoone_snow_home_duration']) ? intval($_POST['yoone_snow_home_duration']) : 0;
update_option('yoone_snow_home_duration', max(0, $display_duration));
$max_count = isset($_POST['yoone_snow_max_count']) ? intval($_POST['yoone_snow_max_count']) : 0;
update_option('yoone_snow_max_count', max(0, min(1000, $max_count)));
$max_breakpoints = array(
'small' => isset($_POST['yoone_snow_max_count_small']) ? intval($_POST['yoone_snow_max_count_small']) : 0,
'medium' => isset($_POST['yoone_snow_max_count_medium']) ? intval($_POST['yoone_snow_max_count_medium']) : 0,
'large' => isset($_POST['yoone_snow_max_count_large']) ? intval($_POST['yoone_snow_max_count_large']) : 0
);
foreach ($max_breakpoints as $k => $v) { $max_breakpoints[$k] = max(0, min(1000, intval($v))); }
update_option('yoone_snow_max_count_breakpoints', $max_breakpoints);
$radius_min = isset($_POST['yoone_snow_radius_min']) ? floatval($_POST['yoone_snow_radius_min']) : 1.0;
$radius_max = isset($_POST['yoone_snow_radius_max']) ? floatval($_POST['yoone_snow_radius_max']) : 3.0;
if ($radius_min < 0) { $radius_min = 0.0; }
if ($radius_max < $radius_min) { $radius_max = $radius_min; }
update_option('yoone_snow_size', array('min' => $radius_min, 'max' => $radius_max));
$drift_min = isset($_POST['yoone_snow_drift_min']) ? floatval($_POST['yoone_snow_drift_min']) : 0.4;
$drift_max = isset($_POST['yoone_snow_drift_max']) ? floatval($_POST['yoone_snow_drift_max']) : 1.0;
update_option('yoone_snow_drift_min', $drift_min);
update_option('yoone_snow_drift_max', $drift_max);
$swing_min = isset($_POST['yoone_snow_swing_min']) ? floatval($_POST['yoone_snow_swing_min']) : 0.2;
$swing_max = isset($_POST['yoone_snow_swing_max']) ? floatval($_POST['yoone_snow_swing_max']) : 1.0;
update_option('yoone_snow_swing_min', $swing_min);
update_option('yoone_snow_swing_max', $swing_max);
$mode = isset($_POST['yoone_snow_display_routes_mode']) ? sanitize_text_field($_POST['yoone_snow_display_routes_mode']) : 'home';
if (!in_array($mode, array('home','all','match'), true)) { $mode = 'home'; }
update_option('yoone_snow_display_routes_mode', $mode);
$routes_raw = isset($_POST['yoone_snow_display_routes']) ? (string)$_POST['yoone_snow_display_routes'] : '';
update_option('yoone_snow_display_routes', $routes_raw);
echo '<div class="updated"><p>' . esc_html__('Settings saved', 'yoone-snow') . '</p></div>';
}
$mixed_items = get_option('yoone_snow_mixed_items', array('dot','flake'));
if (is_string($mixed_items)) { $mixed_items = array_filter(array_map('trim', explode(',', $mixed_items))); }
$shape_weights2 = get_option('yoone_snow_shape_weights', array());
$emoji_items2 = get_option('yoone_snow_emoji_items', array());
$emoji_weights2 = get_option('yoone_snow_emoji_weights', array());
$text_items2 = get_option('yoone_snow_text_items', array());
$text_weights2 = get_option('yoone_snow_text_weights', array());
$media_ids2 = get_option('yoone_snow_media_items', array());
$media_weights2 = get_option('yoone_snow_media_weights', array());
$size_group2 = get_option('yoone_snow_size', array('min' => 1.0, 'max' => 3.0));
$radius_min2 = isset($size_group2['min']) ? floatval($size_group2['min']) : 1.0;
$radius_max2 = isset($size_group2['max']) ? floatval($size_group2['max']) : 3.0;
$home_duration2 = intval(get_option('yoone_snow_home_duration', 0));
$max_count2 = intval(get_option('yoone_snow_max_count', 0));
$breakpoints2 = get_option('yoone_snow_max_count_breakpoints', array('small'=>0,'medium'=>0,'large'=>0));
$display_mode2 = get_option('yoone_snow_display_routes_mode', 'home');
$display_routes2 = get_option('yoone_snow_display_routes', '');
?>
<div class="wrap">
<h1><?php echo esc_html__('Yoone Snow', 'yoone-snow'); ?></h1>
<form method="post" action="">
<?php wp_nonce_field('yoone_snow_save_settings'); ?>
<input type="hidden" name="yoone_snow_save_settings" value="1" />
<h2><?php echo esc_html__('Snow Settings', 'yoone-snow'); ?></h2>
<p><?php echo esc_html__('Add different types of shapes here', 'yoone-snow'); ?></p>
<div id="yooneSnowShapeList" style="display:flex;flex-wrap:wrap;gap:10px;">
<div id="yooneSnowAddUnified" style="border:1px solid #ddd;padding:10px;display:flex;flex-direction:column;gap:8px;min-width:280px;">
<label><?php echo esc_html__('Type', 'yoone-snow'); ?>
<select id="yooneSnowAddTypeSelect">
<option value="default"><?php echo esc_html__('Default', 'yoone-snow'); ?></option>
<option value="emoji"><?php echo esc_html__('Emoji', 'yoone-snow'); ?></option>
<option value="media"><?php echo esc_html__('Media', 'yoone-snow'); ?></option>
<option value="text"><?php echo esc_html__('Text', 'yoone-snow'); ?></option>
</select>
</label>
<div id="yooneSnowAddDefaultPane" style="display:flex;gap:8px;align-items:center;">
<div id="yooneSnowAddShapeLabelPreview" style="display:none;align-items:center;"></div>
<select id="yooneSnowAddShapeSelect" style="min-width:240px;">
<option value=""><?php echo esc_html__('Select shape', 'yoone-snow'); ?></option>
<option value="dot"><?php echo esc_html__('Dot', 'yoone-snow'); ?></option>
<option value="flake"><?php echo esc_html__('Snowflake', 'yoone-snow'); ?></option>
<option value="yuanbao"><?php echo esc_html__('Yuanbao', 'yoone-snow'); ?></option>
<option value="coin"><?php echo esc_html__('Coin', 'yoone-snow'); ?></option>
<option value="santa_hat"><?php echo esc_html__('Santa Hat', 'yoone-snow'); ?></option>
<option value="candy_cane"><?php echo esc_html__('Candy Cane', 'yoone-snow'); ?></option>
<option value="christmas_sock"><?php echo esc_html__('Christmas Sock', 'yoone-snow'); ?></option>
<option value="christmas_tree"><?php echo esc_html__('Christmas Tree', 'yoone-snow'); ?></option>
<option value="reindeer"><?php echo esc_html__('Reindeer', 'yoone-snow'); ?></option>
<option value="christmas_berry"><?php echo esc_html__('Christmas Berry', 'yoone-snow'); ?></option>
</select>
</div>
<div id="yooneSnowShapeNativeOverlay" style="display:none;position:absolute;background:#fff;border:1px solid #ddd;padding:8px;z-index:1000;">
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:6px;">
<?php foreach (array('dot','flake','yuanbao','coin','santa_hat','candy_cane','christmas_sock','christmas_tree','reindeer','christmas_berry') as $shape) { ?>
<button type="button" class="yoone-snow-shape-native-item" data-shape-key="<?php echo esc_attr($shape); ?>" style="display:flex;gap:6px;align-items:center;">
<span class="yoone-snow-shape-native-preview" style="width:28px;height:28px;display:inline-block;"></span>
<span><?php echo esc_html(ucwords(str_replace('_',' ', $shape))); ?></span>
</button>
<?php } ?>
</div>
</div>
<div id="yooneSnowAddEmojiPane" style="display:none;gap:8px;align-items:center;">
<select id="yooneSnowEmojiSelect" style="min-width:240px;">
<option value=""><?php echo esc_html__('Select emoji', 'yoone-snow'); ?></option>
</select>
<input id="yooneSnowAddEmojiInput" type="text" placeholder="<?php echo esc_attr__('Type emoji or alias', 'yoone-snow'); ?>" />
<div id="yooneSnowEmojiSuggest" style="display:flex;flex-wrap:wrap;gap:6px;"></div>
</div>
<div id="yooneSnowAddMediaPane" style="display:none;">
<button id="yooneSnowAddMediaUnified" type="button" class="button button-primary"><?php echo esc_html__('Add Images', 'yoone-snow'); ?></button>
</div>
<div id="yooneSnowAddTextPane" style="display:none;">
<input id="yooneSnowAddTextInput" type="text" placeholder="<?php echo esc_attr__('Text', 'yoone-snow'); ?>" />
</div>
</div>
<?php foreach ($mixed_items as $shape_key) { $key = (string)$shape_key; if ($key === '') { continue; } $w = isset($shape_weights2[$key]) ? intval($shape_weights2[$key]) : 1; ?>
<div class="yoone-snow-shape-item" data-shape-key="<?php echo esc_attr($key); ?>" style="border:1px solid #ddd;padding:8px;display:flex;flex-direction:column;align-items:center;min-width:96px;">
<div class="yoone-snow-shape-preview" style="width:32px;height:32px;margin-bottom:6px;background:#e6e6e6;border:1px solid #ddd;border-radius:4px;"></div>
<span><?php echo esc_html(ucwords(str_replace('_',' ', $key))); ?></span>
<input type="number" min="0" name="yoone_snow_shape_weights[<?php echo esc_attr($key); ?>]" value="<?php echo esc_attr($w); ?>" style="width:120px;margin-top:6px;" />
<input type="hidden" name="yoone_snow_mixed_items[]" value="<?php echo esc_attr($key); ?>" />
<button type="button" class="button yoone-snow-cancel-shape" style="margin-top:6px;"><?php echo esc_html__('Cancel', 'yoone-snow'); ?></button>
</div>
<?php } ?>
<?php foreach ($emoji_items2 as $emoji_char) { $ch = (string)$emoji_char; if ($ch === '') { continue; } $w = isset($emoji_weights2[$ch]) ? intval($emoji_weights2[$ch]) : 1; ?>
<div class="yoone-snow-emoji-item" data-emoji-char="<?php echo esc_attr($ch); ?>" style="border:1px solid #ddd;padding:8px;display:flex;flex-direction:column;align-items:center;">
<div style="font-size:28px;line-height:32px;background:#e6e6e6;border:1px solid #ddd;border-radius:4px;width:32px;height:32px;display:flex;align-items:center;justify-content:center;"><?php echo esc_html($ch); ?></div>
<input type="number" min="0" name="yoone_snow_emoji_weights[<?php echo esc_attr($ch); ?>]" value="<?php echo esc_attr($w); ?>" style="width:120px;margin-top:6px;" />
<input type="hidden" name="yoone_snow_emoji_items[]" value="<?php echo esc_attr($ch); ?>" />
<button type="button" class="button yoone-snow-remove-emoji" style="margin-top:6px;"><?php echo esc_html__('Remove', 'yoone-snow'); ?></button>
</div>
<?php } ?>
<?php foreach ($media_ids2 as $mid) { $idv = intval($mid); $thumb = wp_get_attachment_image_url($idv, 'thumbnail'); if (!$thumb) { $thumb = wp_get_attachment_url($idv); } $mw = isset($media_weights2[$idv]) ? intval($media_weights2[$idv]) : 1; ?>
<div class="yoone-snow-media-item" data-attachment-id="<?php echo esc_attr($idv); ?>" style="border:1px solid #ddd;padding:8px;display:flex;flex-direction:column;align-items:center;">
<?php if ($thumb) { ?><img src="<?php echo esc_url($thumb); ?>" alt="media" style="width:72px;height:72px;object-fit:contain;" /><?php } ?>
<?php $mw = isset($media_weights2[(string)$idv]) ? intval($media_weights2[(string)$idv]) : (isset($media_weights2[$idv]) ? intval($media_weights2[$idv]) : 1); ?>
<input type="number" min="0" name="yoone_snow_media_weights[<?php echo esc_attr((string)$idv); ?>]" value="<?php echo esc_attr($mw); ?>" style="width:120px;margin-top:6px;" />
<input type="hidden" name="yoone_snow_media_items[]" value="<?php echo esc_attr($idv); ?>" />
<button type="button" class="button yoone-snow-remove-media" style="margin-top:6px;"><?php echo esc_html__('Remove', 'yoone-snow'); ?></button>
</div>
<?php } ?>
<?php foreach ($text_items2 as $txt) { $t = (string)$txt; if ($t === '') { continue; } $tw = isset($text_weights2[$t]) ? intval($text_weights2[$t]) : 1; ?>
<div class="yoone-snow-text-item" data-text-label="<?php echo esc_attr($t); ?>" style="border:1px solid #ddd;padding:8px;display:flex;flex-direction:column;align-items:center;min-width:96px;">
<div style="font-size:14px;line-height:18px;width:120px;min-height:32px;display:flex;align-items:center;justify-content:center;background:#e6e6e6;border:1px solid #ddd;border-radius:4px;word-break:break-word;text-align:center;"><?php echo esc_html($t); ?></div>
<input type="number" min="0" name="yoone_snow_text_weights[<?php echo esc_attr($t); ?>]" value="<?php echo esc_attr($tw); ?>" style="width:120px;margin-top:6px;" />
<input type="hidden" name="yoone_snow_text_items[]" value="<?php echo esc_attr($t); ?>" />
<button type="button" class="button yoone-snow-remove-text" style="margin-top:6px;"><?php echo esc_html__('Cancel', 'yoone-snow'); ?></button>
</div>
<?php } ?>
</div>
<h2><?php echo esc_html__('Display Duration Seconds', 'yoone-snow'); ?></h2>
<input type="number" min="0" name="yoone_snow_home_duration" value="<?php echo esc_attr($home_duration2); ?>" />
<h2><?php echo esc_html__('Max Snowflakes On Screen', 'yoone-snow'); ?></h2>
<input type="number" min="0" max="1000" name="yoone_snow_max_count" value="<?php echo esc_attr($max_count2); ?>" />
<p>
<label>Small <input type="number" min="0" max="1000" name="yoone_snow_max_count_small" value="<?php echo esc_attr(isset($breakpoints2['small']) ? intval($breakpoints2['small']) : 0); ?>" /></label>
<label>Medium <input type="number" min="0" max="1000" name="yoone_snow_max_count_medium" value="<?php echo esc_attr(isset($breakpoints2['medium']) ? intval($breakpoints2['medium']) : 0); ?>" /></label>
<label>Large <input type="number" min="0" max="1000" name="yoone_snow_max_count_large" value="<?php echo esc_attr(isset($breakpoints2['large']) ? intval($breakpoints2['large']) : 0); ?>" /></label>
</p>
<h2><?php echo esc_html__('Snow Size', 'yoone-snow'); ?></h2>
<p>
<label>Min <input type="number" step="0.1" min="0" name="yoone_snow_radius_min" value="<?php echo esc_attr($radius_min2); ?>" /></label>
<label>Max <input type="number" step="0.1" min="0" name="yoone_snow_radius_max" value="<?php echo esc_attr($radius_max2); ?>" /></label>
</p>
<h2>Drift Speed Random Range</h2>
<p>
<label>Min <input type="number" step="0.1" name="yoone_snow_drift_min" value="<?php echo esc_attr(floatval(get_option('yoone_snow_drift_min', 0.4))); ?>" /></label>
<label>Max <input type="number" step="0.1" name="yoone_snow_drift_max" value="<?php echo esc_attr(floatval(get_option('yoone_snow_drift_max', 1.0))); ?>" /></label>
</p>
<h2>Swing Amplitude Random Range</h2>
<p>
<label>Min <input type="number" step="0.1" name="yoone_snow_swing_min" value="<?php echo esc_attr(floatval(get_option('yoone_snow_swing_min', 0.2))); ?>" /></label>
<label>Max <input type="number" step="0.1" name="yoone_snow_swing_max" value="<?php echo esc_attr(floatval(get_option('yoone_snow_swing_max', 1.0))); ?>" /></label>
</p>
<h2><?php echo esc_html__('Where to display', 'yoone-snow'); ?></h2>
<p>
<label><input type="radio" name="yoone_snow_display_routes_mode" value="home" <?php checked($display_mode2 === 'home'); ?> /> <?php echo esc_html__('Home only', 'yoone-snow'); ?></label>
<label><input type="radio" name="yoone_snow_display_routes_mode" value="all" <?php checked($display_mode2 === 'all'); ?> /> <?php echo esc_html__('All pages', 'yoone-snow'); ?></label>
<label><input type="radio" name="yoone_snow_display_routes_mode" value="match" <?php checked($display_mode2 === 'match'); ?> /> <?php echo esc_html__('Match rules', 'yoone-snow'); ?></label>
</p>
<p>
<textarea name="yoone_snow_display_routes" rows="6" cols="60" placeholder="<?php echo esc_attr__('Example /about\n/blog/*\n/shop', 'yoone-snow'); ?>"><?php echo esc_textarea(is_string($display_routes2) ? $display_routes2 : ''); ?></textarea>
</p>
<p><button type="submit" class="button button-primary"><?php echo esc_html__('Save Changes'); ?></button></p>
</form>
</div>
<?php
}