mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
@@ -1,3 +1,4 @@
|
||||
import clsx from 'clsx';
|
||||
import dayjs from 'dayjs';
|
||||
import { memo, useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
|
||||
@@ -23,6 +24,8 @@ export const DayPicker = memo(function DayPicker(
|
||||
onChange,
|
||||
onCursorChange,
|
||||
onModeChange,
|
||||
monthHeaderCellClassName,
|
||||
monthBodyCellClassName,
|
||||
} = props;
|
||||
|
||||
const matrix = useMemo(() => {
|
||||
@@ -170,7 +173,13 @@ export const DayPicker = memo(function DayPicker(
|
||||
{/* weekDays */}
|
||||
<div className={styles.monthViewRow}>
|
||||
{weekDays.split(',').map(day => (
|
||||
<div key={day} className={styles.monthViewHeaderCell}>
|
||||
<div
|
||||
key={day}
|
||||
className={clsx(
|
||||
styles.monthViewHeaderCell,
|
||||
monthHeaderCellClassName
|
||||
)}
|
||||
>
|
||||
{day}
|
||||
</div>
|
||||
))}
|
||||
@@ -178,10 +187,13 @@ export const DayPicker = memo(function DayPicker(
|
||||
{/* Weeks in month */}
|
||||
{matrix.map((week, i) => {
|
||||
return (
|
||||
<div key={i} className={styles.monthViewRow}>
|
||||
<div key={i} className={clsx(styles.monthViewRow)}>
|
||||
{week.map((cell, j) => (
|
||||
<div
|
||||
className={styles.monthViewBodyCell}
|
||||
className={clsx(
|
||||
styles.monthViewBodyCell,
|
||||
monthBodyCellClassName
|
||||
)}
|
||||
key={j}
|
||||
onClick={() => onChange?.(cell.date.format(format))}
|
||||
>
|
||||
@@ -197,7 +209,15 @@ export const DayPicker = memo(function DayPicker(
|
||||
})}
|
||||
</main>
|
||||
),
|
||||
[customDayRenderer, format, matrix, onChange, weekDays]
|
||||
[
|
||||
customDayRenderer,
|
||||
format,
|
||||
matrix,
|
||||
monthBodyCellClassName,
|
||||
monthHeaderCellClassName,
|
||||
onChange,
|
||||
weekDays,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -50,6 +50,10 @@ export interface DatePickerProps {
|
||||
* when date is clicked
|
||||
*/
|
||||
onChange?: (value: string) => void;
|
||||
|
||||
// style customizations
|
||||
monthHeaderCellClassName?: string;
|
||||
monthBodyCellClassName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,8 +20,6 @@ export interface MenuProps {
|
||||
export interface MenuItemProps
|
||||
extends Omit<MenuItemPropsPrimitive, 'asChild' | 'textValue' | 'prefix'> {
|
||||
type?: 'default' | 'warning' | 'danger';
|
||||
// preFix?: React.ReactNode;
|
||||
// endFix?: React.ReactNode;
|
||||
prefix?: ReactNode;
|
||||
suffix?: ReactNode;
|
||||
prefixIcon?: ReactNode;
|
||||
@@ -29,6 +27,11 @@ export interface MenuItemProps
|
||||
checked?: boolean;
|
||||
selected?: boolean;
|
||||
block?: boolean;
|
||||
/**
|
||||
* add divider after item (if not last one)
|
||||
* - Mobile only for now
|
||||
*/
|
||||
divide?: boolean;
|
||||
}
|
||||
export interface MenuSubProps {
|
||||
children: ReactNode;
|
||||
|
||||
@@ -12,7 +12,7 @@ const preventDefault = () => {
|
||||
export const MobileMenuItem = (props: MenuItemProps) => {
|
||||
const { setOpen } = useContext(MobileMenuContext);
|
||||
const { className, children, otherProps } = useMenuItem(props);
|
||||
const { onSelect, onClick, ...restProps } = otherProps;
|
||||
const { onSelect, onClick, divide, ...restProps } = otherProps;
|
||||
|
||||
const onItemClick = useCallback(
|
||||
(e: any) => {
|
||||
@@ -32,6 +32,7 @@ export const MobileMenuItem = (props: MenuItemProps) => {
|
||||
role="menuitem"
|
||||
onClick={onItemClick}
|
||||
className={className}
|
||||
data-divider={divide}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -43,6 +43,7 @@ export const menuContent = style({
|
||||
export const mobileMenuItem = style({
|
||||
padding: '10px 20px',
|
||||
borderRadius: 0,
|
||||
|
||||
':hover': {
|
||||
vars: {
|
||||
[bgColor]: 'transparent',
|
||||
@@ -66,6 +67,25 @@ export const mobileMenuItem = style({
|
||||
'&.warning:active': {
|
||||
vars: { [bgColor]: cssVar('backgroundWarningColor') },
|
||||
},
|
||||
// divider hack
|
||||
'&[data-divider=true]': {
|
||||
marginBottom: 16,
|
||||
position: 'relative',
|
||||
},
|
||||
'&[data-divider=true]::after': {
|
||||
content: '""',
|
||||
position: 'absolute',
|
||||
bottom: -8,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
borderBottom: `0.5px solid ${cssVarV2('layer/insideBorder/border')}`,
|
||||
},
|
||||
'&[data-divider=true]:last-child': {
|
||||
marginBottom: 0,
|
||||
},
|
||||
'&[data-divider=true]:last-child::after': {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@ const interactive = style({
|
||||
});
|
||||
export const calendar = style({
|
||||
padding: '16px',
|
||||
selectors: {
|
||||
'&[data-mobile=true]': {
|
||||
padding: '8px 16px',
|
||||
},
|
||||
},
|
||||
});
|
||||
export const journalPanel = style({
|
||||
width: '100%',
|
||||
@@ -212,6 +217,13 @@ export const journalDateCell = style([
|
||||
fontWeight: 500,
|
||||
border: `1px solid ${cssVar('primaryColor')}`,
|
||||
},
|
||||
|
||||
'&[data-mobile=true]': {
|
||||
width: 34,
|
||||
height: 34,
|
||||
fontSize: 15,
|
||||
fontWeight: 400,
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
@@ -225,3 +237,7 @@ export const journalDateCellDot = style({
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
});
|
||||
|
||||
export const journalDateCellWrapper = style({
|
||||
height: 34,
|
||||
});
|
||||
|
||||
@@ -90,6 +90,7 @@ interface JournalBlockProps {
|
||||
date: dayjs.Dayjs;
|
||||
}
|
||||
|
||||
const mobile = environment.isMobile;
|
||||
export const EditorJournalPanel = () => {
|
||||
const t = useI18n();
|
||||
const doc = useService(DocService).doc;
|
||||
@@ -129,6 +130,7 @@ export const EditorJournalPanel = () => {
|
||||
data-selected={cell.selected}
|
||||
data-is-journal={isJournal}
|
||||
data-has-journal={hasJournal}
|
||||
data-mobile={mobile}
|
||||
>
|
||||
{cell.label}
|
||||
{hasJournal && !cell.selected ? (
|
||||
@@ -142,7 +144,7 @@ export const EditorJournalPanel = () => {
|
||||
|
||||
return (
|
||||
<div className={styles.journalPanel} data-is-journal={isJournal}>
|
||||
<div className={styles.calendar}>
|
||||
<div data-mobile={mobile} className={styles.calendar}>
|
||||
<DatePicker
|
||||
weekDays={t['com.affine.calendar-date-picker.week-days']()}
|
||||
monthNames={t['com.affine.calendar-date-picker.month-names']()}
|
||||
@@ -150,6 +152,8 @@ export const EditorJournalPanel = () => {
|
||||
customDayRenderer={customDayRenderer}
|
||||
value={date}
|
||||
onChange={onDateSelect}
|
||||
monthHeaderCellClassName={styles.journalDateCellWrapper}
|
||||
monthBodyCellClassName={styles.journalDateCellWrapper}
|
||||
/>
|
||||
</div>
|
||||
<JournalConflictBlock date={dayjs(date)} />
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* TODO(@CatsJuice): replace with `@blocksuite/icons/rc` when ready
|
||||
*/
|
||||
export const HomeIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 31 30"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M24.5957 24.375V13.0977C24.5957 12.9048 24.5067 12.7228 24.3544 12.6044L15.6044 5.7988C15.3787 5.62326 15.0627 5.62326 14.837 5.7988L6.08699 12.6044C5.93475 12.7228 5.8457 12.9048 5.8457 13.0977V24.375C5.8457 24.7202 6.12553 25 6.4707 25H23.9707C24.3159 25 24.5957 24.7202 24.5957 24.375ZM4.93585 11.1243C4.32689 11.598 3.9707 12.3262 3.9707 13.0977V24.375C3.9707 25.7557 5.08999 26.875 6.4707 26.875H23.9707C25.3514 26.875 26.4707 25.7557 26.4707 24.375V13.0977C26.4707 12.3262 26.1145 11.598 25.5056 11.1243L16.7556 4.31876C15.8528 3.61661 14.5886 3.6166 13.6859 4.31876L4.93585 11.1243Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -2,11 +2,10 @@ import {
|
||||
WorkbenchLink,
|
||||
WorkbenchService,
|
||||
} from '@affine/core/modules/workbench';
|
||||
import { AllDocsIcon, SearchIcon } from '@blocksuite/icons/rc';
|
||||
import { AllDocsIcon, MobileHomeIcon, SearchIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import type { Location } from 'react-router-dom';
|
||||
|
||||
import { HomeIcon } from './home-icon';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
interface Route {
|
||||
@@ -19,7 +18,7 @@ interface Route {
|
||||
const routes: Route[] = [
|
||||
{
|
||||
to: '/home',
|
||||
Icon: HomeIcon,
|
||||
Icon: MobileHomeIcon,
|
||||
},
|
||||
{
|
||||
to: '/all',
|
||||
|
||||
@@ -12,12 +12,13 @@ export const appTabs = style({
|
||||
borderTop: `1px solid ${cssVarV2('layer/insideBorder/border')}`,
|
||||
|
||||
width: '100dvw',
|
||||
height: globalVars.appTabHeight,
|
||||
height: `calc(${globalVars.appTabHeight} + 2px)`,
|
||||
padding: 16,
|
||||
gap: 15.5,
|
||||
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
paddingBottom: 18,
|
||||
bottom: -2,
|
||||
zIndex: 1,
|
||||
});
|
||||
export const tabItem = style({
|
||||
@@ -30,6 +31,7 @@ export const tabItem = style({
|
||||
padding: 3,
|
||||
fontSize: 30,
|
||||
color: cssVarV2('icon/primary'),
|
||||
lineHeight: 0,
|
||||
|
||||
selectors: {
|
||||
'&[data-active="true"]': {
|
||||
|
||||
@@ -117,6 +117,7 @@ export const SelectorMenu = ({ onClose }: { onClose?: () => void }) => {
|
||||
title="Cloud Sync"
|
||||
list={cloudWorkspaces}
|
||||
/>
|
||||
<div className={styles.divider} />
|
||||
<WorkspaceList
|
||||
onClose={onClose}
|
||||
title="Local Storage"
|
||||
|
||||
@@ -50,6 +50,7 @@ export const SettingDropdownSelect = <
|
||||
<MobileMenu
|
||||
items={options.map(opt => (
|
||||
<MobileMenuItem
|
||||
divide
|
||||
key={opt.value}
|
||||
selected={value === opt.value}
|
||||
data-testid={opt.testId}
|
||||
|
||||
Reference in New Issue
Block a user