mirror of https://github.com/artifacthub/hub.git
Fix scroll issue in search page (#2596)
Signed-off-by: Cintia Sanchez Garcia <cynthiasg@icloud.com>
This commit is contained in:
parent
b42de22e3c
commit
aeafcf43e0
|
|
@ -36,6 +36,7 @@
|
||||||
"remark-unlink": "^3.1.0",
|
"remark-unlink": "^3.1.0",
|
||||||
"semver": "^7.3.8",
|
"semver": "^7.3.8",
|
||||||
"tinycolor2": "^1.4.2",
|
"tinycolor2": "^1.4.2",
|
||||||
|
"ua-parser-js": "^1.0.32",
|
||||||
"unified": "^9.2.1",
|
"unified": "^9.2.1",
|
||||||
"yaml": "2.0.1"
|
"yaml": "2.0.1"
|
||||||
},
|
},
|
||||||
|
|
@ -76,7 +77,7 @@
|
||||||
"proxy": "http://localhost:8000",
|
"proxy": "http://localhost:8000",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"copy:static": "shx rm -rf src/static && shx mkdir src/static && shx cp -r public/static/* src/static",
|
"copy:static": "shx rm -rf src/static && shx mkdir src/static && shx cp -r public/static/* src/static",
|
||||||
"start": "yarn copy:static && react-scripts start",
|
"start": "yarn copy:static && DANGEROUSLY_DISABLE_HOST_CHECK=true react-scripts start",
|
||||||
"build": "yarn copy:static && INLINE_RUNTIME_CHUNK=false IMAGE_INLINE_SIZE_LIMIT=0 react-scripts build",
|
"build": "yarn copy:static && INLINE_RUNTIME_CHUNK=false IMAGE_INLINE_SIZE_LIMIT=0 react-scripts build",
|
||||||
"test": "sed -i -e 's/const FORCE_EXIT_DELAY = 500;/const FORCE_EXIT_DELAY = 1000;/g' ./node_modules/jest-worker/build/base/BaseWorkerPool.js && TZ=UTC react-scripts test # See https://github.com/facebook/jest/issues/11354",
|
"test": "sed -i -e 's/const FORCE_EXIT_DELAY = 500;/const FORCE_EXIT_DELAY = 1000;/g' ./node_modules/jest-worker/build/base/BaseWorkerPool.js && TZ=UTC react-scripts test # See https://github.com/facebook/jest/issues/11354",
|
||||||
"test:coverage": "TZ=UTC react-scripts test --coverage --watchAll=false",
|
"test:coverage": "TZ=UTC react-scripts test --coverage --watchAll=false",
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import API from '../../../../../api';
|
||||||
import { AppCtx, unselectOrg } from '../../../../../context/AppCtx';
|
import { AppCtx, unselectOrg } from '../../../../../context/AppCtx';
|
||||||
import { AuthorizerAction, ErrorKind, Organization } from '../../../../../types';
|
import { AuthorizerAction, ErrorKind, Organization } from '../../../../../types';
|
||||||
import alertDispatcher from '../../../../../utils/alertDispatcher';
|
import alertDispatcher from '../../../../../utils/alertDispatcher';
|
||||||
|
import scrollToTop from '../../../../../utils/scrollToTop';
|
||||||
import InputField from '../../../../common/InputField';
|
import InputField from '../../../../common/InputField';
|
||||||
import Modal from '../../../../common/Modal';
|
import Modal from '../../../../common/Modal';
|
||||||
import ActionBtn from '../../../ActionBtn';
|
import ActionBtn from '../../../ActionBtn';
|
||||||
|
|
@ -31,7 +32,7 @@ const DeleteOrganization = (props: Props) => {
|
||||||
setIsDeleting(true);
|
setIsDeleting(true);
|
||||||
await API.deleteOrganization(props.organization.name);
|
await API.deleteOrganization(props.organization.name);
|
||||||
dispatch(unselectOrg());
|
dispatch(unselectOrg());
|
||||||
window.scrollTo(0, 0); // Scroll to top when org is deleted
|
scrollToTop(); // Scroll to top when org is deleted
|
||||||
setIsDeleting(false);
|
setIsDeleting(false);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setIsDeleting(false);
|
setIsDeleting(false);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ jest.mock('react-markdown', () => (props: any) => {
|
||||||
return <>{props.children}</>;
|
return <>{props.children}</>;
|
||||||
});
|
});
|
||||||
jest.mock('remark-gfm', () => () => <div />);
|
jest.mock('remark-gfm', () => () => <div />);
|
||||||
|
jest.mock('../../utils/bannerDispatcher', () => ({
|
||||||
|
getBanner: () => null,
|
||||||
|
}));
|
||||||
|
|
||||||
const getMockPackage = (fixtureId: string): Package => {
|
const getMockPackage = (fixtureId: string): Package => {
|
||||||
return require(`./__fixtures__/index/${fixtureId}.json`) as Package;
|
return require(`./__fixtures__/index/${fixtureId}.json`) as Package;
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import bannerDispatcher from '../../utils/bannerDispatcher';
|
||||||
import isFuture from '../../utils/isFuture';
|
import isFuture from '../../utils/isFuture';
|
||||||
import isPackageOfficial from '../../utils/isPackageOfficial';
|
import isPackageOfficial from '../../utils/isPackageOfficial';
|
||||||
import { prepareQueryString } from '../../utils/prepareQueryString';
|
import { prepareQueryString } from '../../utils/prepareQueryString';
|
||||||
|
import scrollToTop from '../../utils/scrollToTop';
|
||||||
import sortPackageVersions from '../../utils/sortPackageVersions';
|
import sortPackageVersions from '../../utils/sortPackageVersions';
|
||||||
import updateMetaIndex from '../../utils/updateMetaIndex';
|
import updateMetaIndex from '../../utils/updateMetaIndex';
|
||||||
import AnchorHeader from '../common/AnchorHeader';
|
import AnchorHeader from '../common/AnchorHeader';
|
||||||
|
|
@ -240,7 +241,7 @@ const PackageView = (props: Props) => {
|
||||||
setApiError(null);
|
setApiError(null);
|
||||||
setCurrentPkgId(detailPkg.packageId);
|
setCurrentPkgId(detailPkg.packageId);
|
||||||
setRelatedPosition(undefined);
|
setRelatedPosition(undefined);
|
||||||
window.scrollTo(0, 0); // Scroll to top when a new version is loaded
|
scrollToTop(); // Scroll to top when a new version is loaded
|
||||||
// Stop loading when readme is not defined or is the same than the previous one
|
// Stop loading when readme is not defined or is the same than the previous one
|
||||||
if (
|
if (
|
||||||
isNull(detailPkg.readme) ||
|
isNull(detailPkg.readme) ||
|
||||||
|
|
@ -508,7 +509,7 @@ const PackageView = (props: Props) => {
|
||||||
if (props.hash !== currentHash) {
|
if (props.hash !== currentHash) {
|
||||||
setCurrentHash(props.hash);
|
setCurrentHash(props.hash);
|
||||||
if (isUndefined(props.hash) || props.hash === '') {
|
if (isUndefined(props.hash) || props.hash === '') {
|
||||||
window.scrollTo(0, 0);
|
scrollToTop();
|
||||||
} else {
|
} else {
|
||||||
scrollIntoView();
|
scrollIntoView();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import { FacetOption, Facets, Package, RepositoryKind, SearchFiltersURL, SearchR
|
||||||
import { TS_QUERY } from '../../utils/data';
|
import { TS_QUERY } from '../../utils/data';
|
||||||
import getSampleQueries from '../../utils/getSampleQueries';
|
import getSampleQueries from '../../utils/getSampleQueries';
|
||||||
import { prepareQueryString } from '../../utils/prepareQueryString';
|
import { prepareQueryString } from '../../utils/prepareQueryString';
|
||||||
|
import scrollToTop from '../../utils/scrollToTop';
|
||||||
import Loading from '../common/Loading';
|
import Loading from '../common/Loading';
|
||||||
import NoData from '../common/NoData';
|
import NoData from '../common/NoData';
|
||||||
import Pagination from '../common/Pagination';
|
import Pagination from '../common/Pagination';
|
||||||
|
|
@ -121,10 +122,6 @@ const SearchView = (props: Props) => {
|
||||||
setScrollPosition(window.scrollY);
|
setScrollPosition(window.scrollY);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateWindowScrollPosition = (newPosition: number) => {
|
|
||||||
window.scrollTo(0, newPosition);
|
|
||||||
};
|
|
||||||
|
|
||||||
const prepareSelectedFilters = (name: string, newFilters: string[], prevFilters: FiltersProp): FiltersProp => {
|
const prepareSelectedFilters = (name: string, newFilters: string[], prevFilters: FiltersProp): FiltersProp => {
|
||||||
let cleanFilters: FiltersProp = {};
|
let cleanFilters: FiltersProp = {};
|
||||||
switch (name) {
|
switch (name) {
|
||||||
|
|
@ -260,7 +257,7 @@ const SearchView = (props: Props) => {
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
setScrollPosition(0);
|
setScrollPosition(0);
|
||||||
updateWindowScrollPosition(0);
|
scrollToTop(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPaginationLimitChange = (newLimit: number): void => {
|
const onPaginationLimitChange = (newLimit: number): void => {
|
||||||
|
|
@ -272,7 +269,7 @@ const SearchView = (props: Props) => {
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
setScrollPosition(0);
|
setScrollPosition(0);
|
||||||
updateWindowScrollPosition(0);
|
scrollToTop(0);
|
||||||
dispatch(updateLimit(newLimit));
|
dispatch(updateLimit(newLimit));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -322,14 +319,14 @@ const SearchView = (props: Props) => {
|
||||||
if (history.action === 'PUSH') {
|
if (history.action === 'PUSH') {
|
||||||
// When search page is open from detail page
|
// When search page is open from detail page
|
||||||
if (props.fromDetail && !isUndefined(scrollPosition)) {
|
if (props.fromDetail && !isUndefined(scrollPosition)) {
|
||||||
updateWindowScrollPosition(scrollPosition);
|
scrollToTop(scrollPosition);
|
||||||
// When search has changed
|
// When search has changed
|
||||||
} else {
|
} else {
|
||||||
updateWindowScrollPosition(0);
|
scrollToTop(0);
|
||||||
}
|
}
|
||||||
// On pop action and when scroll position has been previously saved
|
// On pop action and when scroll position has been previously saved
|
||||||
} else if (!isUndefined(scrollPosition)) {
|
} else if (!isUndefined(scrollPosition)) {
|
||||||
updateWindowScrollPosition(scrollPosition);
|
scrollToTop(scrollPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
const parser = require('ua-parser-js');
|
||||||
|
|
||||||
|
class BrowserDetect {
|
||||||
|
private ua: any = {};
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
this.ua = parser(navigator.userAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isSafari(): boolean {
|
||||||
|
if (this.ua.browser.name.includes('Safari')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const browserDetect = new BrowserDetect();
|
||||||
|
browserDetect.init();
|
||||||
|
export default browserDetect;
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import browserDetect from './browserDetect';
|
||||||
|
|
||||||
|
const scrollToTop = (position?: number): void => {
|
||||||
|
const isSafari = browserDetect.isSafari();
|
||||||
|
window.scrollTo({
|
||||||
|
top: position || 0,
|
||||||
|
// @ts-ignore: Unreachable code error
|
||||||
|
behavior: isSafari ? 'instant' : 'auto',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default scrollToTop;
|
||||||
|
|
@ -10118,6 +10118,11 @@ typescript@^4.9.3:
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db"
|
||||||
integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==
|
integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==
|
||||||
|
|
||||||
|
ua-parser-js@^1.0.32:
|
||||||
|
version "1.0.32"
|
||||||
|
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.32.tgz#786bf17df97de159d5b1c9d5e8e9e89806f8a030"
|
||||||
|
integrity sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==
|
||||||
|
|
||||||
unbox-primitive@^1.0.2:
|
unbox-primitive@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
|
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue