mirror of
https://github.com/imfing/hextra.git
synced 2025-08-23 16:46:37 -04:00
feat(navbar): language switcher (#760)
* feat(navbar): language switcher * docs: add language-switch * chore: just for the demo * fix: drop conflicting CSS * fix: use constant * fix: pre-existing bug with rtl on mobile * docs: add comment to explain the algo * chore: more readable algo * review Co-authored-by: Xin <5097752+imfing@users.noreply.github.com> * feat: different icons * feat: icon as param * fix: inconsitency with rtl * fix: render inside the sidebar * chore: remove the demo --------- Co-authored-by: Xin <5097752+imfing@users.noreply.github.com>
This commit is contained in:

committed by
GitHub

parent
b2ff662c8e
commit
363b1e50ff
@@ -7,11 +7,32 @@
|
|||||||
const optionsElement = switcher.nextElementSibling;
|
const optionsElement = switcher.nextElementSibling;
|
||||||
optionsElement.classList.toggle('hx:hidden');
|
optionsElement.classList.toggle('hx:hidden');
|
||||||
|
|
||||||
// Calculate position of language options element
|
// Calculate the position of a language options element.
|
||||||
const switcherRect = switcher.getBoundingClientRect();
|
const switcherRect = switcher.getBoundingClientRect();
|
||||||
const translateY = switcherRect.top - window.innerHeight - 15;
|
|
||||||
optionsElement.style.transform = `translate3d(${switcherRect.left}px, ${translateY}px, 0)`;
|
// Must be called before optionsElement.clientWidth.
|
||||||
optionsElement.style.minWidth = `${Math.max(switcherRect.width, 50)}px`;
|
optionsElement.style.minWidth = `${Math.max(switcherRect.width, 50)}px`;
|
||||||
|
|
||||||
|
const isOnTop = switcher.dataset.location === 'top';
|
||||||
|
const isRTL = document.body.dir === 'rtl'
|
||||||
|
|
||||||
|
// Stuck on the left side of the switcher.
|
||||||
|
let translateX = switcherRect.left;
|
||||||
|
|
||||||
|
if (isOnTop && !isRTL || !isOnTop && isRTL) {
|
||||||
|
// Stuck on the right side of the switcher.
|
||||||
|
translateX = switcherRect.right - optionsElement.clientWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stuck on the top of the switcher.
|
||||||
|
let translateY = switcherRect.top - window.innerHeight - 15;
|
||||||
|
|
||||||
|
if (isOnTop) {
|
||||||
|
// Stuck on the bottom of the switcher.
|
||||||
|
translateY = switcherRect.top - window.innerHeight + 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
optionsElement.style.transform = `translate3d(${translateX}px, ${translateY}px, 0)`;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -69,6 +69,15 @@ menu:
|
|||||||
- name: Theme Toggle
|
- name: Theme Toggle
|
||||||
params:
|
params:
|
||||||
type: theme-toggle
|
type: theme-toggle
|
||||||
|
label: true # optional, default is false
|
||||||
|
```
|
||||||
|
6. مُبدِّل اللغة
|
||||||
|
```yaml
|
||||||
|
- name: مُبدِّل اللغة
|
||||||
|
params:
|
||||||
|
type: language-switch
|
||||||
|
label: true # optional, default is false
|
||||||
|
icon: "globe-alt" # optional, default is "translate"
|
||||||
```
|
```
|
||||||
|
|
||||||
این آیتمهای منو را میتوان با تنظیم پارامتر `weight` مرتب کرد.
|
این آیتمهای منو را میتوان با تنظیم پارامتر `weight` مرتب کرد.
|
||||||
|
@@ -69,6 +69,15 @@ menu:
|
|||||||
- name: Theme Toggle
|
- name: Theme Toggle
|
||||||
params:
|
params:
|
||||||
type: theme-toggle
|
type: theme-toggle
|
||||||
|
label: true # optional, default is false
|
||||||
|
```
|
||||||
|
6. 言語スイッチャー
|
||||||
|
```yaml
|
||||||
|
- name: 言語スイッチャー
|
||||||
|
params:
|
||||||
|
type: language-switch
|
||||||
|
label: true # optional, default is false
|
||||||
|
icon: "globe-alt" # optional, default is "translate"
|
||||||
```
|
```
|
||||||
|
|
||||||
これらのメニュー項目は `weight` パラメータを設定することで並べ替えられます。
|
これらのメニュー項目は `weight` パラメータを設定することで並べ替えられます。
|
||||||
|
@@ -69,6 +69,15 @@ There are different types of menu items:
|
|||||||
- name: Theme Toggle
|
- name: Theme Toggle
|
||||||
params:
|
params:
|
||||||
type: theme-toggle
|
type: theme-toggle
|
||||||
|
label: true # optional, default is false
|
||||||
|
```
|
||||||
|
6. Language Switcher
|
||||||
|
```yaml
|
||||||
|
- name: Language Switcher
|
||||||
|
params:
|
||||||
|
type: language-switch
|
||||||
|
label: true # optional, default is false
|
||||||
|
icon: "globe-alt" # optional, default is "translate"
|
||||||
```
|
```
|
||||||
|
|
||||||
These menu items can be sorted by setting the `weight` parameter.
|
These menu items can be sorted by setting the `weight` parameter.
|
||||||
|
@@ -69,6 +69,15 @@ menu:
|
|||||||
- name: Theme Toggle
|
- name: Theme Toggle
|
||||||
params:
|
params:
|
||||||
type: theme-toggle
|
type: theme-toggle
|
||||||
|
label: true # optional, default is false
|
||||||
|
```
|
||||||
|
6. 语言切换器
|
||||||
|
```yaml
|
||||||
|
- name: 语言切换器
|
||||||
|
params:
|
||||||
|
type: language-switch
|
||||||
|
label: true # optional, default is false
|
||||||
|
icon: "globe-alt" # optional, default is "translate"
|
||||||
```
|
```
|
||||||
|
|
||||||
通过设置 `weight` 参数可以调整菜单项的排序。
|
通过设置 `weight` 参数可以调整菜单项的排序。
|
||||||
|
@@ -1,4 +1,9 @@
|
|||||||
{{- $page := .context -}}
|
{{- $page := .context -}}
|
||||||
|
{{- $iconName := .iconName | default "globe-alt" -}}
|
||||||
|
{{- $iconHeight := .iconHeight | default 12 -}}
|
||||||
|
{{- $location := .location -}}
|
||||||
|
|
||||||
|
{{- $class := .class | default "hx:h-7 hx:px-2 hx:text-xs hx:text-gray-600 hx:transition-colors hx:dark:text-gray-400 hx:hover:bg-gray-100 hx:hover:text-gray-900 hx:dark:hover:bg-primary-100/5 hx:dark:hover:text-gray-50" -}}
|
||||||
|
|
||||||
{{- $grow := .grow -}}
|
{{- $grow := .grow -}}
|
||||||
{{- $hideLabel := .hideLabel | default false -}}
|
{{- $hideLabel := .hideLabel | default false -}}
|
||||||
@@ -10,12 +15,13 @@
|
|||||||
<button
|
<button
|
||||||
title="{{ $changeLanguage }}"
|
title="{{ $changeLanguage }}"
|
||||||
data-state="closed"
|
data-state="closed"
|
||||||
class="hextra-language-switcher hx:cursor-pointer hx:h-7 hx:rounded-md hx:px-2 hx:text-left hx:text-xs hx:font-medium hx:text-gray-600 hx:transition-colors hx:dark:text-gray-400 hx:hover:bg-gray-100 hx:hover:text-gray-900 hx:dark:hover:bg-primary-100/5 hx:dark:hover:text-gray-50 hx:grow"
|
data-location="{{ $location }}"
|
||||||
|
class="hextra-language-switcher hx:cursor-pointer hx:rounded-md hx:text-left hx:font-medium {{ $class }} hx:grow"
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="{{ $changeLanguage }}"
|
aria-label="{{ $changeLanguage }}"
|
||||||
>
|
>
|
||||||
<div class="hx:flex hx:items-center hx:gap-2 hx:capitalize">
|
<div class="hx:flex hx:items-center hx:gap-2 hx:capitalize">
|
||||||
{{- partial "utils/icon" (dict "name" "globe-alt" "attributes" "height=12") -}}
|
{{- partial "utils/icon" (dict "name" $iconName "attributes" (printf "height=%d" $iconHeight)) -}}
|
||||||
{{- if not $hideLabel }}<span>{{ site.Language.LanguageName }}</span>{{ end -}}
|
{{- if not $hideLabel }}<span>{{ site.Language.LanguageName }}</span>{{ end -}}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
{{ end -}}
|
{{ end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- $page := . -}}
|
||||||
{{- $iconHeight := 24 -}}
|
{{- $iconHeight := 24 -}}
|
||||||
|
|
||||||
<div class="hextra-nav-container hx:sticky hx:top-0 hx:z-20 hx:w-full hx:bg-transparent hx:print:hidden">
|
<div class="hextra-nav-container hx:sticky hx:top-0 hx:z-20 hx:w-full hx:bg-transparent hx:print:hidden">
|
||||||
@@ -39,6 +40,8 @@
|
|||||||
</a>
|
</a>
|
||||||
{{- else if eq .Params.type "theme-toggle" -}}
|
{{- else if eq .Params.type "theme-toggle" -}}
|
||||||
{{- partial "theme-toggle.html" (dict "iconHeight" $iconHeight "class" "hx:p-2" "hideLabel" (not .Params.label)) -}}
|
{{- partial "theme-toggle.html" (dict "iconHeight" $iconHeight "class" "hx:p-2" "hideLabel" (not .Params.label)) -}}
|
||||||
|
{{- else if eq .Params.type "language-switch" -}}
|
||||||
|
{{- partial "language-switch" (dict "context" $page "grow" false "hideLabel" (not .Params.label) "iconName" (.Params.icon | default "translate") "iconHeight" $iconHeight "location" "top" "class" "hx:p-2") -}}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
{{- $active := or ($currentPage.HasMenuCurrent "main" .) ($currentPage.IsMenuCurrent "main" .) -}}
|
{{- $active := or ($currentPage.HasMenuCurrent "main" .) ($currentPage.IsMenuCurrent "main" .) -}}
|
||||||
{{- $activeClass := cond $active "hx:font-medium" "hx:text-gray-600 hx:hover:text-gray-800 hx:dark:text-gray-400 hx:dark:hover:text-gray-200" -}}
|
{{- $activeClass := cond $active "hx:font-medium" "hx:text-gray-600 hx:hover:text-gray-800 hx:dark:text-gray-400 hx:dark:hover:text-gray-200" -}}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{{- $hideLabel := .hideLabel -}}
|
{{- $hideLabel := .hideLabel -}}
|
||||||
{{- $iconHeight := .iconHeight | default 12 -}}
|
{{- $iconHeight := .iconHeight | default 12 -}}
|
||||||
{{- $class := .class | default "hx:px-2 hx:text-xs hx:hover:bg-gray-100 hx:hover:text-gray-900 hx:dark:hover:bg-primary-100/5 hx:dark:hover:text-gray-50 hx:font-medium hx:text-gray-600 hx:transition-colors hx:dark:text-gray-400" -}}
|
{{- $class := .class | default "hx:h-7 hx:px-2 hx:text-xs hx:hover:bg-gray-100 hx:hover:text-gray-900 hx:dark:hover:bg-primary-100/5 hx:dark:hover:text-gray-50 hx:font-medium hx:text-gray-600 hx:transition-colors hx:dark:text-gray-400" -}}
|
||||||
|
|
||||||
{{- $changeTheme := (T "changeTheme") | default "Change theme" -}}
|
{{- $changeTheme := (T "changeTheme") | default "Change theme" -}}
|
||||||
{{- $light := (T "light") | default "Light" -}}
|
{{- $light := (T "light") | default "Light" -}}
|
||||||
|
Reference in New Issue
Block a user