Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions apps/docs/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
@let opened = opened$ | async;

<docs-sidenav
class="kbq-scrollbar"
[class.docs-sidenav_closed]="!opened"
[class.docs-sidenav_opened]="opened"
[@openCloseSidenav]="opened ? 'open' : 'closed'"
/>
@if (isExamplesPage) {
<router-outlet />
} @else {
<docs-sidenav
class="kbq-scrollbar"
[class.docs-sidenav_closed]="!opened"
[class.docs-sidenav_opened]="opened"
[@openCloseSidenav]="opened ? 'open' : 'closed'"
/>

<div class="docs-app-container layout-column flex">
<docs-navbar [class.docs-top-overflown]="docStates.viewerTopOverflown | async" />
<div class="docs-app-container layout-column flex">
<docs-navbar [class.docs-top-overflown]="docStates.viewerTopOverflown | async" />

<kbq-divider />
<kbq-divider />

<router-outlet />
<router-outlet />

<div class="docs-overlay" [@fadeInOutSidenav]="opened ? 'fadeIn' : 'fadeOut'"></div>
</div>
<div class="docs-overlay" [@fadeInOutSidenav]="opened ? 'fadeIn' : 'fadeOut'"></div>
</div>
}
15 changes: 13 additions & 2 deletions apps/docs/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { animate, state, style, transition, trigger } from '@angular/animations';
import { AsyncPipe } from '@angular/common';
import { Component, inject, ViewEncapsulation } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { NavigationEnd, Router, RouterOutlet } from '@angular/router';
import { KbqDividerModule } from '@koobiq/components/divider';
import { map, Observable } from 'rxjs';
import { filter, map, Observable } from 'rxjs';
import { DocsNavbarComponent } from './components/navbar/navbar.component';
import { DocsSidenav } from './components/sidenav/sidenav';
import { DocsDocStates, DocsNavbarState } from './services/doc-states';
Expand Down Expand Up @@ -56,8 +56,19 @@ import { DocsDocStates, DocsNavbarState } from './services/doc-states';
})
export class DocsAppComponent {
readonly docStates = inject(DocsDocStates);
readonly router = inject(Router);

readonly opened$: Observable<boolean> = this.docStates.navbarMenu.pipe(
map((state) => state === DocsNavbarState.Opened)
);

isExamplesPage = false;

constructor() {
this.router.events
.pipe(filter((event): event is NavigationEnd => event instanceof NavigationEnd))
Comment thread
artembelik marked this conversation as resolved.
Outdated
.subscribe((event: NavigationEnd) => {
this.isExamplesPage = event.urlAfterRedirects.startsWith('/examples');
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { CdkScrollable } from '@angular/cdk/overlay';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqButtonModule } from '@koobiq/components/button';
import { KbqPopoverModule } from '@koobiq/components/popover';
import { KbqTopBarModule } from '@koobiq/components/top-bar';

@Component({
selector: 'docs-popover-example',
imports: [KbqButtonModule, KbqTopBarModule, CdkScrollable, KbqPopoverModule],
template: `
<kbq-top-bar style="z-index: 1000">
Comment thread
artembelik marked this conversation as resolved.
Outdated
<div
class="layout-row layout-align-center-center layout-padding-top-3xs layout-padding-bottom-3xs kbq-title kbq-truncate-line"
kbqTopBarContainer
placement="start"
>
<span class="kbq-truncate-line">Page Title</span>
</div>

<div kbqTopBarSpacer></div>
</kbq-top-bar>

<div class="docs-text-container" cdk-scrollable>
<p>
A popover is a transient graphical user interface element that appears on top of the current page's
content to present information, options, or actions related to a specific UI element, which is commonly
referred to as the trigger. It is designed for quick, contextual interactions without permanently
navigating away from the current view.
</p>

<button kbq-button kbqPopover [kbqPopoverContent]="popoverContent" [hideIfNotInViewPort]="false">
Open popover
</button>

<p>
Think of a popover as a lightweight, floating card that is directly tethered to the element that
summoned it. Unlike a modal dialog, it does not usually block interaction with the rest of the page
entirely, allowing for a faster and more in-context workflow. It is often activated by clicking a
button, icon, or link, and it disappears when the user moves their focus away.
</p>
<p>
The core concept of a popover revolves around its contextual and transient nature. It is directly linked
to a specific UI element on the page, providing information or controls that are immediately relevant to
that element. It appears temporarily and disappears when the user interacts outside of it or performs an
action within it, meaning it does not permanently change the main view. Popovers are meant for small,
focused interactions and should not be used for large, complex forms or displaying extensive amounts of
information. In its most common form, a popover is non-modal, which means the user can still interact
with the main page content while the popover is open, though some designs use a light modal scrim to
provide stronger visual focus.
</p>
<p>
Visually, a typical popover consists of several key parts that work together to create a clear and
functional interface element. The container is a floating box with a distinct background color, a drop
shadow to create depth, and often rounded corners. A small visual element, usually a triangle called a
pointer or arrow, points directly to the UI element that triggered it, creating a clear visual
connection between the trigger and the content. The content area is the main body of the popover and can
contain a wide variety of elements such as text labels, simple form elements, lists of actions, icons,
and short instructions. An optional close button in the corner provides an explicit way to dismiss the
popover, which is especially important for users with motor impairments or when the popover contains
important actions, and optional action buttons allow users to perform primary tasks like saving or
confirming.
</p>
</div>
`,
styles: `
:host {
display: flex;
flex-direction: column;

margin: 0 auto;
}

.docs-text-container {
display: flex;
flex-direction: column;

overflow-y: scroll;

height: 344px;
padding-left: var(--kbq-size-xl);
}

.kbq-button {
align-self: center;
}
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DocsPopoverExample {
readonly popoverContent =
'Think of a popover as a lightweight, floating window that is directly tethered to the element that summoned it. Unlike a modal dialog, it doesn\'t usually block interaction with the rest of the page entirely, allowing for a faster, more "in-context" workflow. It\'s often activated by clicking a button, icon, or link, and it disappears when the user moves their focus away.';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { CdkScrollable } from '@angular/cdk/overlay';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqSelectModule } from '@koobiq/components/select';
import { KbqTopBarModule } from '@koobiq/components/top-bar';

@Component({
selector: 'docs-popover-example',
imports: [KbqTopBarModule, CdkScrollable, KbqSelectModule],
template: `
<kbq-top-bar style="z-index: 1000">
<div
class="layout-row layout-align-center-center layout-padding-top-3xs layout-padding-bottom-3xs kbq-title kbq-truncate-line"
kbqTopBarContainer
placement="start"
>
<span class="kbq-truncate-line">Page Title</span>
</div>

<div kbqTopBarSpacer></div>
</kbq-top-bar>

<div class="docs-text-container layout-padding-left-xxl" cdk-scrollable>
<p>
The &lt;select> HTML element represents a control that provides a menu of options. The above example
shows typical &lt;select> usage. It is given an id attribute to enable it to be associated with a
&lt;label> for accessibility purposes, as well as a name attribute to represent the name of the
associated data point submitted to the server. Each menu option is defined by an &lt;option> element
nested inside the &lt;select>.
</p>

<kbq-form-field>
<kbq-select [value]="'Network Watcher'">
<kbq-option [value]="'Network Watcher'">Network Watcher</kbq-option>
<kbq-option [value]="'Firewall Sentinel'">Firewall Sentinel</kbq-option>
<kbq-option [value]="'Threat Hunter'">Threat Hunter</kbq-option>
<kbq-option [value]="'Malware Sentry'">Malware Sentry</kbq-option>
<kbq-option [value]="'Ransomware Shield'">Ransomware Shield</kbq-option>
<kbq-option [value]="'Network Watcher'">Network Watcher</kbq-option>
<kbq-option [value]="'Data Breach Guard'">Data Breach Guard</kbq-option>
<kbq-option [value]="'Endpoint Defender'">Endpoint Defender</kbq-option>
</kbq-select>
</kbq-form-field>

<p>
The &lt;select> element has some unique attributes you can use to control it, such as multiple to
specify whether multiple options can be selected, and size to specify how many options should be shown
at once. It also accepts most of the general form input attributes such as required, disabled,
autofocus, etc.
</p>
<p>
You can further nest &lt;option> elements inside &lt;optgroup> elements to create separate groups of
options inside the dropdown. You can also include &lt;hr> elements to create separators that add visual
breaks between options.
</p>
<p>
In browsers that don't support the modern customization features (or legacy codebases where they can't
be used), you are limited to manipulating the box model, the displayed font, etc. You can also use the
appearance property to remove the default system appearance.
</p>
<p>
You can use the :open pseudo-class to style &lt;select> elements in the open state, that is, when the
drop-down options list is displayed. This doesn't apply to multi-line &lt;select> elements (those with
the multiple attribute set) — they tend to render as a scrolling list box rather than a drop-down, so
don't have an open state.
</p>
<p>
A &lt;select> element is represented in JavaScript by an HTMLSelectElement object, and this object has a
value property which contains the value of the selected &lt;option>.
</p>
<p>
The &lt;select> element has some unique attributes you can use to control it, such as multiple to
specify whether multiple options can be selected, and size to specify how many options should be shown
at once. It also accepts most of the general form input attributes such as required, disabled,
autofocus, etc.
</p>
<p>
Each &lt;option> element should have a value attribute containing the data value to submit to the server
when that option is selected. If no value attribute is included, the value defaults to the text
contained inside the element. You can include a selected attribute on an &lt;option> element to make it
selected by default when the page first loads. If no selected attribute is specified, the first
&lt;option> element will be selected by default.
</p>
</div>
`,
styles: `
:host {
display: flex;
flex-direction: column;

margin: 0 auto;
}

.docs-text-container {
display: flex;
flex-direction: column;

overflow-y: scroll;

height: 344px;
padding-left: var(--kbq-size-xl);
}

.kbq-form-field {
width: 320px;
align-self: center;
}
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DocsSelectExample {
readonly popoverContent =
'Think of a popover as a lightweight, floating window that is directly tethered to the element that summoned it. Unlike a modal dialog, it doesn\'t usually block interaction with the rest of the page entirely, allowing for a faster, more "in-context" workflow. It\'s often activated by clicking a button, icon, or link, and it disappears when the user moves their focus away.';
}
5 changes: 5 additions & 0 deletions apps/docs/src/app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { DocsTokensOverview } from './components/design-tokens-viewers/tokens-ov
import { DocsTypographyTable } from './components/design-tokens-viewers/typography-overview';
import { DocsIconsViewerComponent } from './components/icons-viewer/icons-viewer.component';
import { DocsPageNotFoundComponent } from './components/page-not-found/page-not-found.component';
import { DocsPopoverExample } from './components/popover-example/popover-example.component';
import { DocsSelectExample } from './components/select-example/select-example.component';
import { DocsWelcomeComponent } from './components/welcome/welcome.component';
import { DOCS_DEFAULT_LOCALE } from './constants/locale';
import { DocsLocaleService } from './services/locale';
Expand Down Expand Up @@ -181,6 +183,9 @@ export const DOCS_ROUTES: Routes = [
]
},

// todo DS-4873
{ path: 'examples/popover', component: DocsPopoverExample },
{ path: 'examples/select', component: DocsSelectExample },
/**
* Error routes
*/
Expand Down
6 changes: 1 addition & 5 deletions firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,9 @@
"key": "X-XSS-Protection",
"value": "1"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "Content-Security-Policy",
"value": "upgrade-insecure-requests; default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' * data:; media-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://mc.yandex.ru https://mc.yandex.com https://yastatic.net; frame-src 'self' https://mc.yandex.ru https://mc.yandex.com; child-src 'self' blob: https://mc.yandex.ru https://mc.yandex.com; connect-src 'self' https://koobiq.io https://*.koobiq.io https://mc.yandex.ru https://mc.yandex.com https://*.algolia.net https://*.algolianet.com https://*.algolia.io;"
"value": "upgrade-insecure-requests; frame-ancestors 'self' https://*.web.app; default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' * data:; media-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://mc.yandex.ru https://mc.yandex.com https://yastatic.net; frame-src 'self' https://mc.yandex.ru https://mc.yandex.com; child-src 'self' blob: https://mc.yandex.ru https://mc.yandex.com; connect-src 'self' https://koobiq.io https://*.koobiq.io https://mc.yandex.ru https://mc.yandex.com https://*.algolia.net https://*.algolianet.com https://*.algolia.io;"
}
]
},
Expand Down
18 changes: 13 additions & 5 deletions packages/components-dev/popover/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,21 @@ import { DevThemeToggle } from '../theme-toggle';
selector: 'dev-examples',
imports: [PopoverExamplesModule],
template: `
<popover-scrolling-and-layering-example />
<br />
<popover-paddings-example />
<br />
<popover-small-example />
<!-- <popover-width-example />-->
<!-- <popover-common-example />-->
<!-- <popover-hover-example />-->
<!-- <popover-arrowless-example />-->
<!-- <popover-arrow-and-offset-example />-->
<br />
<popover-width-example />
<br />
<popover-common-example />
<br />
<popover-hover-example />
<br />
<popover-arrowless-example />
<br />
<popover-arrow-and-offset-example />
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
Expand Down
3 changes: 3 additions & 0 deletions packages/components-dev/select/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import { DEV_OPTIONS } from './mock';
selector: 'dev-examples',
imports: [SelectExamplesModule],
template: `
<select-scrolling-and-layering-example />
<hr />

<select-with-multiline-matcher-example />
<hr />

Expand Down
Loading
Loading