a tool for shared writing and social publishing
1import { useUIState } from "src/useUIState"; 2import { ToolbarButton } from "."; 3import { useCallback } from "react"; 4import { Fact, useEntity, useReplicache } from "src/replicache"; 5import { Props } from "components/Icons/Props"; 6 7export function TextAlignmentToolbar() { 8 let focusedBlock = useUIState((s) => s.focusedEntity); 9 let { rep } = useReplicache(); 10 let setAlignment = useCallback( 11 (alignment: Fact<"block/text-alignment">["data"]["value"]) => { 12 let blocks = useUIState.getState().selectedBlocks; 13 if (focusedBlock?.entityType === "page" || !focusedBlock) return null; 14 rep?.mutate.assertFact( 15 blocks.map((b) => ({ 16 entity: b.value, 17 attribute: "block/text-alignment", 18 data: { type: "text-alignment-type-union", value: alignment }, 19 })), 20 ); 21 }, 22 [focusedBlock, rep], 23 ); 24 return ( 25 <> 26 <ToolbarButton 27 onClick={() => setAlignment("left")} 28 tooltipContent="Align Left" 29 > 30 <AlignLeftSmall /> 31 </ToolbarButton> 32 <ToolbarButton 33 onClick={() => setAlignment("center")} 34 tooltipContent="Align Center" 35 > 36 <AlignCenterSmall /> 37 </ToolbarButton> 38 <ToolbarButton 39 onClick={() => setAlignment("right")} 40 tooltipContent="Align Right" 41 > 42 <AlignRightSmall /> 43 </ToolbarButton> 44 45 <ToolbarButton 46 onClick={() => setAlignment("justify")} 47 tooltipContent="Align Justified" 48 > 49 <AlignJustifiedSmall /> 50 </ToolbarButton> 51 </> 52 ); 53} 54 55export function TextAlignmentButton(props: { 56 setToolbarState: (s: "text-alignment") => void; 57 className?: string; 58}) { 59 let focusedBlock = useUIState((s) => s.focusedEntity); 60 let alignment = 61 useEntity(focusedBlock?.entityID || null, "block/text-alignment")?.data 62 .value || "left"; 63 return ( 64 <ToolbarButton 65 hiddenOnCanvas 66 tooltipContent={<div>Align</div>} 67 className={`${props.className}`} 68 onClick={() => { 69 props.setToolbarState("text-alignment"); 70 }} 71 > 72 {alignment === "left" ? ( 73 <AlignLeftSmall /> 74 ) : alignment === "center" ? ( 75 <AlignCenterSmall /> 76 ) : alignment === "justify" ? ( 77 <AlignJustifiedSmall /> 78 ) : ( 79 <AlignRightSmall /> 80 )} 81 </ToolbarButton> 82 ); 83} 84 85export const AlignLeftSmall = (props: Props) => { 86 return ( 87 <svg 88 width="24" 89 height="24" 90 viewBox="0 0 24 24" 91 fill="none" 92 xmlns="http://www.w3.org/2000/svg" 93 {...props} 94 > 95 <path 96 fillRule="evenodd" 97 clipRule="evenodd" 98 d="M3.5 6.19983C3.5 5.64754 3.94772 5.19983 4.5 5.19983H19.6547C20.2069 5.19983 20.6547 5.64754 20.6547 6.19983C20.6547 6.75211 20.2069 7.19983 19.6547 7.19983H4.5C3.94772 7.19983 3.5 6.75211 3.5 6.19983ZM3.5 12C3.5 11.4477 3.94772 11 4.5 11H12.8243C13.3766 11 13.8243 11.4477 13.8243 12C13.8243 12.5523 13.3766 13 12.8243 13H4.5C3.94772 13 3.5 12.5523 3.5 12ZM4.5 16.7999C3.94772 16.7999 3.5 17.2476 3.5 17.7999C3.5 18.3522 3.94772 18.7999 4.5 18.7999H16.1426C16.6949 18.7999 17.1426 18.3522 17.1426 17.7999C17.1426 17.2476 16.6949 16.7999 16.1426 16.7999H4.5Z" 99 fill="currentColor" 100 /> 101 </svg> 102 ); 103}; 104export const AlignCenterSmall = (props: Props) => { 105 return ( 106 <svg 107 width="24" 108 height="24" 109 viewBox="0 0 24 24" 110 fill="none" 111 xmlns="http://www.w3.org/2000/svg" 112 {...props} 113 > 114 <path 115 fillRule="evenodd" 116 clipRule="evenodd" 117 d="M3.5 6.19983C3.5 5.64754 3.94772 5.19983 4.5 5.19983H19.6547C20.2069 5.19983 20.6547 5.64754 20.6547 6.19983C20.6547 6.75211 20.2069 7.19983 19.6547 7.19983H4.5C3.94772 7.19983 3.5 6.75211 3.5 6.19983ZM6.91519 12C6.91519 11.4477 7.36291 11 7.91519 11H16.2395C16.7918 11 17.2395 11.4477 17.2395 12C17.2395 12.5523 16.7918 13 16.2395 13H7.91519C7.36291 13 6.91519 12.5523 6.91519 12ZM6.25601 16.7999C5.70373 16.7999 5.25601 17.2476 5.25601 17.7999C5.25601 18.3522 5.70373 18.7999 6.25601 18.7999H17.8987C18.4509 18.7999 18.8987 18.3522 18.8987 17.7999C18.8987 17.2476 18.4509 16.7999 17.8987 16.7999H6.25601Z" 118 fill="currentColor" 119 /> 120 </svg> 121 ); 122}; 123export const AlignRightSmall = (props: Props) => { 124 return ( 125 <svg 126 width="24" 127 height="24" 128 viewBox="0 0 24 24" 129 fill="none" 130 xmlns="http://www.w3.org/2000/svg" 131 {...props} 132 > 133 <path 134 fillRule="evenodd" 135 clipRule="evenodd" 136 d="M3.5 6.19983C3.5 5.64754 3.94772 5.19983 4.5 5.19983H19.6547C20.2069 5.19983 20.6547 5.64754 20.6547 6.19983C20.6547 6.75211 20.2069 7.19983 19.6547 7.19983H4.5C3.94772 7.19983 3.5 6.75211 3.5 6.19983ZM10.3304 12C10.3304 11.4477 10.7781 11 11.3304 11H19.6547C20.2069 11 20.6547 11.4477 20.6547 12C20.6547 12.5523 20.2069 13 19.6547 13H11.3304C10.7781 13 10.3304 12.5523 10.3304 12ZM8.01202 16.7999C7.45974 16.7999 7.01202 17.2476 7.01202 17.7999C7.01202 18.3522 7.45974 18.7999 8.01202 18.7999H19.6547C20.2069 18.7999 20.6547 18.3522 20.6547 17.7999C20.6547 17.2476 20.2069 16.7999 19.6547 16.7999H8.01202Z" 137 fill="currentColor" 138 /> 139 </svg> 140 ); 141}; 142 143export const AlignJustifiedSmall = (props: Props) => { 144 return ( 145 <svg 146 width="24" 147 height="24" 148 viewBox="0 0 24 24" 149 fill="none" 150 xmlns="http://www.w3.org/2000/svg" 151 {...props} 152 > 153 <path 154 fillRule="evenodd" 155 clipRule="evenodd" 156 d="M3.5 6.19983C3.5 5.64754 3.94772 5.19983 4.5 5.19983H19.6547C20.2069 5.19983 20.6547 5.64754 20.6547 6.19983C20.6547 6.75211 20.2069 7.19983 19.6547 7.19983H4.5C3.94772 7.19983 3.5 6.75211 3.5 6.19983ZM3.5 12C3.5 11.4477 3.94772 11 4.5 11H19.6547C20.2069 11 20.6547 11.4477 20.6547 12C20.6547 12.5523 20.2069 13 19.6547 13H4.5C3.94772 13 3.5 12.5523 3.5 12ZM4.5 16.7999C3.94772 16.7999 3.5 17.2476 3.5 17.7999C3.5 18.3522 3.94772 18.7999 4.5 18.7999H19.6547C20.2069 18.7999 20.6547 18.3522 20.6547 17.7999C20.6547 17.2476 20.2069 16.7999 19.6547 16.7999H4.5Z" 157 fill="currentColor" 158 /> 159 </svg> 160 ); 161};