adb devices
- https://developer.android.com/studio/debug/am-screenshot
- https://developer.android.com/studio/debug/am-video
FN=screenshot_$(date +%F_%T).png adb shell screencap -p $FN
adb pull /sdcard/$FN ~/Downloads/
| import React, { useEffect, useState } from 'react'; | |
| import { withRouter } from 'next/router'; | |
| // @example `"/films/[slug]"` | |
| const IS_DYNAMIC_ROUTE = urlPathname => String(urlPathname).includes('['); | |
| // Usage in your dynamic-route components: | |
| // @example | |
| // export default withDynamicRoute(Page); |
| /** | |
| * Identify `/[param]/` in route string. | |
| * @see https://github.com/vercel/next.js/blob/master/packages/next/next-server/lib/router/utils/is-dynamic.ts#L7 | |
| * | |
| * @param {route} The value from next/router's `route.asPath` (e.g., `/browse/[listingId]`). | |
| * @returns {boolean} True if the route looks like a Next.js dynamic route. | |
| */ | |
| const TEST_ROUTE = /\/\[[^/]+?\](?=\/|$)/; | |
| export function isDynamicRoute(route) { | |
| return TEST_ROUTE.test(route); |
adb devicesFN=screenshot_$(date +%F_%T).png adb shell screencap -p $FN
adb pull /sdcard/$FN ~/Downloads/
| const enableCypressDebug = win => { | |
| if (process.env.DEBUG === '1') { | |
| win.localStorage.setItem('debug', 'cypress:*'); | |
| } | |
| }; | |
| beforeEach(enableCypressDebug); |
| if (process.env.NODE_ENV === 'development') { | |
| // This helps for nodemon to not be prematurely killed. | |
| // See nodemon's docs: https://github.com/remy/nodemon/blob/master/README.md#controlling-shutdown-of-your-script | |
| // Adapted from source: https://www.benjiegillam.com/2011/08/node-js-clean-restart-and-faster-development-with-nodemon/ | |
| const gracefulShutdown = cb => { | |
| setTimeout(() => { | |
| process.exit(0); | |
| cb(); | |
| }, 5000); | |
| }; |
| const stripTrailingSlashesInUrl = str => str.replace(/\/+$/g, ''); |
| function stripHtmlComments(html) { | |
| // Remove HTML comments (useful for removing developer-facing comments from production HTML markup). | |
| return html.replace(/<!--[\s\S]*?(?:-->)/g, ''); | |
| } |
| // Just replace `placeholder_name` with the actual key for which you want its value. | |
| var placeholderName = decodeURIComponent((window.location.search.match(/[?&]placeholder_name=([^&]+)/)||['', ''])[1]); |
| function useMedia(mediaQuery) { | |
| const match = () => { | |
| if (!window.matchMedia) { | |
| return false; | |
| } | |
| return window.matchMedia(mediaQuery).matches; | |
| }; | |
| const [value, set] = useState(match); |
| @mixin text-crop($line-height: 1.3, $top-adjustment: 0px, $bottom-adjustment: 0px) { | |
| // Configured in Step 1 | |
| $top-crop: 4; | |
| $bottom-crop: 14; | |
| $crop-font-size: 36; | |
| $crop-line-height: 1.2; | |
| // Apply values to calculate em-based margins that work with any font size | |
| $dynamic-top-crop: max(($top-crop + ($line-height - $crop-line-height) * ($crop-font-size / 2)), 0) / $crop-font-size; | |
| $dynamic-bottom-crop: max(($bottom-crop + ($line-height - $crop-line-height) * ($crop-font-size / 2)), 0) / $crop-font-size; |