Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added public/images/no-distractions-welcome-hero.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/components/MobileWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,23 @@ interface Props {
dir?: 'ltr' | 'rtl'
/** Max width of the centred column when clamped (wide viewports). */
maxWidth?: string
/** Side borders on the centred column when previewing above 480px. */
showFrameBorder?: boolean
}

const props = withDefaults(defineProps<Props>(), {
lang: undefined,
dir: undefined,
maxWidth: '360px',
showFrameBorder: true,
})
</script>

<template>
<div class="mobile-wrapper">
<div
class="mobile-wrapper__column"
:class="{ 'mobile-wrapper__column--frameless': !props.showFrameBorder }"
:lang="props.lang"
:dir="props.dir"
:style="{ '--mobile-wrapper-max-width': props.maxWidth }"
Expand Down Expand Up @@ -60,5 +64,9 @@ const props = withDefaults(defineProps<Props>(), {
background-color: var(--background-color-base);
border-inline: var(--border-width-base) solid var(--border-color-muted);
}

.mobile-wrapper__column--frameless {
border-inline: none;
}
}
</style>
101 changes: 101 additions & 0 deletions src/components/PrototypeChromeMenuPanel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<script setup lang="ts">
import { CdxButton, CdxSelect } from '@wikimedia/codex'

import {
MICROTASK_SOURCE_MENU_ITEMS,
MORELIKE_STRATEGY_MENU_ITEMS,
usePrototypeDevSettings,
} from '@/composables/usePrototypeDevSettings'
import {
clearAllInterests,
useInterestsSettings,
} from '@/prototypes/template-homepage/suggested-edits/data/useInterestsSettings'

const { morelikeStrategy, microtaskSource } = usePrototypeDevSettings()
const interestsSettings = useInterestsSettings()

function onClearInterests(): void {
clearAllInterests(interestsSettings.value)
}
</script>

<template>
<div class="prototype-chrome-menu-panel">
<p class="prototype-chrome-menu-panel__title">Prototype settings</p>
<p class="prototype-chrome-menu-panel__hint">
Dev-only controls for suggested-edits morelike search and microtask assignment.
</p>

<label class="prototype-chrome-menu-panel__field">
<span class="prototype-chrome-menu-panel__label">Morelike strategy</span>
<CdxSelect
v-model:selected="morelikeStrategy"
:menu-items="MORELIKE_STRATEGY_MENU_ITEMS"
default-label="Serial multi-call"
/>
</label>

<label class="prototype-chrome-menu-panel__field">
<span class="prototype-chrome-menu-panel__label">Microtask source</span>
<CdxSelect
v-model:selected="microtaskSource"
:menu-items="MICROTASK_SOURCE_MENU_ITEMS"
default-label="Microtask Generator API"
/>
</label>

<div class="prototype-chrome-menu-panel__section">
<CdxButton @click="onClearInterests">Clear interests</CdxButton>
</div>
</div>
</template>

<style scoped>
.prototype-chrome-menu-panel {
display: flex;
flex-direction: column;
gap: var(--spacing-100, 16px);
min-width: 16rem;
max-width: 20rem;
padding: var(--spacing-100, 16px);
}

.prototype-chrome-menu-panel__title {
margin: 0;
font-weight: var(--font-weight-bold);
font-size: var(--font-size-medium);
line-height: var(--line-height-medium);
}

.prototype-chrome-menu-panel__hint {
margin: 0;
font-size: var(--font-size-small);
line-height: var(--line-height-small);
color: var(--color-base--subtle, #54595d);
}

.prototype-chrome-menu-panel__field {
display: flex;
flex-direction: column;
gap: var(--spacing-50, 8px);
}

.prototype-chrome-menu-panel__label {
font-size: var(--font-size-small);
font-weight: var(--font-weight-bold);
}

.prototype-chrome-menu-panel__section {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: var(--spacing-50, 8px);
}
</style>

<!-- Teleported popover: allow the select menu to extend past the scrollable body. -->
<style>
.prototype-chrome-menu-popover__overlay .cdx-popover__body {
overflow: visible;
}
</style>
41 changes: 41 additions & 0 deletions src/components/PrototypeChromeMenuPopover.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script setup lang="ts">
import { ref } from 'vue'

import { CdxPopover } from '@wikimedia/codex'

import PrototypeChromeMenuPanel from './PrototypeChromeMenuPanel.vue'

const open = ref(false)
const anchor = ref<HTMLElement | null>(null)

function toggle(): void {
open.value = !open.value
}
</script>

<template>
<div class="prototype-chrome-menu-popover">
<span ref="anchor" class="prototype-chrome-menu-popover__trigger">
<slot :open="open" :toggle="toggle" />
</span>
<CdxPopover
v-model:open="open"
:anchor="anchor"
placement="bottom-start"
class="prototype-chrome-menu-popover__overlay"
>
<PrototypeChromeMenuPanel @click.stop />
</CdxPopover>
</div>
</template>

<style scoped>
.prototype-chrome-menu-popover {
display: inline-flex;
flex-shrink: 0;
}

.prototype-chrome-menu-popover__trigger {
display: inline-flex;
}
</style>
29 changes: 23 additions & 6 deletions src/components/article/ArticleHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { computed, inject, ref, watch } from 'vue'
import { CdxButton, CdxIcon, CdxPopover, CdxTextInput } from '@wikimedia/codex'
import {
cdxIconBookmarkOutline,
cdxIconDownTriangle,
cdxIconDownload,
cdxIconEdit,
Expand Down Expand Up @@ -38,18 +39,34 @@ interface Props {
* Drives the structural mobile vs desktop layout (icon toolbar vs text actions).
*/
skin?: Skin
/**
* Mobile icon toolbar: watchlist star (default) vs reader bookmark (Minerva
* “save for later” affordance in flows like no-distractions).
*/
bookmarkAffordance?: 'watch' | 'bookmark'
}

const props = withDefaults(defineProps<Props>(), {
languagesCount: 18,
skin: undefined,
bookmarkAffordance: 'watch',
})

const inheritedSkin = inject(PROTOWIKI_CHROME_SKIN)
const effectiveSkin = computed<Skin>(() => props.skin ?? inheritedSkin?.value ?? globalSkin.value)
const { user } = useConfig()
const isLoggedOut = computed(() => user.value === 'logged-out')

const bookmarkLabel = computed(() =>
props.bookmarkAffordance === 'bookmark' ? 'Bookmark' : 'Watch',
)
const bookmarkIcon = computed(() =>
props.bookmarkAffordance === 'bookmark' ? cdxIconBookmarkOutline : cdxIconUnStar,
)
const bookmarkIconLoggedOut = computed(() =>
props.bookmarkAffordance === 'bookmark' ? cdxIconBookmarkOutline : cdxIconStar,
)

const languagesButtonLabel = computed(() => {
const n = props.languagesCount ?? 18
return n === 1 ? '1 language' : `${n} languages`
Expand Down Expand Up @@ -148,10 +165,10 @@ function onLanguagePick(row: ArticleLanguageLink) {
<CdxButton
class="article-header__icon-btn"
weight="quiet"
aria-label="Watch"
:aria-label="bookmarkLabel"
@click="$emit('bookmarkClick')"
>
<CdxIcon :icon="cdxIconUnStar" />
<CdxIcon :icon="bookmarkIcon" />
</CdxButton>
</nav>
</div>
Expand Down Expand Up @@ -186,10 +203,10 @@ function onLanguagePick(row: ArticleLanguageLink) {
<button
type="button"
class="article-header__icon-tool"
aria-label="Watch"
:aria-label="bookmarkLabel"
@click="$emit('bookmarkClick')"
>
<CdxIcon :icon="cdxIconStar" />
<CdxIcon :icon="bookmarkIconLoggedOut" />
</button>
<button
type="button"
Expand All @@ -204,10 +221,10 @@ function onLanguagePick(row: ArticleLanguageLink) {
<button
type="button"
class="article-header__icon-tool"
aria-label="Watch"
:aria-label="bookmarkLabel"
@click="$emit('bookmarkClick')"
>
<CdxIcon :icon="cdxIconUnStar" />
<CdxIcon :icon="bookmarkIcon" />
</button>
<button
type="button"
Expand Down
43 changes: 25 additions & 18 deletions src/components/chrome/ChromeHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { DEFAULT_CHROME_NAV_TOOLS, type ChromeNavTool } from './headerNavTools'
import { globalSkin, globalTheme } from '@/theme'
import type { Skin, Theme } from '@/theme'
import UserSettingsPopover from '../settings/UserSettingsPopover.vue'
import PrototypeChromeMenuPopover from '../PrototypeChromeMenuPopover.vue'
import Search from '../Search.vue'

const { user } = useConfig()
Expand Down Expand Up @@ -97,10 +98,17 @@ function navHas(tool: ChromeNavTool): boolean {
<nav v-if="isDesktop" class="chrome-header__nav-desktop" aria-label="Site">
<div class="chrome-header__desktop-start">
<slot name="menu">
<!-- Mock only — not interactive (FakeMediaWiki uses bare chrome / icon affordances). -->
<span class="chrome-header__menu-icon" aria-hidden="true">
<CdxIcon :icon="cdxIconMenu" />
</span>
<PrototypeChromeMenuPopover v-slot="{ toggle, open }">
<CdxButton
class="chrome-header__menu-btn"
weight="quiet"
aria-label="Main menu"
:aria-expanded="open"
@click="toggle"
>
<CdxIcon :icon="cdxIconMenu" />
</CdxButton>
</PrototypeChromeMenuPopover>
</slot>

<RouterLink class="chrome-header__brand-link" to="/" aria-label="Visit the main page">
Expand Down Expand Up @@ -189,11 +197,7 @@ function navHas(tool: ChromeNavTool): boolean {
<CdxButton v-if="navHas('appearance')" weight="quiet" aria-label="Appearance">
<CdxIcon :icon="cdxIconAppearance" />
</CdxButton>
<CdxButton
v-if="navHas('notifications')"
weight="quiet"
aria-label="Notifications"
>
<CdxButton v-if="navHas('notifications')" weight="quiet" aria-label="Notifications">
<CdxIcon :icon="cdxIconBell" />
</CdxButton>
<CdxButton v-if="navHas('notices')" weight="quiet" aria-label="Notices">
Expand Down Expand Up @@ -226,9 +230,17 @@ function navHas(tool: ChromeNavTool): boolean {
<!-- Minerva-style chrome (mobile skin) -->
<nav v-else class="chrome-header__nav-mobile" aria-label="Site">
<slot name="menu">
<CdxButton weight="quiet" size="large" aria-label="Main menu">
<CdxIcon :icon="cdxIconMenu" />
</CdxButton>
<PrototypeChromeMenuPopover v-slot="{ toggle, open }">
<CdxButton
weight="quiet"
size="large"
aria-label="Main menu"
:aria-expanded="open"
@click="toggle"
>
<CdxIcon :icon="cdxIconMenu" />
</CdxButton>
</PrototypeChromeMenuPopover>
</slot>

<RouterLink class="chrome-header__mobile-brand" to="/" aria-label="Visit the main page">
Expand All @@ -251,11 +263,7 @@ function navHas(tool: ChromeNavTool): boolean {
>
<CdxIcon :icon="cdxIconSearch" />
</CdxButton>
<CdxButton
weight="quiet"
size="large"
aria-label="Notifications"
>
<CdxButton weight="quiet" size="large" aria-label="Notifications">
<CdxIcon :icon="cdxIconBell" />
</CdxButton>
<UserSettingsPopover v-slot="{ toggle, open }">
Expand Down Expand Up @@ -489,7 +497,6 @@ function navHas(tool: ChromeNavTool): boolean {
height: var(--size-icon-large, 40px);
padding: 0.45rem 0.5rem;
}

}

@media (max-width: 768px) {
Expand Down
Loading
Loading