Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/webpack/webpack-js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const jsWebpackConfig: Configuration = {
'edit': { import: `${SOURCE_DIR}/edit.ts`, dependOn: 'editor' },
'editor': `${SOURCE_DIR}/editor.ts`,
'import': `${SOURCE_DIR}/import.ts`,
'insights': `${SOURCE_DIR}/insights.ts`,
'manage': `${SOURCE_DIR}/manage.ts`,
'mce': `${SOURCE_DIR}/mce.ts`,
'prism': `${SOURCE_DIR}/prism.ts`,
Expand Down
211 changes: 211 additions & 0 deletions src/css/insights.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
@use 'common/theme';
@use 'common/toolbar';
@use 'common/wp-admin';

.code-snippets-insights {
margin-block: 50px;
margin-inline: auto;
color: #2c3337;

h1 {
padding: 0;
margin: 0;
font-size: 32px;
font-weight: 510;
line-height: 1.25;
}
}

.insights-chart-grid {
display: grid;
gap: 16px;
grid-template-columns: repeat(3, minmax(0, 1fr));
margin-block: 16px;
}

.insights-chart-card {
box-sizing: border-box;
border: 1px solid #dcdcde;
border-radius: 8px;
background: #fff;
padding: 24px;

.insights-chart-card-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-block-end: 20px;
}

h2 {
margin: 0;
font-size: 18px;
}
}

.insights-number-chart {
display: grid;
gap: 4px;
justify-items: center;
padding-block: 12px;
text-align: center;
}

.insights-number-chart-value {
font-size: 140px;
font-variant-numeric: tabular-nums;
line-height: 1;
}

.insights-number-chart-label {
color: #646970;
font-size: 13px;
}

.insights-chart-view-toggle {
display: flex;
align-items: center;
gap: 6px;

.insights-chart-view-toggle-option {
display: flex;
align-items: center;
justify-content: center;
inline-size: 26px;
block-size: 26px;
box-sizing: border-box;
padding: 0;
margin: 0;
background: #f0f0f1;
color: #646970;
border: none;
border-radius: 4.5px;
cursor: pointer;

> .dashicons {
font-size: 18px;
}

&:hover,
&:focus {
color: #2c3337;
}

&:focus-visible {
outline: 2px solid theme.$accent;
outline-offset: -2px;
}

&:focus:not(:focus-visible) {
outline: none;
}

&.active-view {
background: theme.$accent;
color: #fff;

&:hover,
&:focus {
color: #fff;
}
}
}
}

.insights-bar-chart,
.insights-pie-chart-legend {
padding: 0;
margin: 0;
list-style: none;
}

.insights-bar-chart {
display: grid;
gap: 10px;

li {
display: grid;
grid-template-columns: minmax(110px, 1fr) minmax(80px, 3fr) auto;
align-items: center;
gap: 10px;
margin: 0;
}

strong {
min-inline-size: 2ch;
text-align: end;
}
}

.insights-bar-track {
overflow: hidden;
block-size: 10px;
border-radius: 999px;
background: #e2e5e5;
}

.insights-bar-fill {
block-size: 100%;
border-radius: inherit;
}

.insights-pie-chart-content {
display: flex;
align-items: center;
gap: 24px;
}

.insights-pie-chart {
position: relative;
flex: 0 0 auto;
inline-size: 112px;
block-size: 112px;
border-radius: 50%;
background: #e2e5e5;

&::after {
position: absolute;
inset: 25px;
border-radius: 50%;
background: #fff;
content: '';
}
}

.insights-pie-chart-legend {
display: grid;
gap: 12px;
inline-size: 100%;

li {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
margin: 0;
}

span {
display: flex;
align-items: center;
}

i {
display: inline-block;
inline-size: 10px;
block-size: 10px;
border-radius: 50%;
margin-inline-end: 8px;
}
}

@media (width <= 782px) {
.insights-chart-grid {
grid-template-columns: 1fr;
}

.insights-bar-chart li {
grid-template-columns: minmax(90px, 1fr) minmax(64px, 2fr) auto;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,10 @@ import React, { useId } from 'react'
import Select from 'react-select'
import { useSnippetForm } from '../WithSnippetFormContext'
import { SNIPPET_TYPE_SCOPES } from '../../../../types/Snippet'
import { getSnippetType, isCondition } from '../../../../utils/snippets/snippets'
import { SNIPPET_SCOPE_DESCRIPTIONS, SNIPPET_SCOPE_ICONS, getSnippetType, isCondition } from '../../../../utils/snippets/snippets'
import type { SnippetCodeScope } from '../../../../types/Snippet'
import type { SelectOption } from '../../../../types/SelectOption'

const SCOPE_ICONS: Record<SnippetCodeScope, string> = {
'global': 'admin-site',
'admin': 'admin-tools',
'front-end': 'admin-appearance',
'single-use': 'clock',
'content': 'shortcode',
'head-content': 'editor-code',
'body-content': 'editor-code',
'footer-content': 'editor-code',
'admin-css': 'dashboard',
'site-css': 'admin-customizer',
'site-head-js': 'media-code',
'site-footer-js': 'media-code'
}

const SCOPE_DESCRIPTIONS: Record<SnippetCodeScope, string> = {
'global': __('Run everywhere', 'code-snippets'),
'admin': __('Only run in administration area', 'code-snippets'),
'front-end': __('Only run on site front-end', 'code-snippets'),
'single-use': __('Only run once', 'code-snippets'),
'content': __('Where inserted in editor', 'code-snippets'),
'head-content': __('In site header (<head> section)', 'code-snippets'),
'body-content': __('In site content (start of <body>)', 'code-snippets'),
'footer-content': __('In site footer (end of <body>)', 'code-snippets'),
'site-css': __('Site front-end', 'code-snippets'),
'admin-css': __('Administration area', 'code-snippets'),
'site-head-js': __('In site header (<head> section)', 'code-snippets'),
'site-footer-js': __('In site footer (end of <body>)', 'code-snippets')
}

export const SnippetLocationInput: React.FC = () => {
const { snippet, setSnippet, isReadOnly } = useSnippetForm()
const locationId = useId()
Expand All @@ -46,7 +16,7 @@ export const SnippetLocationInput: React.FC = () => {
.map(scope => ({
key: scope,
value: scope,
label: SCOPE_DESCRIPTIONS[scope]
label: SNIPPET_SCOPE_DESCRIPTIONS[scope]
}))

return isCondition(snippet)
Expand All @@ -69,7 +39,7 @@ export const SnippetLocationInput: React.FC = () => {
value={options.find(option => option.value === snippet.scope)}
formatOptionLabel={({ label, value }) =>
<>
<span className={`dashicons dashicons-${SCOPE_ICONS[value]}`} aria-hidden="true"></span>{` ${label}`}
<span className={`dashicons dashicons-${SNIPPET_SCOPE_ICONS[value]}`} aria-hidden="true"></span>{` ${label}`}
</>
}
onChange={option =>
Expand Down
39 changes: 39 additions & 0 deletions src/js/components/InsightsMenu/InsightsChartViewToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { __, sprintf } from '@wordpress/i18n'
import classnames from 'classnames'
import React from 'react'
import type { InsightsChartView } from '../../types/Insights'

export interface InsightsChartViewToggleProps {
title: string
view: InsightsChartView
setView: (view: InsightsChartView) => void
}

export const InsightsChartViewToggle: React.FC<InsightsChartViewToggleProps> = ({ title, view, setView }) =>
<div
className="insights-chart-view-toggle"
role="group"
aria-label={sprintf(__('%s chart view', 'code-snippets'), title)}
>
<button
type="button"
className={classnames('insights-chart-view-toggle-option', { 'active-view': 'pie' === view })}
aria-pressed={'pie' === view}
title={__('Switch to pie chart view', 'code-snippets')}
onClick={() => setView('pie')}
>
<span className="dashicons dashicons-chart-pie" aria-hidden="true" />
<span className="screen-reader-text">{__('Pie chart view', 'code-snippets')}</span>
</button>

<button
type="button"
className={classnames('insights-chart-view-toggle-option', { 'active-view': 'bar' === view })}
aria-pressed={'bar' === view}
title={__('Switch to bar chart view', 'code-snippets')}
onClick={() => setView('bar')}
>
<span className="dashicons dashicons-chart-bar" aria-hidden="true" />
<span className="screen-reader-text">{__('Bar chart view', 'code-snippets')}</span>
</button>
</div>
Loading
Loading