Skip to content

Commit

Permalink
fix: icon unexpected intermediate state while loading the page
Browse files Browse the repository at this point in the history
  • Loading branch information
Yilun-Sun committed May 16, 2024
1 parent f5ce1ed commit a795a86
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 63 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"copy-vendor": "cp -R vendor/ .next/server/vendor/"
},
"dependencies": {
"@ant-design/cssinjs": "^1.20.0",
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-brands-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
Expand Down
9 changes: 6 additions & 3 deletions pnpm-lock.yaml

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

21 changes: 21 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,24 @@ body {
text-wrap: balance;
}
}

.ant-breadcrumb > ol {
flex-wrap: nowrap !important;
align-items: center;
overflow-x: auto;
}

.ant-dropdown-menu-sub {
max-height: 50vh;
overflow-y: auto;
box-shadow:
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
border-radius: 8px;
}

.ant-dropdown-menu-submenu-title {
display: flex;
align-items: center;
}
35 changes: 29 additions & 6 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
import type { Metadata } from 'next';
'use client';
import { Inter } from 'next/font/google';
import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';
import { useState } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import './globals.css';

const inter = Inter({ subsets: ['latin'] });

export const metadata: Metadata = {
title: 'PHP AST Viewer',
description: 'View the Abstract Syntax Tree (AST) of PHP code parsed by the PHP-Parser library.',
};
// https://github.com/vercel/next.js/issues/44125#issuecomment-1372270391
function StyleProviderLayout({ children }: { children: React.ReactNode }) {
const [cache] = useState(() => createCache());

const render = <>{children}</>;

useServerInsertedHTML(() => {
return (
<script
dangerouslySetInnerHTML={{
__html: `</script>${extractStyle(cache)}<script>`,
}}
/>
);
});

if (typeof window !== 'undefined') {
return render;
}

return <StyleProvider cache={cache}>{render}</StyleProvider>;
}

export default function RootLayout({
children,
Expand All @@ -17,7 +38,9 @@ export default function RootLayout({
return (
<html lang='en'>
<link rel='icon' href='./favicon.svg' sizes='any' type='image/svg+xml' />
<body className={inter.className}>{children}</body>
<body className={inter.className}>
<StyleProviderLayout>{children}</StyleProviderLayout>
</body>
</html>
);
}
18 changes: 11 additions & 7 deletions src/app/viewer/json-viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@
width: fit-content;
}

/* #json-viewer .variable-row:hover {
border-radius: 4px;
background-color: #7a86b866;
cursor: pointer;
} */

#json-viewer .object-key-val:not([id$='attributes']) > .object-container > .object-content > .variable-row:hover {
border-radius: 4px;
background-color: #7a86b866;
cursor: pointer;
}

#json-viewer .ant-spin {
position: absolute !important;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}

.react-json-view {
padding: 10px;
}
21 changes: 18 additions & 3 deletions src/app/viewer/json-viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { INode } from '@rightcapital/php-parser/dist/php-parser/types/node';
import _ from 'lodash';
import ReactJson, { CollapsedFieldProps, OnSelectProps } from '@yilun-sun/react-json-view';
import './json-viewer.css';
import { Spin } from 'antd';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons';

interface JsonViewerProps {
jsonData: { data: INode[] };
Expand All @@ -13,11 +16,20 @@ interface JsonViewerProps {
currentNamespace: string[];
expandDepth: number;
isDarkMode: boolean;
isParsing: boolean;
}

export default function JsonViewer(props: JsonViewerProps) {
const { onSelect, enableClipboard, jsonData, alwaysCollapseFieldNames, currentNamespace, expandDepth, isDarkMode } =
props;
const {
onSelect,
isParsing,
enableClipboard,
jsonData,
alwaysCollapseFieldNames,
currentNamespace,
expandDepth,
isDarkMode,
} = props;

const [currentHighlightNode, setCurrentHighlightNode] = useState<HTMLElement | null>(null);

Expand All @@ -38,13 +50,16 @@ export default function JsonViewer(props: JsonViewerProps) {

return (
<div id={'json-viewer'} className={'json-viewer'}>
{document !== undefined && isParsing && (
<Spin size='large' indicator={<FontAwesomeIcon icon={faCircleNotch} spin />} />
)}
<ReactJson
onSelect={onSelect}
quotesOnKeys={false}
src={jsonData}
enableClipboard={enableClipboard}
displayDataTypes={false}
theme={isDarkMode ? 'railscasts' : 'rjv-default'}
theme={isDarkMode ? 'tomorrow' : 'rjv-default'}
forceCalculateShouldCollapseOnNamespaceUpdate={currentNamespace}
shouldCollapse={(field: CollapsedFieldProps) => {
if (currentNamespace.join('-').startsWith(field.namespace.join('-'))) {
Expand Down
21 changes: 1 addition & 20 deletions src/app/viewer/viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,7 @@
#tree-viewer .node-text.selected,
#json-viewer .selected {
background-color: rgba(255, 255, 0, 0.25);
border: solid 1px yellowgreen;
}

.namespace-breadcrumb > ol {
flex-wrap: nowrap;
}

.ant-dropdown-menu-sub {
max-height: 50vh;
overflow-y: auto;
box-shadow:
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
border-radius: 8px;
}

.ant-dropdown-menu-submenu-title {
display: flex;
align-items: center;
border: solid 1px #6faa58b5;
}

.editor-viewer-divider {
Expand Down
65 changes: 41 additions & 24 deletions src/app/viewer/viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faGear, faMoon, faLocationDot, faRotate, faSun, faWarning } from '@fortawesome/free-solid-svg-icons';
import { faGithub } from '@fortawesome/free-brands-svg-icons';
import { RCLogo } from './rc-logo';
import Image from 'next/image';
import '@fortawesome/fontawesome-svg-core/styles.css';
import './viewer.css';

const { Header, Content } = Layout;
Expand Down Expand Up @@ -93,11 +95,11 @@ function BaseViewer({ isDarkMode, setIsDarkMode }: BaseViewerProps) {
const [alwaysCollapseFieldNames, setAlwaysCollapseFieldNames] = useState<string[]>(['attributes']);
const [enableClipboard, setEnableClipboard] = useState(false);
const [isParsing, setIsParsing] = useState(false);
const [currentNamespace, setCurrentNamespace] = useState<string[]>([]);
const [currentNamespace, setCurrentNamespace] = useState<string[]>(['root']);
const [isDisplayRawJson, setIsDisplayRawJson] = useState(true);
const [selectedNode, setSelectedNode] = useState<INode | undefined>(undefined);
const [expandDepth, setExpandDepth] = useState(3);
const [editorContainerSize, setEditorContainerSize] = useState(0);
const [editorContainerSize, setEditorContainerSize] = useState<string | number>('50%');
const [windowInnerWidth, setWindowInnerWidth] = useState(0);
const [isTourOpen, setIsTourOpen] = useState(false);

Expand Down Expand Up @@ -203,6 +205,16 @@ function BaseViewer({ isDarkMode, setIsDarkMode }: BaseViewerProps) {
document.body.addEventListener('mouseup', onMouseUp);
};

const editorViewerDivider = (
<div className='w-[12px] h-[100%] flex align-middle'>
<div
className='editor-viewer-divider'
style={{ borderInlineColor: token.colorText }}
onMouseDown={dividerMouseDownHandler}
/>
</div>
);

const clearRangeAndSelectedNode = () => {
setCurrentNamespace([]);
setSelectedNode(undefined);
Expand Down Expand Up @@ -253,18 +265,26 @@ function BaseViewer({ isDarkMode, setIsDarkMode }: BaseViewerProps) {
},
];

const viewerWidth =
typeof editorContainerSize === 'string'
? editorContainerSize
: windowInnerWidth - editorContainerSize - dividerWidth;

return (
<div className='flex flex-col items-start h-[100vh]' style={{ backgroundColor: token.colorBgContainer }}>
<Tour open={isTourOpen} onClose={() => setIsTourOpen(false)} steps={steps} />
<Layout style={layoutStyle}>
<Header style={headerStyle}>
<div className='flex'>
<Typography.Title className='m-4 text-nowrap' level={3}>
🔎 PHP AST Viewer
</Typography.Title>
<div className='flex'>
<div className='m-auto text-nowrap flex items-center'>
<Typography.Title level={4} className='m-[0!important] flex items-center'>
<Image src='./favicon.svg' className='ml-2 mr-3' alt='' width={28} height={28} />
<span className='m-0 mr-3 leading-[20px] text-lg'>PHP AST Viewer</span>
</Typography.Title>
</div>
<div className='flex items-center'>
<Button
className='m-4 mr-2'
className='mr-2'
onClick={() => {
setTextareaData(sampleCode);
}}
Expand All @@ -273,7 +293,6 @@ function BaseViewer({ isDarkMode, setIsDarkMode }: BaseViewerProps) {
Load sample code
</Button>
<Button
className='m-4 ml-2'
onClick={async () => {
try {
const text = await navigator.clipboard.readText();
Expand Down Expand Up @@ -318,7 +337,11 @@ function BaseViewer({ isDarkMode, setIsDarkMode }: BaseViewerProps) {
<Content style={contentStyle}>
<div className='flex flex-col w-[100%] h-[100%]'>
<div className='flex w-[100%] h-[100%]'>
<div className='h-[100%] overflow-y-auto relative' style={{ width: editorContainerSize }} ref={ref1}>
<div
className='h-[100%] overflow-y-auto relative'
style={{ width: editorContainerSize, backgroundColor: token.colorBgBase }}
ref={ref1}
>
<Editor
className='codeEditor'
theme={isDarkMode ? 'vs-dark' : 'light'}
Expand Down Expand Up @@ -358,20 +381,15 @@ function BaseViewer({ isDarkMode, setIsDarkMode }: BaseViewerProps) {
/>
</div>

<div className='w-[12px] h-[100%] flex align-middle'>
<div
className='editor-viewer-divider'
style={{ borderInlineColor: token.colorText }}
onMouseDown={dividerMouseDownHandler}
/>
</div>
{editorViewerDivider}

<div
className='h-[100%] relative'
style={{ width: windowInnerWidth - editorContainerSize - dividerWidth }}
style={{
width: viewerWidth,
backgroundColor: token.colorBgBase,
}}
>
{isParsing && <Spin className='absolute left-1/2 top-1/2' />}

<div className='fixed flex flex-col z-10 top-[110px] right-[10px]'>
<Button
className='m-2'
Expand Down Expand Up @@ -431,18 +449,16 @@ function BaseViewer({ isDarkMode, setIsDarkMode }: BaseViewerProps) {
)}
</div>

<div
className='w-[100%] h-[40px] mb-[8px]'
style={{ backgroundColor: token.colorBgContainer }}
ref={ref3}
>
<div className='w-[100%] h-[40px]' style={{ backgroundColor: token.colorBgContainer }} ref={ref3}>
<SelectedNodeNamespace
jsonData={jsonDataRef.current}
namespace={currentNamespace}
onSelectNamespace={setSelectedNode}
/>
</div>

<div className='w-[100%] h-[8px]' style={{ backgroundColor: token.colorBgLayout }} />

<div
className='h-[calc(100%-48px)] overflow-y-auto'
style={{ backgroundColor: token.colorBgContainer }}
Expand All @@ -460,6 +476,7 @@ function BaseViewer({ isDarkMode, setIsDarkMode }: BaseViewerProps) {

{isDisplayRawJson && (
<JsonViewer
isParsing={isParsing}
isDarkMode={isDarkMode}
jsonData={jsonData}
selectedNode={selectedNode}
Expand Down

0 comments on commit a795a86

Please sign in to comment.