Skip to content

Commit 313e2df

Browse files
committed
refactor structure & design
1 parent 1f28d44 commit 313e2df

24 files changed

+1383
-242
lines changed
Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: NodeJS with Webpack
1+
name: Build plugin
22

33
on:
44
push:
@@ -20,22 +20,34 @@ jobs:
2020
with:
2121
node-version: ${{ matrix.node-version }}
2222

23-
- name: Cache
23+
- name: Cache NPM dependencies
2424
uses: actions/[email protected]
2525
id: node_modules-cache
2626
with:
2727
path: node_modules
2828
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
2929

30-
- name: Install dependencies
30+
- name: Install NPM dependencies
3131
if: steps.node_modules-cache.outputs.cache-hit != 'true'
3232
run: npm ci
3333

34-
- name: Build
34+
- name: Build assets
3535
run: npm run build
3636

37+
- name: Cache Composer dependencies
38+
uses: actions/[email protected]
39+
id: vendor-cache
40+
with:
41+
path: vendor
42+
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
43+
44+
- name: Install Composer dependencies
45+
uses: php-actions/composer@v6
46+
with:
47+
php_version: "8.2"
48+
3749
- name: Zip
38-
run: git archive -o "${GITHUB_REPOSITORY#*/}.zip" --prefix="${GITHUB_REPOSITORY#*/}/" ${GITHUB_SHA}
50+
run: zip -r "${GITHUB_REPOSITORY#*/}.zip" . -x .git\* -x .github\* -x node_modules\* -x src\* -x .DS_Store
3951
shell: bash
4052

4153
- name: Upload zip

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# WP React Admin Page Example
22

3-
![1](screenshot.png)
3+
![1](screenshot.jpg)

assets/components/App.module.css

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* Set brand color here */
2+
/* :root {
3+
--wp-admin-theme-color: hotpink;
4+
--wp-admin-theme-color-darker-10: deeppink;
5+
--wp-admin-theme-color-darker-20: deeppink;
6+
} */
7+
8+
.topBar {
9+
margin-top: -10px;
10+
margin-inline: -22px -20px;
11+
padding-block: 1em;
12+
padding-inline: 22px 20px;
13+
background-color: #fff;
14+
border-bottom: 1px solid rgba(0, 0, 0, .1);
15+
16+
svg {
17+
max-width: 2em;
18+
max-height: 2em;
19+
vertical-align: middle;
20+
margin-inline-end: .5em;
21+
color: var(--wp-admin-theme-color);
22+
}
23+
24+
h1 {
25+
padding: 0;
26+
}
27+
}
28+
29+
.mainNav :global(.components-tab-panel__tabs) {
30+
background-color: #fff;
31+
box-shadow: rgba(0, 0, 0, .1) 0 0 0 1px;
32+
border-radius: 7px;
33+
overflow: hidden;
34+
}
35+
36+
.snackbar {
37+
position: fixed;
38+
bottom: 2.5em;
39+
z-index: 999;
40+
}

assets/components/App.tsx

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import {
2+
ExternalLink,
3+
Flex,
4+
Notice,
5+
Snackbar,
6+
TabPanel,
7+
__experimentalGrid as Grid,
8+
__experimentalSpacer as Spacer
9+
} from '@wordpress/components';
10+
import { useEffect, useState } from "@wordpress/element";
11+
import { __ } from '@wordpress/i18n';
12+
import style from './App.module.css';
13+
import Icon from '../images/icon.svg';
14+
import useSearchParams from '../hooks/useSearchParams';
15+
import TabOne from './Tab/TabOne';
16+
import TabTwo from './Tab/TabTwo';
17+
import TabThree from './Tab/TabThree';
18+
19+
const App = ({ title }: { title: string }) => {
20+
const [showAnnouncement, setShowAnnouncement] = useState<boolean | null>(null);
21+
const [error, setError] = useState<string | null>(null);
22+
const [success, setSuccess] = useState<string | null>(null);
23+
const [tab, setTab] = useSearchParams('tab', 'tab-1');
24+
25+
useEffect(() => {
26+
setShowAnnouncement(true);
27+
setError(__('This is an example error message.', 'wp-react-page-admin-example'));
28+
setSuccess(__('Example success', 'wp-react-page-admin-example'));
29+
}, []);
30+
31+
return (
32+
<Grid
33+
columns={ 1 }
34+
gap={ 12 }
35+
>
36+
<TopBar
37+
title={ title }
38+
/>
39+
{ showAnnouncement && (
40+
<Notice
41+
status="info"
42+
onRemove={ () => setShowAnnouncement(null) }
43+
actions={[
44+
{
45+
label: 'Click me!',
46+
onClick: () => setShowAnnouncement(null)
47+
},
48+
{
49+
label: 'Or visit a link for more info',
50+
url: 'https://wordpress.org',
51+
variant: 'link'
52+
}
53+
]}
54+
>
55+
<h2>Announcement banner</h2>
56+
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
57+
</Notice>
58+
) }
59+
<TabPanel
60+
activeClass="is-active"
61+
onSelect={ setTab }
62+
initialTabName={ tab }
63+
className={ style.mainNav }
64+
tabs={ [
65+
{
66+
name: 'tab-1',
67+
title: __('Tab 1', 'wp-react-page-admin-example'),
68+
component: TabOne
69+
},
70+
{
71+
name: 'tab-2',
72+
title: __('Tab 2', 'wp-react-page-admin-example'),
73+
component: TabTwo
74+
},
75+
{
76+
name: 'tab-3',
77+
title: __('Tab 3', 'wp-react-page-admin-example'),
78+
component: TabThree
79+
},
80+
] }
81+
>
82+
{ (tab) => {
83+
const TabComponent = tab.component;
84+
return (
85+
<>
86+
<Spacer marginY={ 12 } />
87+
<Grid
88+
columns={ 1 }
89+
gap={ 12 }
90+
>
91+
{ error && (
92+
<Notice
93+
status="error"
94+
onRemove={ () => setError(null) }
95+
>
96+
{ error }
97+
</Notice>
98+
) }
99+
<TabComponent />
100+
</Grid>
101+
</>
102+
);
103+
}}
104+
</TabPanel>
105+
{ success && (
106+
<Snackbar
107+
onRemove={ () => setSuccess(null) }
108+
className={ style.snackbar }
109+
>
110+
{ success }
111+
</Snackbar>
112+
) }
113+
<Spacer marginY={ 12 } />
114+
</Grid>
115+
);
116+
}
117+
118+
const TopBar = ({ title }: { title: string }) => {
119+
return (
120+
<Flex
121+
gap={ 1 }
122+
className={ style.topBar }
123+
>
124+
<Flex
125+
justify="start"
126+
gap={ 1 }
127+
>
128+
<Icon
129+
aria-hidden="true"
130+
focusable="false"
131+
/>
132+
<h1>{ title }</h1>
133+
</Flex>
134+
<ExternalLink href="https://google.com">Help</ExternalLink>
135+
</Flex>
136+
);
137+
};
138+
139+
export default App;

assets/components/Box.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useState } from "@wordpress/element";
2+
import { __ } from "@wordpress/i18n";
3+
import { Button, Card, CardBody, CardFooter, Spinner, TextControl } from "@wordpress/components";
4+
5+
const Box = () => {
6+
const [isProcessing, setIsProcessing] = useState(false);
7+
const [inputValue, setInputValue] = useState('');
8+
9+
return (
10+
<div>
11+
<h2>{ __('Heading', 'wp-react-page-admin-example') }</h2>
12+
<Card>
13+
<CardBody>
14+
<TextControl
15+
help={ __('Help text to explain the input.', 'wp-react-page-admin-example') }
16+
label={ __('Label Text', 'wp-react-page-admin-example') }
17+
onChange={ setInputValue }
18+
value={ inputValue }
19+
/>
20+
</CardBody>
21+
<CardFooter justify="flex-end">
22+
{ isProcessing && <Spinner /> }
23+
<Button
24+
variant="primary"
25+
onClick={ () => setIsProcessing(true) }
26+
>
27+
{ __('Save', 'wp-react-page-admin-example') }
28+
</Button>
29+
</CardFooter>
30+
</Card>
31+
</div>
32+
);
33+
};
34+
35+
export default Box;

assets/components/Tab/TabOne.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { __ } from "@wordpress/i18n";
2+
import { __experimentalGrid as Grid, Card, CardBody } from "@wordpress/components";
3+
import Box from "../Box";
4+
5+
const TabOne = () => {
6+
return (
7+
<>
8+
<div>
9+
<h2>{__('Heading', 'wp-react-page-admin-example')}</h2>
10+
<Card>
11+
<CardBody>
12+
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
13+
</CardBody>
14+
</Card>
15+
</div>
16+
<Grid
17+
columns={2}
18+
gap={10}
19+
templateColumns="repeat(auto-fit, minmax(300px, 1fr))"
20+
>
21+
<Box/>
22+
<Box/>
23+
</Grid>
24+
</>
25+
);
26+
};
27+
28+
export default TabOne;

assets/components/Tab/TabThree.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { __experimentalGrid as Grid } from "@wordpress/components";
2+
import Box from "../Box";
3+
4+
const TabThree = () => {
5+
return (
6+
<Grid
7+
columns={1}
8+
>
9+
<Box/>
10+
</Grid>
11+
);
12+
};
13+
14+
export default TabThree;

assets/components/Tab/TabTwo.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { __experimentalGrid as Grid } from "@wordpress/components";
2+
import Box from "../Box";
3+
4+
const TabTwo = () => {
5+
return (
6+
<Grid
7+
columns={3}
8+
gap={10}
9+
templateColumns="repeat(auto-fit, minmax(300px, 1fr))"
10+
>
11+
<Box/>
12+
<Box/>
13+
<Box/>
14+
</Grid>
15+
);
16+
};
17+
18+
export default TabTwo;
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createRoot } from '@wordpress/element';
2-
import App from './App';
2+
import App from './components/App';
33

44
document.addEventListener('DOMContentLoaded', () => {
55
const appRoot = document.getElementById('root');
@@ -8,5 +8,5 @@ document.addEventListener('DOMContentLoaded', () => {
88
}
99

1010
const root = createRoot(appRoot);
11-
root.render(<App title={ appRoot.dataset.title } />);
11+
root.render(<App title={ appRoot?.dataset?.title || '' } />);
1212
});

assets/hooks/useLanguages.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import apiFetch from '@wordpress/api-fetch';
2+
import { useEffect, useState } from "@wordpress/element";
3+
4+
interface Language {
5+
name: string;
6+
slug: string;
7+
}
8+
9+
const useLanguages = () => {
10+
const [languages, setLanguages] = useState<Language[]>([]);
11+
12+
useEffect(() => {
13+
apiFetch({
14+
path: '/pll/v1/languages',
15+
}).then((value: unknown) => {
16+
const languages = value as Language[];
17+
setLanguages(languages);
18+
});
19+
}, []);
20+
21+
return languages;
22+
};
23+
24+
export default useLanguages;

0 commit comments

Comments
 (0)