initial commit

This commit is contained in:
MrLetsplay 2023-10-24 19:06:56 +02:00
commit 72fcb3e49f
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
17 changed files with 6620 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
dist

34
README.md Normal file
View File

@ -0,0 +1,34 @@
## Usage
Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`.
This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template.
```bash
$ npm install # or pnpm install or yarn install
```
### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
## Available Scripts
In the project directory, you can run:
### `npm run dev` or `npm start`
Runs the app in the development mode.<br>
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br>
### `npm run build`
Builds the app for production to the `dist` folder.<br>
It correctly bundles Solid in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br>
Your app is ready to be deployed!
## Deployment
You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.)

25
index.html Normal file
View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="shortcut icon" type="image/svg" href="/src/assets/favicon.svg" />
<title>Search</title>
<style>
body {
background-color: black;
color: white;
}
</style>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/index.tsx" type="module"></script>
</body>
</html>

3053
index.json Normal file

File diff suppressed because one or more lines are too long

1957
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

21
package.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "vite-template-solid",
"version": "0.0.0",
"description": "",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"license": "MIT",
"devDependencies": {
"solid-devtools": "^0.27.3",
"typescript": "^5.1.3",
"vite": "^4.3.9",
"vite-plugin-solid": "^2.7.0"
},
"dependencies": {
"solid-js": "^1.7.6"
}
}

1190
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

45
src/App.module.css Normal file
View File

@ -0,0 +1,45 @@
.app {
position: relative;
--bg: #111111;
--element-bg: #333333;
background-color: var(--bg);
min-height: 100vh;
color: white;
}
.appContainer {
display: flex;
flex-direction: column;
padding: 10px;
}
.loading {
margin-top: 10px;
}
.progress {
height: 20px;
background: red;
border-radius: 5px;
}
.progressOuter {
position: relative;
height: 20px;
background: gray;
border-radius: 5px;
}
.results {
padding: 0;
list-style: none;
}
.result>a {
color: #88ccff;
}
.result>a:visited {
color: gray;
}

116
src/App.tsx Normal file
View File

@ -0,0 +1,116 @@
import { createEffect, type Component, Show, createSignal, onMount, on, For } from 'solid-js';
import { Icon, SvgIcon } from "@suid/material";
import styles from './App.module.css';
import Search from './components/Search';
import { render } from 'solid-js/web';
interface SearchResult {
name: string;
url: string;
}
interface Index {
[key: string]: IndexEntry;
}
interface IndexEntry {
url: string;
normalizedValue: string;
}
function normalize(text: string): string {
return text.toLowerCase().replace(/[\t\r\n ]/g, "");
}
const App: Component = () => {
const [loading, setLoading] = createSignal(true);
const [progress, setProgress] = createSignal(0);
const [index, setIndex] = createSignal({} as Index);
const [results, setResults] = createSignal([] as SearchResult[]);
const [query, setQuery] = createSignal("");
createEffect(on([index, query], () => {
let results = [] as SearchResult[];
let idx = index();
let normalizedQuery = normalize(query());
for (let key in idx) {
let value = idx[key];
if (key.includes(normalizedQuery) || value.normalizedValue.includes(normalizedQuery)) {
results.push({
name: key,
url: value.url
});
}
}
setResults(results);
}));
createEffect(async () => {
const indexResult = await fetch("index.json");
const totalLength = parseInt(indexResult.headers.get("Content-Length") || "-1");
const reader = indexResult.body?.getReader();
if (!reader || totalLength == -1) {
// Error msg
return;
}
const data: Uint8Array = new Uint8Array(totalLength);
let position = 0;
while (true) {
const { done, value } = await reader.read();
if (done) {
setLoading(false);
break;
}
data.set(value, position);
position += value.length;
setProgress(progress() + value.length / totalLength);
}
// Normalize index
let rawIndex = JSON.parse(new TextDecoder("utf-8").decode(data));
let normalizedIndex = {} as Index;
for (let key in rawIndex) {
normalizedIndex[normalize(key)] = {
url: key,
normalizedValue: normalize(rawIndex[key])
}
}
setIndex(normalizedIndex);
});
return (
<div class={styles.app}>
<div class={styles.appContainer}>
<h2>Search for something</h2>
<Search placeholder='Search' onChange={setQuery} doneTypingTimeout={200} />
<Show when={loading()}>
<div class={styles.loading}>
<span>Loading search index...</span>
<div class={styles.progressOuter}>
<div class={styles.progress} style={{ width: (progress() * 100) + "%" }}></div>
</div>
</div>
</Show>
<Show when={!loading()}>
<ul class={styles.results}>
<For each={results()}>{item => <li class={styles.result}><a href={item.url} target='_blank'>{item.name}</a></li>}</For>
</ul>
</Show>
</div>
</div >
);
};
export default App;

1
src/assets/favicon.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#FFFFFF"><path d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z" /></svg>

After

Width:  |  Height:  |  Size: 352 B

View File

@ -0,0 +1,49 @@
.searchLabel {
margin-right: 5px;
}
.search {
display: flex;
flex-direction: column;
--radius: 5px;
}
.searchBox {
border: none;
outline: none;
background-color: var(--element-bg);
color: white;
padding: 8px;
border-radius: var(--radius);
height: 25px;
}
.searchBox[data-suggestions]:focus {
border-radius: var(--radius) var(--radius) 0 0;
}
.searchSuggestions {
background-color: var(--element-bg);
margin: 0;
list-style: none;
padding: 0;
border-radius: 0 0 var(--radius) var(--radius);
}
.searchSuggestions>li {
display: flex;
align-items: center;
height: 25px;
padding: 8px;
}
.searchSuggestions>li:hover {
background-color: rgba(255, 255, 255, 0.2);
}
.searchSuggestions:empty::after {
content: "No suggestions";
color: gray;
font-style: italic;
}

62
src/components/Search.tsx Normal file
View File

@ -0,0 +1,62 @@
import { createSignal, type Component, JSX, For, createEffect, on } from "solid-js";
import styles from './Search.module.css'
import { render } from "solid-js/web";
interface SearchProps {
placeholder: string;
onChange?: (value: string) => void;
//style?: string | JSX.CSSProperties;
suggestions?: string[];
doneTypingTimeout?: number;
};
const Search: Component<SearchProps> = (props: SearchProps) => {
let [suggestions, setSuggestions] = createSignal(props.suggestions);
let [suggestionsVisible, setSuggestionsVisible] = createSignal(false);
let [query, setQuery] = createSignal("");
const doneTypingTimeout = props.doneTypingTimeout || 0;
let doneTimeout = 0;
const onFocus: JSX.EventHandler<HTMLInputElement, FocusEvent> = e => {
if (props.suggestions) setSuggestionsVisible(true);
};
const onBlur: JSX.EventHandler<HTMLInputElement, FocusEvent> = e => {
if (props.suggestions) setSuggestionsVisible(false);
};
const submitValue = (query: string) => {
console.log("change", query);
props.onChange?.(query);
if (props.suggestions) {
let newSuggestions = props.suggestions.filter(v => v.toLowerCase().includes(query.toLowerCase()));
setSuggestions(newSuggestions);
}
};
createEffect(on(query, query => {
if (doneTypingTimeout > 0) {
clearTimeout(doneTimeout);
doneTimeout = setTimeout(() => submitValue(query), doneTypingTimeout);
return;
}
submitValue(query);
}));
return (
<div class={styles.search}>
<input class={styles.searchBox} placeholder={props.placeholder} data-suggestions={props.suggestions ? true : undefined} onInput={e => setQuery(e.currentTarget.value)} onFocus={onFocus} onBlur={onBlur} value={query()}></input>
<ul class={styles.searchSuggestions} style={{ display: (suggestionsVisible() ? "unset" : "none") }}>
<For each={suggestions()}>{item => <li onMouseDown={() => {
setQuery(item);
}}>{item}</li>}</For>
</ul>
</div >
);
};
export default Search;

13
src/index.css Normal file
View File

@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

15
src/index.tsx Normal file
View File

@ -0,0 +1,15 @@
/* @refresh reload */
import { render } from 'solid-js/web';
import './index.css';
import App from './App';
const root = document.getElementById('root');
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
throw new Error(
'Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?',
);
}
render(() => <App />, root!);

1
src/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 166 155.3"><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" fill="#76b3e1"/><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="27.5" y1="3" x2="152" y2="63.5"><stop offset=".1" stop-color="#76b3e1"/><stop offset=".3" stop-color="#dcf2fd"/><stop offset="1" stop-color="#76b3e1"/></linearGradient><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" opacity=".3" fill="url(#a)"/><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" fill="#518ac8"/><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="95.8" y1="32.6" x2="74" y2="105.2"><stop offset="0" stop-color="#76b3e1"/><stop offset=".5" stop-color="#4377bb"/><stop offset="1" stop-color="#1f3b77"/></linearGradient><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" opacity=".3" fill="url(#b)"/><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="18.4" y1="64.2" x2="144.3" y2="149.8"><stop offset="0" stop-color="#315aa9"/><stop offset=".5" stop-color="#518ac8"/><stop offset="1" stop-color="#315aa9"/></linearGradient><path d="M134 80a45 45 0 00-48-15L24 85 4 120l112 19 20-36c4-7 3-15-2-23z" fill="url(#c)"/><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="75.2" y1="74.5" x2="24.4" y2="260.8"><stop offset="0" stop-color="#4377bb"/><stop offset=".5" stop-color="#1a336b"/><stop offset="1" stop-color="#1a336b"/></linearGradient><path d="M114 115a45 45 0 00-48-15L4 120s53 40 94 30l3-1c17-5 23-21 13-34z" fill="url(#d)"/></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

15
tsconfig.json Normal file
View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite/client"],
"noEmit": true,
"isolatedModules": true
}
}

21
vite.config.ts Normal file
View File

@ -0,0 +1,21 @@
import { defineConfig } from 'vite';
import solidPlugin from 'vite-plugin-solid';
// import devtools from 'solid-devtools/vite';
export default defineConfig({
plugins: [
/*
Uncomment the following line to enable solid-devtools.
For more info see https://github.com/thetarnav/solid-devtools/tree/main/packages/extension#readme
*/
// devtools(),
solidPlugin(),
],
server: {
port: 3000,
},
build: {
target: 'esnext',
},
base: './'
});