[READ-ONLY] Mirror of https://github.com/FoxxMD/komodo-import. Import existing compose stacks into Komodo foxxmd.github.io/komodo-import
compose docker import komodo toml
0

Configure Feed

Select the types of activity you want to include in your feed.

docs: Implement feedback

FoxxMD (Aug 27, 2025, 12:31 AM UTC) 6e4dd156 e9ae8855

+182 -1
+11
.vscode/launch.json
··· 99 99 "${workspaceFolder}/node_modules/**", 100 100 ], 101 101 "type": "node" 102 + }, 103 + { 104 + "name": "Start Docs", 105 + "type": "node", 106 + "request": "launch", 107 + "cwd": "${workspaceRoot}/docsite", 108 + "envFile": "${workspaceFolder}/.env", 109 + "runtimeExecutable": "npm", 110 + "runtimeArgs": [ 111 + "run-script", "start" 112 + ], 102 113 } 103 114 ] 104 115 }
+3
docsite/docusaurus.config.ts
··· 217 217 if (process.env.RY_ANALYTICS_REPLAY !== undefined && process.env.RY_ANALYTICS_REPLAY !== '') { 218 218 script['data-session-replay'] = process.env.RY_ANALYTICS_REPLAY; 219 219 } 220 + if (process.env.RY_ANALYTICS_API !== undefined && process.env.RY_ANALYTICS_API !== '') { 221 + script['data-api-key'] = process.env.RY_ANALYTICS_API; 222 + } 220 223 config.scripts.push(script) 221 224 } 222 225
+46
docsite/rybbit.d.ts
··· 1 + interface Rybbit { 2 + /** 3 + * Tracks a page view 4 + */ 5 + pageview: () => void; 6 + 7 + /** 8 + * Tracks a custom event 9 + * @param name Name of the event 10 + * @param properties Optional properties for the event 11 + */ 12 + event: (name: string, properties?: Record<string, any>) => void; 13 + 14 + /** 15 + * Sets a custom user ID for tracking logged-in users 16 + * @param userId The user ID to set (will be stored in localStorage) 17 + */ 18 + identify: (userId: string) => void; 19 + 20 + /** 21 + * Clears the stored user ID 22 + */ 23 + clearUserId: () => void; 24 + 25 + /** 26 + * Gets the currently set user ID 27 + * @returns The current user ID or null if not set 28 + */ 29 + getUserId: () => string | null; 30 + 31 + /** 32 + * Manually tracks outbound link clicks 33 + * @param url The URL of the outbound link 34 + * @param text Optional text content of the link 35 + * @param target Optional target attribute of the link 36 + */ 37 + trackOutbound: (url: string, text?: string, target?: string) => void; 38 + } 39 + 40 + declare global { 41 + interface Window { 42 + rybbit: Rybbit; 43 + } 44 + } 45 + 46 + export {};
+3 -1
docsite/src/components/Button.tsx
··· 39 39 style = {}, 40 40 link, 41 41 label, 42 - onClick = () => null 42 + onClick = () => null, 43 + ...rest 43 44 }: ButtonProps) { 44 45 // Map the size prop values to corresponding CSS classes. 45 46 const sizeMap = { ··· 76 77 e.preventDefault(); 77 78 onClick() 78 79 }} 80 + {...rest} 79 81 > 80 82 {label} 81 83 </button>
+57
docsite/src/components/DocsRating.tsx
··· 1 + /** 2 + * Copyright (c) Meta Platforms, Inc. and affiliates. 3 + * 4 + * This source code is licensed under the MIT license found in the 5 + * LICENSE file in the root directory of this source tree. (https://github.com/facebook/react-native-website) 6 + */ 7 + 8 + import React, { useState } from 'react'; 9 + import useIsBrowser from '@docusaurus/useIsBrowser'; 10 + 11 + const DocsRating = ({ label }) => { 12 + const isBrowser = useIsBrowser(); 13 + const [haveVoted, setHaveVoted] = useState(false); 14 + 15 + if (!isBrowser) { 16 + return null; 17 + } 18 + 19 + const giveFeedback = value => { 20 + if ('rybbit' in window) { 21 + window.rybbit.event('feedback', { 22 + helpful: value == 1 ? 'true' : 'false' 23 + }); 24 + } 25 + setHaveVoted(true); 26 + }; 27 + 28 + return ( 29 + <div className="docsRating"> 30 + {haveVoted ? ( 31 + 'Thanks for letting us know!' 32 + ) : ( 33 + <div> 34 + Is this page helpful? 35 + <svg 36 + className="i_thumbsup" 37 + aria-label="Like" 38 + onClick={() => giveFeedback(1)} 39 + xmlns="http://www.w3.org/2000/svg" 40 + viewBox="0 0 81.13 89.76"> 41 + <path d="M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z" /> 42 + </svg> 43 + <svg 44 + className="i_thumbsdown" 45 + aria-label="Dislike" 46 + onClick={() => giveFeedback(0)} 47 + xmlns="http://www.w3.org/2000/svg" 48 + viewBox="0 0 81.13 89.76"> 49 + <path d="M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z" /> 50 + </svg> 51 + </div> 52 + )} 53 + </div> 54 + ); 55 + }; 56 + 57 + export default DocsRating;
+42
docsite/src/css/custom.css
··· 33 33 .button--lg { 34 34 --ifm-button-size-multiplier: 1.1; 35 35 } 36 + } 37 + 38 + .docsRating { 39 + text-align:center; 40 + color:#057594; 41 + background-color:#64d7ff4d; 42 + border-radius:var(--ifm-global-radius); 43 + min-height:66px; 44 + margin-top:42px; 45 + padding:16px 30px 16px 40px; 46 + font-weight:500; 47 + line-height:32px; 48 + display:inline-block 49 + } 50 + .docsRating svg { 51 + width:1.5em; 52 + height:1.5em; 53 + margin:0 0 0 6px 54 + } 55 + .docsRating svg:hover, 56 + .docsRating svg:focus { 57 + cursor:pointer; 58 + fill:var(--ifm-color-primary) 59 + } 60 + .docsRating .i_thumbsup { 61 + fill: var(--ifm-link-color); 62 + margin-left:12px; 63 + transform:translateY(.25em) 64 + } 65 + .docsRating .i_thumbsdown { 66 + fill:#e9430f; 67 + transform:scale(-1)translateY(-.25em) 68 + } 69 + html[data-theme=dark] .docsRating { 70 + color:#cee9f3 71 + } 72 + @media only screen and (width<=996px) { 73 + .docsRating { 74 + border-radius:var(--ifm-global-radius); 75 + width:100%; 76 + margin:36px 0 0!important 77 + } 36 78 }
+20
docsite/src/theme/DocItem/index.tsx
··· 1 + import React, {type ReactNode} from 'react'; 2 + import DocItem from '@theme-original/DocItem'; 3 + import type DocItemType from '@theme/DocItem'; 4 + import type {WrapperProps} from '@docusaurus/types'; 5 + import DocsRating from '@site/src/components/DocsRating'; 6 + 7 + type Props = WrapperProps<typeof DocItemType>; 8 + 9 + export default function DocItemWrapper(props: Props): ReactNode { 10 + return ( 11 + <> 12 + <DocItem {...props} /> 13 + <div className="row"> 14 + <div className="col col--9" style={{justifyContent: 'center', display: 'flex'}}> 15 + <DocsRating label="fdsfd"/> 16 + </div> 17 + </div> 18 + </> 19 + ); 20 + }