@flusys/ng-layout 4.1.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -448
- package/assets/layout/_topbar_nav.scss +1 -1
- package/fesm2022/flusys-ng-layout.mjs +110 -67
- package/fesm2022/flusys-ng-layout.mjs.map +1 -1
- package/package.json +3 -3
- package/types/flusys-ng-layout.d.ts +1 -0
|
@@ -1386,7 +1386,9 @@ class AppCompanyBranchSelector {
|
|
|
1386
1386
|
authState = inject(LAYOUT_AUTH_STATE, { optional: true });
|
|
1387
1387
|
authApi = inject(LAYOUT_AUTH_API, { optional: true });
|
|
1388
1388
|
messageService = inject(MessageService);
|
|
1389
|
-
translateAdapter = inject(TRANSLATE_ADAPTER, {
|
|
1389
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, {
|
|
1390
|
+
optional: true,
|
|
1391
|
+
});
|
|
1390
1392
|
document = inject(DOCUMENT$1);
|
|
1391
1393
|
elementRef = inject(ElementRef);
|
|
1392
1394
|
_isActive = signal(false, ...(ngDevMode ? [{ debugName: "_isActive" }] : []));
|
|
@@ -1401,7 +1403,8 @@ class AppCompanyBranchSelector {
|
|
|
1401
1403
|
}
|
|
1402
1404
|
});
|
|
1403
1405
|
}
|
|
1404
|
-
currentCompanyName = computed(() => this.authState?.currentCompanyInfo()?.name ??
|
|
1406
|
+
currentCompanyName = computed(() => this.authState?.currentCompanyInfo()?.name ??
|
|
1407
|
+
this.translate('layout.company.branch.selector.no.company'), ...(ngDevMode ? [{ debugName: "currentCompanyName" }] : []));
|
|
1405
1408
|
currentBranchName = computed(() => this.authState?.currentBranchInfo()?.name ?? null, ...(ngDevMode ? [{ debugName: "currentBranchName" }] : []));
|
|
1406
1409
|
_companies = signal([], ...(ngDevMode ? [{ debugName: "_companies" }] : []));
|
|
1407
1410
|
companies = this._companies.asReadonly();
|
|
@@ -1424,7 +1427,7 @@ class AppCompanyBranchSelector {
|
|
|
1424
1427
|
const currentCompanyId = this.authState?.currentCompanyInfo()?.id;
|
|
1425
1428
|
const currentBranchId = this.authState?.currentBranchInfo()?.id;
|
|
1426
1429
|
const selectedBranch = this.selectedBranchId();
|
|
1427
|
-
return selectedCompany !== currentCompanyId || selectedBranch !== currentBranchId;
|
|
1430
|
+
return (selectedCompany !== currentCompanyId || selectedBranch !== currentBranchId);
|
|
1428
1431
|
}, ...(ngDevMode ? [{ debugName: "canSwitch" }] : []));
|
|
1429
1432
|
onPanelToggle() {
|
|
1430
1433
|
this._isActive.update((v) => !v);
|
|
@@ -1538,20 +1541,24 @@ class AppCompanyBranchSelector {
|
|
|
1538
1541
|
style="background-color: var(--surface-overlay); inset-inline-end: 0;"
|
|
1539
1542
|
>
|
|
1540
1543
|
<div class="flex flex-col gap-4">
|
|
1541
|
-
<span class="text-sm text-muted-color font-semibold"
|
|
1542
|
-
|
|
1543
|
-
>
|
|
1544
|
+
<span class="text-sm text-muted-color font-semibold">{{
|
|
1545
|
+
'layout.company.branch.selector.title' | translate
|
|
1546
|
+
}}</span>
|
|
1544
1547
|
|
|
1545
1548
|
<!-- Company Selector -->
|
|
1546
1549
|
<div class="flex flex-col gap-2">
|
|
1547
|
-
<label class="text-sm text-muted-color font-semibold">{{
|
|
1550
|
+
<label class="text-sm text-muted-color font-semibold">{{
|
|
1551
|
+
'shared.company' | translate
|
|
1552
|
+
}}</label>
|
|
1548
1553
|
<p-select
|
|
1549
1554
|
[options]="companies()"
|
|
1550
1555
|
[ngModel]="selectedCompanyId()"
|
|
1551
1556
|
(ngModelChange)="onCompanyChange($event)"
|
|
1552
1557
|
optionLabel="name"
|
|
1553
1558
|
optionValue="id"
|
|
1554
|
-
[placeholder]="
|
|
1559
|
+
[placeholder]="
|
|
1560
|
+
'layout.company.branch.selector.select.company' | translate
|
|
1561
|
+
"
|
|
1555
1562
|
class="w-full"
|
|
1556
1563
|
[loading]="isLoadingCompanies()"
|
|
1557
1564
|
/>
|
|
@@ -1560,14 +1567,18 @@ class AppCompanyBranchSelector {
|
|
|
1560
1567
|
<!-- Branch Selector -->
|
|
1561
1568
|
@if (selectedCompanyId() && branches().length > 0) {
|
|
1562
1569
|
<div class="flex flex-col gap-2">
|
|
1563
|
-
<label class="text-sm text-muted-color font-semibold">{{
|
|
1570
|
+
<label class="text-sm text-muted-color font-semibold">{{
|
|
1571
|
+
'layout.company.branch.selector.branch' | translate
|
|
1572
|
+
}}</label>
|
|
1564
1573
|
<p-select
|
|
1565
1574
|
[options]="branches()"
|
|
1566
1575
|
[ngModel]="selectedBranchId()"
|
|
1567
1576
|
(ngModelChange)="onBranchChange($event)"
|
|
1568
1577
|
optionLabel="name"
|
|
1569
1578
|
optionValue="id"
|
|
1570
|
-
[placeholder]="
|
|
1579
|
+
[placeholder]="
|
|
1580
|
+
'layout.company.branch.selector.select.branch' | translate
|
|
1581
|
+
"
|
|
1571
1582
|
class="w-full"
|
|
1572
1583
|
[loading]="isLoadingBranches()"
|
|
1573
1584
|
/>
|
|
@@ -1593,7 +1604,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1593
1604
|
type: Component,
|
|
1594
1605
|
args: [{
|
|
1595
1606
|
selector: 'app-company-branch-selector',
|
|
1596
|
-
imports: [
|
|
1607
|
+
imports: [
|
|
1608
|
+
AngularModule,
|
|
1609
|
+
StyleClassModule,
|
|
1610
|
+
ButtonModule,
|
|
1611
|
+
SelectModule,
|
|
1612
|
+
TranslatePipe,
|
|
1613
|
+
],
|
|
1597
1614
|
host: { class: 'relative' },
|
|
1598
1615
|
template: `
|
|
1599
1616
|
<button
|
|
@@ -1619,20 +1636,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1619
1636
|
style="background-color: var(--surface-overlay); inset-inline-end: 0;"
|
|
1620
1637
|
>
|
|
1621
1638
|
<div class="flex flex-col gap-4">
|
|
1622
|
-
<span class="text-sm text-muted-color font-semibold"
|
|
1623
|
-
|
|
1624
|
-
>
|
|
1639
|
+
<span class="text-sm text-muted-color font-semibold">{{
|
|
1640
|
+
'layout.company.branch.selector.title' | translate
|
|
1641
|
+
}}</span>
|
|
1625
1642
|
|
|
1626
1643
|
<!-- Company Selector -->
|
|
1627
1644
|
<div class="flex flex-col gap-2">
|
|
1628
|
-
<label class="text-sm text-muted-color font-semibold">{{
|
|
1645
|
+
<label class="text-sm text-muted-color font-semibold">{{
|
|
1646
|
+
'shared.company' | translate
|
|
1647
|
+
}}</label>
|
|
1629
1648
|
<p-select
|
|
1630
1649
|
[options]="companies()"
|
|
1631
1650
|
[ngModel]="selectedCompanyId()"
|
|
1632
1651
|
(ngModelChange)="onCompanyChange($event)"
|
|
1633
1652
|
optionLabel="name"
|
|
1634
1653
|
optionValue="id"
|
|
1635
|
-
[placeholder]="
|
|
1654
|
+
[placeholder]="
|
|
1655
|
+
'layout.company.branch.selector.select.company' | translate
|
|
1656
|
+
"
|
|
1636
1657
|
class="w-full"
|
|
1637
1658
|
[loading]="isLoadingCompanies()"
|
|
1638
1659
|
/>
|
|
@@ -1641,14 +1662,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1641
1662
|
<!-- Branch Selector -->
|
|
1642
1663
|
@if (selectedCompanyId() && branches().length > 0) {
|
|
1643
1664
|
<div class="flex flex-col gap-2">
|
|
1644
|
-
<label class="text-sm text-muted-color font-semibold">{{
|
|
1665
|
+
<label class="text-sm text-muted-color font-semibold">{{
|
|
1666
|
+
'layout.company.branch.selector.branch' | translate
|
|
1667
|
+
}}</label>
|
|
1645
1668
|
<p-select
|
|
1646
1669
|
[options]="branches()"
|
|
1647
1670
|
[ngModel]="selectedBranchId()"
|
|
1648
1671
|
(ngModelChange)="onBranchChange($event)"
|
|
1649
1672
|
optionLabel="name"
|
|
1650
1673
|
optionValue="id"
|
|
1651
|
-
[placeholder]="
|
|
1674
|
+
[placeholder]="
|
|
1675
|
+
'layout.company.branch.selector.select.branch' | translate
|
|
1676
|
+
"
|
|
1652
1677
|
class="w-full"
|
|
1653
1678
|
[loading]="isLoadingBranches()"
|
|
1654
1679
|
/>
|
|
@@ -1714,7 +1739,9 @@ class AppLauncher {
|
|
|
1714
1739
|
style="background-color: var(--surface-overlay); inset-inline-end: 0;"
|
|
1715
1740
|
>
|
|
1716
1741
|
<div class="flex flex-col gap-2">
|
|
1717
|
-
<span class="text-sm text-muted-color font-semibold">{{
|
|
1742
|
+
<span class="text-sm text-muted-color font-semibold">{{
|
|
1743
|
+
'layout.launcher.applications' | translate
|
|
1744
|
+
}}</span>
|
|
1718
1745
|
<div class="grid grid-cols-2 sm:grid-cols-3 gap-2">
|
|
1719
1746
|
@for (app of layoutService.apps(); track app.id) {
|
|
1720
1747
|
<a
|
|
@@ -1770,7 +1797,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1770
1797
|
style="background-color: var(--surface-overlay); inset-inline-end: 0;"
|
|
1771
1798
|
>
|
|
1772
1799
|
<div class="flex flex-col gap-2">
|
|
1773
|
-
<span class="text-sm text-muted-color font-semibold">{{
|
|
1800
|
+
<span class="text-sm text-muted-color font-semibold">{{
|
|
1801
|
+
'layout.launcher.applications' | translate
|
|
1802
|
+
}}</span>
|
|
1774
1803
|
<div class="grid grid-cols-2 sm:grid-cols-3 gap-2">
|
|
1775
1804
|
@for (app of layoutService.apps(); track app.id) {
|
|
1776
1805
|
<a
|
|
@@ -1807,7 +1836,9 @@ class AppProfile {
|
|
|
1807
1836
|
authApi = inject(LAYOUT_AUTH_API, { optional: true });
|
|
1808
1837
|
layoutService = inject(LayoutService);
|
|
1809
1838
|
messageService = inject(MessageService);
|
|
1810
|
-
translateAdapter = inject(TRANSLATE_ADAPTER, {
|
|
1839
|
+
translateAdapter = inject(TRANSLATE_ADAPTER, {
|
|
1840
|
+
optional: true,
|
|
1841
|
+
});
|
|
1811
1842
|
appConfig = inject(APP_CONFIG, { optional: true });
|
|
1812
1843
|
document = inject(DOCUMENT$1);
|
|
1813
1844
|
elementRef = inject(ElementRef);
|
|
@@ -1826,7 +1857,8 @@ class AppProfile {
|
|
|
1826
1857
|
togglePanel() {
|
|
1827
1858
|
this._isActive.update((v) => !v);
|
|
1828
1859
|
}
|
|
1829
|
-
userName = computed(() => this.authState?.loginUserData()?.name ??
|
|
1860
|
+
userName = computed(() => this.authState?.loginUserData()?.name ??
|
|
1861
|
+
this.translate('layout.profile.guest'), ...(ngDevMode ? [{ debugName: "userName" }] : []));
|
|
1830
1862
|
userEmail = computed(() => this.authState?.loginUserData()?.email ?? '', ...(ngDevMode ? [{ debugName: "userEmail" }] : []));
|
|
1831
1863
|
profilePicture = computed(() => this.layoutService.userProfilePictureUrl() ?? '', ...(ngDevMode ? [{ debugName: "profilePicture" }] : []));
|
|
1832
1864
|
signUpEnabled = computed(() => this.appConfig ? isSignUpEnabled(this.appConfig) : false, ...(ngDevMode ? [{ debugName: "signUpEnabled" }] : []));
|
|
@@ -1838,10 +1870,13 @@ class AppProfile {
|
|
|
1838
1870
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1839
1871
|
.subscribe({
|
|
1840
1872
|
next: (result) => {
|
|
1873
|
+
const r = result;
|
|
1841
1874
|
this.messageService.add({
|
|
1842
1875
|
severity: 'success',
|
|
1843
1876
|
summary: this.translate('shared.success'),
|
|
1844
|
-
detail:
|
|
1877
|
+
detail: r?.messageKey
|
|
1878
|
+
? this.translate(r.messageKey, r.messageVariables)
|
|
1879
|
+
: (r?.message ?? ''),
|
|
1845
1880
|
});
|
|
1846
1881
|
this.authApi?.navigateLogin(false);
|
|
1847
1882
|
},
|
|
@@ -1870,8 +1905,8 @@ class AppProfile {
|
|
|
1870
1905
|
});
|
|
1871
1906
|
});
|
|
1872
1907
|
}
|
|
1873
|
-
translate(key) {
|
|
1874
|
-
return this.translateAdapter?.translate(key) ?? key;
|
|
1908
|
+
translate(key, vars) {
|
|
1909
|
+
return this.translateAdapter?.translate(key, vars) ?? key;
|
|
1875
1910
|
}
|
|
1876
1911
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AppProfile, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1877
1912
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: AppProfile, isStandalone: true, selector: "app-profile", host: { classAttribute: "relative" }, ngImport: i0, template: `
|
|
@@ -1914,8 +1949,12 @@ class AppProfile {
|
|
|
1914
1949
|
</div>
|
|
1915
1950
|
}
|
|
1916
1951
|
<div class="flex flex-col min-w-0 flex-1">
|
|
1917
|
-
<span class="font-semibold text-color truncate">{{
|
|
1918
|
-
|
|
1952
|
+
<span class="font-semibold text-color truncate">{{
|
|
1953
|
+
userName()
|
|
1954
|
+
}}</span>
|
|
1955
|
+
<span class="text-sm text-muted-color truncate">{{
|
|
1956
|
+
userEmail()
|
|
1957
|
+
}}</span>
|
|
1919
1958
|
</div>
|
|
1920
1959
|
</a>
|
|
1921
1960
|
|
|
@@ -1991,8 +2030,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1991
2030
|
</div>
|
|
1992
2031
|
}
|
|
1993
2032
|
<div class="flex flex-col min-w-0 flex-1">
|
|
1994
|
-
<span class="font-semibold text-color truncate">{{
|
|
1995
|
-
|
|
2033
|
+
<span class="font-semibold text-color truncate">{{
|
|
2034
|
+
userName()
|
|
2035
|
+
}}</span>
|
|
2036
|
+
<span class="text-sm text-muted-color truncate">{{
|
|
2037
|
+
userEmail()
|
|
2038
|
+
}}</span>
|
|
1996
2039
|
</div>
|
|
1997
2040
|
</a>
|
|
1998
2041
|
|
|
@@ -2150,7 +2193,10 @@ class AppSearchbar {
|
|
|
2150
2193
|
this.closeSuggestions();
|
|
2151
2194
|
}
|
|
2152
2195
|
onSearch() {
|
|
2153
|
-
|
|
2196
|
+
const query = this.searchTerm();
|
|
2197
|
+
if (this.searchAdapter?.onSearch && query.trim()) {
|
|
2198
|
+
this.searchAdapter.onSearch(query);
|
|
2199
|
+
}
|
|
2154
2200
|
}
|
|
2155
2201
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AppSearchbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2156
2202
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: AppSearchbar, isStandalone: true, selector: "app-searchbar", viewQueries: [{ propertyName: "searchWrapper", first: true, predicate: ["searchWrapper"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
@@ -2849,43 +2895,36 @@ const GreenTheme = definePreset(Material, {
|
|
|
2849
2895
|
});
|
|
2850
2896
|
|
|
2851
2897
|
const LAYOUT_MESSAGES = {
|
|
2852
|
-
//
|
|
2853
|
-
'menu.dashboard': 'Dashboard',
|
|
2854
|
-
'menu.administration': 'Administration',
|
|
2855
|
-
'menu.iam': 'IAM',
|
|
2856
|
-
'menu.storage': 'Storage',
|
|
2857
|
-
'menu.forms': 'Forms',
|
|
2858
|
-
'menu.email': 'Email',
|
|
2859
|
-
'menu.event.manager': 'Event Manager',
|
|
2860
|
-
'menu.notifications': 'Notifications',
|
|
2861
|
-
'menu.localization': 'Localization',
|
|
2862
|
-
'menu.projects': 'Projects',
|
|
2863
|
-
'menu.projects.active': 'Active Projects',
|
|
2864
|
-
'menu.projects.archived': 'Archived Projects',
|
|
2865
|
-
'menu.projects.reports': 'Project Reports',
|
|
2866
|
-
// Profile
|
|
2898
|
+
// components/top-bar/app.profile.ts
|
|
2867
2899
|
'layout.profile.title': 'Profile',
|
|
2868
2900
|
'layout.profile.profile.picture.alt': 'Profile picture',
|
|
2869
2901
|
'layout.profile.copy.sign.up.link': 'Copy SignUp Link',
|
|
2870
2902
|
'layout.profile.logout': 'Logout',
|
|
2903
|
+
'layout.profile.guest': 'Guest',
|
|
2871
2904
|
'layout.profile.link.copied': 'Link Copied',
|
|
2872
2905
|
'layout.profile.sign.up.link.copied': 'Sign Up Link copied.',
|
|
2873
2906
|
'layout.profile.failed.copy.sign.up.link': 'Failed to copy signup link.',
|
|
2874
|
-
|
|
2875
|
-
|
|
2907
|
+
// components/top-bar/app.launcher.ts
|
|
2908
|
+
'layout.launcher.apps': 'Apps',
|
|
2909
|
+
'layout.launcher.applications': 'Applications',
|
|
2910
|
+
// components/top-bar/app.company-branch-selector.ts
|
|
2876
2911
|
'layout.company.branch.selector.title': 'Switch Company & Branch',
|
|
2877
|
-
'layout.company.branch.selector.company': 'Company',
|
|
2878
2912
|
'layout.company.branch.selector.select.company': 'Select Company',
|
|
2879
2913
|
'layout.company.branch.selector.branch': 'Branch',
|
|
2880
2914
|
'layout.company.branch.selector.select.branch': 'Select Branch',
|
|
2881
2915
|
'layout.company.branch.selector.switch.button': 'Switch',
|
|
2916
|
+
'layout.company.branch.selector.no.company': 'No Company',
|
|
2882
2917
|
'layout.company.branch.selector.branch.required': 'Branch Required',
|
|
2883
2918
|
'layout.company.branch.selector.please.select.branch': 'Please select a branch',
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
'layout.
|
|
2887
|
-
|
|
2888
|
-
|
|
2919
|
+
// components/top-bar/app.searchbar.ts
|
|
2920
|
+
'layout.topbar.search': 'Search',
|
|
2921
|
+
'layout.topbar.search.placeholder': 'Search for content...',
|
|
2922
|
+
// components/app.topbar.ts
|
|
2923
|
+
'layout.topbar.toggle.menu': 'Toggle menu',
|
|
2924
|
+
'layout.topbar.toggle.dark.mode': 'Toggle dark mode',
|
|
2925
|
+
'layout.topbar.open.theme.settings': 'Open theme settings',
|
|
2926
|
+
'layout.topbar.more.options': 'More options',
|
|
2927
|
+
// components/app.configurator.ts
|
|
2889
2928
|
'layout.configurator.primary': 'Primary',
|
|
2890
2929
|
'layout.configurator.surface': 'Surface',
|
|
2891
2930
|
'layout.configurator.presets': 'Presets',
|
|
@@ -2893,26 +2932,30 @@ const LAYOUT_MESSAGES = {
|
|
|
2893
2932
|
'layout.configurator.menu.mode.static': 'Static',
|
|
2894
2933
|
'layout.configurator.menu.mode.overlay': 'Overlay',
|
|
2895
2934
|
'layout.configurator.menu.mode.topbar': 'Topbar',
|
|
2896
|
-
//
|
|
2897
|
-
'layout.topbar.toggle.menu': 'Toggle menu',
|
|
2898
|
-
'layout.topbar.toggle.dark.mode': 'Toggle dark mode',
|
|
2899
|
-
'layout.topbar.open.theme.settings': 'Open theme settings',
|
|
2900
|
-
'layout.topbar.more.options': 'More options',
|
|
2901
|
-
// Footer
|
|
2935
|
+
// components/app.footer.ts
|
|
2902
2936
|
'layout.footer.by': 'by',
|
|
2903
|
-
//
|
|
2937
|
+
// app-menu.config.ts (main app menu configuration)
|
|
2938
|
+
'menu.dashboard': 'Dashboard',
|
|
2939
|
+
'menu.administration': 'Administration',
|
|
2940
|
+
'menu.iam': 'IAM',
|
|
2941
|
+
'menu.storage': 'Storage',
|
|
2942
|
+
'menu.forms': 'Forms',
|
|
2943
|
+
'menu.email': 'Email',
|
|
2944
|
+
'menu.event.manager': 'Event Manager',
|
|
2945
|
+
'menu.notifications': 'Notifications',
|
|
2946
|
+
'menu.localization': 'Localization',
|
|
2947
|
+
// Those are layout part from notification module, but we put them here to avoid circular dependency between layout and notification module
|
|
2948
|
+
// components/notification-bell/notification-bell.component.ts
|
|
2904
2949
|
'notification.title': 'Notifications',
|
|
2905
|
-
|
|
2906
|
-
'notification.
|
|
2950
|
+
// components/notification-list/notification-list.component.ts
|
|
2951
|
+
'notification.mark.all.read': 'Mark all read',
|
|
2952
|
+
'notification.view.all': 'View all notifications',
|
|
2953
|
+
'notification.empty': 'No notifications',
|
|
2954
|
+
// components/notification-item/notification-item.component.ts
|
|
2907
2955
|
'notification.time.just.now': 'Just now',
|
|
2908
2956
|
'notification.time.minutes.ago': '{{count}}m ago',
|
|
2909
2957
|
'notification.time.hours.ago': '{{count}}h ago',
|
|
2910
2958
|
'notification.time.days.ago': '{{count}}d ago',
|
|
2911
|
-
'notification.empty': 'No notifications',
|
|
2912
|
-
// Home/Dashboard
|
|
2913
|
-
'home.where.users.from': 'Where users are from',
|
|
2914
|
-
'layout.topbar.search': 'Search',
|
|
2915
|
-
'layout.topbar.search.placeholder': 'Search for content...',
|
|
2916
2959
|
};
|
|
2917
2960
|
|
|
2918
2961
|
// Components
|