donteatfriedrice
2025-04-18 02:44:21 +00:00
parent dd51180acb
commit a555df0200
8 changed files with 44 additions and 62 deletions

View File

@@ -1,6 +1,6 @@
import { cssVar } from '@toeverything/theme';
import { cssVarV2 } from '@toeverything/theme/v2';
import { style } from '@vanilla-extract/css';
import { globalStyle, style } from '@vanilla-extract/css';
export const outlineBlockPreview = style({
fontFamily: cssVar('fontFamily'),
@@ -108,6 +108,11 @@ export const linkedDocPreviewUnavailable = style({
color: cssVarV2('text/disable'),
});
export const linkedDocPreviewAvailable = style({});
globalStyle(`${linkedDocPreviewAvailable} > svg`, {
marginBottom: '0.1em',
});
export const linkedDocTextUnavailable = style({
color: cssVarV2('text/disable'),
textDecoration: 'line-through',

View File

@@ -67,6 +67,7 @@ export class OutlineBlockPreview extends SignalWatcher(
return html`<span
class=${classMap({
[styles.linkedDocPreviewUnavailable]: unavailable,
[styles.linkedDocPreviewAvailable]: !unavailable,
})}
>
${icon}

View File

@@ -29,13 +29,23 @@ export const markdownFootnoteReferenceToDeltaMatcher =
const footnoteReference = FootNoteReferenceParamsSchema.parse(
footnoteDefinitionJson
);
// If the footnote reference is an attachment, and the file type is not set,
// Try to infer the file type from the file name.
const { type: referenceType, fileName, fileType } = footnoteReference;
if (referenceType === 'attachment' && fileName && !fileType) {
const ext = fileName.split('.').pop()?.toLowerCase();
if (ext) {
footnoteReference.fileType = ext;
}
}
const footnote = {
label: ast.identifier,
reference: footnoteReference,
};
return [{ insert: ' ', attributes: { footnote } }];
} catch (error) {
console.warn('Error parsing footnote reference', error);
} catch {
return [];
}
},

View File

@@ -17,7 +17,7 @@ import {
ZERO_WIDTH_FOR_EMPTY_LINE,
} from '@blocksuite/std/inline';
import type { DeltaInsert } from '@blocksuite/store';
import { shift } from '@floating-ui/dom';
import { flip, offset, shift } from '@floating-ui/dom';
import { baseTheme } from '@toeverything/theme';
import { css, html, nothing, unsafeCSS } from 'lit';
import { property } from 'lit/decorators.js';
@@ -28,6 +28,8 @@ import type { FootNoteNodeConfigProvider } from './footnote-config';
// Virtual padding for the footnote popup overflow detection offsets.
const POPUP_SHIFT_PADDING = 8;
// The offset between the footnote node and the popup.
const POPUP_OFFSET = 4;
export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
static override styles = css`
@@ -203,12 +205,16 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
return {
template: this._FootNotePopup(footnote, abortController),
container: this,
container: this.std.host,
computePosition: {
referenceElement: this,
placement: 'top',
autoUpdate: true,
middleware: [shift({ padding: POPUP_SHIFT_PADDING })],
middleware: [
shift({ padding: POPUP_SHIFT_PADDING }),
flip(),
offset(POPUP_OFFSET),
],
},
};
},

View File

@@ -9,48 +9,42 @@ export class FootNotePopupChip extends LitElement {
border-radius: 4px;
max-width: 173px;
height: 24px;
padding: 2px 4px;
padding: 4px;
align-items: center;
gap: 4px;
gap: 8px;
box-sizing: border-box;
cursor: default;
transition: width 0.3s ease-in-out;
}
.prefix-icon,
.suffix-icon {
.prefix-icon {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
width: 16px;
color: ${unsafeCSSVarV2('icon/primary')};
border-radius: 4px;
svg,
object {
img {
width: 16px;
height: 16px;
fill: ${unsafeCSSVarV2('icon/primary')};
}
}
.suffix-icon:hover {
background-color: ${unsafeCSSVarV2('layer/background/hoverOverlay')};
cursor: pointer;
}
.popup-chip-label {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: left;
height: 20px;
line-height: 20px;
height: 22px;
line-height: 22px;
color: ${unsafeCSSVarV2('text/primary')};
font-size: 12px;
font-weight: 400;
font-size: var(--affine-font-sm);
font-weight: 500;
}
`;
@@ -63,11 +57,6 @@ export class FootNotePopupChip extends LitElement {
</div>`
: nothing}
<div class="popup-chip-label" title=${this.tooltip}>${this.label}</div>
${this.suffixIcon
? html`<div class="suffix-icon" @click=${this.onSuffixClick}>
${this.suffixIcon}
</div>`
: nothing}
</div>
`;
}
@@ -78,9 +67,6 @@ export class FootNotePopupChip extends LitElement {
@property({ attribute: false })
accessor label: string = '';
@property({ attribute: false })
accessor suffixIcon: TemplateResult | undefined = undefined;
@property({ attribute: false })
accessor tooltip: string = '';
@@ -89,7 +75,4 @@ export class FootNotePopupChip extends LitElement {
@property({ attribute: false })
accessor onPrefixClick: (() => void) | undefined = undefined;
@property({ attribute: false })
accessor onSuffixClick: (() => void) | undefined = undefined;
}

View File

@@ -12,10 +12,9 @@ import {
} from '@blocksuite/affine-shared/services';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
import { DualLinkIcon, LinkIcon } from '@blocksuite/icons/lit';
import type { BlockStdScope } from '@blocksuite/std';
import { computed, signal } from '@preact/signals-core';
import { css, html, LitElement, type TemplateResult } from 'lit';
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import type { FootNotePopupClickHandler } from './footnote-config';
@@ -56,36 +55,11 @@ export class FootNotePopup extends SignalWatcher(WithDisposable(LitElement)) {
}
const favicon = this._linkPreview$.value?.favicon;
if (!favicon) {
return undefined;
}
const titleIconType =
favicon.split('.').pop() === 'svg'
? 'svg+xml'
: favicon.split('.').pop();
const titleIcon = html`<object
type="image/${titleIconType}"
data=${favicon}
draggable="false"
>
${WebIcon16}
</object>`;
return titleIcon;
return favicon ? html`<img src=${favicon} alt="favicon" />` : WebIcon16;
}
return undefined;
});
private readonly _suffixIcon = (): TemplateResult | undefined => {
const referenceType = this.footnote.reference.type;
if (referenceType === 'doc') {
return DualLinkIcon({ width: '16px', height: '16px' });
} else if (referenceType === 'url') {
return LinkIcon({ width: '16px', height: '16px' });
}
return undefined;
};
private readonly _popupLabel$ = computed(() => {
const referenceType = this.footnote.reference.type;
let label = '';
@@ -157,7 +131,6 @@ export class FootNotePopup extends SignalWatcher(WithDisposable(LitElement)) {
<footnote-popup-chip
.prefixIcon=${this._prefixIcon$.value}
.label=${this._popupLabel$.value}
.suffixIcon=${this._suffixIcon()}
.onClick=${this._onChipClick}
.tooltip=${this._tooltip$.value}
></footnote-popup-chip>

View File

@@ -49,6 +49,10 @@ export class AffineReference extends WithDisposable(ShadowlessElement) {
cursor: pointer;
user-select: none;
padding: 1px 2px 1px 0;
svg {
margin-bottom: 0.1em;
}
}
.affine-reference:hover {
background: var(--affine-hover-color);

View File

@@ -217,7 +217,7 @@ export class DocDisplayMetaService
function iconBuilder(
icon: typeof PageIcon,
size = '1.25em',
style = 'user-select:none;flex-shrink:0;vertical-align:middle;font-size:inherit;margin-bottom:0.1em;'
style = 'user-select:none;flex-shrink:0;vertical-align:middle;font-size:inherit;'
) {
return icon({ width: size, height: size, style });
}