Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Posts analytics React app #21878

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion .github/scripts/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const COMMAND_TYPESCRIPT = {
env: {}
};

const adminXApps = '@tryghost/admin-x-demo,@tryghost/admin-x-settings,@tryghost/admin-x-activitypub';
const adminXApps = '@tryghost/admin-x-demo,@tryghost/admin-x-settings,@tryghost/admin-x-activitypub,@tryghost/posts';

const COMMANDS_ADMINX = [{
name: 'adminXDeps',
Expand Down
3 changes: 2 additions & 1 deletion apps/admin-x-framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@
"dependsOn": [
"test:unit",
"^build",
"@tryghost/admin-x-design-system:test:unit"
"@tryghost/admin-x-design-system:test:unit",
"@tryghost/shade:test:unit"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that if the shade tests fail the admin-x-framework tests will fail too, is that what you want?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... Maybe not yet. We just added the current design system to it to catch DS bugs, but maybe we can leave Shade out until its first release. Good point.

]
}
}
Expand Down
62 changes: 62 additions & 0 deletions apps/admin-x-framework/src/test/render-shade.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {ShadeAppProps} from '@tryghost/shade';
import React from 'react';
import ReactDOM from 'react-dom/client';
import {TopLevelFrameworkProps} from '../providers/FrameworkProvider';

export default function renderShadeApp<Props extends object>(
App: React.ComponentType<Props & {
framework: TopLevelFrameworkProps;
designSystem: ShadeAppProps;
}>,
props: Props
) {
const style = document.createElement('style');
style.appendChild(document.createTextNode(`
:root {
font-size: 62.5%;
line-height: 1.5;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;

text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}

html, body, #root {
width: 100%;
height: 100%;
margin: 0;
letter-spacing: unset;
}
`));
document.head.appendChild(style);

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<App
designSystem={{darkMode: false, fetchKoenigLexical: null}}
framework={{
externalNavigate: (link) => {
// Use the expectExternalNavigate helper to test this dummy external linking
window.location.href = `/external/${encodeURIComponent(JSON.stringify(link))}`;
},
ghostVersion: '5.x',
sentryDSN: null,
unsplashConfig: {
Authorization: '',
'Accept-Version': '',
'Content-Type': '',
'App-Pragma': '',
'X-Unsplash-Cache': false
},
onDelete: () => {},
onInvalidate: () => {},
onUpdate: () => {}
}}
{...props}
/>
</React.StrictMode>
);
}
14 changes: 10 additions & 4 deletions apps/admin-x-framework/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import path from 'path';
import react from '@vitejs/plugin-react';
import glob from 'glob';
import {resolve} from 'path';
Expand All @@ -10,6 +11,11 @@ export default (function viteConfig() {
plugins: [
react()
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this alias used anywhere, can we revert the changes in this file?

}
},
preview: {
port: 4174
},
Expand All @@ -20,13 +26,13 @@ export default (function viteConfig() {
outDir: 'dist',
lib: {
formats: ['es', 'cjs'],
entry: glob.sync(resolve(__dirname, 'src/**/*.{ts,tsx}')).reduce((entries, path) => {
if (path.endsWith('.d.ts')) {
entry: glob.sync(resolve(__dirname, 'src/**/*.{ts,tsx}')).reduce((entries, libpath) => {
if (libpath.endsWith('.d.ts')) {
return entries;
}

const outPath = path.replace(resolve(__dirname, 'src') + '/', '').replace(/\.(ts|tsx)$/, '');
entries[outPath] = path;
const outPath = libpath.replace(resolve(__dirname, 'src') + '/', '').replace(/\.(ts|tsx)$/, '');
entries[outPath] = libpath;
return entries;
}, {} as Record<string, string>)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ const features = [{
title: 'Comment Improvements',
description: 'Enables new comment features',
flag: 'commentImprovements'
}, {
title: 'Post analytics redesign',
description: 'Enables redesigned Post analytics page',
flag: 'postsX'
}];

const AlphaFeatures: React.FC = () => {
Expand Down
56 changes: 56 additions & 0 deletions apps/posts/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* eslint-env node */
module.exports = {
root: true,
extends: [
'plugin:ghost/ts',
'plugin:react/recommended',
'plugin:react-hooks/recommended'
],
plugins: [
'ghost',
'react-refresh',
'tailwindcss'
],
settings: {
react: {
version: 'detect'
}
},
rules: {
// sort multiple import lines into alphabetical groups
'ghost/sort-imports-es6-autofix/sort-imports-es6': ['error', {
memberSyntaxSortOrder: ['none', 'all', 'single', 'multiple']
}],

// TODO: re-enable this (maybe fixed fast refresh?)
'react-refresh/only-export-components': 'off',

// suppress errors for missing 'import React' in JSX files, as we don't need it
'react/react-in-jsx-scope': 'off',
// ignore prop-types for now
'react/prop-types': 'off',

// TODO: re-enable these if deemed useful
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-empty-function': 'off',

// custom react rules
'react/jsx-sort-props': ['error', {
reservedFirst: true,
callbacksLast: true,
shorthandLast: true,
locale: 'en'
}],
'react/button-has-type': 'error',
'react/no-array-index-key': 'error',
'react/jsx-key': 'off',

'tailwindcss/classnames-order': ['error', {config: 'tailwind.config.cjs'}],
'tailwindcss/enforces-negative-arbitrary-values': ['warn', {config: 'tailwind.config.cjs'}],
'tailwindcss/enforces-shorthand': ['warn', {config: 'tailwind.config.cjs'}],
'tailwindcss/migration-from-tailwind-2': ['warn', {config: 'tailwind.config.cjs'}],
'tailwindcss/no-arbitrary-value': 'off',
'tailwindcss/no-custom-classname': 'off',
'tailwindcss/no-contradicting-classname': ['error', {config: 'tailwind.config.cjs'}]
}
};
3 changes: 3 additions & 0 deletions apps/posts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist
playwright-report
test-results
16 changes: 16 additions & 0 deletions apps/posts/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Posts</title>
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/standalone.tsx"></script>
</body>

</html>
55 changes: 55 additions & 0 deletions apps/posts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "@tryghost/posts",
"version": "0.0.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/TryGhost/Ghost/tree/main/apps/posts"
},
"author": "Ghost Foundation",
"files": [
"LICENSE",
"README.md",
"dist/"
],
"main": "./dist/posts.umd.cjs",
"module": "./dist/posts.js",
"private": true,
"scripts": {
"dev": "vite build --watch",
"dev:start": "vite",
"build": "tsc && vite build",
"lint": "yarn run lint:code && yarn run lint:test",
"lint:code": "eslint --ext .js,.ts,.cjs,.tsx --cache src",
"lint:test": "eslint -c test/.eslintrc.cjs --ext .js,.ts,.cjs,.tsx --cache test",
"preview": "vite preview"
},
"devDependencies": {
"@testing-library/react": "14.3.1",
"@tryghost/shade": "0.0.0",
"@tryghost/admin-x-framework": "0.0.0",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
"react": "18.3.1",
"react-dom": "18.3.1"
},
"nx": {
"targets": {
"dev": {
"dependsOn": [
"^build"
]
},
"test:unit": {
"dependsOn": [
"^build"
]
},
"test:acceptance": {
"dependsOn": [
"^build"
]
}
}
}
}
3 changes: 3 additions & 0 deletions apps/posts/playwright.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import {adminXPlaywrightConfig} from '@tryghost/admin-x-framework/playwright';

export default adminXPlaywrightConfig();
1 change: 1 addition & 0 deletions apps/posts/postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@tryghost/shade/postcss.config.cjs');
23 changes: 23 additions & 0 deletions apps/posts/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import PostAnalytics from './pages/PostAnalytics';
import {FrameworkProvider, TopLevelFrameworkProps} from '@tryghost/admin-x-framework';
import {RoutingProvider} from '@tryghost/admin-x-framework/routing';
import {ShadeApp, ShadeAppProps} from '@tryghost/shade';

interface AppProps {
framework: TopLevelFrameworkProps;
designSystem: ShadeAppProps;
}

const App: React.FC<AppProps> = ({framework, designSystem}) => {
return (
<FrameworkProvider {...framework}>
<RoutingProvider basePath='posts-x'>
<ShadeApp className='posts' {...designSystem}>
<PostAnalytics />
</ShadeApp>
</RoutingProvider>
</FrameworkProvider>
);
};

export default App;
26 changes: 26 additions & 0 deletions apps/posts/src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, H1} from '@tryghost/shade';

const Header = () => {
return (
<div className="pt-9">
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/ghost/posts">
Posts
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>
Analytics
</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
<H1 className='mt-1 max-w-[1024px]'>The Evolution of Basketball: From Pastime to Professional and One of the Most Popular Sports</H1>
</div>
);
};

export default Header;
17 changes: 17 additions & 0 deletions apps/posts/src/components/post-analytics/Overview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import ClickPerformance from './overview/ClickPerformance';
import Conversions from './overview/Conversions';
import Feedback from './overview/Feedback';
import NewsletterPerformance from './overview/NewsletterPerformance';

const Overview = () => {
return (
<div className="grid w-full grid-cols-3 gap-6 py-4">
<NewsletterPerformance className='col-span-2' />
<Feedback />
<ClickPerformance className='col-span-2' />
<Conversions />
</div>
);
};

export default Overview;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from 'react';
import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@tryghost/shade';

interface ClickPerformanceProps extends React.ComponentProps<typeof Card> {};

const ClickPerformance: React.FC<ClickPerformanceProps> = (props) => {
return (
<Card {...props}>
<CardHeader>
<CardTitle>Click performance</CardTitle>
<CardDescription>
Links in this newsletter
</CardDescription>
</CardHeader>
<CardContent>
Card contents
</CardContent>
</Card>
);
};

export default ClickPerformance;
22 changes: 22 additions & 0 deletions apps/posts/src/components/post-analytics/overview/Conversions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from 'react';
import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@tryghost/shade';

interface ConversionsProps extends React.ComponentProps<typeof Card> {};

const Conversions: React.FC<ConversionsProps> = (props) => {
return (
<Card {...props}>
<CardHeader>
<CardTitle>Conversions</CardTitle>
<CardDescription>
3 members signed up on this post
</CardDescription>
</CardHeader>
<CardContent>
Card contents
</CardContent>
</Card>
);
};

export default Conversions;
Loading
Loading