mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
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:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
`;
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1360,6 +1360,7 @@ code {
|
||||
|
||||
.${EditorStyleHelper.codeWord} {
|
||||
white-space: nowrap;
|
||||
color: ${props.theme.codeKeyword};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
];
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user