wp
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
abs3nt 2023-01-25 22:24:30 -08:00
parent 5f0d08ebf1
commit b20040d524
8 changed files with 1970 additions and 197 deletions

197
.gitignore vendored
View File

@ -1,197 +0,0 @@
# Created by https://www.toptal.com/developers/gitignore/api/windows,macos,linux,node
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,macos,linux,node
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.env.production
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### Node Patch ###
# Serverless Webpack directories
.webpack/
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/windows,macos,linux,node

BIN
dist/images/Lmgtfy.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

3
dist/images/google.svg vendored Normal file
View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-google" viewBox="0 0 16 16">
<path d="M15.545 6.558a9.42 9.42 0 0 1 .139 1.626c0 2.434-.87 4.492-2.384 5.885h.002C11.978 15.292 10.158 16 8 16A8 8 0 1 1 8 0a7.689 7.689 0 0 1 5.352 2.082l-2.284 2.284A4.347 4.347 0 0 0 8 3.166c-2.087 0-3.86 1.408-4.492 3.304a4.792 4.792 0 0 0 0 3.063h.003c.635 1.893 2.405 3.301 4.492 3.301 1.078 0 2.004-.276 2.722-.764h-.003a3.702 3.702 0 0 0 1.599-2.431H8v-3.08h7.545z"/>
</svg>

After

Width:  |  Height:  |  Size: 513 B

10
dist/index.css vendored Normal file
View File

@ -0,0 +1,10 @@
#cursor {
position: absolute;
top: 0;
left: 0;
}
#message {
transition-property: opacity;
transition-duration: 0.3s;
}

117
dist/index.html vendored Normal file
View File

@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="images/google.svg" />
<meta name="author" content="Nato Boram" />
<meta name="keywords" content="Google, Lmgtfy" />
<meta property="og:image" content="images/Lmgtfy.png" />
<meta property="og:title" content="Let me Google that for you" />
<!-- Bootstrap -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
crossorigin="anonymous"
/>
<script
src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js"
integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB"
crossorigin="anonymous"
></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"
integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13"
crossorigin="anonymous"
></script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.6.1/font/bootstrap-icons.css"
/>
<link rel="stylesheet" href="index.css" />
<script src="index.js"></script>
<title>Let me Google that for you</title>
</head>
<body class="bg-light">
<!-- Navbar -->
<nav class="navbar navbar-light bg-light">
<div class="container-fluid">
<div></div>
<button
class="btn bi-brightness-high btn-light"
onclick="toggleBrightness()"
></button>
</div>
</nav>
<!-- Content -->
<div class="container">
<form class="row g-3 text-center mt-5">
<!-- Google -->
<label class="display-1 form-label fw-normal mb-0" for="input">
<span class="text-primary">G</span><span class="text-danger">o</span
><span class="text-warning">o</span><span class="text-primary">g</span
><span class="text-success">l</span><span class="text-danger">e</span>
</label>
<small class="text-muted mt-0">Let me Google that for you</small>
<!-- Input -->
<div
class="
bg-light
border border-1 border-light
input-group
rounded-pill
shadow-sm
"
>
<label
class="bg-light bi-search border-0 input-group-text text-dark"
for="input"
id="searchicon"
></label>
<input
class="form-control border-0 bg-light text-dark"
id="input"
maxlength="2048"
name="search"
placeholder="Search"
required
type="text"
/>
</div>
<!-- Actions -->
<div>
<button class="btn btn-light" id="search" type="submit">
Google Search
</button>
<button
class="btn btn-light"
id="lucky"
name="lucky"
title="Open the first search result"
type="submit"
value="true"
>
I'm feeling lucky
</button>
</div>
<!-- Alert -->
<div id="message" class="alert text-start opacity-0">
<h5 id="message-heading" class="alert-heading"></h5>
<div id="message-content"></div>
</div>
</form>
</div>
</body>
</html>

160
dist/index.js vendored Normal file
View File

@ -0,0 +1,160 @@
"use strict"
/** @type {{search: string; lucky?: boolean;}} */
const query = window.location.search
.substr(1)
.split("&")
.map(keyValue => keyValue.split("="))
.map(([key, value]) => ({
[decodeURIComponent(key)]: decodeURIComponent(
value?.replaceAll("+", "%20")
),
}))
.reduce((previous, current) => ({ ...previous, ...current }), {})
/** @type {HTMLInputElement} */
let input
window.addEventListener("load", async () => {
input = document.getElementById("input")
input.value = ""
setBrightness(JSON.parse(localStorage.getItem("dark") ?? "false"))
if (!query.search) return
await setMessage("Step 1", "Type in your question")
const cursor = makeCursor()
await move(cursor, input)
input.focus()
await write()
await new Promise(resolve => setTimeout(resolve, 1000))
input.blur()
await setMessage("Step 2", "Click on the search button")
const button = query.lucky
? document.getElementById("lucky")
: document.getElementById("search")
await move(cursor, button)
button.focus()
await new Promise(resolve => setTimeout(resolve, 1000))
await setMessage("Come on", "Was it really that hard?", "alert-success")
await new Promise(resolve => setTimeout(resolve, 3000))
window.location.href = `https://www.google.com/search?${
query.lucky ? "btnI&" : ""
}q=${query.search}`
})
function makeCursor() {
const dark = JSON.parse(localStorage.getItem("dark") ?? "false")
const cursor = document.createElement("span")
cursor.className = `bi-cursor-fill text-${dark ? "light" : "dark"}`
cursor.id = "cursor"
document.body.appendChild(cursor)
return cursor
}
/**
* Move the cursor to the targeted element
* @param {HTMLSpanElement} cursor
* @param {HTMLButtonElement} target
*/
async function move(cursor, target) {
return new Promise(resolve => {
const diffX =
target.getBoundingClientRect().left +
target.clientWidth / 2 -
cursor.getBoundingClientRect().left
const diffY =
target.getBoundingClientRect().top +
target.clientHeight / 2 -
cursor.getBoundingClientRect().top
const steps = 60
const stepX = diffX / steps
const stepY = diffY / steps
let step = 0
const interval = setInterval(frame, 1000 / 60)
function frame() {
if (step >= steps) {
clearInterval(interval)
resolve()
} else {
step++
cursor.style.top = (parseFloat(cursor.style.top) || 0) + stepY + "px"
cursor.style.left = (parseFloat(cursor.style.left) || 0) + stepX + "px"
}
}
})
}
async function write() {
for (const letter of query.search) {
await new Promise(resolve => setTimeout(resolve, Math.random() * 200 + 100))
input.value += letter
input.scrollLeft = input.scrollWidth
}
}
/**
* Set the message box under the search buttons.
* @param {string} heading
* @param {string} content
* @param {string} type
*/
async function setMessage(heading, content, type = "alert-primary") {
const message = document.getElementById("message")
message.classList.add("opacity-0")
await new Promise(resolve => setTimeout(resolve, 300))
message.classList.remove("alert-primary")
message.classList.remove("alert-success")
message.classList.add(type)
document.getElementById("message-heading").innerText = heading
document.getElementById("message-content").innerText = content
message.classList.remove("opacity-0")
await new Promise(resolve => setTimeout(resolve, 300))
}
function toggleBrightness() {
const dark = JSON.parse(localStorage.getItem("dark") ?? "false")
localStorage.setItem("dark", !dark)
setBrightness(!dark)
}
/**
* Apply brightness on the page.
* @param {boolean} dark
*/
function setBrightness(dark) {
const newbrightness = dark ? "dark" : "light"
const oldBrightness = dark ? "light" : "dark"
for (const oldClass of [
`bg-${oldBrightness}`,
`navbar-${oldBrightness}`,
`btn-${oldBrightness}`,
`border-${oldBrightness}`,
]) {
const newClass = oldClass.replace(oldBrightness, newbrightness)
for (const element of document.querySelectorAll(`.${oldClass}`)) {
element.classList.remove(oldClass)
element.classList.add(newClass)
}
}
for (const oldClass of [`text-${newbrightness}`]) {
const newClass = oldClass.replace(newbrightness, oldBrightness)
for (const element of document.querySelectorAll(`.${oldClass}`)) {
element.classList.remove(oldClass)
element.classList.add(newClass)
}
}
}

92
dist/jsconfig.json vendored Normal file
View File

@ -0,0 +1,92 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Projects */
// "incremental": true, /* Enable incremental compilation */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
"module": "ESNext" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "resolveJsonModule": true, /* Enable importing .json files */
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

1588
dist/pnpm-lock.yaml vendored Normal file

File diff suppressed because it is too large Load Diff