-
-
Notifications
You must be signed in to change notification settings - Fork 1
Release/1.5.0 #64
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
Release/1.5.0 #64
Changes from all commits
ba15359
ed1d72f
eacba36
9fedb24
1bca67c
ec9c67a
40dc5ad
d648a67
e6227d0
1c9cb06
b39cf87
188b152
d749b53
0b2e42e
52c6fa8
7eb16fa
4fb977b
14ac81b
6908623
d2ef20b
b4e1e20
784c13c
90da8dd
d78f942
9b264c6
c99c61a
265ba6d
db8adad
945a28f
c82014d
5510a93
49d67dc
1afd38b
87ae9cd
b145b66
a966760
90c6fd6
1332af0
55daa79
115b3ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| { | ||
| "landingPage": "/wp-admin/options-general.php?page=perform", | ||
| "features": { | ||
| "networking": true | ||
| }, | ||
| "plugins": [ | ||
| "perform" | ||
| ], | ||
| "preferredVersions": { | ||
| "php": "8.2", | ||
| "wp": "6.8" | ||
| }, | ||
| "steps": [ | ||
| { | ||
| "step": "login" | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| { | ||
| "landingPage": "/wp-admin/options-general.php?page=perform", | ||
| "features": { | ||
| "networking": true | ||
| }, | ||
| "plugins": [ | ||
| "perform" | ||
| ], | ||
| "preferredVersions": { | ||
| "php": "8.2", | ||
| "wp": "6.8" | ||
| }, | ||
| "steps": [ | ||
| { | ||
| "step": "login" | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,4 +5,5 @@ | |
| --menu-color: #f0f0f1; | ||
| --menu-hover-color: #f5f5f5; | ||
| --text-color: #333333; | ||
| } | ||
| --white-color: #ffffff; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { Card, CardHeader, CardBody } from '@wordpress/components'; | ||
|
|
||
| const SettingsCard = ({ title, description, children }) => ( | ||
| <Card style={{ marginBottom: '24px' }}> | ||
| <CardHeader> | ||
| <strong>{title}</strong> | ||
| </CardHeader> | ||
| {description && <CardBody><p>{description}</p></CardBody>} | ||
| <CardBody>{children}</CardBody> | ||
| </Card> | ||
| ); | ||
|
|
||
| export default SettingsCard; |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,35 @@ | ||||
| import { Button, Spinner } from '@wordpress/components'; | ||||
| import { useEffect } from '@wordpress/element'; | ||||
|
|
||||
| const Footer = ({ dirty, saving, message, onSave }) => { | ||||
| // message: { text, type } where type is 'success' | 'error' | '' | ||||
| return ( | ||||
| <div className="perform-savebar" style={{ | ||||
| position: 'sticky', | ||||
| bottom: 0, | ||||
| left: 0, | ||||
| right: 0, | ||||
| background: '#fff', | ||||
| borderTop: '1px solid #eee', | ||||
| padding: 12, | ||||
| zIndex: 1000, | ||||
| display: 'flex', | ||||
| justifyContent: 'flex-end', | ||||
| gap: 12, | ||||
| alignItems: 'center', | ||||
| marginBottom: '-20px', | ||||
|
||||
| marginBottom: '-20px', |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,140 @@ | ||||||||||||||
| import SettingsHeader from './SettingsHeader'; | ||||||||||||||
| import SettingsNav from './SettingsNav'; | ||||||||||||||
| import Footer from './Footer'; | ||||||||||||||
| import { useState, useEffect, useMemo, useRef } from '@wordpress/element'; | ||||||||||||||
|
|
||||||||||||||
| const SettingsApp = () => { | ||||||||||||||
| const tabs = window.performwpSettings?.tabs || {}; | ||||||||||||||
| const fields = window.performwpSettings?.fields || {}; | ||||||||||||||
| const initialValues = useMemo(() => { | ||||||||||||||
| // Build a map of field id => saved value (if present) or default value (empty string or false) | ||||||||||||||
| const saved = window.performwpSettings?.saved || {}; | ||||||||||||||
| const values = {}; | ||||||||||||||
| Object.keys(fields).forEach((tab) => { | ||||||||||||||
| fields[tab].forEach((card) => { | ||||||||||||||
| (card.fields || []).forEach((f) => { | ||||||||||||||
| const savedVal = saved && Object.prototype.hasOwnProperty.call(saved, f.id) ? saved[f.id] : undefined; | ||||||||||||||
| if (typeof savedVal !== 'undefined') { | ||||||||||||||
| values[f.id] = savedVal; | ||||||||||||||
| } else { | ||||||||||||||
| values[f.id] = f.default ?? (f.type === 'toggle' ? false : ''); | ||||||||||||||
| } | ||||||||||||||
| }); | ||||||||||||||
| }); | ||||||||||||||
| }); | ||||||||||||||
| return values; | ||||||||||||||
| }, [fields]); | ||||||||||||||
|
|
||||||||||||||
| const [fieldValues, setFieldValues] = useState(initialValues); | ||||||||||||||
| const [saving, setSaving] = useState(false); | ||||||||||||||
| const [message, setMessage] = useState(null); | ||||||||||||||
| const [activeTab, setActiveTab] = useState(Object.keys(tabs)[0] || ''); | ||||||||||||||
| const messageTimerRef = useRef(null); | ||||||||||||||
|
|
||||||||||||||
| // dirty detection | ||||||||||||||
|
|
||||||||||||||
| const handleFieldChange = (id, value) => { | ||||||||||||||
| setFieldValues((prev) => ({ ...prev, [id]: value })); | ||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| const handleSave = async () => { | ||||||||||||||
| setSaving(true); | ||||||||||||||
| setMessage(null); | ||||||||||||||
| try { | ||||||||||||||
| const res = await fetch(ajaxurl, { | ||||||||||||||
|
||||||||||||||
| const res = await fetch(ajaxurl, { | |
| const ajaxUrl = window.performwpSettings?.ajaxurl || window.ajaxurl; | |
| if (!ajaxUrl) { | |
| throw new Error('AJAX URL not defined.'); | |
| } | |
| const res = await fetch(ajaxUrl, { |
Copilot
AI
Nov 3, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These commented-out thoughts/implementation notes should be removed. They describe the problem-solving process but don't add value to the final code. The implementation using savedSnapshot is clear from the code itself. Remove these comments to improve code cleanliness.
| // mutate initialValues object won't update memo, so reset by rebuild: setFieldValues equals current, but we need to reset initialValues - simplest approach: set initial snapshot to current by resetting via a state. | |
| // We'll set the initialValues by replacing the state used for comparison: emulate by setting all initialValues to current values via a ref - but here we'll just clear dirty by resetting initialValues via resetting fieldValues baseline. | |
| // For simplicity, update initialValues by assigning to window.performwpSettings._initial = fieldValues (not ideal), but we can update local initialValues via a small trick: setFieldValues to same and update a savedSnapshot state. | |
| // Implement savedSnapshot state instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import useEffect.