Skip to content

Commit

Permalink
Initial design work
Browse files Browse the repository at this point in the history
  • Loading branch information
HardeepAsrani committed Dec 24, 2023
1 parent 40d5ddf commit e3f93ab
Show file tree
Hide file tree
Showing 18 changed files with 811 additions and 9 deletions.
66 changes: 66 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": "wordpress",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2021,
"sourceType": "module"
},
"ignorePatterns": [ "node_modules", "assets" ],
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"prefer-destructuring": [
"warn",
{
"array": false,
"object": true
},
{
"enforceForRenamedProperties": false
}
],
"array-bracket-spacing": [
"warn",
"always",
{
"arraysInArrays": false,
"objectsInArrays": false
}
],
"key-spacing": [
"warn",
{
"beforeColon": false,
"afterColon": true
}
],
"object-curly-spacing": [
"warn",
"always",
{
"arraysInObjects": true,
"objectsInObjects": false
}
],
}
}
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@
"homepage": "https://github.com/Codeinwp/quickwp#readme",
"devDependencies": {
"@wordpress/scripts": "^26.19.0",
"eslint-config-wordpress": "^2.0.0",
"simple-git-hooks": "^2.9.0",
"tailwindcss": "^3.4.0"
},
"simple-git-hooks": {
"pre-commit": "npm run lint:js && composer run-script lint && composer run-script phpstan"
},
"dependencies": {
"classnames": "^2.3.2"
}
}
2 changes: 1 addition & 1 deletion postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = {
plugins: [ require( 'tailwindcss' ) ],
plugins: [ require( 'tailwindcss' ) ]
};
38 changes: 35 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
/**
* WordPress dependencies.
*/
import { __ } from '@wordpress/i18n';

import { useSelect } from '@wordpress/data';

/**
* Internal dependencies.
*/
import { useIsSiteEditorLoading } from './hooks';
import Loader from './components/Loader';
import Header from './parts/Header';

const App = () => {
const isEditorLoading = useIsSiteEditorLoading();

const currentStep = useSelect( ( select ) =>
select( 'quickwp/data' ).getStep()
);
const StepControls = currentStep?.view || null;

if ( isEditorLoading ) {
return (
<div
id="quickwp"
className="flex flex-col items-center justify-center fixed py-12 px-14 z-50 bg-bg overflow-auto inset-0"
>
<Loader />
</div>
);
}

return (
<div className="fixed z-50 bg-black overflow-auto inset-0">
<h1>QuickWP</h1>
<p>This is an example starter modal.</p>
<div
id="quickwp"
className="flex flex-col fixed py-12 px-14 z-50 bg-bg overflow-auto inset-0"
>
<Header />
<StepControls />
</div>
);
};
Expand Down
53 changes: 53 additions & 0 deletions src/components/Loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* External dependencies.
*/
import classnames from 'classnames';

/**
* WordPress dependencies.
*/
import { __ } from '@wordpress/i18n';

import { memo, useEffect, useMemo, useState } from '@wordpress/element';

/**
* Internal dependencies.
*/
import { PageControlIcon } from '../utils';

import STEPS from '../steps';

const Loader = () => {
const [ currentPage, setCurrentPage ] = useState( 0 );
const numberOfPages = useMemo( () => STEPS.length, []);

useEffect( () => {
const interval = setInterval( () => {
setCurrentPage( ( prevPage ) =>
prevPage === numberOfPages - 1 ? 0 : prevPage + 1
);
}, 500 );

return () => clearInterval( interval );
}, [ numberOfPages ]);

return (
<ul className="m-0" aria-label={ __( 'Loading', 'quickwp' ) }>
{ Array.from({ length: numberOfPages }).map( ( _, page ) => (
<li
key={ page }
className={ classnames(
'inline-flex m-0 justify-center items-center text-fg h-6 w-6 !min-w-0 !min-h-0 transition-all',
{
'opacity-30': page !== currentPage
}
) }
>
<PageControlIcon isFilled={ page === currentPage } />
</li>
) ) }
</ul>
);
};

export default memo( Loader );
54 changes: 54 additions & 0 deletions src/components/PageControl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* WordPress dependencies.
*/
import { __ } from '@wordpress/i18n';

import { Button } from '@wordpress/components';

import { useSelect, useDispatch } from '@wordpress/data';

/**
* Internal dependencies.
*/
import { PageControlIcon } from '../utils';
import STEPS from '../steps';

const numberOfPages = STEPS.length;

const PageControl = () => {
const currentStep = useSelect( ( select ) =>
select( 'quickwp/data' ).getStep()
);
const { setStep } = useDispatch( 'quickwp/data' );

const currentPage = STEPS.findIndex(
( step ) => step.value === currentStep.value
);

return (
<ul className="m-0" aria-label={ __( 'Pagination', 'quickwp' ) }>
{ Array.from({ length: numberOfPages }).map( ( _, page ) => (
<li
key={ page }
aria-current={ page === currentPage ? 'step' : undefined }
className="inline-block m-0"
>
<Button
key={ page }
disabled={ page > currentPage }
icon={
<PageControlIcon
isFilled={ page === currentPage }
/>
}
aria-label={ STEPS[ page ]?.label }
className="text-fg h-6 w-6 !min-w-0 !min-h-0"
onClick={ () => setStep( STEPS[ page ]?.value ) }
/>
</li>
) ) }
</ul>
);
};

export default PageControl;
111 changes: 111 additions & 0 deletions src/hooks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* WordPress dependencies
*/
import { useEffect, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { decodeEntities } from '@wordpress/html-entities';

const MAX_LOADING_TIME = 10000; // 10 seconds

// This is a copy of the useEditedEntityRecord function from the Gutenberg plugin.
export const useEditedEntityRecord = ( postType, postId ) => {
const { record, title, description, isLoaded, icon } = useSelect(
( select ) => {
const { getEditedPostType, getEditedPostId } =
select( 'core/edit-site' );
const { getEditedEntityRecord, hasFinishedResolution } =
select( 'core' );
const { __experimentalGetTemplateInfo: getTemplateInfo } =
select( 'core/editor' );
const usedPostType = postType ?? getEditedPostType();
const usedPostId = postId ?? getEditedPostId();
const _record = getEditedEntityRecord(
'postType',
usedPostType,
usedPostId
);
const _isLoaded =
usedPostId &&
hasFinishedResolution( 'getEditedEntityRecord', [
'postType',
usedPostType,
usedPostId
]);
const templateInfo = getTemplateInfo( _record );

return {
record: _record,
title: templateInfo.title,
description: templateInfo.description,
isLoaded: _isLoaded,
icon: templateInfo.icon
};
},
[ postType, postId ]
);

return {
isLoaded,
icon,
record,
getTitle: () => ( title ? decodeEntities( title ) : null ),
getDescription: () =>
description ? decodeEntities( description ) : null
};
};

// This is a copy of the useIsSiteEditorLoading function from the Gutenberg plugin.
export const useIsSiteEditorLoading = () => {
const { isLoaded: hasLoadedPost } = useEditedEntityRecord();
const [ loaded, setLoaded ] = useState( false );
const inLoadingPause = useSelect(
( select ) => {
const hasResolvingSelectors =
select( 'core' ).hasResolvingSelectors();
return ! loaded && ! hasResolvingSelectors;
},
[ loaded ]
);

/*
* If the maximum expected loading time has passed, we're marking the
* editor as loaded, in order to prevent any failed requests from blocking
* the editor canvas from appearing.
*/
useEffect( () => {
let timeout;

if ( ! loaded ) {
timeout = setTimeout( () => {
setLoaded( true );
}, MAX_LOADING_TIME );
}

return () => {
clearTimeout( timeout );
};
}, [ loaded ]);

useEffect( () => {
if ( inLoadingPause ) {

/*
* We're using an arbitrary 1s timeout here to catch brief moments
* without any resolving selectors that would result in displaying
* brief flickers of loading state and loaded state.
*
* It's worth experimenting with different values, since this also
* adds 1s of artificial delay after loading has finished.
*/
const timeout = setTimeout( () => {
setLoaded( true );
}, 1000 );

return () => {
clearTimeout( timeout );
};
}
}, [ inLoadingPause ]);

return ! loaded || ! hasLoadedPost;
};
Loading

0 comments on commit e3f93ab

Please sign in to comment.