🚀 next-release

Dev
This commit is contained in:
Leifer Mendez
2022-12-23 09:47:37 +01:00
committed by GitHub
88 changed files with 5629 additions and 10191 deletions

7
.github/FUNDING.yml vendored
View File

@@ -1,9 +1,4 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: leifermendez
open_collective: bot-whatsapp
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
patreon: leifermendez
custom: https://www.buymeacoffee.com/leifermendez

View File

@@ -1,7 +1,25 @@
# CONTRIBUTING
### 📄 Bienvenido/a
Si deseas colaborar con el proyecto existen varias maneras, la primera de ellas es aportando conocimiento y mejorando el repositorio (actualizando documentación, mejorando código, revisando __[issues](https://github.com/codigoencasa/bot-whatsapp/issues)__, etc).
También es bien recibido los aportes económicos que se utilizaran para diferentes fines __[ver más](https://opencollective.com/bot-whatsapp)__
El lenguaje principal que se utilizó para desarrollar este proyecto fue __JavaScript__ con el fin de qué personas que están iniciando en el mundo de la programación puedan entender fácilmente.
### 🤔 Preguntas frecuentes
- ¿Como puedo hacer aportaciones de código en el proyecto?: [Ver Video](https://youtu.be/Lxt8Acob6aU)
- ¿Como ejecutar el entorno de pruebas?: [Ver Video](https://youtu.be/Mf9V-dloBfk)
- ¿Como crear un nuevo proveedor?: [Ver Video](https://youtu.be/cahK9zH3SI8)
- ¿Que son los GithubActions?: [Ver Video](https://youtu.be/nYBEBFKLiqw)
- ¿Canales de comunicación?: [Discord](https://link.codigoencasa.com/DISCORD)
-----
![](https://i.giphy.com/media/ntMt6TvalpstTIx7Ak/giphy.webp)
__Requerimientos:__
- Node v16 o superior __[descargar node](https://nodejs.org/es/download/)__
- __[Yarn](https://classic.yarnpkg.com/lang/en/docs/install/#windows-stable)__ como gestor de paquetes. En el link conseguirás las intrucciones para instalar yarn.
@@ -75,14 +93,8 @@ En la consola encontraras los pasos a seguir -->
![](https://i.imgur.com/dC6lEwy.png)
### 🤔 Preguntas frecuentes
- ¿Como puedo hacer aportaciones de código en el proyecto?: [Ver Video](https://youtu.be/Lxt8Acob6aU)
- ¿Como ejecutar el entorno de pruebas?: [Ver Video](https://youtu.be/Mf9V-dloBfk)
- ¿Como crear un nuevo proveedor?: [Ver Video](https://youtu.be/cahK9zH3SI8)
- ¿Que son los GithubActions?: [Ver Video](https://youtu.be/nYBEBFKLiqw)
> __NOTA:__ Documento en constante actualización....
> __NOTA:__ [Eres libre de aportar informacion a este documento o arreglar ortografia 🤣](
https://github.com/codigoencasa/bot-whatsapp/edit/dev/CONTRIBUTING.md)
------
- [Discord](https://link.codigoencasa.com/DISCORD)

View File

@@ -1,8 +1,13 @@
## MIGRANDO DE LA VERSIÓN 1 A LAS VERSIÓN 2
# Migración
Pasar los flujos del bot de la versión 1 a la 2 es muy fácil, supongamos que en tu initial.json y response.json tienes un flujo como el siguiente:
#### Versión (legacy)
```js
En la ***versión (legacy)*** se implementas los flujos de esta manera, en dos archivos independientes.
> __`initial.json`__ para establecer las palabras claves y el flujo a responder, por otro lado tambien se necesitaba implementar.
> __`response.json`__ donde se escriben los mensajes a responder.
```json
//initial.json
[
{
@@ -13,15 +18,21 @@ Pasar los flujos del bot de la versión 1 a la 2 es muy fácil, supongamos que e
],
"key": "hola"
},
{
"keywords": ["productos", "info"],
"key": "productos"
},
{
"keywords": ["adios", "bye"],
"key": "adios"
},
{
"keywords": ["imagen", "foto"],
"key": "catalogo"
}
]
```
y
```js
```json
//response.json
{
"hola":{
@@ -35,34 +46,77 @@ y
"replyMessage":[
"Que te vaya bien!!"
],
"media":null
}
},
"productos":{
"replyMessage":[
"Más productos aquí"
],
"trigger":null,
"actions":{
"title":"¿Que te interesa ver?",
"message":"Abajo unos botons",
"footer":"",
"buttons":[
{"body":"Telefonos"},
{"body":"Computadoras"},
{"body":"Otros"}
]
}
},
"catalogo":{
"replyMessage":[
"Te envio una imagen"
],
"media":"https://media2.giphy.com/media/VQJu0IeULuAmCwf5SL/giphy.gif",
"trigger":null,
},
}
```
En la versión 2, no es necesario tener esos 2 archivos, los flujos se ponen directamente en app.js de la siguiente manera:
#### Versión 2 (0.2.X)
En esta versión es mucho más sencillo abajo encontraras un ejemplo del mismo flujo anteriormente mostrado.
```js
//app.js
const {
createBot,
createProvider,
createFlow,
addKeyword,
addChild,
} = require('@bot-whatsapp/bot')
const BaileysProvider = require('@bot-whatsapp/provider/baileys')
const MockAdapter = require('@bot-whatsapp/database/mock')
/**
* Declarando flujos principales.
*/
const flowHola = addKeyword(['hola', 'ola', 'alo']) //Aqui van los "keywords" de initial.json
.addAnswer('Gracias a ti!') // Aquí va la respuesta del response.json, no es necesario especificar nuevamente los "keywords"
.addAnswer('Siempre un placer!!!') // Y se pueden agregar varias respuestas encadenadas ... TANTAS com sean necesarias.
const flowHola = addKeyword(['hola', 'ola', 'alo'])
.addAnswer('Bienvenido a tu tienda online!')
const flowAdios = addKeyword(['adios', 'bye']) //Aqui van los "keywords" de initial.json
.addAnswer('Que te vaya bien!!') // Aquí va la respuesta del response.json, no es necesario especificar nuevamente los "keywords"
.addAnswer('Hasta luego!', // Y se pueden agregar varias respuestas encadenadas ... TANTAS com sean necesarias.
null, null,[...addChild(flowHijo1)] // Y se pueden agregar flujos HIJOS (Sub Menus). Los flujos hijos se tienen que definir ANTES que los principales.
)
const flowAdios = addKeyword(['adios', 'bye'])
.addAnswer('Que te vaya bien!!')
.addAnswer('Hasta luego!')
const flowProductos = addKeyword(['productos', 'info'])
.addAnswer('Te envio una imagen', {
buttons:[
{body:"Telefonos"},
{body:"Computadoras"},
{body:"Otros"}
]
})
##FALTAN EJEMPLOS DE ENVIOS DE IMAGENES!
const flowCatalogo = addKeyword(['imagen', 'foto'])
.addAnswer('Te envio una imagen', {media:'https://media2.giphy.com/media/VQJu0IeULuAmCwf5SL/giphy.gif'})
const main = async () => {
const adapterDB = new MockAdapter()
const adapterFlow = createFlow([flowHola, flowAdios]) // Aqui se crean los flujos.
const adapterFlow = createFlow([flowHola, flowAdios, flowProductos, flowCatalogo])
const adapterProvider = createProvider(BaileysProvider)
createBot({
flow: adapterFlow,
@@ -70,4 +124,11 @@ const flowAdios = addKeyword(['adios', 'bye']) //Aqui van los "keywords" de init
database: adapterDB,
})
}
```
```
> Forma parte de este proyecto.
- [Discord](https://link.codigoencasa.com/DISCORD)
- [Twitter](https://twitter.com/leifermendez)
- [Youtube](https://www.youtube.com/watch?v=5lEMCeWEJ8o&list=PL_WGMLcL4jzWPhdhcUyhbFU6bC0oJd2BR)
- [Telegram](https://t.me/leifermendez)

View File

@@ -83,7 +83,15 @@ Video como hacer PR: https://youtu.be/Lxt8Acob6aU
<br />
<sub><b>Yonathan Suarez</b></sub>
</a>
</td></tr>
</td>
<td align="center">
<a href="https://github.com/jlferrete">
<img src="https://avatars.githubusercontent.com/u/36698913?v=4" width="50;" alt="jlferrete"/>
<br />
<sub><b>José Luis Ferrete</b></sub>
</a>
</td>
</tr>
</table>
<!-- readme: collaborators,contributors -end -->

View File

@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/bot",
"version": "0.0.24-alpha.0",
"version": "0.0.25-alpha.0",
"description": "",
"main": "./lib/bundle.bot.cjs",
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/cli",
"version": "0.0.31-alpha.0",
"version": "0.0.32-alpha.0",
"description": "",
"main": "index.js",
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "create-bot-whatsapp",
"version": "0.0.42-alpha.0",
"version": "0.0.43-alpha.0",
"description": "",
"main": "./lib/bundle.create-bot-whatsapp.cjs",
"files": [

View File

@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/database",
"version": "0.0.23-alpha.0",
"version": "0.0.24-alpha.0",
"description": "Esto es el conector a mysql, pg, mongo",
"main": "./lib/mock/index.cjs",
"keywords": [],
@@ -12,8 +12,7 @@
"dependencies": {
"dotenv": "^16.0.3",
"mongodb": "^4.11.0",
"mysql2": "^2.3.3",
"stormdb": "^0.6.0"
"mysql2": "^2.3.3"
},
"exports": {
"./mock": "./lib/mock/index.cjs",

View File

@@ -1,27 +1,42 @@
const StormDB = require('stormdb')
const { join } = require('path')
const engine = new StormDB.localFileEngine(join(process.cwd(), './db.stormdb'))
const { existsSync, writeFileSync, readFileSync } = require('fs')
class JsonFileAdapter {
db
pathFile
listHistory = []
constructor() {
this.pathFile = join(process.cwd(), 'db.json')
this.init().then()
}
init() {
return new Promise((resolve) => {
this.db = new StormDB(engine)
this.db.default({ history: [] })
resolve(this.db)
})
databaseExists() {
return existsSync(this.pathFile)
}
async init() {
const dbExists = await this.databaseExists()
if (!dbExists) {
const data = {
history: [],
}
await this.saveData(data)
}
}
readDatabase() {
const db = readFileSync(this.pathFile)
return JSON.parse(db)
}
saveData(data) {
writeFileSync(this.pathFile, JSON.stringify(data))
}
getPrevByNumber = async (from) => {
const response = await this.db.get('history')
const { history } = response.state
const { history } = await this.readDatabase()
if (!history.length) {
return null
@@ -35,12 +50,14 @@ class JsonFileAdapter {
}
save = async (ctx) => {
await this.db
.get('history')
.push({ ...ctx })
.save()
console.log('Guardado en DB...', ctx)
this.db = await this.readDatabase()
this.db.history.push(ctx)
await this.saveData(this.db)
this.listHistory.push(ctx)
console.log('Guardado en DB...', ctx)
}
}

View File

@@ -6,35 +6,35 @@ module.exports = {
node: true,
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:qwik/recommended',
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:qwik/recommended",
],
parser: '@typescript-eslint/parser',
parser: "@typescript-eslint/parser",
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
project: ["./tsconfig.json"],
ecmaVersion: 2021,
sourceType: 'module',
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
plugins: ['@typescript-eslint'],
plugins: ["@typescript-eslint"],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-this-alias': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'prefer-spread': 'off',
'no-case-declarations': 'off',
'no-console': 'off',
'@typescript-eslint/no-unused-vars': ['error'],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/ban-ts-comment": "off",
"prefer-spread": "off",
"no-case-declarations": "off",
"no-console": "off",
"@typescript-eslint/no-unused-vars": ["error"],
},
};

View File

@@ -5,7 +5,7 @@
/server
# Development
node_modules
node_modules/
# Cache
.cache
@@ -37,5 +37,7 @@ lerna-debug.log*
.yarn/*
!.yarn/releases
package-lock.json
# Cloudflare
functions/**/*.js

View File

@@ -0,0 +1,6 @@
{
"startCommand": "npm start",
"env": {
"ENABLE_CJS_IMPORTS": true
}
}

21
packages/docs/LICENSE.md Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 onWidget
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,11 +1,287 @@
### 😎 Documentación Bot-Whatsapp
# 💠 Qwind
👉 [https://bot-whatsapp.pages.dev/](https://bot-whatsapp.pages.dev/)
**Qwind** is a free and open-source template to make your website using **[Qwik](https://qwik.builder.io/) + [Tailwind CSS](https://tailwindcss.com/)**. Ready to start a new project and designed taking into account best practices.
Se esta iniciando una documentación oficial sobre como usar e implementar los diferentes funcionalidades del bot-wahtsapp
## Features
- ✅ Integration with **Tailwind CSS** supporting **Dark mode**.
-**Production-ready** scores in [Lighthouse](https://web.dev/measure/) and [PageSpeed Insights](https://pagespeed.web.dev/) reports.
-**Image optimization** and **Font optimization**.
La idea es cada usuario pueda ir aportando a la documentacion y formar parte de este proyecto.
<br>
<img src="./screenshot.jpg" alt="Qwind Theme Screenshot">
##### ¿Como agregar documentación? [Video]
[![onWidget](https://custom-icon-badges.demolab.com/badge/made%20by%20-onWidget-556bf2?style=flat-square&logo=onwidget&logoColor=white&labelColor=101827)](https://onwidget.com)
[![License](https://img.shields.io/github/license/onwidget/qwind?style=flat-square&color=dddddd&labelColor=000000)](https://github.com/onwidget/qwind/blob/main/LICENSE.md)
[![Maintained](https://img.shields.io/badge/maintained%3F-yes-brightgreen.svg?style=flat-square)](https://github.com/onwidget)
[![Contributions Welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat-square)](https://github.com/onwidget/qwind#contributing)
[![Known Vulnerabilities](https://snyk.io/test/github/onwidget/qwind/badge.svg?style=flat-square)](https://snyk.io/test/github/onwidget/qwind)
<br>
<details open>
<summary>Table of Contents</summary>
- [Demo](#demo)
- [Getting started](#getting-started)
- [Project structure](#project-structure)
- [Commands](#commands)
- [Configuration](#configuration)
- [Deploy](#deploy)
- [Roadmap](#roadmap)
- [Contributing](#contributing)
- [Acknowledgements](#acknowledgements)
- [License](#license)
</details>
<br>
## Demo
📌 [https://qwind.pages.dev/](https://qwind.pages.dev/)
<br>
## Getting started
This project is using Qwik with [QwikCity](https://qwik.builder.io/qwikcity/overview/). QwikCity is just a extra set of tools on top of Qwik to make it easier to build a full site, including directory-based routing, layouts, and more.
### Project structure
Inside **Qwind** template, you'll see the following folders and files:
```
/
├── adaptors/
| └── static/
| └── vite.config.ts
├── public/
│ ├── favicon.svg
│ ├── manifest.json
│ └── robots.txt
├── src/
│ ├── assets/
│ │ ├── images/
| | └── styles/
| | └── global.css
│ ├── components/
│ │ ├── atoms/
│ │ ├── core/
│ │ ├── icons/
| | └── widgets/
| | ├── Header.astro
| | ├── Footer.astro
| | └── ...
│ ├── routes/
│ | ├── blog/
│ | ├── index.astro
| | ├── layout.tsx
| | └-- service-worker.ts
│ ├── config.mjs
│ ├── entry.dev.tsx
│ ├── entry.preview.tsx
│ ├── entry.ssr.tsx
│ └── root.tsx
├── package.json
└── ...
```
- `src/routes`: Provides the directory based routing, which can include a hierarchy of `layout.tsx` layout files, and an `index.tsx` file as the page. Additionally, `index.ts` files are endpoints. Please see the [routing docs](https://qwik.builder.io/qwikcity/routing/overview/) for more info.
- `src/components`: Recommended directory for components.
- `public`: Any static assets, like images, can be placed in the public directory. Please see the [Vite public directory](https://vitejs.dev/guide/assets.html#the-public-directory) for more info.
[![Edit Qwind on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://githubbox.com/onwidget/qwind/tree/main)
> **Seasoned qwik expert?** Delete this file. Update `config.mjs` and contents. Have fun!
<br>
### Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :-------------------- | :------------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `127.0.0.1:5173/` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run fmt` | Format codes with Prettier |
| `npm run lint` | Run Eslint |
| `npm run qwik ...` | Run CLI commands like `qwik add`, `qwik build` |
<br>
### Configuration
Basic configuration file: `./src/config.mjs`
```javascript
export const SITE = {
name: 'Example',
origin: 'https://example.com',
basePathname: '/', // Change this if you need to deploy to Github Pages, for example
trailingSlash: true, // Generate permalinks with or without "/" at the end
};
```
<br>
### Deploy
#### Deploy to production (manual)
You can create an optimized production build with:
```shell
npm run build
```
Now, your website is ready to be deployed. All generated files are located at
`dist` folder, which you can deploy the folder to any hosting service you
prefer.
#### Deploy to Netlify
Clone this repository on own GitHub account and deploy to Netlify:
[![Netlify Deploy button](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/onwidget/qwind)
#### Deploy to Vercel
Clone this repository on own GitHub account and deploy to Vercel:
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fonwidget%2Fqwind)
<br>
## Roadmap
### Base
- [ ] Create utilities to generate permalinks tailored to the domain and base pathname.
- [ ] Simplify the way to optimize images.
- [ ] Create component to make SEO simpler and more intuitive.
- [ ] Create configurable blog with categories, tags and authors using MDX.
- [ ] Add more frequently used pages (Portfolio, Services, Contact, Docs ...).
- [ ] Find or create a library to have more icon sources available.
- [ ] Refactor some code that doesn't follow Qwik conventions yet.
### Advanced
- [ ] Achieve perfect 100% Google Page Speed score.
- [ ] Insert complex javascript example widget on home page to demonstrate Qwik features.
- [ ] Create small illustrative admin backend.
<br>
## Contributing
If you have any idea, suggestions or find any bugs, feel free to open a discussion, an issue or create a pull request.
That would be very useful for all of us and we would be happy to listen and take action.
## Acknowledgements
Initially created by [onWidget](https://onwidget.com) and maintained by a community of [contributors](https://github.com/onwidget/qwind/graphs/contributors).
## License
**Qwind** is licensed under the MIT license — see the [LICENSE](https://github.com/onwidget/qwind/blob/main/LICENSE.md) file for details.
## Cloudflare Pages
Cloudflare's [wrangler](https://github.com/cloudflare/wrangler) CLI can be used to preview a production build locally. To start a local server, run:
```
npm run serve
```
Then visit [http://localhost:8787/](http://localhost:8787/)
### Deployments
[Cloudflare Pages](https://pages.cloudflare.com/) are deployable through their [Git provider integrations](https://developers.cloudflare.com/pages/platform/git-integration/).
If you don't already have an account, then [create a Cloudflare account here](https://dash.cloudflare.com/sign-up/pages). Next go to your dashboard and follow the [Cloudflare Pages deployment guide](https://developers.cloudflare.com/pages/framework-guides/deploy-anything/).
Within the projects "Settings" for "Build and deployments", the "Build command" should be `npm run build`, and the "Build output directory" should be set to `dist`.
### Function Invocation Routes
Cloudflare Page's [function-invocation-routes config](https://developers.cloudflare.com/pages/platform/functions/function-invocation-routes/) can be used to include, or exclude, certain paths to be used by the worker functions. Having a `_routes.json` file gives developers more granular control over when your Function is invoked.
This is useful to determine if a page response should be Server-Side Rendered (SSR) or if the response should use a static-site generated (SSG) `index.html` file.
By default, the Cloudflare pages adaptor _does not_ include a `public/_routes.json` config, but rather it is auto-generated from the build by the Cloudflare adaptor. An example of an auto-generate `dist/_routes.json` would be:
```
{
"include": [
"/*"
],
"exclude": [
"/_headers",
"/_redirects",
"/build/*",
"/favicon.ico",
"/manifest.json",
"/service-worker.js",
"/about"
],
"version": 1
}
```
In the above example, it's saying _all_ pages should be SSR'd. However, the root static files such as `/favicon.ico` and any static assets in `/build/*` should be excluded from the Functions, and instead treated as a static file.
In most cases the generated `dist/_routes.json` file is ideal. However, if you need more granular control over each path, you can instead provide you're own `public/_routes.json` file. When the project provides its own `public/_routes.json` file, then the Cloudflare adaptor will not auto-generate the routes config and instead use the committed one within the `public` directory.
## Cloudflare Pages
Cloudflare's [wrangler](https://github.com/cloudflare/wrangler) CLI can be used to preview a production build locally. To start a local server, run:
```
npm run serve
```
Then visit [http://localhost:8787/](http://localhost:8787/)
### Deployments
[Cloudflare Pages](https://pages.cloudflare.com/) are deployable through their [Git provider integrations](https://developers.cloudflare.com/pages/platform/git-integration/).
If you don't already have an account, then [create a Cloudflare account here](https://dash.cloudflare.com/sign-up/pages). Next go to your dashboard and follow the [Cloudflare Pages deployment guide](https://developers.cloudflare.com/pages/framework-guides/deploy-anything/).
Within the projects "Settings" for "Build and deployments", the "Build command" should be `npm run build`, and the "Build output directory" should be set to `dist`.
### Function Invocation Routes
Cloudflare Page's [function-invocation-routes config](https://developers.cloudflare.com/pages/platform/functions/function-invocation-routes/) can be used to include, or exclude, certain paths to be used by the worker functions. Having a `_routes.json` file gives developers more granular control over when your Function is invoked.
This is useful to determine if a page response should be Server-Side Rendered (SSR) or if the response should use a static-site generated (SSG) `index.html` file.
By default, the Cloudflare pages adaptor _does not_ include a `public/_routes.json` config, but rather it is auto-generated from the build by the Cloudflare adaptor. An example of an auto-generate `dist/_routes.json` would be:
```
{
"include": [
"/*"
],
"exclude": [
"/_headers",
"/_redirects",
"/build/*",
"/favicon.ico",
"/manifest.json",
"/service-worker.js",
"/about"
],
"version": 1
}
```
In the above example, it's saying _all_ pages should be SSR'd. However, the root static files such as `/favicon.ico` and any static assets in `/build/*` should be excluded from the Functions, and instead treated as a static file.
In most cases the generated `dist/_routes.json` file is ideal. However, if you need more granular control over each path, you can instead provide you're own `public/_routes.json` file. When the project provides its own `public/_routes.json` file, then the Cloudflare adaptor will not auto-generate the routes config and instead use the committed one within the `public` directory.

View File

@@ -0,0 +1,21 @@
import { staticAdaptor } from '@builder.io/qwik-city/adaptors/static/vite'
import { extendConfig } from '@builder.io/qwik-city/vite'
import baseConfig from '../../vite.config'
import { SITE } from '../../src/config.mjs'
export default extendConfig(baseConfig, () => {
return {
build: {
ssr: true,
rollupOptions: {
input: ['@qwik-city-plan'],
},
},
plugins: [
staticAdaptor({
origin: SITE.origin,
}),
],
}
})

View File

@@ -0,0 +1,7 @@
[build]
publish = "dist"
command = "npm run build"
[[headers]]
for = "/build/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"

View File

@@ -1,44 +1,50 @@
{
"name": "bot-whatsapp-docs",
"version": "0.0.1",
"description": "Basic start point to build a docs site with Qwik",
"engines": {
"node": ">=15.0.0"
},
"private": true,
"scripts": {
"build": "qwik build",
"build.client": "vite build",
"build.preview": "vite build --ssr src/entry.preview.tsx",
"build.server": "vite build -c adaptors/cloudflare-pages/vite.config.ts",
"build.types": "tsc --incremental --noEmit",
"deploy": "wrangler pages dev ./dist",
"dev": "vite --mode ssr",
"dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force",
"fmt": "prettier --write .",
"fmt.check": "prettier --check .",
"lint": "eslint \"src/**/*.ts*\"",
"preview": "qwik build preview && vite preview --open",
"start": "vite --open --mode ssr",
"qwik": "qwik"
},
"devDependencies": {
"@builder.io/qwik": "0.14.1",
"@builder.io/qwik-city": "0.0.127",
"@types/eslint": "8.4.10",
"@types/node": "latest",
"@typescript-eslint/eslint-plugin": "5.43.0",
"@typescript-eslint/parser": "5.43.0",
"autoprefixer": "10.4.11",
"eslint": "8.28.0",
"eslint-plugin-qwik": "0.14.1",
"node-fetch": "3.3.0",
"postcss": "^8.4.16",
"prettier": "2.7.1",
"tailwindcss": "^3.1.8",
"typescript": "4.9.3",
"vite": "3.2.4",
"vite-tsconfig-paths": "3.5.0",
"wrangler": "latest"
}
"name": "qwind",
"description": "A template to make your website using Qwik + Tailwind CSS.",
"version": "0.1.1",
"scripts": {
"build": "qwik build && npm run subfont",
"build.client": "vite build",
"build.preview": "vite build --ssr src/entry.preview.tsx",
"build.server": "vite build -c adaptors/cloudflare-pages/vite.config.ts",
"build.types": "tsc --incremental --noEmit",
"deploy": "wrangler pages dev ./dist",
"dev": "vite --mode ssr",
"dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force",
"fmt": "prettier --write .",
"fmt.check": "prettier --check .",
"lint": "eslint \"src/**/*.ts*\"",
"preview": "qwik build preview && vite preview --open",
"start": "vite --open --mode ssr",
"subfont": "subfont -i --inline-css --no-fallbacks --silent --root dist",
"qwik": "qwik"
},
"devDependencies": {
"@builder.io/qwik": "0.15.0",
"@builder.io/qwik-city": "0.0.128",
"@fontsource/inter": "^4.5.14",
"@iconify-json/tabler": "^1.1.49",
"@types/eslint": "8.4.10",
"@types/node": "latest",
"@typescript-eslint/eslint-plugin": "5.45.0",
"@typescript-eslint/parser": "5.45.0",
"autoprefixer": "10.4.13",
"eslint": "8.29.0",
"eslint-plugin-qwik": "0.15.0",
"imagetools-core": "^3.2.3",
"node-fetch": "3.3.0",
"postcss": "^8.4.19",
"prettier": "2.8.0",
"rehype-autolink-headings": "^6.1.1",
"subfont": "^6.12.2",
"tailwindcss": "^3.1.8",
"typescript": "4.8.4",
"vite": "3.2.4",
"vite-imagetools": "^4.0.11",
"vite-tsconfig-paths": "3.6.0",
"wrangler": "latest"
},
"engines": {
"node": ">=15.0.0"
}
}

View File

@@ -0,0 +1,11 @@
{
"infiniteLoopProtection": true,
"hardReloadOnChange": false,
"view": "browser",
"template": "node",
"container": {
"port": 5173,
"startScript": "start",
"node": "16"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,73 @@
/**
* WHAT IS THIS FILE?
*
* Globally applied styles. No matter which components are in the page or matching route,
* the styles in here will be applied to the Document, without any sort of CSS scoping.
*
*/
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn {
@apply inline-flex items-center justify-center rounded-md shadow-md border-gray-400 border bg-transparent font-medium text-center text-base text-gray-700 leading-snug transition py-3 px-6 md:px-8 ease-in duration-200 focus:ring-blue-500 focus:ring-offset-blue-200 focus:ring-2 focus:ring-offset-2 hover:bg-gray-100 hover:border-gray-600 dark:text-slate-300 dark:border-slate-500 dark:hover:bg-slate-800 dark:hover:border-slate-800;
}
.btn-ghost {
@apply border-none shadow-none text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white;
}
.btn-primary {
@apply font-semibold bg-primary-600 text-white border-primary-600 hover:bg-primary-800 hover:border-primary-800 hover:text-white dark:text-white dark:bg-primary-700 dark:border-primary-700 dark:hover:border-primary-900 dark:hover:bg-primary-900;
}
.slot h1 {
@apply mb-2 font-semibold text-2xl;
}
.slot h2 {
@apply mb-2 font-semibold text-lg;
}
.slot h3 {
@apply mb-2 font-semibold text-base;
}
.slot code {
@apply bg-slate-100 dark:bg-slate-800 p-1 px-2 rounded w-full;
}
.slot pre {
@apply w-full flex my-2;
}
.slot a {
@apply text-sky-900 font-medium dark:text-sky-400;
}
.slot hr {
@apply my-5;
}
[data-aw-toggle-menu] path {
@apply transition;
}
[data-aw-toggle-menu].expanded g > path:first-child {
@apply -rotate-45 translate-y-[15px] translate-x-[-3px];
}
p,
li {
@apply mt-2 text-sm text-slate-700 dark:text-slate-400;
}
[data-aw-toggle-menu].expanded g > path:last-child {
@apply rotate-45 translate-y-[-8px] translate-x-[14px];
}
}
.dropdown:hover .dropdown-menu {
display: block;
}

View File

@@ -0,0 +1,18 @@
import { component$ } from '@builder.io/qwik'
// @ts-ignore
import logoSrc from '~/assets/images/logo.png?width=64&height=64&png'
export default component$(() => (
<span class="self-center ml-2 text-2xl md:text-xl font-bold text-gray-900 whitespace-nowrap dark:text-white flex items-center">
<img
src={logoSrc}
class="inline-block mr-1"
width={32}
height={32}
alt="Qwind Logo"
loading="lazy"
/>
Qwind
</span>
))

View File

@@ -1,25 +0,0 @@
nav.breadcrumbs {
padding: 5px;
border-bottom: 1px solid #ddd;
}
nav.breadcrumbs > span {
display: inline-block;
padding: 5px 0;
font-size: 12px;
}
nav.breadcrumbs > span a {
text-decoration: none;
color: inherit;
}
nav.breadcrumbs > span::after {
content: '>';
padding: 0 5px;
opacity: 0.4;
}
nav.breadcrumbs > span:last-child::after {
display: none;
}

View File

@@ -1,77 +0,0 @@
import { component$, useStyles$ } from '@builder.io/qwik'
import { useContent, useLocation, ContentMenu } from '@builder.io/qwik-city'
import styles from './breadcrumbs.css?inline'
export const Breadcrumbs = component$(() => {
useStyles$(styles)
const { menu } = useContent()
const loc = useLocation()
const breadcrumbs = createBreadcrumbs(menu, loc.pathname)
if (breadcrumbs.length === 0) {
return null
}
return (
<nav class="breadcrumbs">
{breadcrumbs.map((b) => (
<span>{b.href ? <a href={b.href}>{b.text}</a> : b.text}</span>
))}
</nav>
)
})
export function createBreadcrumbs(
menu: ContentMenu | undefined,
pathname: string
) {
if (menu?.items) {
for (const indexA of menu.items) {
const breadcrumbA: ContentBreadcrumb = {
text: indexA.text,
}
if (typeof indexA.href === 'string') {
breadcrumbA.href = indexA.href
}
if (indexA.href === pathname) {
return [breadcrumbA]
}
if (indexA.items) {
for (const indexB of indexA.items) {
const breadcrumbB: ContentBreadcrumb = {
text: indexB.text,
}
if (typeof indexB.href === 'string') {
breadcrumbB.href = indexB.href
}
if (indexB.href === pathname) {
return [breadcrumbA, breadcrumbB]
}
if (indexB.items) {
for (const indexC of indexB.items) {
const breadcrumbC: ContentBreadcrumb = {
text: indexC.text,
}
if (typeof indexC.href === 'string') {
breadcrumbC.href = indexC.href
}
if (indexC.href === pathname) {
return [breadcrumbA, breadcrumbB, breadcrumbC]
}
}
}
}
}
}
}
return []
}
interface ContentBreadcrumb {
text: string
href?: string
}

View File

@@ -0,0 +1,3 @@
export const DarkThemeLauncher = () => (
<script>{`if(localStorage.theme==="dark"){document.documentElement.classList.add("dark");}else if(typeof localStorage.theme==="undefined"){if(window.matchMedia("(prefers-color-scheme: dark)").matches){document.documentElement.classList.add("dark");}}`}</script>
)

View File

@@ -0,0 +1,38 @@
import { component$, useStore } from '@builder.io/qwik'
import { IconMenu } from '~/components/icons/IconMenu'
interface ItemProps {
iconClass?: string
}
export default component$((props: ItemProps) => {
const { iconClass } = props
const store = useStore({
isExpanded: false,
})
return (
<button
type="button"
class={`ml-1.5 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5 inline-flex items-center transition ${
store.isExpanded ? 'expanded' : ''
}`}
aria-label="Toggle Menu"
data-aw-toggle-menu={true}
onClick$={() => {
store.isExpanded = store.isExpanded ? false : true
// TODO:
document.body.classList.toggle('overflow-hidden')
document.getElementById('header')?.classList.toggle('h-screen')
document
.querySelector('#header nav')
?.classList.toggle('hidden')
}}
>
<IconMenu class={iconClass} />
</button>
)
})

View File

@@ -0,0 +1,52 @@
import { component$, useStore, useClientEffect$ } from '@builder.io/qwik'
import { IconSun } from '~/components/icons/IconSun'
import { IconMoon } from '../icons/IconMoon'
interface ItemProps {
iconClass?: string
}
export default component$((props: ItemProps) => {
const { iconClass } = props
const store = useStore({
theme:
(typeof window !== 'undefined' && window?.localStorage?.theme) ||
undefined,
})
useClientEffect$(() => {
store.theme =
window.localStorage.theme === 'dark' ||
(!('theme' in window.localStorage) &&
window.matchMedia('(prefers-color-scheme: dark)').matches)
? 'dark'
: 'light'
})
return (
<button
type="button"
class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5 inline-flex items-center"
aria-label="Toggle between Dark and Light mode"
onClick$={() => {
switch (store.theme) {
case 'dark':
document.documentElement.classList.remove('dark')
store.theme = window.localStorage.theme = 'light'
break
default:
document.documentElement.classList.add('dark')
store.theme = window.localStorage.theme = 'dark'
break
}
}}
>
{store.theme == 'dark' ? (
<IconMoon class={iconClass} />
) : (
<IconSun class={iconClass} />
)}
</button>
)
})

View File

@@ -1,22 +0,0 @@
footer {
border-top: 0.5px solid #ddd;
margin-top: 40px;
padding: 20px;
text-align: center;
}
footer a {
color: #9e9e9e;
font-size: 12px;
}
footer ul {
list-style: none;
margin: 0;
padding: 0;
}
footer li {
display: inline-block;
padding: 6px 12px;
}

View File

@@ -1,40 +0,0 @@
import { component$, useStyles$ } from '@builder.io/qwik'
import styles from './footer.css?inline'
export default component$(() => {
useStyles$(styles)
return (
<footer>
<ul>
<li>
<a href="/docs">Docs</a>
</li>
<li>
<a href="/about-us">About Us</a>
</li>
<li>
<a href="https://qwik.builder.io/">Qwik</a>
</li>
<li>
<a href="https://twitter.com/QwikDev">Twitter</a>
</li>
<li>
<a href="https://github.com/BuilderIO/qwik">GitHub</a>
</li>
<li>
<a href="https://qwik.builder.io/chat">Chat</a>
</li>
</ul>
<div>
<a
href="https://www.builder.io/"
target="_blank"
class="builder"
>
Made with by Builder.io
</a>
</div>
</footer>
)
})

View File

@@ -1,34 +0,0 @@
header {
position: sticky;
top: 0;
z-index: 11;
display: grid;
grid-template-columns: minmax(130px, auto) 1fr;
gap: 30px;
height: 80px;
width: 100%;
padding: 10px;
background-color: white;
overflow: hidden;
}
header a.logo {
display: block;
}
header a {
text-decoration: none;
}
header nav {
text-align: right;
}
header nav a {
display: inline-block;
padding: 5px 15px;
}
header nav a:hover {
text-decoration: underline;
}

View File

@@ -1,32 +0,0 @@
import { component$, useStyles$ } from '@builder.io/qwik'
import { useLocation } from '@builder.io/qwik-city'
import { QwikLogo } from '../icons/qwik'
import styles from './header.css?inline'
export default component$(() => {
useStyles$(styles)
const { pathname } = useLocation()
return (
<header>
<a class="logo" href="/">
<QwikLogo />
</a>
<nav>
<a
href="/docs"
class={{ active: pathname.startsWith('/docs') }}
>
Docs
</a>
<a
href="/about-us"
class={{ active: pathname.startsWith('/about-us') }}
>
About Us
</a>
</nav>
</header>
)
})

View File

@@ -0,0 +1,27 @@
interface ItemProps {
class?: string
}
export const IconArrowDownRight = (props: ItemProps) => {
const { class: className } = props
return (
<svg
xmlns="http://www.w3.org/2000/svg"
class={`icon icon-tabler icon-tabler-arrow-down-right ${
className || 'w-5 h-5'
}`}
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<line x1="7" y1="7" x2="17" y2="17"></line>
<polyline points="17 8 17 17 8 17"></polyline>
</svg>
)
}

View File

@@ -0,0 +1,17 @@
export const IconFacebook = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-brand-facebook w-5 h-5"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M7 10v4h3v7h4v-7h3l1 -4h-4v-2a1 1 0 0 1 1 -1h3v-4h-3a5 5 0 0 0 -5 5v2h-3"></path>
</svg>
)

View File

@@ -0,0 +1,17 @@
export const IconGithub = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-brand-github w-5 h-5"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5"></path>
</svg>
)

View File

@@ -0,0 +1,19 @@
export const IconInstagram = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-brand-instagram w-5 h-5"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<rect x="4" y="4" width="16" height="16" rx="4"></rect>
<circle cx="12" cy="12" r="3"></circle>
<line x1="16.5" y1="7.5" x2="16.5" y2="7.501"></line>
</svg>
)

View File

@@ -0,0 +1,30 @@
interface ItemProps {
class?: string
}
export const IconMenu = (props: ItemProps) => {
const { class: className } = props
return (
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class={`icon icon-tabler icon-tabler-menu ${
className || 'w-5 h-5'
}`}
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<g
class="icon-tabler"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M4 8h16"></path>
<path d="M4 16h16"></path>
</g>
</svg>
)
}

View File

@@ -0,0 +1,26 @@
interface ItemProps {
class?: string
}
export const IconMoon = (props: ItemProps) => {
const { class: className } = props
return (
<svg
xmlns="http://www.w3.org/2000/svg"
class={`icon icon-tabler icon-tabler-moon ${
className || 'w-5 h-5'
}`}
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
)
}

View File

@@ -0,0 +1,17 @@
export const IconStar = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-star w-5 h-5"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z"></path>
</svg>
)

View File

@@ -0,0 +1,25 @@
interface ItemProps {
class?: string
}
export const IconSun = (props: ItemProps) => {
const { class: className } = props
return (
<svg
xmlns="http://www.w3.org/2000/svg"
class={`icon icon-tabler icon-tabler-sun ${className || 'w-5 h-5'}`}
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<circle cx="12" cy="12" r="4"></circle>
<path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7"></path>
</svg>
)
}

View File

@@ -0,0 +1,17 @@
export const IconTwitter = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-brand-twitter w-5 h-5"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M22 4.01c-1 .49 -1.98 .689 -3 .99c-1.121 -1.265 -2.783 -1.335 -4.38 -.737s-2.643 2.06 -2.62 3.737v1c-3.245 .083 -6.135 -1.395 -8 -4c0 0 -4.182 7.433 4 11c-1.872 1.247 -3.739 2.088 -6 2c3.308 1.803 6.913 2.423 10.034 1.517c3.58 -1.04 6.522 -3.723 7.651 -7.742a13.84 13.84 0 0 0 .497 -3.753c-.002 -.249 1.51 -2.772 1.818 -4.013z"></path>
</svg>
)

View File

@@ -1,20 +0,0 @@
export const QwikLogo = () => (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 167 53">
<path
fill="#000"
d="M81.95 46.59h-6.4V35.4a12.25 12.25 0 0 1-7.06 2.17c-3.47 0-6.06-.94-7.67-2.92-1.6-1.96-2.42-5.45-2.42-10.43 0-5.1.95-8.62 2.87-10.67 1.96-2.08 5.1-3.09 9.43-3.09 4.1 0 7.82.57 11.25 1.67V46.6Zm-6.4-30.31a16.6 16.6 0 0 0-4.85-.66c-2.17 0-3.73.56-4.6 1.7-.85 1.17-1.32 3.38-1.32 6.65 0 3.08.41 5.14 1.26 6.26.86 1.1 2.33 1.67 4.5 1.67 2.84 0 5.01-1.17 5.01-2.62v-13Zm15.58-5.14c2.27 6.3 4.2 12.6 5.86 18.95 2.22-6.5 4.1-12.8 5.55-18.95h5.61a187.5 187.5 0 0 1 5.3 18.95c2.52-6.9 4.5-13.21 5.95-18.95h6.31a285.68 285.68 0 0 1-8.92 25.76h-7.53c-.86-4.6-2.22-10.14-4.04-16.75a151.51 151.51 0 0 1-4.89 16.75H92.8a287.88 287.88 0 0 0-8.17-25.76h6.5Zm41.7-3.58c-2.83 0-3.63-.7-3.63-3.59 0-2.57.82-3.18 3.63-3.18 2.83 0 3.63.6 3.63 3.18 0 2.89-.8 3.59-3.63 3.59Zm-3.18 3.58h6.4V36.9h-6.4V11.14Zm36.65 0c-4.54 6.46-7.72 10.39-9.49 11.8 1.46.95 5.36 5.95 10.2 13.98h-7.38c-6.02-9.13-8.89-13.07-10.3-13.67v13.67h-6.4V0h6.4v23.23c1.45-1.06 4.63-5.1 9.54-12.09h7.43Z"
/>
<path
fill="#18B6F6"
d="M40.97 52.54 32.1 43.7l-.14.02v-.1l-18.9-18.66 4.66-4.5-2.74-15.7L2 20.87a7.14 7.14 0 0 0-1.03 8.52l8.11 13.45a6.81 6.81 0 0 0 5.92 3.3l4.02-.05 21.96 6.46Z"
/>
<path
fill="#AC7EF4"
d="m45.82 20.54-1.78-3.3-.93-1.68-.37-.66-.04.04-4.9-8.47a6.85 6.85 0 0 0-5.99-3.43l-4.28.12-12.8.04a6.85 6.85 0 0 0-5.85 3.37L1.1 21.99 15 4.73l18.24 20.04L30 28.04l1.94 15.68.02-.04v.04h-.04l.04.04 1.51 1.47 7.36 7.19c.3.29.81-.06.6-.43l-4.54-8.93 7.91-14.63.26-.3a6.73 6.73 0 0 0 .76-7.6Z"
/>
<path
fill="#fff"
d="M33.3 24.69 15.02 4.75l2.6 15.62-4.66 4.51L31.91 43.7l-1.7-15.62 3.1-3.4Z"
/>
</svg>
)

View File

@@ -1,13 +0,0 @@
.menu {
background: #eee;
padding: 20px 10px;
}
.menu h5 {
margin: 0;
}
.menu ul {
padding-left: 20px;
margin: 5px 0 25px 0;
}

View File

@@ -1,37 +0,0 @@
import { component$, useStyles$ } from '@builder.io/qwik'
import { useContent, Link, useLocation } from '@builder.io/qwik-city'
import styles from './menu.css?inline'
export default component$(() => {
useStyles$(styles)
const { menu } = useContent()
const loc = useLocation()
return (
<aside class="menu">
{menu
? menu.items?.map((item) => (
<>
<h5>{item.text}</h5>
<ul>
{item.items?.map((item) => (
<li>
<Link
href={item.href}
class={{
'is-active':
loc.pathname === item.href,
}}
>
{item.text}
</Link>
</li>
))}
</ul>
</>
))
: null}
</aside>
)
})

View File

@@ -1,33 +0,0 @@
.on-this-page {
padding-bottom: 20px;
font-size: 0.9em;
}
.on-this-page h6 {
margin: 10px 0;
font-weight: bold;
text-transform: uppercase;
}
.on-this-page ul {
margin: 0;
padding: 0 0 20px 0;
list-style: none;
}
.on-this-page a {
position: relative;
display: block;
border: 0 solid #ddd;
border-left-width: 2px;
padding: 4px 2px 4px 8px;
text-decoration: none;
}
.on-this-page a.indent {
padding-left: 30px;
}
.on-this-page a:hover {
border-color: var(--theme-accent);
}

View File

@@ -1,63 +0,0 @@
import { useContent, useLocation } from '@builder.io/qwik-city'
import { component$, useStyles$ } from '@builder.io/qwik'
import styles from './on-this-page.css?inline'
export default component$(() => {
useStyles$(styles)
const { headings } = useContent()
const contentHeadings =
headings?.filter((h) => h.level === 2 || h.level === 3) || []
const { pathname } = useLocation()
const editUrl = `#update-your-edit-url-for-${pathname}`
return (
<aside class="on-this-page">
{contentHeadings.length > 0 ? (
<>
<h6>On This Page</h6>
<ul>
{contentHeadings.map((h) => (
<li>
<a
href={`#${h.id}`}
class={{
block: true,
indent: h.level > 2,
}}
>
{h.text}
</a>
</li>
))}
</ul>
</>
) : null}
<h6>More</h6>
<ul>
<li>
<a href={editUrl} target="_blank">
Edit this page
</a>
</li>
<li>
<a href="https://qwik.builder.io/chat" target="_blank">
Join our community
</a>
</li>
<li>
<a href="https://github.com/BuilderIO/qwik" target="_blank">
GitHub
</a>
</li>
<li>
<a href="https://twitter.com/QwikDev" target="_blank">
@QwikDev
</a>
</li>
</ul>
</aside>
)
})

View File

@@ -0,0 +1,37 @@
import { component$ } from '@builder.io/qwik'
export default component$(() => {
return (
<section class="relative">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="py-12 md:py-20">
<div class="max-w-3xl mx-auto text-center p-6 rounded-md shadow-xl dark:shadow-none">
<h2 class="text-4xl md:text-4xl font-bold leading-tighter tracking-tighter mb-4 font-heading">
<span class="text-[#039de1]">Qwik</span> +{' '}
<br class="block sm:hidden" />
<span class="text-[#039de1] sm:whitespace-nowrap">
Tailwind CSS
</span>
</h2>
<p class="text-xl text-gray-600 dark:text-slate-400">
Be very surprised by these huge fake numbers you are
seeing on this page. <br class="hidden md:inline" />
Don't waste more time!
</p>
<div class="mt-6">
<a
class="btn btn-primary mb-4 sm:mb-0 w-full sm:w-auto"
href="https://github.com/onwidget/qwind"
target="_blank"
rel="noopener"
>
Get template
</a>
</div>
</div>
</div>
</div>
</section>
)
})

View File

@@ -0,0 +1,27 @@
import { component$ } from '@builder.io/qwik'
import { useLocation } from '@builder.io/qwik-city'
/**
* options = [] array con la lista de opciones de la documentacion
*/
export default component$(
({
options = [],
}: {
options: { link: string; name: string; class?: string }[]
}) => {
const { pathname } = useLocation()
const editUrl = ` https://github.com/codigoencasa/bot-whatsapp/edit/dev/packages/docs/src/routes${pathname}index.mdx`
return (
<div>
<ul>
{options.map((opt) => (
<li class={opt.class}>
<a href={editUrl}>{opt.name}</a>
</li>
))}
</ul>
</div>
)
}
)

View File

@@ -0,0 +1,84 @@
import { component$ } from '@builder.io/qwik'
import { IconArrowDownRight } from '../icons/IconArrowDownRight'
export default component$(() => {
const items = [
[
{
question: 'What do I need to start?',
answer: `Space, the final frontier. These are the voyages of the Starship Enterprise. Its five-year mission: to explore strange new worlds.
Many say exploration is part of our destiny, but its actually our duty to future generations.`,
},
{
question: 'How to install the Qwik + Tailwind CSS template?',
answer: `Well, the way they make shows is, they make one show. That show's called a pilot.
Then they show that show to the people who make shows, and on the strength of that one show they decide if they're going to make more shows. Some pilots get picked and become television programs. Some don't, become nothing. She starred in one of the ones that became nothing.`,
},
{
question:
"What's something that you completely don't understand?",
answer: `A flower in my garden, a mystery in my panties. Heart attack never stopped old Big Bear. I didn't even know we were calling him Big Bear.`,
},
],
[
{
question: "What's an example of when you changed your mind?",
answer: `Michael Knight a young loner on a crusade to champion the cause of the innocent. The helpless. The powerless in a world of criminals who operate above the law. Here he comes Here comes Speed Racer. He's a demon on wheels.`,
},
{
question:
'What is something that you would really like to try again?',
answer: `A business big enough that it could be listed on the NASDAQ goes belly up. Disappears!
It ceases to exist without me. No, you clearly don't know who you're talking to, so let me clue you in.`,
},
{
question:
'If you could only ask one question to each person you meet, what would that question be?',
answer: `This is not about revenge. This is about justice. A lot of things can change in twelve years, Admiral. Well, that's certainly good to know. About four years. I got tired of hearing how young I looked.`,
},
],
]
return (
<section class="border-t border-gray-200 dark:border-slate-800">
<div class="px-4 py-16 mx-auto max-w-6xl lg:py-20">
<div class="max-w-xl sm:mx-auto lg:max-w-2xl">
<div class="max-w-xl mb-10 md:mx-auto sm:text-center lg:max-w-2xl md:mb-12">
<p class="text-base text-primary-600 dark:text-purple-200 font-semibold tracking-wide uppercase">
FAQs
</p>
<h2 class="max-w-lg mb-4 text-3xl font-bold leading-none tracking-tight sm:text-4xl md:mx-auto font-heading">
Frequently Asked Questions
</h2>
</div>
</div>
<div class="max-w-screen-xl sm:mx-auto">
<div class="grid grid-cols-1 gap-x-8 gap-y-8 lg:gap-x-16 md:grid-cols-2">
{items.map((subitems) => (
<div class="space-y-8">
{subitems.map(({ question, answer }) => (
<div>
<p class="mb-4 text-xl font-bold">
<IconArrowDownRight class="w-7 h-7 text-secondary-500 inline-block" />
{question}
</p>
{answer
.split('\n\n')
.map((paragraph) => (
<p class="text-gray-700 dark:text-gray-400 mb-2">
{paragraph}
</p>
))}
</div>
))}
</div>
))}
</div>
</div>
</div>
</section>
)
})

View File

@@ -0,0 +1,91 @@
import { component$ } from '@builder.io/qwik'
import { IconStar } from '~/components/icons/IconStar'
export default component$(() => {
const items = [
[
{
title: 'Qwik + Tailwind CSS Integration',
description:
'A seamless integration between two great frameworks that offer high productivity, performance and versatility.',
icon: 'tabler:brand-tailwind',
},
{
title: 'Ready-to-use Components',
description:
'Widgets made with Tailwind CSS ready to be used in Marketing Websites, SaaS, Blogs, Personal Profiles, Small Business...',
icon: 'tabler:components',
},
{
title: 'Best Practices',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sagittis, quam nec venenatis lobortis, mi risus tempus nulla.',
icon: 'tabler:list-check',
},
],
[
{
title: 'Excellent Page Speed',
description:
'Having a good page speed impacts organic search ranking, improves user experience (UI/UX) and increase conversion rates.',
icon: 'tabler:rocket',
},
{
title: 'Search Engine Optimization (SEO)',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sagittis, quam nec venenatis lobortis, mi risus tempus nulla.',
icon: 'tabler:arrows-right-left',
},
{
title: 'Open to new ideas and contributions',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi sagittis, quam nec venenatis lobortis, mi risus tempus nulla.',
icon: 'tabler:bulb',
},
],
]
return (
<section class="scroll-mt-16" id="features">
<div class="px-4 py-16 mx-auto max-w-6xl lg:px-8 lg:py-20">
<div class="mb-10 md:mx-auto sm:text-center md:mb-12 max-w-3xl">
<p class="text-base text-primary-600 dark:text-purple-200 font-semibold tracking-wide uppercase">
Features
</p>
<h2 class="text-4xl md:text-5xl font-bold leading-tighter tracking-tighter mb-4 font-heading">
What you get with{' '}
<span class="whitespace-nowrap">Qwind</span>
</h2>
<p class="max-w-3xl mx-auto sm:text-center text-xl text-gray-600 dark:text-slate-400">
Sed ut perspiciatis unde omnis iste natus error sit
voluptatem accusantium doloremque rem aperiam, eaque
ipsa quae.
</p>
</div>
<div class="grid mx-auto space-y-6 md:grid-cols-2 md:space-y-0">
{items.map((subitems) => (
<div class="space-y-8 sm:px-8">
{subitems.map(({ title, description }) => (
<div class="flex flex-row max-w-md">
<div class="mb-4 mr-4">
<div class="text-white flex items-center justify-center w-12 h-12 rounded-full bg-secondary-500 dark:bg-secondary-700">
<IconStar />
</div>
</div>
<div>
<h3 class="mb-3 text-xl font-bold">
{title}
</h3>
<p class="text-gray-600 dark:text-slate-400">
{description}
</p>
</div>
</div>
))}
</div>
))}
</div>
</div>
</section>
)
})

View File

@@ -0,0 +1,128 @@
import { component$ } from '@builder.io/qwik'
import { Link } from '@builder.io/qwik-city'
import { IconTwitter } from '~/components/icons/IconTwitter'
import { IconInstagram } from '~/components/icons/IconInstagram'
import { IconFacebook } from '~/components/icons/IconFacebook'
import { IconGithub } from '~/components/icons/IconGithub'
export default component$(() => {
const links = [
{
title: 'Product',
items: [
{ title: 'Features', href: '#' },
{ title: 'Security', href: '#' },
],
},
{
title: 'Platform',
items: [
{ title: 'Developer API', href: '#' },
{ title: 'Partners', href: '#' },
],
},
{
title: 'Support',
items: [
{ title: 'Docs', href: '#' },
{ title: 'Community Forum', href: '#' },
],
},
{
title: 'Company',
items: [
{ title: 'About', href: '#' },
{ title: 'Blog', href: '#' },
],
},
]
const social = [
{ label: 'Twitter', icon: IconTwitter, href: '#' },
{ label: 'Instagram', icon: IconInstagram, href: '#' },
{ label: 'Facebook', icon: IconFacebook, href: '#' },
{
label: 'Github',
icon: IconGithub,
href: 'https://github.com/onwidget/qwind',
},
]
return (
<footer class="border-t border-gray-200 dark:border-slate-800">
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="grid grid-cols-12 gap-4 gap-y-8 sm:gap-8 py-8 md:py-12">
<div class="col-span-12 lg:col-span-4 pr-8">
<div class="mb-2">
<Link
class="inline-block font-bold text-xl"
href={'/'}
>
Qwind
</Link>
</div>
<div class="text-sm text-gray-600 dark:text-gray-400">
Nos sentimos muy afortunados de poder contribuir a
este proyecto y esperamos poder seguir trabajando
juntos para ayudar a los pequeños comercios a
impulsar sus ventas y fortalecer la economía local.
</div>
</div>
{links.map(({ title, items }) => (
<div class="col-span-6 md:col-span-3 lg:col-span-2">
<div class="text-gray-800 dark:text-gray-300 font-medium mb-2">
{title}
</div>
{items &&
Array.isArray(items) &&
items.length > 0 && (
<ul class="text-sm">
{items.map(({ title, href }) => (
<li class="mb-2">
<Link
class="text-gray-600 hover:text-gray-700 hover:underline dark:text-gray-400 transition duration-150 ease-in-out"
href={href}
>
{title}
</Link>
</li>
))}
</ul>
)}
</div>
))}
</div>
<div class="md:flex md:items-center md:justify-between py-6 md:py-8">
<ul class="flex mb-4 md:order-1 -ml-2 md:ml-4 md:mb-0">
{social.map(({ label, href, icon: Icon }) => (
<li>
<Link
class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5 inline-flex items-center"
aria-label={label}
title={label}
href={href}
>
{Icon && <Icon />}
</Link>
</li>
))}
</ul>
<div class="text-sm text-gray-700 mr-4 dark:text-slate-400">
<span class="w-5 h-5 md:w-6 md:h-6 md:-mt-0.5 bg-cover mr-1.5 float-left rounded-sm bg-[url(https://onwidget.com/favicon/favicon-32x32.png)]"></span>
Made by{' '}
<a
class="text-secondary-700 hover:underline dark:text-gray-200"
href="https://onwidget.com/"
>
{' '}
onWidget
</a>{' '}
· All rights reserved.
</div>
</div>
</div>
</footer>
)
})

View File

@@ -0,0 +1,119 @@
import { component$, useStore } from '@builder.io/qwik'
import Logo from '~/components/atoms/Logo'
import { IconGithub } from '~/components/icons/IconGithub'
import ToggleTheme from '~/components/core/ToggleTheme'
import ToggleMenu from '~/components/core/ToggleMenu'
export default component$(() => {
const store = useStore({
isScrolling: false,
})
return (
<header
class={`sticky top-0 z-40 flex-none mx-auto w-full transition-all ${
store.isScrolling
? ' md:bg-white/90 md:backdrop-blur-sm dark:md:bg-slate-900/90 bg-white dark:bg-slate-900'
: ''
}`}
id="header"
window:onScroll$={() => {
if (!store.isScrolling && window.scrollY >= 10) {
store.isScrolling = true
} else if (store.isScrolling && window.scrollY < 10) {
store.isScrolling = false
}
}}
>
<div class="py-3 px-3 mx-auto w-full md:flex md:justify-between max-w-6xl md:px-4">
<div class="flex justify-between">
<a class="flex items-center" href={'/'}>
<Logo />
</a>
<div class="flex items-center md:hidden">
<ToggleTheme iconClass="w-6 h-6" />
<ToggleMenu iconClass="w-6 h-6" />
</div>
</div>
<nav
class="items-center w-full md:w-auto hidden md:flex text-gray-600 dark:text-slate-200 h-[calc(100vh-100px)] md:h-auto overflow-y-auto md:overflow-visible"
aria-label="Main navigation"
>
<ul class="flex flex-col pt-8 md:pt-0 md:flex-row md:self-center w-full md:w-auto text-xl md:text-base">
<li class="dropdown">
<button class="font-medium hover:text-gray-900 dark:hover:text-white px-4 py-3 flex items-center transition duration-150 ease-in-out">
Pages
</button>
<ul class="dropdown-menu rounded md:absolute pl-4 md:pl-0 md:hidden font-medium md:bg-white md:min-w-[200px] dark:md:bg-slate-800 drop-shadow-xl">
<li>
<a
class="font-medium rounded-t md:hover:bg-gray-100 dark:hover:bg-gray-700 py-2 px-4 block whitespace-no-wrap"
href="#"
>
Features
</a>
</li>
<li>
<a
class="font-medium md:hover:bg-gray-100 dark:hover:bg-gray-700 py-2 px-4 block whitespace-no-wrap"
href="#"
>
Profile
</a>
</li>
<li>
<a
class="font-medium rounded-b md:hover:bg-gray-100 dark:hover:bg-gray-700 py-2 px-4 block whitespace-no-wrap"
href="#"
>
Pricing
</a>
</li>
</ul>
</li>
<li>
<a
class="font-medium hover:text-gray-900 dark:hover:text-white px-4 py-3 flex items-center transition duration-150 ease-in-out"
href={'/docs'}
>
Documentación
</a>
</li>
<li>
<a
target={'_blank'}
class="font-medium hover:text-gray-900 dark:hover:text-white px-4 py-3 flex items-center transition duration-150 ease-in-out"
href={
'https://codigoencasa.com/tag/bot-whatsapp/'
}
>
Blog
</a>
</li>
<li class="md:hidden">
<a
target={'_blank'}
class="font-bold hover:text-gray-900 dark:hover:text-white px-4 py-3 flex items-center transition duration-150 ease-in-out"
href="https://github.com/codigoencasa/bot-whatsapp"
>
Github
</a>
</li>
</ul>
<div class="md:self-center flex items-center mb-4 md:mb-0 ml-2">
<div class="hidden items-center md:flex">
<ToggleTheme />
<a
href="https://github.com/codigoencasa/bot-whatsapp"
class="inline-block text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5"
aria-label="Qwind Github"
>
<IconGithub />
</a>
</div>
</div>
</nav>
</div>
</header>
)
})

View File

@@ -0,0 +1,87 @@
import { component$ } from '@builder.io/qwik'
// @ts-ignore
import srcsetAvif from '~/assets/images/hero.jpg?w=400;900&avif&srcset'
// @ts-ignore
import srcsetWebp from '~/assets/images/hero.jpg?w=400;900&webp&srcset'
// @ts-ignore
import { src as placeholder } from '~/assets/images/hero.jpg?width=400&metadata'
export default component$(() => {
return (
<section
class={`bg-gradient-to-b md:bg-gradient-to-r from-white via-purple-50 to-sky-100 dark:bg-none mt-[-72px]`}
>
<div class="max-w-6xl mx-auto px-4 sm:px-6 md:flex md:h-screen 2xl:h-auto pt-[72px]">
<div class="py-12 md:py-12 lg:py-16 block md:flex text-center md:text-left">
<div class="pb-12 md:pb-0 md:py-0 max-w-5xl mx-auto md:pr-16 flex items-center basis-[56%]">
<div>
<h1 class="text-5xl md:text-[3.48rem] font-bold leading-tighter tracking-tighter mb-4 font-heading px-4 md:px-0">
Free template for <br class="hidden lg:block" />{' '}
<span class="hidden lg:inline">
create a website using{' '}
</span>{' '}
<span class="text-[#039de1]">Qwik</span> +{' '}
<span class="sm:whitespace-nowrap text-[#039de1]">
Tailwind CSS
</span>
</h1>
<div class="max-w-3xl mx-auto">
<p class="text-xl text-gray-600 mb-8 dark:text-slate-400">
<span class="font-semibold underline decoration-wavy decoration-1 decoration-secondary-600 underline-offset-2">
Qwind
</span>{' '}
is a production ready template to start your
new website using <em>Qwik</em> +{' '}
<em>Tailwind CSS</em>. It has been designed
following Best Practices, SEO,
Accessibility,{' '}
<span class="inline md:hidden">...</span>
<span class="hidden md:inline">
Dark Mode, Great Page Speed, image
optimization, sitemap generation and
more.
</span>
</p>
<div class="max-w-xs sm:max-w-md flex flex-nowrap flex-col sm:flex-row gap-4 m-auto md:m-0 justify-center md:justify-start">
<div class="flex w-full sm:w-auto">
<a
class="btn btn-primary sm:mb-0 w-full"
href="https://github.com/onwidget/qwind"
target="_blank"
rel="noopener"
>
Get template
</a>
</div>
<div class="flex w-full sm:w-auto">
<button class="btn w-full bg-gray-50 dark:bg-transparent">
Learn more
</button>
</div>
</div>
</div>
</div>
</div>
<div class="block md:flex items-center flex-1">
<div class="relative m-auto max-w-4xl">
<picture>
<source srcSet={srcsetAvif} type="image/avif" />
<source srcSet={srcsetWebp} type="image/webp" />
<img
src={placeholder}
width={1000}
height={1250}
class="mx-auto w-full rounded-md md:h-full drop-shadow-2xl bg-gray-400 dark:bg-slate-700"
alt="Qwind Hero Image (Cool dog)"
loading="eager"
decoding="async"
/>
</picture>
</div>
</div>
</div>
</div>
</section>
)
})

View File

@@ -0,0 +1,32 @@
import { component$ } from '@builder.io/qwik'
import { useLocation } from '@builder.io/qwik-city'
/**
* options = [] array con la lista de opciones de la documentacion
*/
export default component$(
({ options = [] }: { options: { link: string; name: string }[] }) => {
const location = useLocation()
const currentPage = location.pathname
return (
<div>
<ul>
{options.map((opt) => (
<li>
<a
class={
currentPage === `${opt.link}/`
? 'font-semibold'
: ''
}
href={opt.link}
>
{opt.name}
</a>
</li>
))}
</ul>
</div>
)
}
)

View File

@@ -0,0 +1,42 @@
import { component$ } from '@builder.io/qwik'
export default component$(() => {
return (
<div class="px-4 py-8 md:py-16 sm:px-6 mx-auto md:px-24 lg:px-8 lg:py-20 max-w-6xl">
<div class="grid grid-cols-2 row-gap-8 md:grid-cols-4">
<div class="text-center md:border-r dark:md:border-slate-500 mb-10 md:mb-0">
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1] font-heading">
132K
</div>
<p class="text-sm font-medium tracking-widest text-gray-800 dark:text-slate-400 uppercase lg:text-base">
Downloads
</p>
</div>
<div class="text-center md:border-r dark:md:border-slate-500 mb-10 md:mb-0">
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1] font-heading">
24.8K
</div>
<p class="text-sm font-medium tracking-widest text-gray-800 dark:text-slate-400 uppercase lg:text-base">
Stars
</p>
</div>
<div class="text-center md:border-r dark:md:border-slate-500 font-heading">
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1]">
10.3K
</div>
<p class="text-sm font-medium tracking-widest text-gray-800 dark:text-slate-400 uppercase lg:text-base">
Forks
</p>
</div>
<div class="text-center">
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1] font-heading">
48.4K
</div>
<p class="text-sm font-medium tracking-widest text-gray-800 dark:text-slate-400 uppercase lg:text-base">
Users
</p>
</div>
</div>
</div>
)
})

View File

@@ -0,0 +1,7 @@
export const SITE = {
name: "Qwind",
origin: "https://qwind.pages.dev",
basePathname: "/",
trailingSlash: true
};

View File

@@ -20,7 +20,9 @@ export default function (opts: RenderToStreamOptions) {
...opts,
// Use container attributes to set attributes on the html tag.
containerAttributes: {
lang: 'en-us',
lang: 'en',
dir: 'ltr',
class: 'motion-safe:scroll-smooth 2xl:text-[20px]',
...opts.containerAttributes,
},
})

View File

@@ -1,67 +0,0 @@
* {
box-sizing: border-box;
}
:root {
--user-font-scale: 1rem - 16px;
--max-width: calc(100% - 1rem);
--font-body: system-ui, -apple-system, BlinkMacSystemFont, Segoe UI,
Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
--font-mono: 'IBM Plex Mono', Consolas, 'Andale Mono WT', 'Andale Mono',
'Lucida Console', 'Lucida Sans Typewriter', 'DejaVu Sans Mono',
'Bitstream Vera Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco,
'Courier New', Courier, monospace;
color-scheme: light;
--theme-accent: #006ce9;
--theme-text: #181818;
}
@media (min-width: 50em) {
:root {
--max-width: 46em;
}
}
body {
display: flex;
flex-direction: column;
min-height: 100vh;
font-family: var(--font-body);
font-size: 1rem;
font-size: clamp(0.9rem, 0.75rem + 0.375vw + var(--user-font-scale), 1rem);
line-height: 1.5;
max-width: 100vw;
background: var(--theme-bg);
color: var(--theme-text);
}
main {
padding: 10px 20px;
max-width: 960px;
margin: 0 auto;
}
a {
color: var(--theme-accent);
}
a:hover {
text-decoration: none;
}
code,
kbd,
samp,
pre {
font-family: var(--font-mono);
}
code {
background-color: rgb(224, 224, 224);
padding: 2px 4px;
border-radius: 3px;
font-size: 0.9em;
border-bottom: 2px solid #bfbfbf;
}

View File

@@ -1,27 +1,42 @@
import { component$ } from '@builder.io/qwik'
import { component$, useStyles$ } from '@builder.io/qwik'
import {
QwikCityProvider,
RouterOutlet,
ServiceWorkerRegister,
} from '@builder.io/qwik-city'
import { RouterHead } from './components/router-head/router-head'
import './global.css'
import { RouterHead } from '~/components/core/RouterHead'
import { DarkThemeLauncher } from '~/components/core/DarkThemeLauncher'
import globalStyles from '~/assets/styles/global.css?inline'
export default component$(() => {
/*
/**
* The root of a QwikCity site always start with the <QwikCityProvider> component,
* immediately followed by the document's <head> and <body>.
*
* Dont remove the `<head>` and `<body>` elements.
*/
useStyles$(globalStyles)
return (
<QwikCityProvider>
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
<link rel="manifest" href="/manifest.json" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap"
rel="stylesheet"
/>
<RouterHead />
<DarkThemeLauncher />
</head>
<body lang="en">
<body class="text-gray-900 dark:text-slate-300 tracking-tight bg-white dark:bg-gray-900 antialiased">
<RouterOutlet />
<ServiceWorkerRegister />
</body>

View File

@@ -1,15 +0,0 @@
---
title: About Bot-Whatsapp .
---
# About Qwik
Hola soy una prueba
## More info:
- [Layouts](https://qwik.builder.io/qwikcity/layout/overview/)
- [Routing](https://qwik.builder.io/qwikcity/routing/overview/)
- [Authoring Content](https://qwik.builder.io/qwikcity/content/component/)
- [Deployment](https://qwik.builder.io/qwikcity/adaptors/overview/)
- [Static Site Generation (SSG)](https://qwik.builder.io/qwikcity/static-site-generation/overview/)

View File

@@ -0,0 +1,27 @@
import { component$ } from '@builder.io/qwik'
import type { DocumentHead } from '@builder.io/qwik-city'
export default component$(() => {
return (
<>
<section>
<div class="max-w-6xl mx-auto py-6 px-4 sm:px-6 h-[60vh]">
<h1 class="text-4xl font-bold leading-tighter tracking-tighter mb-8 font-heading">
Blog
</h1>
<p class="text-xl">Coming soon ...</p>
</div>
</section>
</>
)
})
export const head: DocumentHead = {
title: 'Blog — Qwind',
meta: [
{
name: 'description',
content: 'Lorem ipsum lorem ...',
},
],
}

View File

@@ -1,11 +0,0 @@
---
title: Advanced
---
# Advanced
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
## Ferrari
[Ferrari](https://en.wikipedia.org/wiki/Ferrari) (/fəˈrɑːri/; Italian: [ferˈraːri]) is an Italian luxury sports car manufacturer based in Maranello, Italy. Founded by Enzo Ferrari (18981988) in 1939 from the Alfa Romeo racing division as Auto Avio Costruzioni, the company built its first car in 1940, and produced its first Ferrari-badged car in 1947.

View File

@@ -1,22 +0,0 @@
.docs {
display: grid;
grid-template-columns: 210px auto 190px;
grid-template-areas: 'menu article on-this-page';
gap: 40px;
}
.docs h1 {
margin-top: 0;
}
.docs .menu {
grid-area: menu;
}
.docs article {
grid-area: article;
}
.docs .on-this-page {
grid-area: on-this-page;
}

View File

@@ -1,13 +0,0 @@
---
title: Getting Started
---
# Getting Started
```
npm create qwik@latest
```
## Ford GT40
The [Ford GT40](https://en.wikipedia.org/wiki/Ford_GT40) is a high-performance endurance racing car commissioned by the Ford Motor Company. It grew out of the "Ford GT" (for Grand Touring) project, an effort to compete in European long-distance sports car races, against Ferrari, which won the prestigious 24 Hours of Le Mans race from 1960 to 1965. Ford succeeded with the GT40, winning the 1966 through 1969 races.

View File

@@ -1,22 +0,0 @@
---
title: Overview
---
# Docs Site Overview
This page is wrapped by two layouts because this source file `src/routes/docs/index.md` is nested. The applied layouts are:
- `src/routes/docs/layout.tsx`
- `src/routes/layout.tsx`
## Left Menu
The left menu ordering is created with the `src/routes/docs/menu.md` markdown file.
## More info:
- [Layouts](https://qwik.builder.io/qwikcity/layout/overview/)
- [Routing](https://qwik.builder.io/qwikcity/routing/overview/)
- [Authoring Content](https://qwik.builder.io/qwikcity/content/component/)
- [Deployment](https://qwik.builder.io/qwikcity/adaptors/overview/)
- [Static Site Generation (SSG)](https://qwik.builder.io/qwikcity/static-site-generation/overview/)

View File

@@ -0,0 +1,19 @@
# Primeros Pasos
Los chatbots son una herramienta poderosa para que las empresas y
organizaciones comuniquen de forma personalizada y automatizada con sus clientes.
Está documentación te ayudará a instalar tu bot de whatsapp en simples pasos con el proposito de
que tengas un chatbot funcional en solo minutos.
---
### Ejecutar
Es muy sencillo solo deberas ejecutar el siguiente comando 🚀
```shell
npm create bot-whatsapp@latest
```
![](https://camo.githubusercontent.com/97cd563fb448c72cc50dd60d71e85d269e5b1c738473d56fee6e023e1e0723bb/68747470733a2f2f692e67697068792e636f6d2f6d656469612f6e744d74365476616c70737454497837416b2f67697068792e77656270)

View File

@@ -0,0 +1,10 @@
---
title: Overview
contributors:
- adamdbradley
- steve8708
- manucorporat
- gabrielgrant
---
# Instalación

View File

@@ -0,0 +1,55 @@
import { component$, Slot, useStore } from '@builder.io/qwik'
import type { DocumentHead } from '@builder.io/qwik-city'
import Footer from '~/components/widgets/Footer'
import Header from '~/components/widgets/Header'
import NavBar from '~/components/widgets/NavBar'
import ExtraBar from '~/components/widgets/ExtraBar'
export default component$(() => {
const store = useStore({
options: [
{ name: 'Primeros pasos', link: '/docs' },
{ name: 'Instalación', link: '/docs/install' },
{ name: 'Configuración', link: '/docs/settings' },
{ name: 'Migración', link: '/docs/migration' },
],
extraOptions: [
{ name: 'Primeros pasos', link: '/docs', class: 'font-semibold' },
{ name: 'Instalación', link: '/docs' },
{ name: 'Configuración', link: '/docs' },
{ name: 'Forma de pensar', link: '/docs' },
],
})
return (
<>
<Header />
<main class="container mx-auto px-12 ">
<div class={'grid grid-cols-5 gap-1 min-h-min'}>
<div class={'px-3 col-span-1 '}>
<NavBar options={store.options} />
</div>
<div class={'col-span-3 slot pb-5'}>
<Slot />
</div>
<div class={'px-3 col-span-1 '}>
<ExtraBar options={store.extraOptions} />
</div>
</div>
</main>
<Footer />
</>
)
})
export const head: DocumentHead = {
title: 'Qwind — Free template for starts a website using Qwik + Tailwind CSS',
meta: [
{
name: 'description',
content:
'Qwind is a free and ready to start template to make your website using Qwik and Tailwind CSS.',
},
],
}

View File

@@ -1,25 +0,0 @@
import { component$, Slot, useStyles$ } from '@builder.io/qwik'
import type { DocumentHead } from '@builder.io/qwik-city'
import Menu from '~/components/menu/menu'
import OnThisPage from '~/components/on-this-page/on-this-page'
import styles from './docs.css?inline'
export default component$(() => {
useStyles$(styles)
return (
<div class="docs">
<Menu />
<article>
<Slot />
</article>
<OnThisPage />
</div>
)
})
export const head: DocumentHead = ({ head }) => {
return {
title: `${head.title} - Documentation`,
}
}

View File

@@ -2,20 +2,12 @@
## Guides
- [Getting Started](getting-started/index.md)
- [Overview](overview/index.mdx)
## Advanced
- [Overview](advanced/index.md)
## Examples
- [Hello World](https://qwik.builder.io/examples/introduction/hello-world/)
- [Tutorials](https://qwik.builder.io/tutorial/welcome/overview/)
- [Playground](https://qwik.builder.io/playground/)
## Community
- [GitHub](https://github.com/BuilderIO/qwik)
- [@QwikDev](https://twitter.com/QwikDev)
- [Discord](https://qwik.builder.io/chat)
- [GitHub](https://github.com/BuilderIO/qwik)

View File

@@ -0,0 +1,10 @@
---
title: Overview
contributors:
- adamdbradley
- steve8708
- manucorporat
- gabrielgrant
---
# Migracion

View File

@@ -0,0 +1,65 @@
---
title: Overview
contributors:
- adamdbradley
- steve8708
- manucorporat
- gabrielgrant
---
# Welcome to Qwik
Qwik is a new kind of web framework that can deliver instant loading web applications at any size or complexity. Your sites and apps can boot with about 1kb of JS (regardless of application complexity), and achieve consistent performance at scale.
[See more presentations, videos, and podcasts](/media/)
[Check out sites built with Qwik](/showcase/)
## Getting Started with Qwik
<div class="card-grid">
<a class="card card-center" href="/docs/getting-started/">
<p class="icon">🚀</p>
<h3>npm create qwik</h3>
</a>
<a class="card card-center" href="/docs/think-qwik/">
<p class="icon">🤔</p>
<h3>Why Qwik?</h3>
</a>
<a class="card card-center" href="/docs/components/overview/">
<p class="icon">📚</p>
<h3>API</h3>
</a>
<a class="card card-center" href="https://qwik.builder.io/chat">
<h3>Community</h3>
</a>
<a class="card card-center" href="/qwikcity/overview/">
<p class="icon">🌃</p>
<h3>QwikCity & Routing</h3>
</a>
</div>
## Qwik Goals
<div class="card-grid">
<div class="card">
<h3>General-purpose</h3>
<p>Qwik can be used to build any type of web site or application</p>
</div>
<div class="card">
<h3>Instant-on</h3>
<p>
Unlike other frameworks, Qwik is resumable which means Qwik
applications require 0 hydration. This allows Qwik apps to have
instant-on interactivity, regardless of size or complexity
</p>
</div>
<div class="card">
<h3>Optimized for speed</h3>
<p>
Qwik has unprecedented performance, offering sub-second full page
loads even on mobile devices. Qwik achieves this by delivering pure
HTML, and incrementally loading JS only as-needed.
</p>
</div>
</div>

View File

@@ -0,0 +1,10 @@
---
title: Overview
contributors:
- adamdbradley
- steve8708
- manucorporat
- gabrielgrant
---
# Ajustes

View File

@@ -1,236 +1,31 @@
import { component$ } from '@builder.io/qwik'
import type { DocumentHead } from '@builder.io/qwik-city'
import Hero from '~/components/widgets/Hero'
import Features from '~/components/widgets/Features'
import FAQs from '~/components/widgets/FAQs'
import Stats from '~/components/widgets/Stats'
import CallToAction from '~/components/widgets/CallToAction'
export default component$(() => {
return (
<>
<h1>Bienvenido</h1>
<p>
Un robot (bot) de Whatsapp es un programa que reconoce palabras
clave en los mensajes que entran, y contesta con respuestas
pre-programadas, facilitando así el dar información a posibles
clientes desde tu cuenta de Whatsapp automáticamente.
</p>
<p>
Este bot esta hecho en Javascript y usa NodeJS y es{' '}
<a href="https://www.redhat.com/es/topics/open-source/what-is-open-source">
Open Source
</a>
.
</p>
<p>
Está programado de tal forma que se pueden usar varias librerías
(hasta ahora whatsapp-web.js, twilio y Venom) y se puden agregar
más.
</p>
<p>
Si se quiere cambiar la librería que se está usando, esto se
puede hacer con solo cambiar unas lineas en el código.
</p>
<table border>
<thead>
<tr>
<th>Características</th>
<th>Estatus</th>
</tr>
</thead>
<tbody>
<tr>
<td>Menus y Submenus</td>
<td>
<g-emoji
class="g-emoji"
alias="white_check_mark"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png"
>
</g-emoji>
</td>
</tr>
<tr>
<td>Dialogflow</td>
<td>
<g-emoji
class="g-emoji"
alias="white_check_mark"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png"
>
</g-emoji>
</td>
</tr>
<tr>
<td>MySQL</td>
<td>
<g-emoji
class="g-emoji"
alias="white_check_mark"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png"
>
</g-emoji>
</td>
</tr>
<tr>
<td>JSON File</td>
<td>
<g-emoji
class="g-emoji"
alias="white_check_mark"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png"
>
</g-emoji>
</td>
</tr>
<tr>
<td>QR Scan (route)</td>
<td>
<g-emoji
class="g-emoji"
alias="white_check_mark"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png"
>
</g-emoji>
</td>
</tr>
<tr>
<td>Easy deploy heroku</td>
<td>
<g-emoji
class="g-emoji"
alias="white_check_mark"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png"
>
</g-emoji>
</td>
</tr>
<tr>
<td>Buttons</td>
<td>
<g-emoji
class="g-emoji"
alias="white_check_mark"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png"
>
</g-emoji>
<g-emoji
class="g-emoji"
alias="information_source"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2139.png"
>
</g-emoji>{' '}
(No funciona en multi-device)
</td>
</tr>
<tr>
<td>Send Voice Note</td>
<td>
<g-emoji
class="g-emoji"
alias="white_check_mark"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png"
>
</g-emoji>
</td>
</tr>
<tr>
<td>Add support ubuntu/linux</td>
<td>
<g-emoji
class="g-emoji"
alias="white_check_mark"
fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/2705.png"
>
</g-emoji>
</td>
</tr>
</tbody>
</table>
<h2>Requisitos</h2>
<ul>
<li>Node v14 o superior</li>
<li>
VSCode (Editor de codigo){' '}
<a
href="https://code.visualstudio.com/download"
rel="nofollow"
>
Descargar
</a>
</li>
<li>
MySql (opcional) solo aplica si vas a usar el modo 'mysql'{' '}
<a href="https://github.com/leifermendez/bot-whatsapp/blob/main/sql-bot.sql">
sql-bot.sql migración
</a>
</li>
<li>
Dialogflow (opcional) solo aplica si vas a usar el modo
'dialogflow'
</li>
</ul>
<h2>Instalación</h2>
<ul>
<li>
Abre VSCode y muevete al directorio en donde quieres
instalar el bot.
</li>
<li>Ejecuta este comando: npm create bot-whatsapp@latest</li>
<li>Contesta que SI quieres crear un bot nuevo (Y)</li>
<li>
Selecciona con las flechas (arriba y abajo) la librería que
vas usar para el bot, cuando estes sobre la opción que
quieres, oprime la barra de espacio y luego la tecla "Enter"
</li>
<li>
De igual forma selecciona la base de datos que quieres usar.
</li>
<li>
Cambiate al directorio que se creo dependiendo de la base de
datos que hayas seleccionado, si seleccionaste "Memory"
sería "cd base-wweb-memory"
</li>
<li>
Ya estando en el nuevo subdirectorio, ejecuta el comando
"npm install" y espera a que se instalen las dependencias.
</li>
<li>
Una vez que termine la instalación ejecuta el comando "npm
start"y espera a que te mande el mensaje de que necesitas
escanear el código QR, para esto ve al directorio en el que
se instaló y busca el archivo "qr.svg" y abrelo, te debe de
mostrar un código QR que tienes que escanear en el Whatsapp
que quieres ligar con el bot, para esto ve a tu Whatsapp,
haz clic en los tres botones de arriba a la derecha y entra
en "Linked devices", y luego en el botón que dice "LINK
DEVICE", esto va a abrir la camara para que escanes el
código.
</li>
<li>
Una vez ligado el Whatsapp, vas a ver el mensaje de
"Proveedor conectado y listo".
</li>
<li>
Desde OTRO celular manda un mensaje al número del Whatsapp
que acabas de ligar al bot con la palabra "Hola" y LISTO.
</li>
<li>Debes de recibir una respuesta automática del bot.</li>
</ul>
<Hero />
<Features />
<FAQs />
<Stats />
<CallToAction />
</>
)
})
export const head: DocumentHead = {
title: 'Welcome to Qwik Docs Starter',
title: 'Qwind — Free template for starts a website using Qwik + Tailwind CSS',
meta: [
{
name: 'description',
content:
'Qwind is a free and ready to start template to make your website using Qwik and Tailwind CSS.',
},
],
}

View File

@@ -1,8 +1,21 @@
import { component$, Slot } from '@builder.io/qwik'
import Footer from '~/components/footer/footer'
import Header from '~/components/header/header'
import Footer from '~/components/widgets/Footer'
import Header from '~/components/widgets/Header'
export default component$(() => {
// useClientEffect$(() => {
// if (
// localStorage.theme === "dark" ||
// (!("theme" in localStorage) &&
// window.matchMedia("(prefers-color-scheme: dark)").matches)
// ) {
// document.documentElement.classList.add("dark");
// } else {
// document.documentElement.classList.remove("dark");
// }
// });
return (
<>
<Header />

View File

@@ -16,6 +16,7 @@
"outDir": "tmp",
"noEmit": true,
"types": ["node", "vite/client"],
"baseUrl": ".",
"paths": {
"~/*": ["./src/*"]
}

15
packages/docs/vercel.json Normal file
View File

@@ -0,0 +1,15 @@
{
"cleanUrls": true,
"trailingSlash": false,
"headers": [
{
"source": "/build/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
}
]
}

View File

@@ -1,15 +1,37 @@
import { defineConfig } from 'vite'
import { qwikVite } from '@builder.io/qwik/optimizer'
import { qwikCity } from '@builder.io/qwik-city/vite'
import { imagetools } from 'vite-imagetools'
import tsconfigPaths from 'vite-tsconfig-paths'
import { SITE } from './src/config.mjs'
const path = require('path')
export default defineConfig(() => {
return {
plugins: [qwikCity(), qwikVite(), tsconfigPaths()],
plugins: [
qwikCity({
basePathname: SITE.basePathname,
trailingSlash: SITE.trailingSlash,
mdxPlugins: {
rehypeSyntaxHighlight: true,
rehypeAutolinkHeadings: false,
remarkGfm: true,
},
}),
qwikVite(),
tsconfigPaths(),
imagetools(),
],
preview: {
headers: {
'Cache-Control': 'public, max-age=600',
},
},
resolve: {
alias: {
'~': path.resolve(__dirname, './src'),
},
},
}
})

View File

@@ -1,6 +1,6 @@
{
"name": "@bot-whatsapp/provider",
"version": "0.0.29-alpha.0",
"version": "0.0.30-alpha.0",
"description": "Esto es el conector a Twilio, Meta, etc...",
"main": "./lib/mock/index.cjs",
"keywords": [],

View File

@@ -1,4 +1,5 @@
const { ProviderClass } = require('@bot-whatsapp/bot')
const { Sticker } = require('wa-sticker-formatter')
const pino = require('pino')
const mime = require('mime-types')
const { existsSync, createWriteStream } = require('fs')
@@ -7,6 +8,7 @@ const { Console } = require('console')
const {
default: makeWASocket,
useMultiFileAuthState,
DisconnectReason,
} = require('@adiwajshing/baileys')
const {
baileyGenerateImage,
@@ -25,6 +27,7 @@ const logger = new Console({
*/
class BaileysProvider extends ProviderClass {
vendor
saveCredsGlobal = null
constructor() {
super()
this.initBailey().then(() => this.initBusEvents())
@@ -35,25 +38,13 @@ class BaileysProvider extends ProviderClass {
*/
initBailey = async () => {
const { state, saveCreds } = await useMultiFileAuthState('sessions')
this.saveCredsGlobal = saveCreds
try {
this.vendor = makeWASocket({
printQRInTerminal: false,
auth: state,
logger: pino({ level: 'error' }),
})
this.vendor.ev.on(
'connection.update',
async ({ qr, connection, lastDisconnect }) => {
if (qr) baileyGenerateImage(qr)
if (connection === 'open') this.emit('ready', true)
if (lastDisconnect?.error) {
saveCreds()
this.initBailey()
}
}
)
} catch (e) {
logger.log(e)
this.emit('auth_failure', [
@@ -75,6 +66,11 @@ class BaileysProvider extends ProviderClass {
{
event: 'connection.update',
func: async ({ qr, connection, lastDisconnect }) => {
const statusCode = lastDisconnect?.error?.output?.statusCode
if (statusCode && statusCode !== DisconnectReason.loggedOut)
this.initBailey()
if (qr) {
this.emit('require_action', {
instructions: [
@@ -86,15 +82,6 @@ class BaileysProvider extends ProviderClass {
await baileyGenerateImage(qr)
}
if (lastDisconnect?.error) {
this.emit('require_action', {
instructions: [
`Algo sucedio reinicia el bot o revisa tu whatsapp`,
`Necesitas ayuda: https://link.codigoencasa.com/DISCORD`,
],
})
}
if (connection === 'open') this.emit('ready', true)
},
},
@@ -228,6 +215,97 @@ class BaileysProvider extends ProviderClass {
return this.sendMedia(number, options.media, message)
return this.sendText(number, message)
}
/**
* @param {string} remoteJid
* @param {string} latitude
* @param {string} longitude
* @param {any} messages
* @example await sendLocation("xxxxxxxxxxx@c.us" || "xxxxxxxxxxxxxxxxxx@g.us", "xx.xxxx", "xx.xxxx", messages)
*/
sendLocation = async (remoteJid, latitude, longitude, messages = null) => {
await this.vendor.sendMessage(
remoteJid,
{
location: {
degreesLatitude: latitude,
degreesLongitude: longitude,
},
},
{ quoted: messages }
)
return { status: 'success' }
}
/**
* @param {string} remoteJid
* @param {string} contactNumber
* @param {string} displayName
* @param {any} messages - optional
* @example await sendContact("xxxxxxxxxxx@c.us" || "xxxxxxxxxxxxxxxxxx@g.us", "+xxxxxxxxxxx", "Robin Smith", messages)
*/
sendContact = async (
remoteJid,
contactNumber,
displayName,
messages = null
) => {
const cleanContactNumber = contactNumber.replaceAll(' ', '')
const waid = cleanContactNumber.replace('+', '')
const vcard =
'BEGIN:VCARD\n' +
'VERSION:3.0\n' +
`FN:${displayName}\n` +
'ORG:Ashoka Uni;\n' +
`TEL;type=CELL;type=VOICE;waid=${waid}:${cleanContactNumber}\n` +
'END:VCARD'
await this.client.sendMessage(
remoteJid,
{
contacts: {
displayName: 'XD',
contacts: [{ vcard }],
},
},
{ quoted: messages }
)
return { status: 'success' }
}
/**
* @param {string} remoteJid
* @param {string} WAPresence
* @example await sendPresenceUpdate("xxxxxxxxxxx@c.us" || "xxxxxxxxxxxxxxxxxx@g.us", "recording")
*/
sendPresenceUpdate = async (remoteJid, WAPresence) => {
await this.client.sendPresenceUpdate(WAPresence, remoteJid)
}
/**
* @param {string} remoteJid
* @param {string} url
* @param {object} stickerOptions
* @param {any} messages - optional
* @example await sendSticker("xxxxxxxxxxx@c.us" || "xxxxxxxxxxxxxxxxxx@g.us", "https://dn/image.png" || "https://dn/image.gif" || "https://dn/image.mp4", {pack: 'User', author: 'Me'} messages)
*/
sendSticker = async (remoteJid, url, stickerOptions, messages = null) => {
const sticker = new Sticker(url, {
...stickerOptions,
quality: 50,
type: 'crop',
})
const buffer = await sticker.toMessage()
await this.client.sendMessage(remoteJid, buffer, { quoted: messages })
}
}
module.exports = BaileysProvider

View File

@@ -10,16 +10,16 @@ const URL = `https://graph.facebook.com/v15.0`
*
*
* Necesitas las siguientes tokens y valores
* { token, numberId, vendorNumber, verify_token }
* { jwtToken, numberId, vendorNumber, verifyToken }
*/
class MetaProvider extends ProviderClass {
metHook
token
jwtToken
numberId
constructor({ token, numberId, verifyToken }, _port = 3000) {
constructor({ jwtToken, numberId, verifyToken }, _port = 3000) {
super()
this.token = token
this.jwtToken = jwtToken
this.numberId = numberId
this.metHook = new MetaWebHookServer(verifyToken, _port)
this.metHook.start()
@@ -60,7 +60,7 @@ class MetaProvider extends ProviderClass {
body,
{
headers: {
Authorization: `Bearer ${this.token}`,
Authorization: `Bearer ${this.jwtToken}`,
},
}
)

View File

@@ -5,12 +5,12 @@ const { urlencoded } = require('body-parser')
class MetaWebHookServer extends EventEmitter {
metaServer
metaPort
verifyToken
constructor(_verifyToken, _metaPort) {
token
constructor(_token, _metaPort) {
super()
this.metaServer = this.buildHTTPServer()
this.metaPort = _metaPort
this.verifyToken = _verifyToken
this.token = _token
}
/**
@@ -32,14 +32,54 @@ class MetaWebHookServer extends EventEmitter {
res.end(json)
}
/**
* Valida el token
* @alpha
* @param {string} mode
* @param {string} token
* @example tokenIsValid('subscribe', 'MYTOKEN')
*/
tokenIsValid(mode, token) {
return mode === 'subscribe' && this.token === token
}
/**
* Verificación del token
* @param {*} req
* @param {*} res
*/
verifyToken = (req, res) => {
const { query } = req
const mode = query['hub.mode']
const token = query['hub.verify_token']
const challenge = query['hub.challenge']
if (!mode || !token) {
return res.sendStatus(403)
}
if (this.tokenIsValid(mode, token)) {
console.log('Webhook verified--->😎😎😎😎')
res.status(200).send(challenge)
}
if (!this.tokenIsValid(mode, token)) {
res.sendStatus(403)
}
}
/**
* Contruir HTTP Server
* @returns
*/
buildHTTPServer = () => {
polka()
.use(urlencoded({ extended: true }))
.get('/webhook', this.verifyToken)
return polka()
.use(urlencoded({ extended: true }))
.post('/meta-hook', this.incomingMsg)
.post('/webhook', this.incomingMsg)
}
/**

View File

@@ -14,7 +14,8 @@
"@bot-whatsapp/database": "latest",
"@bot-whatsapp/provider": "latest",
"@adiwajshing/baileys": "^4.4.0",
"mime-types": "^2.1.35"
"mime-types": "^2.1.35",
"wa-sticker-formatter": "^4.3.2"
},
"author": "",
"license": "ISC"

View File

@@ -15,7 +15,8 @@
"@bot-whatsapp/provider": "latest",
"@adiwajshing/baileys": "^4.4.0",
"mime-types": "^2.1.35",
"mongodb": "^4.12.1"
"mongodb": "^4.12.1",
"wa-sticker-formatter": "^4.3.2"
},
"author": "",
"license": "ISC"

View File

@@ -15,7 +15,8 @@
"@bot-whatsapp/provider": "latest",
"@adiwajshing/baileys": "^4.4.0",
"mime-types": "^2.1.35",
"mysql2": "^2.3.3"
"mysql2": "^2.3.3",
"wa-sticker-formatter": "^4.3.2"
},
"author": "",
"license": "ISC"

File diff suppressed because it is too large Load Diff

3850
yarn.lock

File diff suppressed because it is too large Load Diff