aboutsummaryrefslogtreecommitdiff
path: root/plugins/base
diff options
context:
space:
mode:
authorMarcin Aman <marcin.aman@gmail.com>2020-11-10 16:54:57 +0100
committerGitHub <noreply@github.com>2020-11-10 16:54:57 +0100
commit07e43676665bdc009e135b767e6d43c536b413fa (patch)
treed389a7257ef4a508a7672abca16c626965c1e04d /plugins/base
parent470ccfca37041ff0f1924318fae8820f674d26f4 (diff)
downloaddokka-07e43676665bdc009e135b767e6d43c536b413fa.tar.gz
dokka-07e43676665bdc009e135b767e6d43c536b413fa.tar.bz2
dokka-07e43676665bdc009e135b767e6d43c536b413fa.zip
New breadcrumbs (#1590)
Add top navbar
Diffstat (limited to 'plugins/base')
-rw-r--r--plugins/base/frontend/src/main/components/app/index.scss6
-rw-r--r--plugins/base/frontend/src/main/components/pageSummary/pageSummary.scss1
-rw-r--r--plugins/base/frontend/src/main/components/pageSummary/pageSummary.tsx24
-rw-r--r--plugins/base/frontend/src/main/components/root.tsx70
-rw-r--r--plugins/base/frontend/src/main/components/search/search.scss1
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt37
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt2
-rw-r--r--plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js28
-rw-r--r--plugins/base/src/main/resources/dokka/styles/style.css103
9 files changed, 165 insertions, 107 deletions
diff --git a/plugins/base/frontend/src/main/components/app/index.scss b/plugins/base/frontend/src/main/components/app/index.scss
index 601ddfa7..97f91292 100644
--- a/plugins/base/frontend/src/main/components/app/index.scss
+++ b/plugins/base/frontend/src/main/components/app/index.scss
@@ -17,17 +17,11 @@ html,
}
.search-content {
- padding-top: 24px;
- margin: 0 41px;
- position: absolute;
- top: 0;
- right: 0;
z-index: 8;
background-color: #f4f4f4;
}
@media screen and (max-width: 759px){
.search-content {
- margin: 0 8px;
}
}
diff --git a/plugins/base/frontend/src/main/components/pageSummary/pageSummary.scss b/plugins/base/frontend/src/main/components/pageSummary/pageSummary.scss
index 400631e6..aaa897a8 100644
--- a/plugins/base/frontend/src/main/components/pageSummary/pageSummary.scss
+++ b/plugins/base/frontend/src/main/components/pageSummary/pageSummary.scss
@@ -52,6 +52,7 @@
&>a {
margin: 0 2em;
+ cursor: pointer;
}
&.selected {
diff --git a/plugins/base/frontend/src/main/components/pageSummary/pageSummary.tsx b/plugins/base/frontend/src/main/components/pageSummary/pageSummary.tsx
index 1aa65d9b..c5a8344f 100644
--- a/plugins/base/frontend/src/main/components/pageSummary/pageSummary.tsx
+++ b/plugins/base/frontend/src/main/components/pageSummary/pageSummary.tsx
@@ -5,6 +5,8 @@ import Scrollspy from 'react-scrollspy'
type PageSummaryProps = {
entries: PageSummaryEntry[],
+ containerId: string, //Id of a container that has scroll enabled
+ offsetComponentId: string, //Id of a top navbar component
}
type PageSummaryEntry = {
@@ -15,13 +17,12 @@ type PageSummaryEntry = {
type SourceSetFilterKey = string
-export const PageSummary: React.FC<PageSummaryProps> = ({ entries }: PageSummaryProps) => {
+const getElementHeightFromDom = (elementId: string): number => document.getElementById(elementId).offsetHeight
+
+export const PageSummary: React.FC<PageSummaryProps> = ({ entries, containerId, offsetComponentId }: PageSummaryProps) => {
const [hidden, setHidden] = useState<Boolean>(true);
const [displayableEntries, setDisplayableEntries] = useState<PageSummaryEntry[]>(entries)
-
- const handleMouseHover = () => {
- setHidden(!hidden)
- }
+ const topOffset = getElementHeightFromDom(offsetComponentId)
useEffect(() => {
const handeEvent = (event: CustomEvent<SourceSetFilterKey[]>) => {
@@ -33,6 +34,17 @@ export const PageSummary: React.FC<PageSummaryProps> = ({ entries }: PageSummary
return () => window.removeEventListener('sourceset-filter-change', handeEvent)
}, [entries])
+ const handleMouseHover = () => {
+ setHidden(!hidden)
+ }
+
+ const handleClick = (entry: PageSummaryEntry) => {
+ document.getElementById(containerId).scrollTo({
+ top: document.getElementById(entry.location).offsetTop - topOffset,
+ behavior: 'smooth'
+ })
+ }
+
let classnames = "page-summary"
if (hidden) classnames += " hidden"
@@ -45,7 +57,7 @@ export const PageSummary: React.FC<PageSummaryProps> = ({ entries }: PageSummary
<div className={"content-wrapper"}>
<h4>On this page</h4>
{!hidden && <Scrollspy items={displayableEntries.map((e) => e.location)} currentClassName="selected">
- {displayableEntries.map((item) => <li><a href={'#' + item.location}>{item.label}</a></li>)}
+ {displayableEntries.map((item) => <li><a onClick={() => handleClick(item)}>{item.label}</a></li>)}
</Scrollspy>}
</div>
</div>
diff --git a/plugins/base/frontend/src/main/components/root.tsx b/plugins/base/frontend/src/main/components/root.tsx
index cb070dfb..4161a4c1 100644
--- a/plugins/base/frontend/src/main/components/root.tsx
+++ b/plugins/base/frontend/src/main/components/root.tsx
@@ -1,6 +1,5 @@
import React from 'react';
import { render } from 'react-dom';
-import RedBox from 'redbox-react';
import _ from "lodash";
import App from "./app";
@@ -8,9 +7,6 @@ import './app/index.scss';
import { NavigationPaneSearch } from './navigationPaneSearch/navigationPaneSearch';
import { PageSummary } from './pageSummary/pageSummary';
-const appEl = document.getElementById('searchBar');
-const rootEl = document.createElement('div');
-
const renderNavigationPane = () => {
render(
<NavigationPaneSearch />,
@@ -19,57 +15,33 @@ const renderNavigationPane = () => {
}
const renderOnThisPage = () => {
- document.addEventListener('DOMContentLoaded', () => {
- for (const e of document.querySelectorAll('.tabs-section-body > div[data-togglable]')) {
- const entries = Array.from(e.querySelectorAll('a[anchor-label]')).map((element: HTMLElement) => {
- return {
- location: element.getAttribute('data-name'),
- label: element.getAttribute('anchor-label'),
- sourceSets: _.sortBy(element.getAttribute('data-filterable-set').split(' '))
- }
- })
- const unique = _.uniqBy(entries, ({label}) => label)
- if (unique.length) {
- const element = document.createElement('div')
- render(<PageSummary entries={unique} />, element)
- e.appendChild(element)
+ for (const e of document.querySelectorAll('.tabs-section-body > div[data-togglable]')) {
+ const entries = Array.from(e.querySelectorAll('a[anchor-label]')).map((element: HTMLElement) => {
+ return {
+ location: element.getAttribute('data-name'),
+ label: element.getAttribute('anchor-label'),
+ sourceSets: _.sortBy(element.getAttribute('data-filterable-set').split(' '))
}
+ })
+ const unique = _.uniqBy(entries, ({label}) => label)
+ if (unique.length) {
+ const element = document.createElement('div')
+ render(<PageSummary entries={unique} containerId={'main'} offsetComponentId={'navigation-wrapper'}/>, element)
+ e.appendChild(element)
}
- })
+ }
+}
+
+const renderMainSearch = () => {
+ render(<App />, document.getElementById('searchBar'));
}
let renderApp = () => {
- render(
- <App />,
- rootEl
- );
+ renderMainSearch();
renderNavigationPane();
renderOnThisPage();
-};
-// @ts-ignore
-if (module.hot) {
- const renderAppHot = renderApp;
- const renderError = (error: Error) => {
- render(
- <RedBox error={error} />,
- rootEl
- );
- };
-
- renderApp = () => {
- try {
- renderAppHot();
- } catch (error) {
- renderError(error);
- }
- };
-
- // @ts-ignore
- module.hot.accept('./app', () => {
- setTimeout(renderApp);
- });
-}
+ document.removeEventListener('DOMContentLoaded', renderApp);
+};
-renderApp();
-appEl!.appendChild(rootEl);
+document.addEventListener('DOMContentLoaded', renderApp); \ No newline at end of file
diff --git a/plugins/base/frontend/src/main/components/search/search.scss b/plugins/base/frontend/src/main/components/search/search.scss
index e7e7673d..8965c5ea 100644
--- a/plugins/base/frontend/src/main/components/search/search.scss
+++ b/plugins/base/frontend/src/main/components/search/search.scss
@@ -4,6 +4,7 @@
fill: #637282;
background: #F4F4F4;
cursor: pointer;
+ margin-top: 3px;
&:focus {
outline: none;
diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
index 05eda494..615bbfc3 100644
--- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt
@@ -99,8 +99,7 @@ open class HtmlRenderer(
node.hasStyle(TextStyle.Span) -> span() { childrenCallback() }
node.dci.kind == ContentKind.Symbol -> div("symbol $additionalClasses") { childrenCallback() }
node.dci.kind == ContentKind.BriefComment -> div("brief $additionalClasses") { childrenCallback() }
- node.dci.kind == ContentKind.Cover -> div("cover $additionalClasses") {
- filterButtons(pageContext)
+ node.dci.kind == ContentKind.Cover -> div("cover $additionalClasses") { //TODO this can be removed
childrenCallback()
}
node.hasStyle(TextStyle.Paragraph) -> p(additionalClasses) { childrenCallback() }
@@ -110,8 +109,8 @@ open class HtmlRenderer(
}
}
- private fun FlowContent.filterButtons(page: ContentPage) {
- if (shouldRenderSourceSetBubbles) {
+ private fun FlowContent.filterButtons(page: PageNode) {
+ if (shouldRenderSourceSetBubbles && page is ContentPage) {
div(classes = "filter-section") {
id = "filter-section"
page.content.withDescendants().flatMap { it.sourceSets }.distinct().forEach {
@@ -584,13 +583,22 @@ open class HtmlRenderer(
override fun FlowContent.buildNavigation(page: PageNode) =
- div(classes = "breadcrumbs") {
- val path = locationProvider.ancestors(page).filterNot { it is RendererSpecificPage }.asReversed()
- if (path.isNotEmpty()) {
- buildNavigationElement(path.first(), page)
- path.drop(1).forEach { node ->
- text("/")
- buildNavigationElement(node, page)
+ div("navigation-wrapper") {
+ id = "navigation-wrapper"
+ div(classes = "breadcrumbs") {
+ val path = locationProvider.ancestors(page).filterNot { it is RendererSpecificPage }.asReversed()
+ if (path.isNotEmpty()) {
+ buildNavigationElement(path.first(), page)
+ path.drop(1).forEach { node ->
+ text("/")
+ buildNavigationElement(node, page)
+ }
+ }
+ }
+ div("pull-right d-flex") {
+ filterButtons(page)
+ div {
+ id = "searchBar"
}
}
}
@@ -706,7 +714,7 @@ open class HtmlRenderer(
override fun buildPage(page: ContentPage, content: (FlowContent, ContentPage) -> Unit): String =
buildHtml(page, page.embeddedResources) {
- div {
+ div("main-content") {
id = "content"
attributes["pageIds"] = page.pageId
content(this, page)
@@ -762,15 +770,12 @@ open class HtmlRenderer(
id = "leftToggler"
span("icon-toggler")
}
- div {
- id = "searchBar"
- }
script(type = ScriptType.textJavaScript, src = page.root("scripts/pages.js")) {}
script(type = ScriptType.textJavaScript, src = page.root("scripts/main.js")) {}
content()
div(classes = "footer") {
span("go-to-top-icon") {
- a(href = "#container")
+ a(href = "#content")
}
span { text("© 2020 Copyright") }
span("pull-right") {
diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
index 93fe8221..8e31fbc6 100644
--- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
@@ -85,7 +85,7 @@ object ScriptsInstaller : PageTransformer {
"scripts/clipboard.js",
"scripts/navigation-loader.js",
"scripts/platform-content-handler.js",
- "scripts/main.js"
+ "scripts/main.js",
)
override fun invoke(input: RootPageNode): RootPageNode {
diff --git a/plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js b/plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js
index 26dd9424..07a6642b 100644
--- a/plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js
+++ b/plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js
@@ -4,6 +4,8 @@ filteringContext = {
activeFilters: []
}
let highlightedAnchor;
+let topNavbarOffset;
+var scrollNavbarBreakPoint = 300
window.addEventListener('load', () => {
document.querySelectorAll("div[data-platform-hinted]")
@@ -18,6 +20,13 @@ window.addEventListener('load', () => {
initTabs()
handleAnchor()
initHidingLeftNavigation()
+
+ document.getElementById('main').addEventListener("scroll", (e) => {
+ const element = document.getElementsByClassName("navigation-wrapper")[0]
+ const additionalOffset = element.classList.contains("sticky-navigation") ? 14 : 0
+ element.classList.toggle("sticky-navigation", e.target.scrollTop + additionalOffset > scrollNavbarBreakPoint)
+ })
+ topNavbarOffset = document.getElementById('navigation-wrapper')
})
const initHidingLeftNavigation = () => {
@@ -64,7 +73,24 @@ function handleAnchor() {
content.classList.add('anchor-highlight')
highlightedAnchor = content
}
- element.scrollIntoView({behavior: "smooth"})
+
+ const scrollToElement = () => document.getElementById('main').scrollTo({ top: element.offsetTop - topNavbarOffset.offsetHeight, behavior: "smooth"})
+
+ const waitAndScroll = () => {
+ setTimeout(() => {
+ if(topNavbarOffset){
+ scrollToElement()
+ } else {
+ waitForScroll()
+ }
+ }, 100)
+ }
+
+ if(topNavbarOffset){
+ scrollToElement()
+ } else {
+ waitAndScroll()
+ }
}
}
}
diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css
index 5e505f33..9e843fe1 100644
--- a/plugins/base/src/main/resources/dokka/styles/style.css
+++ b/plugins/base/src/main/resources/dokka/styles/style.css
@@ -11,16 +11,68 @@
--horizontal-spacing-for-content: 42px;
--mobile-horizontal-spacing-for-content: 8px;
--bottom-spacing: 16px;
+ --color-scrollbar: rgba(39, 40, 44, 0.40);
+ --color-scrollbar-track: #f4f4f4;
}
-#content {
- padding: 0 var(--horizontal-spacing-for-content) var(--bottom-spacing) var(--horizontal-spacing-for-content);
+html {
+ height: 100%;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ scrollbar-color: rgba(39, 40, 44, 0.40) #F4F4F4;
+ scrollbar-color: var(--color-scrollbar) var(--color-scrollbar-track);
}
-.breadcrumbs {
+html ::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+html ::-webkit-scrollbar-track {
+ background-color: var(--color-scrollbar-track);
+}
+
+html ::-webkit-scrollbar-thumb {
+ width: 8px;
+ border-radius: 6px;
+ background: rgba(39, 40, 44, 0.40);
+ background: var(--color-scrollbar);
+}
+
+
+.main-content {
+ padding-bottom: var(--bottom-spacing);
+ z-index: 0;
+}
+
+.main-content>* {
+ margin-left: var(--horizontal-spacing-for-content);
+ margin-right: var(--horizontal-spacing-for-content);
+}
+
+.navigation-wrapper {
+ display: flex;
padding: 24px 0;
+ flex-wrap: wrap;
+}
+
+.navigation-wrapper.sticky-navigation {
+ position: sticky;
+ top: 0;
+ background-color: #f4f4f4;
+ border-bottom: 1px solid #DADFE6;
+ padding-top: 19px;
+ padding-bottom: 18px;
+ z-index: 8;
+
+ /* Reset margin and use padding for border */
+ margin-left: 0;
+ margin-right: 0;
+ padding-left: var(--horizontal-spacing-for-content);
+ padding-right: var(--horizontal-spacing-for-content);
+}
+
+.breadcrumbs {
color: var(--breadcrumb-font-color);
- max-width: calc(100% - 32px);
overflow-wrap: break-word;
}
@@ -93,7 +145,6 @@
.cover {
display: flex;
flex-direction: column;
- width: 100%;
}
.cover .platform-hinted .sourceset-depenent-content > .symbol,
@@ -145,10 +196,6 @@
border-bottom: 2px solid white;
}
-.title {
- overflow-x: auto;
-}
-
.title > .divergent-group:first-of-type {
padding-top: 0;
}
@@ -157,6 +204,7 @@
display: flex;
flex-direction: row;
min-height: 100%;
+ height: 100%;
}
#main {
@@ -164,6 +212,8 @@
max-width: calc(100% - 280px);
display: flex;
flex-direction: column;
+ height: auto;
+ overflow: auto;
}
#leftColumn {
@@ -177,6 +227,8 @@
padding-top: 16px;
position: relative;
max-height: calc(100% - 140px);
+ height: 100%;
+ overflow-y: auto;
}
#sideMenu img {
@@ -187,10 +239,6 @@
background: #DADFE6;
}
-#searchBar {
- float: right;
-}
-
#logo {
background-size: 125px 26px;
border-bottom: 1px solid #DADFE6;
@@ -464,9 +512,6 @@ h1.cover {
line-height: 64px;
letter-spacing: -1.5px;
- margin-left: calc(-1 * var(--horizontal-spacing-for-content));
- margin-right: calc(-1 * var(--horizontal-spacing-for-content));
- padding-left: var(--horizontal-spacing-for-content);
border-bottom: 1px solid #DADFE6;
margin-bottom: 0;
@@ -720,11 +765,7 @@ footer {
flex-direction: row;
align-self: flex-end;
min-height: 30px;
- position: absolute;
- top: 20px;
- right: 88px;
z-index: 0;
- flex-wrap: wrap;
}
.platform-selector:hover {
@@ -1039,7 +1080,7 @@ td.content {
display: flex;
align-items: center;
position: relative;
- height: var(--footer-height);
+ min-height: var(--footer-height);
border-top: 1px solid #DADFE6;
font-size: 12px;
line-height: 16px;
@@ -1105,11 +1146,11 @@ div.runnablesample {
padding: 0;
}
+.d-flex {
+ display: flex;
+}
+
@media screen and (max-width: 1119px) {
- /* TODO this feels wrong as only is an aproximation of correct solution*/
- .filter-section {
- position: unset;
- }
h1.cover {
font-size: 48px;
line-height: 48px;
@@ -1166,10 +1207,16 @@ div.runnablesample {
padding-right: 0.5em;
margin-left: -0.5em;
}
- #content {
- padding: var(--mobile-horizontal-spacing-for-content);
- padding-top: 0;
+ .main-content > * {
+ margin-left: var(--mobile-horizontal-spacing-for-content);
+ margin-right: var(--mobile-horizontal-spacing-for-content);
}
+
+ .navigation-wrapper.sticky-navigation {
+ padding-left: var(--mobile-horizontal-spacing-for-content);
+ padding-right: var(--mobile-horizontal-spacing-for-content);
+ }
+
#sideMenu {
padding-bottom: 16px;
overflow: auto;