chore: Public share cleanup (#10541)

* chore: More public share cleanup

* fix: Use correct amount of spaces for tab

* fix: Pointer on public shares

* fix: Tweak AAA contrast

* Show code language on public share
This commit is contained in:
Tom Moor
2025-11-01 15:25:38 +01:00
committed by GitHub
parent bf9065d6e6
commit e4268c9a1f
10 changed files with 77 additions and 41 deletions
+15 -4
View File
@@ -23,6 +23,7 @@ import { SharedDocumentLink } from "./components/SharedDocumentLink";
import SidebarButton from "./components/SidebarButton";
import ToggleButton from "./components/ToggleButton";
import { useEffect } from "react";
import { ProsemirrorHelper } from "@shared/utils/ProsemirrorHelper";
type Props = {
share: Share;
@@ -31,12 +32,16 @@ type Props = {
function SharedSidebar({ share }: Props) {
const team = useTeamContext();
const user = useCurrentUser({ rejectOnEmpty: false });
const { ui, documents } = useStores();
const { ui, documents, collections } = useStores();
const { t } = useTranslation();
const teamAvailable = !!team?.name;
const rootNode = share.tree;
const shareId = share.urlId || share.id;
const collection = collections.get(rootNode?.id);
const hideRootNode = collection
? ProsemirrorHelper.isEmptyData(collection?.data)
: false;
useEffect(() => {
ui.tocVisible = share.showTOC;
@@ -54,8 +59,10 @@ function SharedSidebar({ share }: Props) {
image={
<TeamLogo model={team} size={AvatarSize.XLarge} alt={t("Logo")} />
}
onClick={() =>
history.push(user ? homePath() : sharedModelPath(shareId))
onClick={
hideRootNode
? undefined
: () => history.push(user ? homePath() : sharedModelPath(shareId))
}
/>
)}
@@ -72,7 +79,11 @@ function SharedSidebar({ share }: Props) {
</TopSection>
<Section>
{share.collectionId ? (
<SharedCollectionLink node={rootNode} shareId={shareId} />
<SharedCollectionLink
node={rootNode}
shareId={shareId}
hideRootNode={hideRootNode}
/>
) : (
<SharedDocumentLink
index={0}
@@ -6,26 +6,21 @@ import useStores from "~/hooks/useStores";
import { sharedModelPath } from "~/utils/routeHelpers";
import { SharedDocumentLink } from "./SharedDocumentLink";
import SidebarLink from "./SidebarLink";
import { ProsemirrorHelper } from "@shared/utils/ProsemirrorHelper";
type Props = {
node: NavigationNode;
shareId: string;
hideRootNode?: boolean;
};
function CollectionLink({ node, shareId }: Props) {
function CollectionLink({ node, shareId, hideRootNode }: Props) {
const { t } = useTranslation();
const { documents, collections, ui } = useStores();
const collection = collections.get(node.id);
const { documents, ui } = useStores();
const icon = node.icon ?? node.emoji;
const showCollectionRoot = collection
? !ProsemirrorHelper.isEmptyData(collection?.data)
: true;
return (
<>
{showCollectionRoot && (
{!hideRootNode && (
<SidebarLink
to={{
pathname: sharedModelPath(shareId),
@@ -45,7 +40,7 @@ function CollectionLink({ node, shareId }: Props) {
<SharedDocumentLink
key={childNode.id}
index={index}
depth={showCollectionRoot ? 2 : 0}
depth={hideRootNode ? 0 : 2}
shareId={shareId}
node={childNode}
prefetchDocument={documents.prefetchDocument}
@@ -25,6 +25,7 @@ const SidebarButton = React.forwardRef<HTMLButtonElement, SidebarButtonProps>(
image,
title,
children,
onClick,
...rest
}: SidebarButtonProps,
ref
@@ -38,10 +39,12 @@ const SidebarButton = React.forwardRef<HTMLButtonElement, SidebarButtonProps>(
>
<Button
{...rest}
onClick={onClick}
$position={position}
as="button"
ref={ref}
role="button"
disabled={!onClick}
>
<Content gap={8} align="center">
{image}
@@ -96,17 +99,17 @@ const Button = styled(Flex)<{
text-decoration: none;
text-align: left;
user-select: none;
cursor: var(--pointer);
position: relative;
${undraggableOnDesktop()}
${extraArea(4)}
&:active,
&:${hover},
&[aria-expanded="true"] {
&:not(:disabled):active,
&:not(:disabled):${hover},
&:not(:disabled)[aria-expanded="true"] {
color: ${s("sidebarText")};
background: ${s("sidebarActiveBackground")};
cursor: var(--pointer);
}
&:last-child {
-2
View File
@@ -1,5 +1,4 @@
import styled from "styled-components";
import { s } from "@shared/styles";
import { Avatar } from "./Avatar";
import { AvatarVariant } from "./Avatar/Avatar";
@@ -7,7 +6,6 @@ const TeamLogo = styled(Avatar).attrs({
variant: AvatarVariant.Square,
})`
border-radius: 4px;
box-shadow: inset 0 0 0 1px ${s("divider")};
border: 0;
`;
+4 -3
View File
@@ -30,9 +30,10 @@ const Theme: React.FC = ({ children }: Props) => {
<ThemeProvider theme={theme}>
<>
<GlobalStyles
useCursorPointer={auth.user?.getPreference(
UserPreference.UseCursorPointer
)}
useCursorPointer={
// Default to showing the cursor pointer if no user is logged in (public share)
auth.user?.getPreference(UserPreference.UseCursorPointer) ?? true
}
/>
{children}
</>
+14 -12
View File
@@ -30,31 +30,33 @@ export default function codeMenuItems(
)
.map(([value, item]) => langToMenuItem({ node, value, label: item.label }));
const languageMenuItems = frequentLangMenuItems.length
? [
...frequentLangMenuItems,
{ name: "separator" },
...remainingLangMenuItems,
]
: remainingLangMenuItems;
const getLanguageMenuItems = () =>
frequentLangMenuItems.length
? [
...frequentLangMenuItems,
{ name: "separator" },
...remainingLangMenuItems,
]
: remainingLangMenuItems;
return [
{
name: "copyToClipboard",
icon: <CopyIcon />,
label: readOnly ? dictionary.copy : undefined,
label: readOnly
? getLabelForLanguage(node.attrs.language ?? "none")
: undefined,
tooltip: dictionary.copy,
},
{
name: "separator",
visible: !readOnly,
},
{
visible: !readOnly,
name: "code_block",
icon: <ExpandedIcon />,
label: getLabelForLanguage(node.attrs.language ?? "none"),
children: languageMenuItems,
icon: <ExpandedIcon />,
children: getLanguageMenuItems(),
visible: !readOnly,
},
];
}
+19 -2
View File
@@ -1,12 +1,12 @@
import { exitCode } from "prosemirror-commands";
import { Command, TextSelection } from "prosemirror-state";
import { Command, EditorState, TextSelection } from "prosemirror-state";
import { findNextNewline, findPreviousNewline } from "../queries/findNewlines";
import { isInCode } from "../queries/isInCode";
import { findParentNode } from "../queries/findParentNode";
import { isCode } from "../lib/isCode";
import { languagesWithFourSpaceIndent } from "../lib/code";
const newline = "\n";
const tabSize = 2;
/**
* Moves the current selection to the previous newline, this is used inside
@@ -93,6 +93,7 @@ export const indentInCode: Command = (state, dispatch) => {
return false;
}
const tabSize = getTabSize(state);
const spaces = " ".repeat(tabSize);
const { tr, selection } = state;
const { $from, from, to } = selection;
@@ -155,6 +156,7 @@ export const outdentInCode: Command = (state, dispatch) => {
let totalSpacesRemoved = 0;
let spacesRemovedOnFirstLine = 0;
const startOfFirstLine = findPreviousNewline($from);
const tabSize = getTabSize(state);
while (index >= startOfFirstLine - line * tabSize) {
const newLineBefore =
@@ -268,3 +270,18 @@ export const splitCodeBlockOnTripleBackticks: Command = (state, dispatch) => {
return true;
};
function getTabSize(state: EditorState): number {
const codeBlock = findParentNode(isCode)(state.selection);
if (!codeBlock) {
return 2;
}
if (languagesWithFourSpaceIndent.includes(codeBlock.node.attrs.language)) {
return 4;
}
const existingText = codeBlock.node.textContent;
const usesFourSpaces = existingText.includes(" ");
return usesFourSpaces ? 4 : 2;
}
+1
View File
@@ -1360,6 +1360,7 @@ code {
.${EditorStyleHelper.codeWord} {
white-space: nowrap;
color: ${props.theme.codeKeyword};
}
}
+8
View File
@@ -425,3 +425,11 @@ export const getFrequentCodeLanguages = () => {
const sortFrequencies = <T>(freqs: [T, number][]) =>
freqs.sort((a, b) => (a[1] >= b[1] ? -1 : 1));
export const languagesWithFourSpaceIndent = [
"python",
"java",
"cpp",
"csharp",
"rust",
];
+4 -4
View File
@@ -75,10 +75,10 @@ const buildBaseTheme = (input: Partial<Colors>) => {
code: colors.lightBlack,
codeComment: "#008000",
codePunctuation: "#393a34",
codeNumber: "#36acaa",
codeNumber: "#0550ae",
codeProperty: "#ff0000",
codeTag: "#800000",
codeClassName: "#2b91af",
codeClassName: "#00578a",
codeString: "#a31515",
codeSelector: "#800000",
codeAttrName: "#ff0000",
@@ -88,9 +88,9 @@ const buildBaseTheme = (input: Partial<Colors>) => {
codeFunction: "#393A34",
codeStatement: "#ff0000",
codePlaceholder: "#3d8fd1",
codeInserted: "#36acaa",
codeInserted: "#0550ae",
codeImportant: "#e90e90",
codeConstant: "#36acaa",
codeConstant: "#0550ae",
codeParameter: colors.lightBlack,
codeOperator: "#393a34",
noticeInfoBackground: colors.brand.blue,