Initial commit: Atomaste website

This commit is contained in:
2025-12-10 12:17:30 -05:00
commit 0b9e5d1605
19260 changed files with 5206382 additions and 0 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-date', 'wp-element', 'wp-i18n'), 'version' => 'ad0c02ae7d9e6c646bff');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,93 @@
<?php
defined( 'ABSPATH' ) or die( 'you do not have access to this page!' );
if ( ! class_exists( 'burst_dashboard_widget' ) ) {
class burst_dashboard_widget {
private static $_this;
public $error_message = '';
function __construct() {
if ( isset( self::$_this ) ) {
wp_die(
burst_sprintf(
'%s is a singleton class and you cannot create a second instance.',
get_class( $this )
)
);
}
self::$_this = $this;
add_action( 'wp_dashboard_setup', [ $this, 'add_burst_dashboard_widget' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] );
}
static function this() {
return self::$_this;
}
/**
*
* Add a dashboard widget
*
* @since 1.1
*/
public function add_burst_dashboard_widget() {
if ( ! burst_user_can_view() ) {
return;
}
wp_add_dashboard_widget(
'dashboard_widget_burst',
'Burst Statistics',
[
$this,
'render_dashboard_widget',
]
);
}
public function enqueue( $hook ) {
if ( $hook !== 'index.php' ) {
return;
}
if ( ! burst_user_can_view() ) {
return;
}
$js_data = burst_get_chunk_translations( 'dashboard-widget/build' );
if ( empty( $js_data ) ) {
return;
}
wp_enqueue_style( 'wp-components' );
$handle = 'burst-settings';
wp_enqueue_script(
$handle,
plugins_url( 'build/' . $js_data['js_file'], __FILE__ ),
$js_data['dependencies'],
$js_data['version'],
true
);
wp_enqueue_style(
$handle,
plugins_url( 'build/index.css', __FILE__ ),
array(),
$js_data['version']
);
wp_set_script_translations( $handle, 'burst-statistics' );
wp_localize_script(
$handle,
'burst_settings',
burst_localized_settings( $js_data )
);
}
/**
*
* Renders the dashboard widget
*/
public function render_dashboard_widget() {
echo '<div id="burst-widget-root"></div>';
}
}
} //class closure

View File

@@ -0,0 +1,195 @@
import {useEffect, useState} from '@wordpress/element';
import './DashboardWidget.scss';
import {setLocaleData} from '@wordpress/i18n';
import {
getAvailableRangesWithKeys
} from '../../../../settings/src/utils/formatting';
import getLiveVisitors from '../../../../settings/src/api/getLiveVisitors';
import getTodayData from '../../../../settings/src/api/getTodayData';
import GridItem from '../../../../settings/src/components/common/GridItem';
import Icon from '../../../../settings/src/utils/Icon';
import {format} from 'date-fns';
import {__} from '@wordpress/i18n';
import {useQueries} from '@tanstack/react-query';
import {
getLocalStorage,
setLocalStorage
} from '../../../../settings/src/utils/api';
/**
* Lazy load everything to keep light weight.
*/
function selectVisitorIcon( value ) {
value = parseInt( value );
if ( 100 < value ) {
return 'visitors-crowd';
} else if ( 10 < value ) {
return 'visitors';
} else {
return 'visitor';
}
}
const DashboardWidget = () => {
const [ range, setRange ] = useState( getLocalStorage( 'widget_date_range', 'last-7-days' ) );
useEffect( () => {
burst_settings.json_translations.forEach( ( translationsString ) => {
let translations = JSON.parse( translationsString );
let localeData = translations.locale_data['burst-statistics'] ||
translations.locale_data.messages;
localeData[''].domain = 'burst-statistics';
setLocaleData( localeData, 'burst-statistics' );
});
}, []);
// This function would be triggered when the user selects a new range.
const handleRangeSelect = ( rangeKey ) => {
setLocalStorage( 'widget_date_range', rangeKey );
setRange( rangeKey );
};
// Get the display dates for the selected range.
const availableRanges = getAvailableRangesWithKeys(
[ 'today', 'yesterday', 'last-7-days', 'last-30-days', 'last-90-days' ]);
// Get the currently selected range object.
const selectedRange = availableRanges[range] ?
availableRanges[range].range() :
availableRanges['last-7-days'].range();
const startDate = format( selectedRange.startDate, 'yyyy-MM-dd' );
const endDate = format( selectedRange.endDate, 'yyyy-MM-dd' );
const [ interval, setInterval ] = useState( 5000 );
const placeholderData = {
live: {
title: __( 'Live', 'burst-statistics' ),
icon: 'visitor'
},
today: {
title: __( 'Total', 'burst-statistics' ),
value: '-',
icon: 'visitor'
},
mostViewed: {
title: '-',
value: '-'
},
pageviews: {
title: '-',
value: '-'
},
referrer: {
title: '-',
value: '-'
},
timeOnPage: {
title: '-',
value: '-'
}
};
const queries = useQueries({
queries: [
{
queryKey: [ 'live-visitors' ],
queryFn: getLiveVisitors,
refetchInterval: interval,
placeholderData: '-',
onError: () => {
setInterval( 0 );
}
},
{
queryKey: [ range, startDate, endDate ],
queryFn: () => getTodayData({startDate, endDate}),
refetchInterval: interval * 2,
placeholderData: placeholderData,
onError: () => {
setInterval( 0 );
}
}
]
}
);
// Your existing code
const live = queries[0].data;
let data = queries[1].data;
if ( queries.some( ( query ) => query.isError ) ) {
data = placeholderData;
}
let liveIcon = selectVisitorIcon( live ? live : 0 );
let todayIcon = 'loading';
if ( data && data.today ) {
todayIcon = selectVisitorIcon( data.today.value ? data.today.value : 0 );
}
return (
<GridItem
className={'border-to-border burst-today'}
title={__( 'Today', 'burst-statistics' )}
controls={<>{queries[0].isFetching ?
<Icon name={'loading'}/> :
null}</>}
footer={
<>
<a className={'burst-button burst-button--secondary'}
href={burst_settings.dashboard_url + '#statistics'}>{__(
'View all statistics', 'burst-statistics' )}</a>
<select onChange={( e ) => handleRangeSelect( e.target.value )}
value={range}>
{Object.keys( availableRanges ).map( ( key ) => (
<option key={key} value={key}>
{availableRanges[key].label}
</option>
) )}
</select>
</>
}
>
<div className="burst-today">
<div className="burst-today-select">
<div className="burst-today-select-item">
<Icon name={liveIcon} size="23"/>
<h2>{live}</h2>
<span><Icon name="live" size="12" color={'red'}/> {__( 'Live',
'burst-statistics' )}</span>
</div>
<div className="burst-today-select-item">
<Icon name={todayIcon} size="23"/>
<h2>{data.today.value}</h2>
<span><Icon name="total" size="13"
color={'green'}/> {__( 'Total',
'burst-statistics' )}</span>
</div>
</div>
<div className="burst-today-list">
<div className="burst-today-list-item">
<Icon name="winner"/>
<p className="burst-today-list-item-text">{decodeURI(
data.mostViewed.title )}</p>
<p className="burst-today-list-item-number">{data.mostViewed.value}</p>
</div>
<div className="burst-today-list-item">
<Icon name="referrer"/>
<p className="burst-today-list-item-text">{decodeURI(
data.referrer.title )}</p>
<p className="burst-today-list-item-number">{data.referrer.value}</p>
</div>
<div className="burst-today-list-item">
<Icon name="pageviews"/>
<p className="burst-today-list-item-text">{data.pageviews.title}</p>
<p className="burst-today-list-item-number">{data.pageviews.value}</p>
</div>
<div className="burst-today-list-item">
<Icon name="time"/>
<p className="burst-today-list-item-text">{data.timeOnPage.title}</p>
<p className="burst-today-list-item-number">{data.timeOnPage.value}</p>
</div>
</div>
</div>
</GridItem>
);
};
export default DashboardWidget;

View File

@@ -0,0 +1,276 @@
#dashboard_widget_burst {
.inside{
padding: 0;
margin: 0;
}
}
#dashboard-widgets .burst-today {
.burst-grid-item-header {
display:none;
}
&-select {
background: #ecf4ed;
padding-inline: var(--rsp-spacing-l);
padding-block: var(--rsp-spacing-m);
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--rsp-spacing-s);
&-item {
border-radius: var(--rsp-border-radius-xs);
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
padding-block: var(--rsp-spacing-m);
justify-items: center;
flex-wrap: wrap;
background: var(--rsp-white);
.burst-icon{
display: flex;
align-items: center;
justify-content: center;
}
&.active {
box-shadow: inset 0 0 3px 2px var(--rsp-green-faded);
border: 2px solid var(--rsp-green);
}
h2 {
margin-top: var(--rsp-spacing-xxs);
font-weight: 800;
}
span {
display: flex;
gap: 3px;
justify-content: center;
font-size: var(--rsp-fs-100);
.burst-icon-live {
animation-name: pulse;
animation-duration: 1.5s;
animation-timing-function: ease-in;
animation-direction: alternate;
animation-iteration-count: infinite;
animation-play-state: running;
@keyframes pulse {
0% {
transform: scale(0.9);
opacity: 0.2;
}
100% {
transform: scale(1.0);
opacity: 1;
}
}
}
}
}
}
&-list {
width: 100%;
&-item {
display: grid;
justify-items: flex-start;
grid-template-columns: auto 1fr auto;
gap: var(--rsp-spacing-s);
padding-block: var(--rsp-spacing-xs);
padding-inline: var(--rsp-spacing-l);
&:nth-of-type(even) {
background: var(--rsp-grey-200);
}
&-text {
width: 100%;
margin: 0;
margin-right: auto;
}
&-number {
margin: 0;
font-weight: 600;
}
}
}
&-controls-flex {
display: flex;
//justify-content: space-between;
align-items: center;
gap: var(--rsp-spacing-xs);
.burst-divider {
width: 1px;
height: 80%;
background: var(--rsp-grey-500);
}
}
.burst-grid-item-footer {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--rsp-grid-margin);
width: 100%;
min-height: calc(30px + var(--rsp-spacing-s) * 2);
box-sizing: border-box;
padding-inline: var(--rsp-spacing-l);
align-self: flex-end;
}
a.burst-button--secondary {
background: var(--rsp-grey-100);
color: var(--rsp-text-color-light);
border: 1px solid var(--rsp-grey-400);
}
}
/* Global Variables */
:root {
--button-font-size: var(--rsp-fs-300);
--button-font-weight: 400;
--button-line-height: 2;
--button-letter-spacing: 0.5px;
--button-transition: all 0.3s ease;
--button-min-height: 30px;
--button-padding: 0 10px;
--button-border-radius: 4px;
--button-accent-color: #2271b1;
--button-contrast-color: #000;
--button-secondary-bg: #fff;
}
/* Button Base Styles */
a.burst-button, button.burst-button, input.burst-button {
display: flex;
align-items: center;
gap: var(--rsp-spacing-xxs);
font-size: var(--button-font-size);
font-weight: var(--button-font-weight);
line-height: var(--button-line-height);
letter-spacing: var(--button-letter-spacing);
transition: var(--button-transition);
min-height: var(--button-min-height);
margin: 0;
padding: var(--button-padding);
border-radius: var(--button-border-radius);
text-align: center;
cursor: pointer;
text-decoration: none;
&--primary {
background: var(--button-accent-color);
color: var(--button-secondary-bg);
border: 1px solid var(--button-accent-color);
&:hover {
background: var(--button-accent-color);
color: var(--button-secondary-bg);
border-color: var(--button-accent-color);
box-shadow: 0 0 0 3px rgba(34, 113, 177, 0.3);
}
}
&--secondary {
background: var(--rsp-grey-100);
color: var(--rsp-text-color-light);
border: 1px solid var(--rsp-grey-400);
&:hover {
background: var(--rsp-grey-200);
color: var(--rsp-text-color);
border-color: var(--rsp-grey-400);
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.1);
}
}
&--tertiary {
// red button
background: var(--rsp-red);
color: var(--rsp-text-color-white);
border: 1px solid var(--rsp-red);
&:hover {
background: var(--rsp-red-faded);
color: var(--rsp-red);
border-color: var(--rsp-red);
box-shadow: 0 0 0 3px rgba(255, 0, 0, 0.3);
}
}
&--pro {
background: var(--rsp-brand-primary);
color: var(--rsp-text-color-white);
border: 1px solid var(--rsp-brand-primary-dark);
&:hover {
background: var(--rsp-brand-primary-dark);
color: var(--button-secondary-bg);
border-color: var(--rsp-brand-primary-darker);
box-shadow: 0 0 0 3px var(--rsp-brand-primary-light);
}
}
}
.burst-button-icon {
background: transparent;
background: var(--rsp-grey-300);
color: #2271b1;
border: 1px solid transparent;
border-radius: 50%;
width: 1em;
height: 1em;
padding: 10px;
margin: 5px;
display: inline-flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
cursor: pointer;
&:hover {
padding: 15px;
margin: 0;
}
&--delete {
&:hover {
background: var(--rsp-red-faded);
svg path {
fill: var(--rsp-red);
}
}
}
}
.burst .burst-button.burst-button--date-range {
display: flex;
align-items: center;
padding: var(---rsp-filter-padding);
box-shadow: var(--rsp-box-shadow);
cursor: pointer;
gap: var(--rsp-spacing-xs);
color: var(--rsp-text-color-light);
background-color: var(--rsp-input-background-color);
background: var(--rsp-grey-200);
border: 1px solid var(--rsp-input-border-color);
border-radius: var(--rsp-border-radius-xs);
.burst-icon {
height: max-content;
}
}

View File

@@ -0,0 +1,44 @@
import {
render
} from '@wordpress/element';
import DashboardWidget from './components/DashboardWidget/DashboardWidget';
import '../../assets/css/variables.scss';
import {
QueryClient,
QueryCache,
QueryClientProvider
} from '@tanstack/react-query';
const HOUR_IN_SECONDS = 3600;
const queryCache = new QueryCache({
onError: ( error ) => {
// any error handling code...
}
});
let config = {
defaultOptions: {
queries: {
staleTime: HOUR_IN_SECONDS * 1000, // ms
refetchOnWindowFocus: false,
retry: false
}
}
};
// merge queryCache with config
config = {...config, ...{queryCache}};
const queryClient = new QueryClient( config );
document.addEventListener( 'DOMContentLoaded', () => {
const container = document.getElementById( 'burst-widget-root' );
if ( container ) {
render(
<QueryClientProvider client={queryClient}>
<DashboardWidget/>
</QueryClientProvider>,
container
);
}
});

View File

@@ -0,0 +1,6 @@
const developmentConfig = require( './webpack.dev.js' );
const productionConfig = require( './webpack.prod.js' );
const environment = process.env.BURST_ENV;
module.exports = 'production' === environment ? productionConfig : developmentConfig;

View File

@@ -0,0 +1,10 @@
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
module.exports = {
...defaultConfig,
output: {
...defaultConfig.output,
filename: '[name].js',
chunkFilename: '[name].js'
}
};

View File

@@ -0,0 +1,10 @@
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
module.exports = {
...defaultConfig,
output: {
...defaultConfig.output,
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js'
}
};