Compare commits
104 Commits
6e1e5dd185
...
v1.11.0-rc
Author | SHA1 | Date | |
---|---|---|---|
|
3a57261590 | ||
|
a86a1a461c | ||
|
2257e1df0c | ||
|
ccb72c8970 | ||
|
740ff941a5 | ||
|
117a683d9a | ||
|
1716dd5a65 | ||
|
66f9a674f1 | ||
|
41fc5274ff | ||
|
bcebdb5fd9 | ||
|
876487ad11 | ||
|
18da75ad97 | ||
|
c80ac1415d | ||
|
bb21184ea2 | ||
|
0c3740fdf2 | ||
|
701819d018 | ||
|
68e151b2bd | ||
|
06ff272541 | ||
|
4154d5e4b1 | ||
|
1862491496 | ||
|
073b5e897c | ||
|
7e1d6ebd19 | ||
|
9a332e79e4 | ||
|
72450b9217 | ||
|
7e1dc33a08 | ||
|
aa240009ab | ||
|
41b258e4d8 | ||
|
da1123d84b | ||
|
627775c430 | ||
|
245573efca | ||
|
28b9cca413 | ||
|
a85f762c58 | ||
|
3ddcceda0a | ||
|
e226645bc7 | ||
|
5447530ece | ||
|
ed6d46a440 | ||
|
588e68e93e | ||
|
c4440327db | ||
|
64e2d457cc | ||
|
bf705afc21 | ||
|
2e4433a6b3 | ||
|
09661ae11d | ||
|
a8d410bc2f | ||
|
7d52fbb368 | ||
|
4b8e0ea1aa | ||
|
5b1055e8c9 | ||
|
4b2a7916fd | ||
|
97e64aa65e | ||
|
90e303f737 | ||
|
7955d8e408 | ||
|
b285cb4323 | ||
|
5d60ab1139 | ||
|
9095996356 | ||
|
310c8a75fd | ||
|
191d1dc25f | ||
|
d3b2f8983d | ||
|
27286465a3 | ||
|
defc677932 | ||
|
45df9dc5bf | ||
|
06db95d7c0 | ||
|
74f7eaed6e | ||
|
dddd944a18 | ||
|
7eccd4d75b | ||
|
62e6c24840 | ||
|
04a0342b52 | ||
|
5c016127cb | ||
|
8b552010f9 | ||
|
97804e7b4d | ||
|
33b895b75e | ||
|
048de2cb74 | ||
|
274e6ca88c | ||
|
f628b6e416 | ||
|
cf7144db96 | ||
|
ffa793056d | ||
|
584d02b92a | ||
|
008c7cbec0 | ||
|
4d1ee79b8d | ||
|
ea638279e5 | ||
|
403d13eb50 | ||
|
217736d05a | ||
|
8a24572cd2 | ||
|
649c68f292 | ||
|
bab5dba6e1 | ||
|
c24edac16d | ||
|
3150c21f17 | ||
|
c46fd7a9c8 | ||
|
bab32e8d70 | ||
|
1130746f5d | ||
|
d1e9361665 | ||
|
3bf2337697 | ||
|
ee6e197ec0 | ||
|
32f26bb4e8 | ||
|
4cb20542a5 | ||
|
97f6196d9b | ||
|
6c227cab6f | ||
|
e9e34ddff9 | ||
|
e29a08dc46 | ||
|
5c313e9bed | ||
|
6b5bd9d79b | ||
|
64d2a467b0 | ||
|
9a2c4fe3b6 | ||
|
060c68a900 | ||
|
e6b87f89ec | ||
|
8aaee2c40c |
127
.github/workflows/docker-build.yaml
vendored
@@ -8,18 +8,12 @@ on:
|
|||||||
types: [published]
|
types: [published]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-amd64:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
service: [backend, app]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
with:
|
with:
|
||||||
@@ -36,38 +30,109 @@ jobs:
|
|||||||
id: version
|
id: version
|
||||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Build and push Docker image for ${{ matrix.service }}
|
- name: Build and push AMD64 Docker image
|
||||||
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||||
run: |
|
run: |
|
||||||
docker buildx create --use
|
DOCKERFILE=app.dockerfile
|
||||||
if [[ "${{ matrix.service }}" == "backend" ]]; then \
|
IMAGE_NAME=perplexica
|
||||||
DOCKERFILE=backend.dockerfile; \
|
docker buildx build --platform linux/amd64 \
|
||||||
IMAGE_NAME=perplexica-backend; \
|
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:amd64 \
|
||||||
else \
|
|
||||||
DOCKERFILE=app.dockerfile; \
|
|
||||||
IMAGE_NAME=perplexica-frontend; \
|
|
||||||
fi
|
|
||||||
docker buildx build --platform linux/amd64,linux/arm64 \
|
|
||||||
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:main \
|
|
||||||
--cache-to=type=inline \
|
--cache-to=type=inline \
|
||||||
|
--provenance false \
|
||||||
-f $DOCKERFILE \
|
-f $DOCKERFILE \
|
||||||
-t itzcrazykns1337/${IMAGE_NAME}:main \
|
-t itzcrazykns1337/${IMAGE_NAME}:amd64 \
|
||||||
--push .
|
--push .
|
||||||
|
|
||||||
- name: Build and push release Docker image for ${{ matrix.service }}
|
- name: Build and push AMD64 release Docker image
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
run: |
|
run: |
|
||||||
docker buildx create --use
|
DOCKERFILE=app.dockerfile
|
||||||
if [[ "${{ matrix.service }}" == "backend" ]]; then \
|
IMAGE_NAME=perplexica
|
||||||
DOCKERFILE=backend.dockerfile; \
|
docker buildx build --platform linux/amd64 \
|
||||||
IMAGE_NAME=perplexica-backend; \
|
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-amd64 \
|
||||||
else \
|
|
||||||
DOCKERFILE=app.dockerfile; \
|
|
||||||
IMAGE_NAME=perplexica-frontend; \
|
|
||||||
fi
|
|
||||||
docker buildx build --platform linux/amd64,linux/arm64 \
|
|
||||||
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }} \
|
|
||||||
--cache-to=type=inline \
|
--cache-to=type=inline \
|
||||||
|
--provenance false \
|
||||||
-f $DOCKERFILE \
|
-f $DOCKERFILE \
|
||||||
-t itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }} \
|
-t itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-amd64 \
|
||||||
--push .
|
--push .
|
||||||
|
|
||||||
|
build-arm64:
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
with:
|
||||||
|
install: true
|
||||||
|
|
||||||
|
- name: Log in to DockerHub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Extract version from release tag
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
id: version
|
||||||
|
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Build and push ARM64 Docker image
|
||||||
|
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||||
|
run: |
|
||||||
|
DOCKERFILE=app.dockerfile
|
||||||
|
IMAGE_NAME=perplexica
|
||||||
|
docker buildx build --platform linux/arm64 \
|
||||||
|
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:arm64 \
|
||||||
|
--cache-to=type=inline \
|
||||||
|
--provenance false \
|
||||||
|
-f $DOCKERFILE \
|
||||||
|
-t itzcrazykns1337/${IMAGE_NAME}:arm64 \
|
||||||
|
--push .
|
||||||
|
|
||||||
|
- name: Build and push ARM64 release Docker image
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
run: |
|
||||||
|
DOCKERFILE=app.dockerfile
|
||||||
|
IMAGE_NAME=perplexica
|
||||||
|
docker buildx build --platform linux/arm64 \
|
||||||
|
--cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-arm64 \
|
||||||
|
--cache-to=type=inline \
|
||||||
|
--provenance false \
|
||||||
|
-f $DOCKERFILE \
|
||||||
|
-t itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-arm64 \
|
||||||
|
--push .
|
||||||
|
|
||||||
|
manifest:
|
||||||
|
needs: [build-amd64, build-arm64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Log in to DockerHub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Extract version from release tag
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
id: version
|
||||||
|
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Create and push multi-arch manifest for main
|
||||||
|
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||||
|
run: |
|
||||||
|
IMAGE_NAME=perplexica
|
||||||
|
docker manifest create itzcrazykns1337/${IMAGE_NAME}:main \
|
||||||
|
--amend itzcrazykns1337/${IMAGE_NAME}:amd64 \
|
||||||
|
--amend itzcrazykns1337/${IMAGE_NAME}:arm64
|
||||||
|
docker manifest push itzcrazykns1337/${IMAGE_NAME}:main
|
||||||
|
|
||||||
|
- name: Create and push multi-arch manifest for releases
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
run: |
|
||||||
|
IMAGE_NAME=perplexica
|
||||||
|
docker manifest create itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }} \
|
||||||
|
--amend itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-amd64 \
|
||||||
|
--amend itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-arm64
|
||||||
|
docker manifest push itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}
|
||||||
|
6
.gitignore
vendored
@@ -4,9 +4,9 @@ npm-debug.log
|
|||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
|
||||||
# Build output
|
# Build output
|
||||||
/.next/
|
.next/
|
||||||
/out/
|
out/
|
||||||
/dist/
|
dist/
|
||||||
|
|
||||||
# IDE/Editor specific
|
# IDE/Editor specific
|
||||||
.vscode/
|
.vscode/
|
||||||
|
@@ -6,7 +6,6 @@ const config = {
|
|||||||
endOfLine: 'auto',
|
endOfLine: 'auto',
|
||||||
singleQuote: true,
|
singleQuote: true,
|
||||||
tabWidth: 2,
|
tabWidth: 2,
|
||||||
semi: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
@@ -1,32 +1,43 @@
|
|||||||
# How to Contribute to Perplexica
|
# How to Contribute to Perplexica
|
||||||
|
|
||||||
Hey there, thanks for deciding to contribute to Perplexica. Anything you help with will support the development of Perplexica and will make it better. Let's walk you through the key aspects to ensure your contributions are effective and in harmony with the project's setup.
|
Thanks for your interest in contributing to Perplexica! Your help makes this project better. This guide explains how to contribute effectively.
|
||||||
|
|
||||||
|
Perplexica is a modern AI chat application with advanced search capabilities.
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
Perplexica's design consists of two main domains:
|
Perplexica's codebase is organized as follows:
|
||||||
|
|
||||||
- **Frontend (`ui` directory)**: This is a Next.js application holding all user interface components. It's a self-contained environment that manages everything the user interacts with.
|
- **UI Components and Pages**:
|
||||||
- **Backend (root and `src` directory)**: The backend logic is situated in the `src` folder, but the root directory holds the main `package.json` for backend dependency management.
|
- **Components (`src/components`)**: Reusable UI components.
|
||||||
- All of the focus modes are created using the Meta Search Agent class present in `src/search/metaSearchAgent.ts`. The main logic behind Perplexica lies there.
|
- **Pages and Routes (`src/app`)**: Next.js app directory structure with page components.
|
||||||
|
- Main app routes include: home (`/`), chat (`/c`), discover (`/discover`), library (`/library`), and settings (`/settings`).
|
||||||
|
- **API Routes (`src/app/api`)**: API endpoints implemented with Next.js API routes.
|
||||||
|
- `/api/chat`: Handles chat interactions.
|
||||||
|
- `/api/search`: Provides direct access to Perplexica's search capabilities.
|
||||||
|
- Other endpoints for models, files, and suggestions.
|
||||||
|
- **Backend Logic (`src/lib`)**: Contains all the backend functionality including search, database, and API logic.
|
||||||
|
- The search functionality is present inside `src/lib/search` directory.
|
||||||
|
- All of the focus modes are implemented using the Meta Search Agent class in `src/lib/search/metaSearchAgent.ts`.
|
||||||
|
- Database functionality is in `src/lib/db`.
|
||||||
|
- Chat model and embedding model providers are managed in `src/lib/providers`.
|
||||||
|
- Prompt templates and LLM chain definitions are in `src/lib/prompts` and `src/lib/chains` respectively.
|
||||||
|
|
||||||
|
## API Documentation
|
||||||
|
|
||||||
|
Perplexica exposes several API endpoints for programmatic access, including:
|
||||||
|
|
||||||
|
- **Search API**: Access Perplexica's advanced search capabilities directly via the `/api/search` endpoint. For detailed documentation, see `docs/api/search.md`.
|
||||||
|
|
||||||
## Setting Up Your Environment
|
## Setting Up Your Environment
|
||||||
|
|
||||||
Before diving into coding, setting up your local environment is key. Here's what you need to do:
|
Before diving into coding, setting up your local environment is key. Here's what you need to do:
|
||||||
|
|
||||||
### Backend
|
|
||||||
|
|
||||||
1. In the root directory, locate the `sample.config.toml` file.
|
1. In the root directory, locate the `sample.config.toml` file.
|
||||||
2. Rename it to `config.toml` and fill in the necessary configuration fields specific to the backend.
|
2. Rename it to `config.toml` and fill in the necessary configuration fields.
|
||||||
3. Run `npm install` to install dependencies.
|
3. Run `npm install` to install all dependencies.
|
||||||
4. Run `npm run db:push` to set up the local sqlite.
|
4. Run `npm run db:push` to set up the local sqlite database.
|
||||||
5. Use `npm run dev` to start the backend in development mode.
|
5. Use `npm run dev` to start the application in development mode.
|
||||||
|
|
||||||
### Frontend
|
|
||||||
|
|
||||||
1. Navigate to the `ui` folder and repeat the process of renaming `.env.example` to `.env`, making sure to provide the frontend-specific variables.
|
|
||||||
2. Execute `npm install` within the `ui` directory to get the frontend dependencies ready.
|
|
||||||
3. Launch the frontend development server with `npm run dev`.
|
|
||||||
|
|
||||||
**Please note**: Docker configurations are present for setting up production environments, whereas `npm run dev` is used for development purposes.
|
**Please note**: Docker configurations are present for setting up production environments, whereas `npm run dev` is used for development purposes.
|
||||||
|
|
||||||
|
12
README.md
@@ -109,14 +109,13 @@ There are mainly 2 ways of installing Perplexica - With Docker, Without Docker.
|
|||||||
|
|
||||||
1. Install SearXNG and allow `JSON` format in the SearXNG settings.
|
1. Install SearXNG and allow `JSON` format in the SearXNG settings.
|
||||||
2. Clone the repository and rename the `sample.config.toml` file to `config.toml` in the root directory. Ensure you complete all required fields in this file.
|
2. Clone the repository and rename the `sample.config.toml` file to `config.toml` in the root directory. Ensure you complete all required fields in this file.
|
||||||
3. Rename the `.env.example` file to `.env` in the `ui` folder and fill in all necessary fields.
|
3. After populating the configuration run `npm i`.
|
||||||
4. After populating the configuration and environment files, run `npm i` in both the `ui` folder and the root directory.
|
4. Install the dependencies and then execute `npm run build`.
|
||||||
5. Install the dependencies and then execute `npm run build` in both the `ui` folder and the root directory.
|
5. Finally, start the app by running `npm rum start`
|
||||||
6. Finally, start both the frontend and the backend by running `npm run start` in both the `ui` folder and the root directory.
|
|
||||||
|
|
||||||
**Note**: Using Docker is recommended as it simplifies the setup process, especially for managing environment variables and dependencies.
|
**Note**: Using Docker is recommended as it simplifies the setup process, especially for managing environment variables and dependencies.
|
||||||
|
|
||||||
See the [installation documentation](https://github.com/ItzCrazyKns/Perplexica/tree/master/docs/installation) for more information like exposing it your network, etc.
|
See the [installation documentation](https://github.com/ItzCrazyKns/Perplexica/tree/master/docs/installation) for more information like updating, etc.
|
||||||
|
|
||||||
### Ollama Connection Errors
|
### Ollama Connection Errors
|
||||||
|
|
||||||
@@ -154,12 +153,13 @@ For more details, check out the full documentation [here](https://github.com/Itz
|
|||||||
|
|
||||||
## Expose Perplexica to network
|
## Expose Perplexica to network
|
||||||
|
|
||||||
You can access Perplexica over your home network by following our networking guide [here](https://github.com/ItzCrazyKns/Perplexica/blob/master/docs/installation/NETWORKING.md).
|
Perplexica runs on Next.js and handles all API requests. It works right away on the same network and stays accessible even with port forwarding.
|
||||||
|
|
||||||
## One-Click Deployment
|
## One-Click Deployment
|
||||||
|
|
||||||
[](https://usw.sealos.io/?openapp=system-template%3FtemplateName%3Dperplexica)
|
[](https://usw.sealos.io/?openapp=system-template%3FtemplateName%3Dperplexica)
|
||||||
[](https://repocloud.io/details/?app_id=267)
|
[](https://repocloud.io/details/?app_id=267)
|
||||||
|
[](https://template.run.claw.cloud/?referralCode=U11MRQ8U9RM4&openapp=system-fastdeploy%3FtemplateName%3Dperplexica)
|
||||||
|
|
||||||
## Upcoming Features
|
## Upcoming Features
|
||||||
|
|
||||||
|
@@ -1,15 +1,35 @@
|
|||||||
FROM node:20.18.0-alpine
|
FROM node:20.18.0-slim AS builder
|
||||||
|
|
||||||
ARG NEXT_PUBLIC_WS_URL=ws://127.0.0.1:3001
|
|
||||||
ARG NEXT_PUBLIC_API_URL=http://127.0.0.1:3001/api
|
|
||||||
ENV NEXT_PUBLIC_WS_URL=${NEXT_PUBLIC_WS_URL}
|
|
||||||
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
|
||||||
|
|
||||||
WORKDIR /home/perplexica
|
WORKDIR /home/perplexica
|
||||||
|
|
||||||
COPY ui /home/perplexica/
|
COPY package.json yarn.lock ./
|
||||||
|
RUN yarn install --frozen-lockfile --network-timeout 600000
|
||||||
|
|
||||||
RUN yarn install --frozen-lockfile
|
COPY tsconfig.json next.config.mjs next-env.d.ts postcss.config.js drizzle.config.ts tailwind.config.ts ./
|
||||||
|
COPY src ./src
|
||||||
|
COPY public ./public
|
||||||
|
|
||||||
|
RUN mkdir -p /home/perplexica/data
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
CMD ["yarn", "start"]
|
RUN yarn add --dev @vercel/ncc
|
||||||
|
RUN yarn ncc build ./src/lib/db/migrate.ts -o migrator
|
||||||
|
|
||||||
|
FROM node:20.18.0-slim
|
||||||
|
|
||||||
|
WORKDIR /home/perplexica
|
||||||
|
|
||||||
|
COPY --from=builder /home/perplexica/public ./public
|
||||||
|
COPY --from=builder /home/perplexica/.next/static ./public/_next/static
|
||||||
|
|
||||||
|
COPY --from=builder /home/perplexica/.next/standalone ./
|
||||||
|
COPY --from=builder /home/perplexica/data ./data
|
||||||
|
COPY drizzle ./drizzle
|
||||||
|
COPY --from=builder /home/perplexica/migrator/build ./build
|
||||||
|
COPY --from=builder /home/perplexica/migrator/index.js ./migrate.js
|
||||||
|
|
||||||
|
RUN mkdir /home/perplexica/uploads
|
||||||
|
|
||||||
|
COPY entrypoint.sh ./entrypoint.sh
|
||||||
|
RUN chmod +x ./entrypoint.sh
|
||||||
|
CMD ["./entrypoint.sh"]
|
@@ -1,17 +0,0 @@
|
|||||||
FROM node:18-slim
|
|
||||||
|
|
||||||
WORKDIR /home/perplexica
|
|
||||||
|
|
||||||
COPY src /home/perplexica/src
|
|
||||||
COPY tsconfig.json /home/perplexica/
|
|
||||||
COPY drizzle.config.ts /home/perplexica/
|
|
||||||
COPY package.json /home/perplexica/
|
|
||||||
COPY yarn.lock /home/perplexica/
|
|
||||||
|
|
||||||
RUN mkdir /home/perplexica/data
|
|
||||||
RUN mkdir /home/perplexica/uploads
|
|
||||||
|
|
||||||
RUN yarn install --frozen-lockfile --network-timeout 600000
|
|
||||||
RUN yarn build
|
|
||||||
|
|
||||||
CMD ["yarn", "start"]
|
|
@@ -9,41 +9,22 @@ services:
|
|||||||
- perplexica-network
|
- perplexica-network
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
perplexica-backend:
|
app:
|
||||||
build:
|
image: itzcrazykns1337/perplexica:main
|
||||||
context: .
|
|
||||||
dockerfile: backend.dockerfile
|
|
||||||
image: itzcrazykns1337/perplexica-backend:main
|
|
||||||
environment:
|
|
||||||
- SEARXNG_API_URL=http://searxng:8080
|
|
||||||
depends_on:
|
|
||||||
- searxng
|
|
||||||
ports:
|
|
||||||
- 3001:3001
|
|
||||||
volumes:
|
|
||||||
- backend-dbstore:/home/perplexica/data
|
|
||||||
- uploads:/home/perplexica/uploads
|
|
||||||
- ./config.toml:/home/perplexica/config.toml
|
|
||||||
extra_hosts:
|
|
||||||
- 'host.docker.internal:host-gateway'
|
|
||||||
networks:
|
|
||||||
- perplexica-network
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
perplexica-frontend:
|
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: app.dockerfile
|
dockerfile: app.dockerfile
|
||||||
args:
|
environment:
|
||||||
- NEXT_PUBLIC_API_URL=http://127.0.0.1:3001/api
|
- SEARXNG_API_URL=http://searxng:8080
|
||||||
- NEXT_PUBLIC_WS_URL=ws://127.0.0.1:3001
|
- DATA_DIR=/home/perplexica
|
||||||
image: itzcrazykns1337/perplexica-frontend:main
|
|
||||||
depends_on:
|
|
||||||
- perplexica-backend
|
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
networks:
|
networks:
|
||||||
- perplexica-network
|
- perplexica-network
|
||||||
|
volumes:
|
||||||
|
- backend-dbstore:/home/perplexica/data
|
||||||
|
- uploads:/home/perplexica/uploads
|
||||||
|
- ./config.toml:/home/perplexica/config.toml
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
|
@@ -6,9 +6,9 @@ Perplexica’s Search API makes it easy to use our AI-powered search engine. You
|
|||||||
|
|
||||||
## Endpoint
|
## Endpoint
|
||||||
|
|
||||||
### **POST** `http://localhost:3001/api/search`
|
### **POST** `http://localhost:3000/api/search`
|
||||||
|
|
||||||
**Note**: Replace `3001` with any other port if you've changed the default PORT
|
**Note**: Replace `3000` with any other port if you've changed the default PORT
|
||||||
|
|
||||||
### Request
|
### Request
|
||||||
|
|
||||||
@@ -20,11 +20,11 @@ The API accepts a JSON object in the request body, where you define the focus mo
|
|||||||
{
|
{
|
||||||
"chatModel": {
|
"chatModel": {
|
||||||
"provider": "openai",
|
"provider": "openai",
|
||||||
"model": "gpt-4o-mini"
|
"name": "gpt-4o-mini"
|
||||||
},
|
},
|
||||||
"embeddingModel": {
|
"embeddingModel": {
|
||||||
"provider": "openai",
|
"provider": "openai",
|
||||||
"model": "text-embedding-3-large"
|
"name": "text-embedding-3-large"
|
||||||
},
|
},
|
||||||
"optimizationMode": "speed",
|
"optimizationMode": "speed",
|
||||||
"focusMode": "webSearch",
|
"focusMode": "webSearch",
|
||||||
@@ -32,24 +32,26 @@ The API accepts a JSON object in the request body, where you define the focus mo
|
|||||||
"history": [
|
"history": [
|
||||||
["human", "Hi, how are you?"],
|
["human", "Hi, how are you?"],
|
||||||
["assistant", "I am doing well, how can I help you today?"]
|
["assistant", "I am doing well, how can I help you today?"]
|
||||||
]
|
],
|
||||||
|
"systemInstructions": "Focus on providing technical details about Perplexica's architecture.",
|
||||||
|
"stream": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Request Parameters
|
### Request Parameters
|
||||||
|
|
||||||
- **`chatModel`** (object, optional): Defines the chat model to be used for the query. For model details you can send a GET request at `http://localhost:3001/api/models`. Make sure to use the key value (For example "gpt-4o-mini" instead of the display name "GPT 4 omni mini").
|
- **`chatModel`** (object, optional): Defines the chat model to be used for the query. For model details you can send a GET request at `http://localhost:3000/api/models`. Make sure to use the key value (For example "gpt-4o-mini" instead of the display name "GPT 4 omni mini").
|
||||||
|
|
||||||
- `provider`: Specifies the provider for the chat model (e.g., `openai`, `ollama`).
|
- `provider`: Specifies the provider for the chat model (e.g., `openai`, `ollama`).
|
||||||
- `model`: The specific model from the chosen provider (e.g., `gpt-4o-mini`).
|
- `name`: The specific model from the chosen provider (e.g., `gpt-4o-mini`).
|
||||||
- Optional fields for custom OpenAI configuration:
|
- Optional fields for custom OpenAI configuration:
|
||||||
- `customOpenAIBaseURL`: If you’re using a custom OpenAI instance, provide the base URL.
|
- `customOpenAIBaseURL`: If you’re using a custom OpenAI instance, provide the base URL.
|
||||||
- `customOpenAIKey`: The API key for a custom OpenAI instance.
|
- `customOpenAIKey`: The API key for a custom OpenAI instance.
|
||||||
|
|
||||||
- **`embeddingModel`** (object, optional): Defines the embedding model for similarity-based searching. For model details you can send a GET request at `http://localhost:3001/api/models`. Make sure to use the key value (For example "text-embedding-3-large" instead of the display name "Text Embedding 3 Large").
|
- **`embeddingModel`** (object, optional): Defines the embedding model for similarity-based searching. For model details you can send a GET request at `http://localhost:3000/api/models`. Make sure to use the key value (For example "text-embedding-3-large" instead of the display name "Text Embedding 3 Large").
|
||||||
|
|
||||||
- `provider`: The provider for the embedding model (e.g., `openai`).
|
- `provider`: The provider for the embedding model (e.g., `openai`).
|
||||||
- `model`: The specific embedding model (e.g., `text-embedding-3-large`).
|
- `name`: The specific embedding model (e.g., `text-embedding-3-large`).
|
||||||
|
|
||||||
- **`focusMode`** (string, required): Specifies which focus mode to use. Available modes:
|
- **`focusMode`** (string, required): Specifies which focus mode to use. Available modes:
|
||||||
|
|
||||||
@@ -62,6 +64,8 @@ The API accepts a JSON object in the request body, where you define the focus mo
|
|||||||
|
|
||||||
- **`query`** (string, required): The search query or question.
|
- **`query`** (string, required): The search query or question.
|
||||||
|
|
||||||
|
- **`systemInstructions`** (string, optional): Custom instructions provided by the user to guide the AI's response. These instructions are treated as user preferences and have lower priority than the system's core instructions. For example, you can specify a particular writing style, format, or focus area.
|
||||||
|
|
||||||
- **`history`** (array, optional): An array of message pairs representing the conversation history. Each pair consists of a role (either 'human' or 'assistant') and the message content. This allows the system to use the context of the conversation to refine results. Example:
|
- **`history`** (array, optional): An array of message pairs representing the conversation history. Each pair consists of a role (either 'human' or 'assistant') and the message content. This allows the system to use the context of the conversation to refine results. Example:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -71,11 +75,13 @@ The API accepts a JSON object in the request body, where you define the focus mo
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- **`stream`** (boolean, optional): When set to `true`, enables streaming responses. Default is `false`.
|
||||||
|
|
||||||
### Response
|
### Response
|
||||||
|
|
||||||
The response from the API includes both the final message and the sources used to generate that message.
|
The response from the API includes both the final message and the sources used to generate that message.
|
||||||
|
|
||||||
#### Example Response
|
#### Standard Response (stream: false)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -100,6 +106,28 @@ The response from the API includes both the final message and the sources used t
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Streaming Response (stream: true)
|
||||||
|
|
||||||
|
When streaming is enabled, the API returns a stream of newline-delimited JSON objects. Each line contains a complete, valid JSON object. The response has Content-Type: application/json.
|
||||||
|
|
||||||
|
Example of streamed response objects:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"type":"init","data":"Stream connected"}
|
||||||
|
{"type":"sources","data":[{"pageContent":"...","metadata":{"title":"...","url":"..."}},...]}
|
||||||
|
{"type":"response","data":"Perplexica is an "}
|
||||||
|
{"type":"response","data":"innovative, open-source "}
|
||||||
|
{"type":"response","data":"AI-powered search engine..."}
|
||||||
|
{"type":"done"}
|
||||||
|
```
|
||||||
|
|
||||||
|
Clients should process each line as a separate JSON object. The different message types include:
|
||||||
|
|
||||||
|
- **`init`**: Initial connection message
|
||||||
|
- **`sources`**: All sources used for the response
|
||||||
|
- **`response`**: Chunks of the generated answer text
|
||||||
|
- **`done`**: Indicates the stream is complete
|
||||||
|
|
||||||
### Fields in the Response
|
### Fields in the Response
|
||||||
|
|
||||||
- **`message`** (string): The search result, generated based on the query and focus mode.
|
- **`message`** (string): The search result, generated based on the query and focus mode.
|
||||||
|
@@ -4,7 +4,7 @@ Curious about how Perplexica works? Don't worry, we'll cover it here. Before we
|
|||||||
|
|
||||||
We'll understand how Perplexica works by taking an example of a scenario where a user asks: "How does an A.C. work?". We'll break down the process into steps to make it easier to understand. The steps are as follows:
|
We'll understand how Perplexica works by taking an example of a scenario where a user asks: "How does an A.C. work?". We'll break down the process into steps to make it easier to understand. The steps are as follows:
|
||||||
|
|
||||||
1. The message is sent via WS to the backend server where it invokes the chain. The chain will depend on your focus mode. For this example, let's assume we use the "webSearch" focus mode.
|
1. The message is sent to the `/api/chat` route where it invokes the chain. The chain will depend on your focus mode. For this example, let's assume we use the "webSearch" focus mode.
|
||||||
2. The chain is now invoked; first, the message is passed to another chain where it first predicts (using the chat history and the question) whether there is a need for sources and searching the web. If there is, it will generate a query (in accordance with the chat history) for searching the web that we'll take up later. If not, the chain will end there, and then the answer generator chain, also known as the response generator, will be started.
|
2. The chain is now invoked; first, the message is passed to another chain where it first predicts (using the chat history and the question) whether there is a need for sources and searching the web. If there is, it will generate a query (in accordance with the chat history) for searching the web that we'll take up later. If not, the chain will end there, and then the answer generator chain, also known as the response generator, will be started.
|
||||||
3. The query returned by the first chain is passed to SearXNG to search the web for information.
|
3. The query returned by the first chain is passed to SearXNG to search the web for information.
|
||||||
4. After the information is retrieved, it is based on keyword-based search. We then convert the information into embeddings and the query as well, then we perform a similarity search to find the most relevant sources to answer the query.
|
4. After the information is retrieved, it is based on keyword-based search. We then convert the information into embeddings and the query as well, then we perform a similarity search to find the most relevant sources to answer the query.
|
||||||
|
@@ -1,109 +0,0 @@
|
|||||||
# Expose Perplexica to a network
|
|
||||||
|
|
||||||
This guide will show you how to make Perplexica available over a network. Follow these steps to allow computers on the same network to interact with Perplexica. Choose the instructions that match the operating system you are using.
|
|
||||||
|
|
||||||
## Windows
|
|
||||||
|
|
||||||
1. Open PowerShell as Administrator
|
|
||||||
|
|
||||||
2. Navigate to the directory containing the `docker-compose.yaml` file
|
|
||||||
|
|
||||||
3. Stop and remove the existing Perplexica containers and images:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose down --rmi all
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Open the `docker-compose.yaml` file in a text editor like Notepad++
|
|
||||||
|
|
||||||
5. Replace `127.0.0.1` with the IP address of the server Perplexica is running on in these two lines:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
args:
|
|
||||||
- NEXT_PUBLIC_API_URL=http://127.0.0.1:3001/api
|
|
||||||
- NEXT_PUBLIC_WS_URL=ws://127.0.0.1:3001
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Save and close the `docker-compose.yaml` file
|
|
||||||
|
|
||||||
7. Rebuild and restart the Perplexica container:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d --build
|
|
||||||
```
|
|
||||||
|
|
||||||
## macOS
|
|
||||||
|
|
||||||
1. Open the Terminal application
|
|
||||||
|
|
||||||
2. Navigate to the directory with the `docker-compose.yaml` file:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /path/to/docker-compose.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Stop and remove existing containers and images:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose down --rmi all
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Open `docker-compose.yaml` in a text editor like Sublime Text:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nano docker-compose.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Replace `127.0.0.1` with the server IP in these lines:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
args:
|
|
||||||
- NEXT_PUBLIC_API_URL=http://127.0.0.1:3001/api
|
|
||||||
- NEXT_PUBLIC_WS_URL=ws://127.0.0.1:3001
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Save and exit the editor
|
|
||||||
|
|
||||||
7. Rebuild and restart Perplexica:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d --build
|
|
||||||
```
|
|
||||||
|
|
||||||
## Linux
|
|
||||||
|
|
||||||
1. Open the terminal
|
|
||||||
|
|
||||||
2. Navigate to the `docker-compose.yaml` directory:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /path/to/docker-compose.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Stop and remove containers and images:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose down --rmi all
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Edit `docker-compose.yaml`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nano docker-compose.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Replace `127.0.0.1` with the server IP:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
args:
|
|
||||||
- NEXT_PUBLIC_API_URL=http://127.0.0.1:3001/api
|
|
||||||
- NEXT_PUBLIC_WS_URL=ws://127.0.0.1:3001
|
|
||||||
```
|
|
||||||
|
|
||||||
6. Save and exit the editor
|
|
||||||
|
|
||||||
7. Rebuild and restart Perplexica:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d --build
|
|
||||||
```
|
|
@@ -39,11 +39,8 @@ To update Perplexica to the latest version, follow these steps:
|
|||||||
2. Navigate to the project directory.
|
2. Navigate to the project directory.
|
||||||
|
|
||||||
3. Check for changes in the configuration files. If the `sample.config.toml` file contains new fields, delete your existing `config.toml` file, rename `sample.config.toml` to `config.toml`, and update the configuration accordingly.
|
3. Check for changes in the configuration files. If the `sample.config.toml` file contains new fields, delete your existing `config.toml` file, rename `sample.config.toml` to `config.toml`, and update the configuration accordingly.
|
||||||
|
4. After populating the configuration run `npm i`.
|
||||||
4. Execute `npm i` in both the `ui` folder and the root directory.
|
5. Install the dependencies and then execute `npm run build`.
|
||||||
|
6. Finally, start the app by running `npm rum start`
|
||||||
5. Once the packages are updated, execute `npm run build` in both the `ui` folder and the root directory.
|
|
||||||
|
|
||||||
6. Finally, start both the frontend and the backend by running `npm run start` in both the `ui` folder and the root directory.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
import { defineConfig } from 'drizzle-kit';
|
import { defineConfig } from 'drizzle-kit';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
dialect: 'sqlite',
|
dialect: 'sqlite',
|
||||||
schema: './src/db/schema.ts',
|
schema: './src/lib/db/schema.ts',
|
||||||
out: './drizzle',
|
out: './drizzle',
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
url: './data/db.sqlite',
|
url: path.join(process.cwd(), 'data', 'db.sqlite'),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
16
drizzle/0000_fuzzy_randall.sql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `chats` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`title` text NOT NULL,
|
||||||
|
`createdAt` text NOT NULL,
|
||||||
|
`focusMode` text NOT NULL,
|
||||||
|
`files` text DEFAULT '[]'
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS `messages` (
|
||||||
|
`id` integer PRIMARY KEY NOT NULL,
|
||||||
|
`content` text NOT NULL,
|
||||||
|
`chatId` text NOT NULL,
|
||||||
|
`messageId` text NOT NULL,
|
||||||
|
`type` text,
|
||||||
|
`metadata` text
|
||||||
|
);
|
116
drizzle/meta/0000_snapshot.json
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"version": "6",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"id": "ef3a044b-0f34-40b5-babb-2bb3a909ba27",
|
||||||
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"tables": {
|
||||||
|
"chats": {
|
||||||
|
"name": "chats",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"focusMode": {
|
||||||
|
"name": "focusMode",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"name": "files",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'[]'"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"messages": {
|
||||||
|
"name": "messages",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"name": "content",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"chatId": {
|
||||||
|
"name": "chatId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"messageId": {
|
||||||
|
"name": "messageId",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "metadata",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"views": {},
|
||||||
|
"enums": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"indexes": {}
|
||||||
|
}
|
||||||
|
}
|
13
drizzle/meta/_journal.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1748405503809,
|
||||||
|
"tag": "0000_fuzzy_randall",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
6
entrypoint.sh
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
node migrate.js
|
||||||
|
|
||||||
|
exec node server.js
|
5
next-env.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
@@ -1,5 +1,6 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
|
output: 'standalone',
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
@@ -7,6 +8,7 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
serverExternalPackages: ['pdf-parse'],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
89
package.json
@@ -1,53 +1,68 @@
|
|||||||
{
|
{
|
||||||
"name": "perplexica-backend",
|
"name": "perplexica-frontend",
|
||||||
"version": "1.10.0-rc3",
|
"version": "1.11.0-rc1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "ItzCrazyKns",
|
"author": "ItzCrazyKns",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npm run db:push && node dist/app.js",
|
"dev": "next dev",
|
||||||
"build": "tsc",
|
"build": "npm run db:push && next build",
|
||||||
"dev": "nodemon --ignore uploads/ src/app.ts ",
|
"start": "next start",
|
||||||
"db:push": "drizzle-kit push sqlite",
|
"lint": "next lint",
|
||||||
"format": "prettier . --check",
|
"format:write": "prettier . --write",
|
||||||
"format:write": "prettier . --write"
|
"db:push": "drizzle-kit push"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/better-sqlite3": "^7.6.10",
|
|
||||||
"@types/cors": "^2.8.17",
|
|
||||||
"@types/express": "^4.17.21",
|
|
||||||
"@types/html-to-text": "^9.0.4",
|
|
||||||
"@types/multer": "^1.4.12",
|
|
||||||
"@types/pdf-parse": "^1.1.4",
|
|
||||||
"@types/readable-stream": "^4.0.11",
|
|
||||||
"@types/ws": "^8.5.12",
|
|
||||||
"drizzle-kit": "^0.22.7",
|
|
||||||
"nodemon": "^3.1.0",
|
|
||||||
"prettier": "^3.2.5",
|
|
||||||
"ts-node": "^10.9.2",
|
|
||||||
"typescript": "^5.4.3"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@headlessui/react": "^2.2.0",
|
||||||
"@iarna/toml": "^2.2.5",
|
"@iarna/toml": "^2.2.5",
|
||||||
"@langchain/anthropic": "^0.2.3",
|
"@icons-pack/react-simple-icons": "^12.3.0",
|
||||||
"@langchain/community": "^0.2.16",
|
"@langchain/anthropic": "^0.3.15",
|
||||||
|
"@langchain/community": "^0.3.36",
|
||||||
|
"@langchain/core": "^0.3.42",
|
||||||
|
"@langchain/google-genai": "^0.1.12",
|
||||||
"@langchain/openai": "^0.0.25",
|
"@langchain/openai": "^0.0.25",
|
||||||
"@langchain/google-genai": "^0.0.23",
|
"@langchain/textsplitters": "^0.1.0",
|
||||||
"@xenova/transformers": "^2.17.1",
|
"@tailwindcss/typography": "^0.5.12",
|
||||||
"axios": "^1.6.8",
|
"@xenova/transformers": "^2.17.2",
|
||||||
"better-sqlite3": "^11.0.0",
|
"axios": "^1.8.3",
|
||||||
|
"better-sqlite3": "^11.9.1",
|
||||||
|
"clsx": "^2.1.0",
|
||||||
"compute-cosine-similarity": "^1.1.0",
|
"compute-cosine-similarity": "^1.1.0",
|
||||||
"compute-dot": "^1.1.0",
|
"compute-dot": "^1.1.0",
|
||||||
"cors": "^2.8.5",
|
"drizzle-orm": "^0.40.1",
|
||||||
"dotenv": "^16.4.5",
|
|
||||||
"drizzle-orm": "^0.31.2",
|
|
||||||
"express": "^4.19.2",
|
|
||||||
"html-to-text": "^9.0.5",
|
"html-to-text": "^9.0.5",
|
||||||
|
"jspdf": "^3.0.1",
|
||||||
"langchain": "^0.1.30",
|
"langchain": "^0.1.30",
|
||||||
"mammoth": "^1.8.0",
|
"lucide-react": "^0.363.0",
|
||||||
"multer": "^1.4.5-lts.1",
|
"mammoth": "^1.9.1",
|
||||||
|
"markdown-to-jsx": "^7.7.2",
|
||||||
|
"next": "^15.2.2",
|
||||||
|
"next-themes": "^0.3.0",
|
||||||
"pdf-parse": "^1.1.1",
|
"pdf-parse": "^1.1.1",
|
||||||
"winston": "^3.13.0",
|
"react": "^18",
|
||||||
"ws": "^8.17.1",
|
"react-dom": "^18",
|
||||||
|
"react-text-to-speech": "^0.14.5",
|
||||||
|
"react-textarea-autosize": "^8.5.3",
|
||||||
|
"sonner": "^1.4.41",
|
||||||
|
"tailwind-merge": "^2.2.2",
|
||||||
|
"winston": "^3.17.0",
|
||||||
|
"yet-another-react-lightbox": "^3.17.2",
|
||||||
"zod": "^3.22.4"
|
"zod": "^3.22.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/better-sqlite3": "^7.6.12",
|
||||||
|
"@types/html-to-text": "^9.0.4",
|
||||||
|
"@types/jspdf": "^2.0.0",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/pdf-parse": "^1.1.4",
|
||||||
|
"@types/react": "^18",
|
||||||
|
"@types/react-dom": "^18",
|
||||||
|
"autoprefixer": "^10.0.1",
|
||||||
|
"drizzle-kit": "^0.30.5",
|
||||||
|
"eslint": "^8",
|
||||||
|
"eslint-config-next": "14.1.4",
|
||||||
|
"postcss": "^8",
|
||||||
|
"prettier": "^3.2.5",
|
||||||
|
"tailwindcss": "^3.3.0",
|
||||||
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 629 B After Width: | Height: | Size: 629 B |
131
public/weather-ico/clear-day.svg
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.34167" y="-.34167" width="1.6833" height="1.85">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-sun-shiny {
|
||||||
|
0% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
stroke-dasharray: 0.1px 10px;
|
||||||
|
stroke-dashoffset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun-shiny line {
|
||||||
|
-webkit-animation-name: am-weather-sun-shiny;
|
||||||
|
-moz-animation-name: am-weather-sun-shiny;
|
||||||
|
-ms-animation-name: am-weather-sun-shiny;
|
||||||
|
animation-name: am-weather-sun-shiny;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun"
|
||||||
|
style="-moz-animation-duration:9s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-sun;-moz-animation-timing-function:linear;-ms-animation-duration:9s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-sun;-ms-animation-timing-function:linear;-webkit-animation-duration:9s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-sun;-webkit-animation-timing-function:linear">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round" stroke-width="2" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffa500" stroke="#ffa500" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.9 KiB |
159
public/weather-ico/clear-night.svg
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.3038" y="-.3318" width="1.6076" height="1.894">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="night" transform="translate(-4,-18)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .78534 36 20.022)" stroke-width="1.2616">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="4 2.7 5.2 3.3 4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5" fill="#ffa500" stroke-miterlimit="10"
|
||||||
|
stroke-width="1.4105" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="4 2.7 5.2 3.3 4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5"
|
||||||
|
fill="#ffa500" stroke-miterlimit="10" stroke-width="1.4105" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffa500" stroke="#ffa500" stroke-linejoin="round" stroke-width="2.5232" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.7 KiB |
178
public/weather-ico/cloudy-1-day.svg
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.28472" width="1.403" height="1.6944">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-sun-shiny {
|
||||||
|
0% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
stroke-dasharray: 0.1px 10px;
|
||||||
|
stroke-dashoffset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun-shiny line {
|
||||||
|
-webkit-animation-name: am-weather-sun-shiny;
|
||||||
|
-moz-animation-name: am-weather-sun-shiny;
|
||||||
|
-ms-animation-name: am-weather-sun-shiny;
|
||||||
|
animation-name: am-weather-sun-shiny;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun"
|
||||||
|
style="-moz-animation-duration:9s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-sun;-moz-animation-timing-function:linear;-ms-animation-duration:9s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-sun;-ms-animation-timing-function:linear;-webkit-animation-duration:9s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-sun;-webkit-animation-timing-function:linear">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round" stroke-width="2" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffa500" stroke="#ffa500" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-2"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#c6deff" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.8 KiB |
206
public/weather-ico/cloudy-1-night.svg
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.19471" y="-.26087" width="1.3744" height="1.6884">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3 4 4 3.3 5.2 2.7 4" fill="#ffa500"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3 4 4 3.3 5.2 2.7 4"
|
||||||
|
fill="#ffa500" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffa500" stroke="#ffa500" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-2"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#c6deff" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.6 KiB |
244
public/weather-ico/fog-day.svg
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.21122" width="1.403" height="1.4997">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** FOG
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-fog-1 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translate(7px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-fog-1 {
|
||||||
|
-webkit-animation-name: am-weather-fog-1;
|
||||||
|
-moz-animation-name: am-weather-fog-1;
|
||||||
|
-ms-animation-name: am-weather-fog-1;
|
||||||
|
animation-name: am-weather-fog-1;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-fog-2 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
21.05% {
|
||||||
|
transform: translate(-6px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
78.95% {
|
||||||
|
transform: translate(9px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-fog-2 {
|
||||||
|
-webkit-animation-name: am-weather-fog-2;
|
||||||
|
-moz-animation-name: am-weather-fog-2;
|
||||||
|
-ms-animation-name: am-weather-fog-2;
|
||||||
|
animation-name: am-weather-fog-2;
|
||||||
|
-webkit-animation-duration: 20s;
|
||||||
|
-moz-animation-duration: 20s;
|
||||||
|
-ms-animation-duration: 20s;
|
||||||
|
animation-duration: 20s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-fog-3 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
25% {
|
||||||
|
transform: translate(4px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
75% {
|
||||||
|
transform: translate(-4px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-fog-3 {
|
||||||
|
-webkit-animation-name: am-weather-fog-3;
|
||||||
|
-moz-animation-name: am-weather-fog-3;
|
||||||
|
-ms-animation-name: am-weather-fog-3;
|
||||||
|
animation-name: am-weather-fog-3;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-fog-4 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translate(-4px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-fog-4 {
|
||||||
|
-webkit-animation-name: am-weather-fog-4;
|
||||||
|
-moz-animation-name: am-weather-fog-4;
|
||||||
|
-ms-animation-name: am-weather-fog-4;
|
||||||
|
animation-name: am-weather-fog-4;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun" transform="translate(0,16)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round" stroke-width="2" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />F
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffc04a" stroke="#ffc04a" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-fog" transform="translate(-10,20)" fill="none" stroke="#c6deff" stroke-linecap="round"
|
||||||
|
stroke-width="2">
|
||||||
|
<line class="am-weather-fog-1" y1="0" y2="0" x1="1" x2="37" stroke-dasharray="3, 5, 17, 5, 7" />
|
||||||
|
<line class="am-weather-fog-2" y1="5" y2="5" x1="9" x2="33" stroke-dasharray="11, 7, 15" />
|
||||||
|
<line class="am-weather-fog-3" y1="10" y2="10" x1="5" x2="40" stroke-dasharray="11, 7, 3, 5, 9" />
|
||||||
|
<line class="am-weather-fog-4" y1="15" y2="15" x1="7" x2="42" stroke-dasharray="13, 5, 9, 5, 3" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.0 KiB |
309
public/weather-ico/fog-night.svg
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.21122" width="1.403" height="1.4997">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** FOG
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-fog-1 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translate(7px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-fog-1 {
|
||||||
|
-webkit-animation-name: am-weather-fog-1;
|
||||||
|
-moz-animation-name: am-weather-fog-1;
|
||||||
|
-ms-animation-name: am-weather-fog-1;
|
||||||
|
animation-name: am-weather-fog-1;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-fog-2 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
21.05% {
|
||||||
|
transform: translate(-6px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
78.95% {
|
||||||
|
transform: translate(9px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-fog-2 {
|
||||||
|
-webkit-animation-name: am-weather-fog-2;
|
||||||
|
-moz-animation-name: am-weather-fog-2;
|
||||||
|
-ms-animation-name: am-weather-fog-2;
|
||||||
|
animation-name: am-weather-fog-2;
|
||||||
|
-webkit-animation-duration: 20s;
|
||||||
|
-moz-animation-duration: 20s;
|
||||||
|
-ms-animation-duration: 20s;
|
||||||
|
animation-duration: 20s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-fog-3 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
25% {
|
||||||
|
transform: translate(4px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
75% {
|
||||||
|
transform: translate(-4px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-fog-3 {
|
||||||
|
-webkit-animation-name: am-weather-fog-3;
|
||||||
|
-moz-animation-name: am-weather-fog-3;
|
||||||
|
-ms-animation-name: am-weather-fog-3;
|
||||||
|
animation-name: am-weather-fog-3;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-fog-4 {
|
||||||
|
0% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: translate(-4px, 0px)
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translate(0px, 0px)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-fog-4 {
|
||||||
|
-webkit-animation-name: am-weather-fog-4;
|
||||||
|
-moz-animation-name: am-weather-fog-4;
|
||||||
|
-ms-animation-name: am-weather-fog-4;
|
||||||
|
animation-name: am-weather-fog-4;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3" fill="#ffc04a"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3"
|
||||||
|
fill="#ffc04a" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffc04a" stroke="#ffc04a" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-fog" transform="translate(-10,20)" fill="none" stroke="#c6deff" stroke-linecap="round"
|
||||||
|
stroke-width="2">
|
||||||
|
<line class="am-weather-fog-1" y1="0" y2="0" x1="1" x2="37" stroke-dasharray="3, 5, 17, 5, 7" />
|
||||||
|
<line class="am-weather-fog-2" y1="5" y2="5" x1="9" x2="33" stroke-dasharray="11, 7, 15" />
|
||||||
|
<line class="am-weather-fog-3" y1="10" y2="10" x1="5" x2="40" stroke-dasharray="11, 7, 3, 5, 9" />
|
||||||
|
<line class="am-weather-fog-4" y1="15" y2="15" x1="7" x2="42" stroke-dasharray="13, 5, 9, 5, 3" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
204
public/weather-ico/frost-day.svg
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.21122" width="1.403" height="1.4997">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** FROST
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-frost {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
1% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
3% {
|
||||||
|
-webkit-transform: translate(-0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(-0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(-0.3px, 0.0px);
|
||||||
|
transform: translate(-0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
5% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
7% {
|
||||||
|
-webkit-transform: translate(-0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(-0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(-0.3px, 0.0px);
|
||||||
|
transform: translate(-0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
9% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
11% {
|
||||||
|
-webkit-transform: translate(-0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(-0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(-0.3px, 0.0px);
|
||||||
|
transform: translate(-0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
13% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
15% {
|
||||||
|
-webkit-transform: translate(-0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(-0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(-0.3px, 0.0px);
|
||||||
|
transform: translate(-0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
16% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-frost {
|
||||||
|
-webkit-animation-name: am-weather-frost;
|
||||||
|
-moz-animation-name: am-weather-frost;
|
||||||
|
animation-name: am-weather-frost;
|
||||||
|
-webkit-animation-duration: 1.11s;
|
||||||
|
-moz-animation-duration: 1.11s;
|
||||||
|
animation-duration: 1.11s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun" transform="translate(0,16)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round" stroke-width="2" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />F
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffc04a" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffc04a" stroke="#ffc04a" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-16,4)">
|
||||||
|
<g class="am-weather-frost" stroke="#57a0ee" transform="translate(0,2)" fill="none" stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
style="-moz-animation-duration:1.11s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-frost;-moz-animation-timing-function:linear;-webkit-animation-duration:1.11s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-frost;-webkit-animation-timing-function:linear">
|
||||||
|
<path d="M11,32H45" />
|
||||||
|
<path d="M15.5,37H40.5" />
|
||||||
|
<path d="M22.5,42H33.5" />
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#57a0ee" transform="translate(0,0)" fill="none" stroke-width="2" stroke-linecap="round"
|
||||||
|
d="M28,31V9M28,22l11,-3.67M34,20l2,-4M34,20l4,2M28,22l-11,-3.67M22,20l-2,-4M22,20l-4,2M28,14.27l3.01,-3.02M28,14.27l-3.01,-3.02" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.3 KiB |
269
public/weather-ico/frost-night.svg
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.21122" width="1.403" height="1.4997">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** FROST
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-frost {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
1% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
3% {
|
||||||
|
-webkit-transform: translate(-0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(-0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(-0.3px, 0.0px);
|
||||||
|
transform: translate(-0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
5% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
7% {
|
||||||
|
-webkit-transform: translate(-0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(-0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(-0.3px, 0.0px);
|
||||||
|
transform: translate(-0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
9% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
11% {
|
||||||
|
-webkit-transform: translate(-0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(-0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(-0.3px, 0.0px);
|
||||||
|
transform: translate(-0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
13% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
15% {
|
||||||
|
-webkit-transform: translate(-0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(-0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(-0.3px, 0.0px);
|
||||||
|
transform: translate(-0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
16% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-frost {
|
||||||
|
-webkit-animation-name: am-weather-frost;
|
||||||
|
-moz-animation-name: am-weather-frost;
|
||||||
|
animation-name: am-weather-frost;
|
||||||
|
-webkit-animation-duration: 1.11s;
|
||||||
|
-moz-animation-duration: 1.11s;
|
||||||
|
animation-duration: 1.11s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3" fill="#ffc04a"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3"
|
||||||
|
fill="#ffc04a" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffc04a" stroke="#ffc04a" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-16,4)">
|
||||||
|
<g class="am-weather-frost" stroke="#57a0ee" transform="translate(0,2)" fill="none" stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
style="-moz-animation-duration:1.11s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-frost;-moz-animation-timing-function:linear;-webkit-animation-duration:1.11s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-frost;-webkit-animation-timing-function:linear">
|
||||||
|
<path d="M11,32H45" />
|
||||||
|
<path d="M15.5,37H40.5" />
|
||||||
|
<path d="M22.5,42H33.5" />
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path stroke="#57a0ee" transform="translate(0,0)" fill="none" stroke-width="2" stroke-linecap="round"
|
||||||
|
d="M28,31V9M28,22l11,-3.67M34,20l2,-4M34,20l4,2M28,22l-11,-3.67M22,20l-2,-4M22,20l-4,2M28,14.27l3.01,-3.02M28,14.27l-3.01,-3.02" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
141
public/weather-ico/rain-and-sleet-mix.svg
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<!-- Mix of Rain and Sleet | Contributed by hsoJ95 on GitHub: https://github.com/hsoj95 -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.24684" y="-.22776" width="1.4937" height="1.5756">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** RAIN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-rain {
|
||||||
|
0% {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: -100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-1 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-2 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-delay: 0.25s;
|
||||||
|
-moz-animation-delay: 0.25s;
|
||||||
|
-ms-animation-delay: 0.25s;
|
||||||
|
animation-delay: 0.25s;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-3 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-3 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-3;
|
||||||
|
-moz-animation-name: am-weather-cloud-3;
|
||||||
|
animation-name: am-weather-cloud-3;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-3;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-3;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-sleet-2" transform="translate(-20,-10) rotate(10,-247.39,200.17)" fill="none" stroke="#91c0f8"
|
||||||
|
stroke-linecap="round">
|
||||||
|
<line class="am-weather-rain-1" transform="translate(-5,1)" y2="8" stroke-dasharray="0.1, 7" stroke-width="2"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
<line class="am-weather-rain-1" transform="translate(5)" y2="8" stroke-dasharray="0.1, 7" stroke-width="2"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-rain-3" transform="translate(-20,-10) rotate(10,-245.89,217.31)" fill="none" stroke="#91c0f8"
|
||||||
|
stroke-dasharray="4, 7" stroke-linecap="round" stroke-width="2">
|
||||||
|
<line class="am-weather-rain-1" transform="translate(-13,1)" y2="8"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
<line class="am-weather-rain-1" transform="translate(-3,2)" y2="8"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
<line class="am-weather-rain-2" transform="translate(7,-1)" y2="8"
|
||||||
|
style="-moz-animation-delay:0.25s;-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-delay:0.25s;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-delay:0.25s;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.6 KiB |
179
public/weather-ico/rainy-1-day.svg
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.21122" width="1.403" height="1.4997">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** RAIN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-rain {
|
||||||
|
0% {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: -100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-1 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun"
|
||||||
|
style="-moz-animation-duration:9s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-sun;-moz-animation-timing-function:linear;-ms-animation-duration:9s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-sun;-ms-animation-timing-function:linear;-webkit-animation-duration:9s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-sun;-webkit-animation-timing-function:linear">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round" stroke-width="2" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffa500" stroke="#ffa500" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-rain-1" transform="translate(-20,-10) rotate(10,-238.68,233.96)">
|
||||||
|
<line class="am-weather-rain-1" transform="translate(-6,1)" y2="8" fill="none" stroke="#91c0f8"
|
||||||
|
stroke-dasharray="4, 7" stroke-linecap="round" stroke-width="2"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.4 KiB |
243
public/weather-ico/rainy-1-night.svg
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.21122" width="1.403" height="1.4997">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** RAIN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-rain {
|
||||||
|
0% {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: -100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-1 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3" fill="#ffa500"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3"
|
||||||
|
fill="#ffa500" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffa500" stroke="#ffa500" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weaher-rain-1" transform="translate(-20,-10) rotate(10,-238.68,233.96)">
|
||||||
|
<line class="am-weather-rain-1" transform="translate(-6,1)" y2="8" fill="none" stroke="#91c0f8"
|
||||||
|
stroke-dasharray="4, 7" stroke-linecap="round" stroke-width="2"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 10 KiB |
204
public/weather-ico/rainy-2-day.svg
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.20592" width="1.403" height="1.4872">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** RAIN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-rain {
|
||||||
|
0% {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: -100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-1 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-2 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-delay: 0.25s;
|
||||||
|
-moz-animation-delay: 0.25s;
|
||||||
|
-ms-animation-delay: 0.25s;
|
||||||
|
animation-delay: 0.25s;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun"
|
||||||
|
style="-moz-animation-duration:9s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-sun;-moz-animation-timing-function:linear;-ms-animation-duration:9s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-sun;-ms-animation-timing-function:linear;-webkit-animation-duration:9s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-sun;-webkit-animation-timing-function:linear">
|
||||||
|
<line transform="translate(0,9)" y2="3" stroke="#ffa500" stroke-linecap="round" stroke-width="2" fifll="none" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffa500" stroke="#ffa500" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-20,-10) rotate(10,-245.89,217.31)" fill="none" stroke="#91c0f8" stroke-dasharray="4, 7" stroke-linecap="round"
|
||||||
|
stroke-width="2">
|
||||||
|
<line class="am-weather-rain-1" transform="translate(-6,1)" y2="8"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
<line class="am-weather-rain-2" transform="translate(0,-1)" y2="8"
|
||||||
|
style="-moz-animation-delay:0.25s;-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-delay:0.25s;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-delay:0.25s;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.8 KiB |
256
public/weather-ico/rainy-2-night.svg
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** RAIN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-rain {
|
||||||
|
0% {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: -100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-1 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-2 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-delay: 0.25s;
|
||||||
|
-moz-animation-delay: 0.25s;
|
||||||
|
-ms-animation-delay: 0.25s;
|
||||||
|
animation-delay: 0.25s;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g class="layer" transform="translate(16,-2)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3" fill="#ffa500"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3"
|
||||||
|
fill="#ffa500" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffa500" stroke="#ffa500" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-rain-2" transform="translate(-20,-10) rotate(10,34,46)" fill="none" stroke="#91c0f8"
|
||||||
|
stroke-dasharray="4, 7" stroke-linecap="round" stroke-width="2">
|
||||||
|
<line class="am-weather-rain-1" transform="translate(-6,1)" x1="34" x2="34" y1="46" y2="54"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
<line class="am-weather-rain-2" transform="translate(0,-1)" x1="34" x2="34" y1="46" y2="54"
|
||||||
|
style="-moz-animation-delay:0.25s;-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-delay:0.25s;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-delay:0.25s;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
206
public/weather-ico/rainy-3-day.svg
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.24684" y="-.22892" width="1.4937" height="1.5576">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** RAIN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-rain {
|
||||||
|
0% {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: -100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-1 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-2 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-delay: 0.25s;
|
||||||
|
-moz-animation-delay: 0.25s;
|
||||||
|
-ms-animation-delay: 0.25s;
|
||||||
|
animation-delay: 0.25s;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun"
|
||||||
|
style="-moz-animation-duration:9s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-sun;-moz-animation-timing-function:linear;-ms-animation-duration:9s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-sun;-ms-animation-timing-function:linear;-webkit-animation-duration:9s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-sun;-webkit-animation-timing-function:linear">
|
||||||
|
<line transform="translate(0,9)" y2="3" stroke="#ffa500" stroke-linecap="round" stroke-width="2" fifll="none" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffa500" stroke="#ffa500" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-20,-10) rotate(10,-247.39,200.17)" fill="none" stroke="#91c0f8" stroke-dasharray="4, 4"
|
||||||
|
stroke-linecap="round" stroke-width="2">
|
||||||
|
<line class="am-weather-rain-1" transform="translate(-4,1)" y2="8"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
<line class="am-weather-rain-2" transform="translate(0,-1)" y2="8"
|
||||||
|
style="-moz-animation-delay:0.25s;-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-delay:0.25s;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-delay:0.25s;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
<line class="am-weather-rain-1" transform="translate(4)" y2="8"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 9.3 KiB |
270
public/weather-ico/rainy-3-night.svg
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.24684" y="-.22892" width="1.4937" height="1.5576">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** RAIN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-rain {
|
||||||
|
0% {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: -100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-1 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-rain-2 {
|
||||||
|
-webkit-animation-name: am-weather-rain;
|
||||||
|
-moz-animation-name: am-weather-rain;
|
||||||
|
-ms-animation-name: am-weather-rain;
|
||||||
|
animation-name: am-weather-rain;
|
||||||
|
-webkit-animation-delay: 0.25s;
|
||||||
|
-moz-animation-delay: 0.25s;
|
||||||
|
-ms-animation-delay: 0.25s;
|
||||||
|
animation-delay: 0.25s;
|
||||||
|
-webkit-animation-duration: 8s;
|
||||||
|
-moz-animation-duration: 8s;
|
||||||
|
-ms-animation-duration: 8s;
|
||||||
|
animation-duration: 8s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3" fill="#ffa500"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3"
|
||||||
|
fill="#ffa500" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffa500" stroke="#ffa500" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-20,-10) rotate(10,-247.39,200.17)" fill="none" stroke="#91c0f8" stroke-dasharray="4, 4"
|
||||||
|
stroke-linecap="round" stroke-width="2">
|
||||||
|
<line class="am-weather-rain-1" transform="translate(-4,1)" y2="8"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
<line class="am-weather-rain-2" transform="translate(0,-1)" y2="8"
|
||||||
|
style="-moz-animation-delay:0.25s;-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-delay:0.25s;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-delay:0.25s;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
<line class="am-weather-rain-1" transform="translate(4)" y2="8"
|
||||||
|
style="-moz-animation-duration:8s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-rain;-moz-animation-timing-function:linear;-ms-animation-duration:8s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-rain;-ms-animation-timing-function:linear;-webkit-animation-duration:8s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-rain;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
374
public/weather-ico/scattered-thunderstorms-day.svg
Normal file
@@ -0,0 +1,374 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<!-- Scattered Thunderstorms | Contributed by hsoJ95 on GitHub: https://github.com/hsoj95 -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.1975" width="1.403" height="1.4766">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-3 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(-5px, 0px);
|
||||||
|
-moz-transform: translate(-5px, 0px);
|
||||||
|
-ms-transform: translate(-5px, 0px);
|
||||||
|
transform: translate(-5px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(10px, 0px);
|
||||||
|
-moz-transform: translate(10px, 0px);
|
||||||
|
-ms-transform: translate(10px, 0px);
|
||||||
|
transform: translate(10px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(-5px, 0px);
|
||||||
|
-moz-transform: translate(-5px, 0px);
|
||||||
|
-ms-transform: translate(-5px, 0px);
|
||||||
|
transform: translate(-5px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-3 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-3;
|
||||||
|
-moz-animation-name: am-weather-cloud-3;
|
||||||
|
animation-name: am-weather-cloud-3;
|
||||||
|
-webkit-animation-duration: 7s;
|
||||||
|
-moz-animation-duration: 7s;
|
||||||
|
animation-duration: 7s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-sun-shiny {
|
||||||
|
0% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
stroke-dasharray: 0.1px 10px;
|
||||||
|
stroke-dashoffset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun-shiny line {
|
||||||
|
-webkit-animation-name: am-weather-sun-shiny;
|
||||||
|
-moz-animation-name: am-weather-sun-shiny;
|
||||||
|
-ms-animation-name: am-weather-sun-shiny;
|
||||||
|
animation-name: am-weather-sun-shiny;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** STROKE
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-stroke {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
2% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
4% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
6% {
|
||||||
|
-webkit-transform: translate(0.5px, 0.4px);
|
||||||
|
-moz-transform: translate(0.5px, 0.4px);
|
||||||
|
-ms-transform: translate(0.5px, 0.4px);
|
||||||
|
transform: translate(0.5px, 0.4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
8% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
12% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
14% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
16% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
18% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
22% {
|
||||||
|
-webkit-transform: translate(1px, 0.0px);
|
||||||
|
-moz-transform: translate(1px, 0.0px);
|
||||||
|
-ms-transform: translate(1px, 0.0px);
|
||||||
|
transform: translate(1px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
24% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
26% {
|
||||||
|
-webkit-transform: translate(-1px, 0.0px);
|
||||||
|
-moz-transform: translate(-1px, 0.0px);
|
||||||
|
-ms-transform: translate(-1px, 0.0px);
|
||||||
|
transform: translate(-1px, 0.0px);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
28% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
fill: orange;
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
65% {
|
||||||
|
fill: white;
|
||||||
|
-webkit-transform: translate(-1px, 5.0px);
|
||||||
|
-moz-transform: translate(-1px, 5.0px);
|
||||||
|
-ms-transform: translate(-1px, 5.0px);
|
||||||
|
transform: translate(-1px, 5.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
61% {
|
||||||
|
fill: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-stroke {
|
||||||
|
-webkit-animation-name: am-weather-stroke;
|
||||||
|
-moz-animation-name: am-weather-stroke;
|
||||||
|
animation-name: am-weather-stroke;
|
||||||
|
-webkit-animation-duration: 1.11s;
|
||||||
|
-moz-animation-duration: 1.11s;
|
||||||
|
animation-duration: 1.11s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="thunder" transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun"
|
||||||
|
style="-moz-animation-duration:9s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-sun;-moz-animation-timing-function:linear;-ms-animation-duration:9s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-sun;-ms-animation-timing-function:linear;-webkit-animation-duration:9s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-sun;-webkit-animation-timing-function:linear">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round" stroke-width="2" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffa500" stroke="#ffa500" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-lightning" transform="matrix(1.2,0,0,1.2,-4,28)">
|
||||||
|
<polygon class="am-weather-stroke" points="11.1 6.9 14.3 -2.9 20.5 -2.9 16.4 4.3 20.3 4.3 11.5 14.6 14.9 6.9"
|
||||||
|
fill="#ffa500" stroke="#fff"
|
||||||
|
style="-moz-animation-duration:1.11s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-stroke;-moz-animation-timing-function:linear;-webkit-animation-duration:1.11s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-stroke;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 13 KiB |
283
public/weather-ico/scattered-thunderstorms-night.svg
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<!-- Scattered Thunderstorms | Contributed by hsoJ95 on GitHub: https://github.com/hsoj95 -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.1975" width="1.403" height="1.4766">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-3 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(-5px, 0px);
|
||||||
|
-moz-transform: translate(-5px, 0px);
|
||||||
|
-ms-transform: translate(-5px, 0px);
|
||||||
|
transform: translate(-5px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(10px, 0px);
|
||||||
|
-moz-transform: translate(10px, 0px);
|
||||||
|
-ms-transform: translate(10px, 0px);
|
||||||
|
transform: translate(10px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(-5px, 0px);
|
||||||
|
-moz-transform: translate(-5px, 0px);
|
||||||
|
-ms-transform: translate(-5px, 0px);
|
||||||
|
transform: translate(-5px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-3 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-3;
|
||||||
|
-moz-animation-name: am-weather-cloud-3;
|
||||||
|
animation-name: am-weather-cloud-3;
|
||||||
|
-webkit-animation-duration: 7s;
|
||||||
|
-moz-animation-duration: 7s;
|
||||||
|
animation-duration: 7s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** STROKE
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-stroke {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
2% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
4% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
6% {
|
||||||
|
-webkit-transform: translate(0.5px, 0.4px);
|
||||||
|
-moz-transform: translate(0.5px, 0.4px);
|
||||||
|
-ms-transform: translate(0.5px, 0.4px);
|
||||||
|
transform: translate(0.5px, 0.4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
8% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
12% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
14% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
16% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
18% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
22% {
|
||||||
|
-webkit-transform: translate(1px, 0.0px);
|
||||||
|
-moz-transform: translate(1px, 0.0px);
|
||||||
|
-ms-transform: translate(1px, 0.0px);
|
||||||
|
transform: translate(1px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
24% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
26% {
|
||||||
|
-webkit-transform: translate(-1px, 0.0px);
|
||||||
|
-moz-transform: translate(-1px, 0.0px);
|
||||||
|
-ms-transform: translate(-1px, 0.0px);
|
||||||
|
transform: translate(-1px, 0.0px);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
28% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
fill: orange;
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
65% {
|
||||||
|
fill: white;
|
||||||
|
-webkit-transform: translate(-1px, 5.0px);
|
||||||
|
-moz-transform: translate(-1px, 5.0px);
|
||||||
|
-ms-transform: translate(-1px, 5.0px);
|
||||||
|
transform: translate(-1px, 5.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
61% {
|
||||||
|
fill: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-stroke {
|
||||||
|
-webkit-animation-name: am-weather-stroke;
|
||||||
|
-moz-animation-name: am-weather-stroke;
|
||||||
|
animation-name: am-weather-stroke;
|
||||||
|
-webkit-animation-duration: 1.11s;
|
||||||
|
-moz-animation-duration: 1.11s;
|
||||||
|
animation-duration: 1.11s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="thunder" transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="3.3 1.5 4 2.7 5.2 3.3 4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7" fill="#ffa500"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="3.3 1.5 4 2.7 5.2 3.3 4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7"
|
||||||
|
fill="#ffa500" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffa500" stroke="#ffa500" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-lightning" transform="matrix(1.2,0,0,1.2,-4,28)">
|
||||||
|
<polygon class="am-weather-stroke" points="11.1 6.9 14.3 -2.9 20.5 -2.9 16.4 4.3 20.3 4.3 11.5 14.6 14.9 6.9"
|
||||||
|
fill="#ffa500" stroke="#fff"
|
||||||
|
style="-moz-animation-duration:1.11s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-stroke;-moz-animation-timing-function:linear;-webkit-animation-duration:1.11s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-stroke;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
307
public/weather-ico/severe-thunderstorm.svg
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<!-- Severe Thunderstorm | Contributed by hsoJ95 on GitHub: https://github.com/hsoj95 -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.17571" y="-.19575" width="1.3379" height="1.4959">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-3 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(-5px, 0px);
|
||||||
|
-moz-transform: translate(-5px, 0px);
|
||||||
|
-ms-transform: translate(-5px, 0px);
|
||||||
|
transform: translate(-5px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(10px, 0px);
|
||||||
|
-moz-transform: translate(10px, 0px);
|
||||||
|
-ms-transform: translate(10px, 0px);
|
||||||
|
transform: translate(10px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(-5px, 0px);
|
||||||
|
-moz-transform: translate(-5px, 0px);
|
||||||
|
-ms-transform: translate(-5px, 0px);
|
||||||
|
transform: translate(-5px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-3 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-3;
|
||||||
|
-moz-animation-name: am-weather-cloud-3;
|
||||||
|
animation-name: am-weather-cloud-3;
|
||||||
|
-webkit-animation-duration: 7s;
|
||||||
|
-moz-animation-duration: 7s;
|
||||||
|
animation-duration: 7s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-cloud-1 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-1 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-1;
|
||||||
|
-moz-animation-name: am-weather-cloud-1;
|
||||||
|
animation-name: am-weather-cloud-1;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** STROKE
|
||||||
|
*/
|
||||||
|
|
||||||
|
@keyframes am-weather-stroke {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
2% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
4% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
6% {
|
||||||
|
-webkit-transform: translate(0.5px, 0.4px);
|
||||||
|
-moz-transform: translate(0.5px, 0.4px);
|
||||||
|
-ms-transform: translate(0.5px, 0.4px);
|
||||||
|
transform: translate(0.5px, 0.4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
8% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
10% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
12% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
14% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
16% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
18% {
|
||||||
|
-webkit-transform: translate(0.3px, 0.0px);
|
||||||
|
-moz-transform: translate(0.3px, 0.0px);
|
||||||
|
-ms-transform: translate(0.3px, 0.0px);
|
||||||
|
transform: translate(0.3px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
22% {
|
||||||
|
-webkit-transform: translate(1px, 0.0px);
|
||||||
|
-moz-transform: translate(1px, 0.0px);
|
||||||
|
-ms-transform: translate(1px, 0.0px);
|
||||||
|
transform: translate(1px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
24% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
26% {
|
||||||
|
-webkit-transform: translate(-1px, 0.0px);
|
||||||
|
-moz-transform: translate(-1px, 0.0px);
|
||||||
|
-ms-transform: translate(-1px, 0.0px);
|
||||||
|
transform: translate(-1px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
28% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
fill: orange;
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
65% {
|
||||||
|
fill: white;
|
||||||
|
-webkit-transform: translate(-1px, 5.0px);
|
||||||
|
-moz-transform: translate(-1px, 5.0px);
|
||||||
|
-ms-transform: translate(-1px, 5.0px);
|
||||||
|
transform: translate(-1px, 5.0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
61% {
|
||||||
|
fill: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0.0px, 0.0px);
|
||||||
|
-moz-transform: translate(0.0px, 0.0px);
|
||||||
|
-ms-transform: translate(0.0px, 0.0px);
|
||||||
|
transform: translate(0.0px, 0.0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-stroke {
|
||||||
|
-webkit-animation-name: am-weather-stroke;
|
||||||
|
-moz-animation-name: am-weather-stroke;
|
||||||
|
animation-name: am-weather-stroke;
|
||||||
|
-webkit-animation-duration: 1.11s;
|
||||||
|
-moz-animation-duration: 1.11s;
|
||||||
|
animation-duration: 1.11s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes error {
|
||||||
|
0% {
|
||||||
|
fill: #cc0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
fill: #ff0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
fill: #cc0000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Shape {
|
||||||
|
-webkit-animation-name: error;
|
||||||
|
-moz-animation-name: error;
|
||||||
|
animation-name: error;
|
||||||
|
-webkit-animation-duration: 1s;
|
||||||
|
-moz-animation-duration: 1s;
|
||||||
|
animation-duration: 1s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g class="am-weather-cloud-1"
|
||||||
|
style="-moz-animation-duration:7s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-1;-moz-animation-timing-function:linear;-webkit-animation-duration:7s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-1;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="matrix(.6 0 0 .6 -10 -6)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#666" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#333" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.2,0,0,1.2,-4,28)">
|
||||||
|
<polygon class="am-weather-stroke"
|
||||||
|
points="11.1 6.9 14.3 -2.9 20.5 -2.9 16.4 4.3 20.3 4.3 11.5 14.6 14.9 6.9" fill="#ffa500" stroke="#fff"
|
||||||
|
style="-moz-animation-duration:1.11s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-stroke;-moz-animation-timing-function:linear;-webkit-animation-duration:1.11s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-stroke;-webkit-animation-timing-function:linear" />
|
||||||
|
</g>
|
||||||
|
<g class="warning" transform="translate(20,30)">
|
||||||
|
<path
|
||||||
|
d="m7.7791 2.906-5.9912 10.117c-0.56283 0.95042-0.24862 2.1772 0.7018 2.74 0.30853 0.18271 0.66051 0.27911 1.0191 0.27911h11.982c1.1046 0 2-0.89543 2-2 0-0.35857-0.0964-0.71056-0.27911-1.0191l-5.9912-10.117c-0.56283-0.95042-1.7896-1.2646-2.74-0.7018-0.28918 0.17125-0.53055 0.41262-0.7018 0.7018z"
|
||||||
|
fill="#c00" />
|
||||||
|
<path d="m9.5 10.5v-5" stroke="#fff" stroke-linecap="round" stroke-width="1.5" />
|
||||||
|
<circle cx="9.5" cy="13" r="1" fill="#fff" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 13 KiB |
241
public/weather-ico/snowy-1-day.svg
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.23099" width="1.403" height="1.5634">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-sun-shiny {
|
||||||
|
0% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
stroke-dasharray: 0.1px 10px;
|
||||||
|
stroke-dashoffset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun-shiny line {
|
||||||
|
-webkit-animation-name: am-weather-sun-shiny;
|
||||||
|
-moz-animation-name: am-weather-sun-shiny;
|
||||||
|
-ms-animation-name: am-weather-sun-shiny;
|
||||||
|
animation-name: am-weather-sun-shiny;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SNOW
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-snow {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translateX(0) translateY(0);
|
||||||
|
-moz-transform: translateX(0) translateY(0);
|
||||||
|
-ms-transform: translateX(0) translateY(0);
|
||||||
|
transform: translateX(0) translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.33% {
|
||||||
|
-webkit-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-moz-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-ms-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
transform: translateX(-1.2px) translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.66% {
|
||||||
|
-webkit-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-moz-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-ms-transform: translateX(1.4px) translateY(4px);
|
||||||
|
transform: translateX(1.4px) translateY(4px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-moz-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-ms-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
transform: translateX(-1.6px) translateY(6px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-1 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun" transform="translate(0,16)"
|
||||||
|
style="-moz-animation-duration:9s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-sun;-moz-animation-timing-function:linear;-ms-animation-duration:9s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-sun;-ms-animation-timing-function:linear;-webkit-animation-duration:9s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-sun;-webkit-animation-timing-function:linear">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round" stroke-width="2" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffa500" stroke="#ffa500" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-1"
|
||||||
|
style="-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(12,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 9.6 KiB |
269
public/weather-ico/snowy-1-night.svg
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.23099" width="1.403" height="1.5634">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SNOW
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-snow {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translateX(0) translateY(0);
|
||||||
|
-moz-transform: translateX(0) translateY(0);
|
||||||
|
-ms-transform: translateX(0) translateY(0);
|
||||||
|
transform: translateX(0) translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.33% {
|
||||||
|
-webkit-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-moz-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-ms-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
transform: translateX(-1.2px) translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.66% {
|
||||||
|
-webkit-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-moz-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-ms-transform: translateX(1.4px) translateY(4px);
|
||||||
|
transform: translateX(1.4px) translateY(4px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-moz-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-ms-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
transform: translateX(-1.6px) translateY(6px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-1 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3" fill="#ffa500"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3"
|
||||||
|
fill="#ffa500" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffa500" stroke="#ffa500" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-1"
|
||||||
|
style="-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(12,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
273
public/weather-ico/snowy-2-day.svg
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.23099" width="1.403" height="1.5634">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-sun-shiny {
|
||||||
|
0% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
stroke-dasharray: 0.1px 10px;
|
||||||
|
stroke-dashoffset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun-shiny line {
|
||||||
|
-webkit-animation-name: am-weather-sun-shiny;
|
||||||
|
-moz-animation-name: am-weather-sun-shiny;
|
||||||
|
-ms-animation-name: am-weather-sun-shiny;
|
||||||
|
animation-name: am-weather-sun-shiny;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SNOW
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-snow {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translateX(0) translateY(0);
|
||||||
|
-moz-transform: translateX(0) translateY(0);
|
||||||
|
-ms-transform: translateX(0) translateY(0);
|
||||||
|
transform: translateX(0) translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.33% {
|
||||||
|
-webkit-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-moz-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-ms-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
transform: translateX(-1.2px) translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.66% {
|
||||||
|
-webkit-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-moz-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-ms-transform: translateX(1.4px) translateY(4px);
|
||||||
|
transform: translateX(1.4px) translateY(4px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-moz-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-ms-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
transform: translateX(-1.6px) translateY(6px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-1 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-2 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-delay: 1.2s;
|
||||||
|
-moz-animation-delay: 1.2s;
|
||||||
|
-ms-animation-delay: 1.2s;
|
||||||
|
animation-delay: 1.2s;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun"
|
||||||
|
style="-moz-animation-duration:9s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-sun;-moz-animation-timing-function:linear;-ms-animation-duration:9s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-sun;-ms-animation-timing-function:linear;-webkit-animation-duration:9s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-sun;-webkit-animation-timing-function:linear">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round" stroke-width="2" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffa500" stroke="#ffa500" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-1"
|
||||||
|
style="-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(7,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-2"
|
||||||
|
style="-moz-animation-delay:1.2s;-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-delay:1.2s;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-delay:1.2s;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(16,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
301
public/weather-ico/snowy-2-night.svg
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.20655" y="-.23099" width="1.403" height="1.5634">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SNOW
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-snow {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translateX(0) translateY(0);
|
||||||
|
-moz-transform: translateX(0) translateY(0);
|
||||||
|
-ms-transform: translateX(0) translateY(0);
|
||||||
|
transform: translateX(0) translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.33% {
|
||||||
|
-webkit-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-moz-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-ms-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
transform: translateX(-1.2px) translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.66% {
|
||||||
|
-webkit-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-moz-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-ms-transform: translateX(1.4px) translateY(4px);
|
||||||
|
transform: translateX(1.4px) translateY(4px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-moz-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-ms-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
transform: translateX(-1.6px) translateY(6px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-1 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-2 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-delay: 1.2s;
|
||||||
|
-moz-animation-delay: 1.2s;
|
||||||
|
-ms-animation-delay: 1.2s;
|
||||||
|
animation-delay: 1.2s;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3" fill="#ffa500"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3"
|
||||||
|
fill="#ffa500" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffa500" stroke="#ffa500" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-3"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-1"
|
||||||
|
style="-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(7,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-2"
|
||||||
|
style="-moz-animation-delay:1.2s;-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-delay:1.2s;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-delay:1.2s;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(16,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 13 KiB |
334
public/weather-ico/snowy-3-day.svg
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.24684" y="-.26897" width="1.4937" height="1.6759">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SUN
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-sun {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
-moz-transform: rotate(360deg);
|
||||||
|
-ms-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun {
|
||||||
|
-webkit-animation-name: am-weather-sun;
|
||||||
|
-moz-animation-name: am-weather-sun;
|
||||||
|
-ms-animation-name: am-weather-sun;
|
||||||
|
animation-name: am-weather-sun;
|
||||||
|
-webkit-animation-duration: 9s;
|
||||||
|
-moz-animation-duration: 9s;
|
||||||
|
-ms-animation-duration: 9s;
|
||||||
|
animation-duration: 9s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-sun-shiny {
|
||||||
|
0% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
stroke-dasharray: 0.1px 10px;
|
||||||
|
stroke-dashoffset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
stroke-dasharray: 3px 10px;
|
||||||
|
stroke-dashoffset: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-sun-shiny line {
|
||||||
|
-webkit-animation-name: am-weather-sun-shiny;
|
||||||
|
-moz-animation-name: am-weather-sun-shiny;
|
||||||
|
-ms-animation-name: am-weather-sun-shiny;
|
||||||
|
animation-name: am-weather-sun-shiny;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SNOW
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-snow {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translateX(0) translateY(0);
|
||||||
|
-moz-transform: translateX(0) translateY(0);
|
||||||
|
-ms-transform: translateX(0) translateY(0);
|
||||||
|
transform: translateX(0) translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.33% {
|
||||||
|
-webkit-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-moz-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-ms-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
transform: translateX(-1.2px) translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.66% {
|
||||||
|
-webkit-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-moz-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-ms-transform: translateX(1.4px) translateY(4px);
|
||||||
|
transform: translateX(1.4px) translateY(4px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-moz-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-ms-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
transform: translateX(-1.6px) translateY(6px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-snow-reverse {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translateX(0) translateY(0);
|
||||||
|
-moz-transform: translateX(0) translateY(0);
|
||||||
|
-ms-transform: translateX(0) translateY(0);
|
||||||
|
transform: translateX(0) translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.33% {
|
||||||
|
-webkit-transform: translateX(1.2px) translateY(2px);
|
||||||
|
-moz-transform: translateX(1.2px) translateY(2px);
|
||||||
|
-ms-transform: translateX(1.2px) translateY(2px);
|
||||||
|
transform: translateX(1.2px) translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.66% {
|
||||||
|
-webkit-transform: translateX(-1.4px) translateY(4px);
|
||||||
|
-moz-transform: translateX(-1.4px) translateY(4px);
|
||||||
|
-ms-transform: translateX(-1.4px) translateY(4px);
|
||||||
|
transform: translateX(-1.4px) translateY(4px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translateX(1.6px) translateY(6px);
|
||||||
|
-moz-transform: translateX(1.6px) translateY(6px);
|
||||||
|
-ms-transform: translateX(1.6px) translateY(6px);
|
||||||
|
transform: translateX(1.6px) translateY(6px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-1 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-2 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-delay: 1.2s;
|
||||||
|
-moz-animation-delay: 1.2s;
|
||||||
|
-ms-animation-delay: 1.2s;
|
||||||
|
animation-delay: 1.2s;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-3 {
|
||||||
|
-webkit-animation-name: am-weather-snow-reverse;
|
||||||
|
-moz-animation-name: am-weather-snow-reverse;
|
||||||
|
-ms-animation-name: am-weather-snow-reverse;
|
||||||
|
animation-name: am-weather-snow-reverse;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="translate(0,16)">
|
||||||
|
<g class="am-weather-sun"
|
||||||
|
style="-moz-animation-duration:9s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-sun;-moz-animation-timing-function:linear;-ms-animation-duration:9s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-sun;-ms-animation-timing-function:linear;-webkit-animation-duration:9s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-sun;-webkit-animation-timing-function:linear">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
<g transform="rotate(45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(135)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="scale(-1)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(225)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-90)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(-45)">
|
||||||
|
<line transform="translate(0,9)" y2="3" fill="none" stroke="#ffa500" stroke-linecap="round"
|
||||||
|
stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<circle r="5" fill="#ffa500" stroke="#ffa500" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-2"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-1"
|
||||||
|
style="-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(3,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-2"
|
||||||
|
style="-moz-animation-delay:1.2s;-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-delay:1.2s;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-delay:1.2s;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(11,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-3"
|
||||||
|
style="-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow-reverse;-moz-animation-timing-function:linear;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow-reverse;-ms-animation-timing-function:linear;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow-reverse;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(20,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 15 KiB |
361
public/weather-ico/snowy-3-night.svg
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- (c) ammap.com | SVG weather icons -->
|
||||||
|
<svg width="56" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<filter id="blur" x="-.24684" y="-.26897" width="1.4937" height="1.6759">
|
||||||
|
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
|
||||||
|
<feOffset dx="0" dy="4" result="offsetblur" />
|
||||||
|
<feComponentTransfer>
|
||||||
|
<feFuncA slope="0.05" type="linear" />
|
||||||
|
</feComponentTransfer>
|
||||||
|
<feMerge>
|
||||||
|
<feMergeNode />
|
||||||
|
<feMergeNode in="SourceGraphic" />
|
||||||
|
</feMerge>
|
||||||
|
</filter>
|
||||||
|
<style type="text/css">
|
||||||
|
<![CDATA[
|
||||||
|
/*
|
||||||
|
** CLOUDS
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-cloud-2 {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: translate(2px, 0px);
|
||||||
|
-moz-transform: translate(2px, 0px);
|
||||||
|
-ms-transform: translate(2px, 0px);
|
||||||
|
transform: translate(2px, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate(0px, 0px);
|
||||||
|
-moz-transform: translate(0px, 0px);
|
||||||
|
-ms-transform: translate(0px, 0px);
|
||||||
|
transform: translate(0px, 0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-cloud-2 {
|
||||||
|
-webkit-animation-name: am-weather-cloud-2;
|
||||||
|
-moz-animation-name: am-weather-cloud-2;
|
||||||
|
animation-name: am-weather-cloud-2;
|
||||||
|
-webkit-animation-duration: 3s;
|
||||||
|
-moz-animation-duration: 3s;
|
||||||
|
animation-duration: 3s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** MOON
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-moon {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
-moz-transform: rotate(15deg);
|
||||||
|
-ms-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-ms-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon {
|
||||||
|
-webkit-animation-name: am-weather-moon;
|
||||||
|
-moz-animation-name: am-weather-moon;
|
||||||
|
-ms-animation-name: am-weather-moon;
|
||||||
|
animation-name: am-weather-moon;
|
||||||
|
-webkit-animation-duration: 6s;
|
||||||
|
-moz-animation-duration: 6s;
|
||||||
|
-ms-animation-duration: 6s;
|
||||||
|
animation-duration: 6s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
-webkit-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-moz-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
-ms-transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
transform-origin: 12.5px 15.15px 0;
|
||||||
|
/* TODO FF CENTER ISSUE */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-1 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-1 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-1;
|
||||||
|
-moz-animation-name: am-weather-moon-star-1;
|
||||||
|
-ms-animation-name: am-weather-moon-star-1;
|
||||||
|
animation-name: am-weather-moon-star-1;
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
-webkit-animation-duration: 5s;
|
||||||
|
-moz-animation-duration: 5s;
|
||||||
|
-ms-animation-duration: 5s;
|
||||||
|
animation-duration: 5s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-moon-star-2 {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-moon-star-2 {
|
||||||
|
-webkit-animation-name: am-weather-moon-star-2;
|
||||||
|
-moz-animation-name: am-weather-moon-star-2;
|
||||||
|
-ms-animation-name: am-weather-moon-star-2;
|
||||||
|
animation-name: am-weather-moon-star-2;
|
||||||
|
-webkit-animation-delay: 5s;
|
||||||
|
-moz-animation-delay: 5s;
|
||||||
|
-ms-animation-delay: 5s;
|
||||||
|
animation-delay: 5s;
|
||||||
|
-webkit-animation-duration: 4s;
|
||||||
|
-moz-animation-duration: 4s;
|
||||||
|
-ms-animation-duration: 4s;
|
||||||
|
animation-duration: 4s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
-moz-animation-iteration-count: 1;
|
||||||
|
-ms-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SNOW
|
||||||
|
*/
|
||||||
|
@keyframes am-weather-snow {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translateX(0) translateY(0);
|
||||||
|
-moz-transform: translateX(0) translateY(0);
|
||||||
|
-ms-transform: translateX(0) translateY(0);
|
||||||
|
transform: translateX(0) translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.33% {
|
||||||
|
-webkit-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-moz-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
-ms-transform: translateX(-1.2px) translateY(2px);
|
||||||
|
transform: translateX(-1.2px) translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.66% {
|
||||||
|
-webkit-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-moz-transform: translateX(1.4px) translateY(4px);
|
||||||
|
-ms-transform: translateX(1.4px) translateY(4px);
|
||||||
|
transform: translateX(1.4px) translateY(4px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-moz-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
-ms-transform: translateX(-1.6px) translateY(6px);
|
||||||
|
transform: translateX(-1.6px) translateY(6px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes am-weather-snow-reverse {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translateX(0) translateY(0);
|
||||||
|
-moz-transform: translateX(0) translateY(0);
|
||||||
|
-ms-transform: translateX(0) translateY(0);
|
||||||
|
transform: translateX(0) translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
33.33% {
|
||||||
|
-webkit-transform: translateX(1.2px) translateY(2px);
|
||||||
|
-moz-transform: translateX(1.2px) translateY(2px);
|
||||||
|
-ms-transform: translateX(1.2px) translateY(2px);
|
||||||
|
transform: translateX(1.2px) translateY(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
66.66% {
|
||||||
|
-webkit-transform: translateX(-1.4px) translateY(4px);
|
||||||
|
-moz-transform: translateX(-1.4px) translateY(4px);
|
||||||
|
-ms-transform: translateX(-1.4px) translateY(4px);
|
||||||
|
transform: translateX(-1.4px) translateY(4px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translateX(1.6px) translateY(6px);
|
||||||
|
-moz-transform: translateX(1.6px) translateY(6px);
|
||||||
|
-ms-transform: translateX(1.6px) translateY(6px);
|
||||||
|
transform: translateX(1.6px) translateY(6px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-1 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-2 {
|
||||||
|
-webkit-animation-name: am-weather-snow;
|
||||||
|
-moz-animation-name: am-weather-snow;
|
||||||
|
-ms-animation-name: am-weather-snow;
|
||||||
|
animation-name: am-weather-snow;
|
||||||
|
-webkit-animation-delay: 1.2s;
|
||||||
|
-moz-animation-delay: 1.2s;
|
||||||
|
-ms-animation-delay: 1.2s;
|
||||||
|
animation-delay: 1.2s;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.am-weather-snow-3 {
|
||||||
|
-webkit-animation-name: am-weather-snow-reverse;
|
||||||
|
-moz-animation-name: am-weather-snow-reverse;
|
||||||
|
-ms-animation-name: am-weather-snow-reverse;
|
||||||
|
animation-name: am-weather-snow-reverse;
|
||||||
|
-webkit-animation-duration: 2s;
|
||||||
|
-moz-animation-duration: 2s;
|
||||||
|
-ms-animation-duration: 2s;
|
||||||
|
animation-duration: 2s;
|
||||||
|
-webkit-animation-timing-function: linear;
|
||||||
|
-moz-animation-timing-function: linear;
|
||||||
|
-ms-animation-timing-function: linear;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
-webkit-animation-iteration-count: infinite;
|
||||||
|
-moz-animation-iteration-count: infinite;
|
||||||
|
-ms-animation-iteration-count: infinite;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g transform="translate(16,-2)" filter="url(#blur)">
|
||||||
|
<g transform="matrix(.8 0 0 .8 16 4)">
|
||||||
|
<g class="am-weather-moon-star-1"
|
||||||
|
style="-moz-animation-delay:3s;-moz-animation-duration:5s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-1;-moz-animation-timing-function:linear;-ms-animation-delay:3s;-ms-animation-duration:5s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-1;-ms-animation-timing-function:linear;-webkit-animation-delay:3s;-webkit-animation-duration:5s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-1;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3" fill="#ffa500"
|
||||||
|
stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon-star-2"
|
||||||
|
style="-moz-animation-delay:5s;-moz-animation-duration:4s;-moz-animation-iteration-count:1;-moz-animation-name:am-weather-moon-star-2;-moz-animation-timing-function:linear;-ms-animation-delay:5s;-ms-animation-duration:4s;-ms-animation-iteration-count:1;-ms-animation-name:am-weather-moon-star-2;-ms-animation-timing-function:linear;-webkit-animation-delay:5s;-webkit-animation-duration:4s;-webkit-animation-iteration-count:1;-webkit-animation-name:am-weather-moon-star-2;-webkit-animation-timing-function:linear">
|
||||||
|
<polygon transform="translate(20,10)" points="4 4 3.3 5.2 2.7 4 1.5 3.3 2.7 2.7 3.3 1.5 4 2.7 5.2 3.3"
|
||||||
|
fill="#ffa500" stroke-miterlimit="10" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-moon"
|
||||||
|
style="-moz-animation-duration:6s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-moon;-moz-animation-timing-function:linear;-moz-transform-origin:12.5px 15.15px 0;-ms-animation-duration:6s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-moon;-ms-animation-timing-function:linear;-ms-transform-origin:12.5px 15.15px 0;-webkit-animation-duration:6s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-moon;-webkit-animation-timing-function:linear;-webkit-transform-origin:12.5px 15.15px 0">
|
||||||
|
<path
|
||||||
|
d="m14.5 13.2c0-3.7 2-6.9 5-8.7-1.5-0.9-3.2-1.3-5-1.3-5.5 0-10 4.5-10 10s4.5 10 10 10c1.8 0 3.5-0.5 5-1.3-3-1.7-5-5-5-8.7z"
|
||||||
|
fill="#ffa500" stroke="#ffa500" stroke-linejoin="round" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-cloud-2"
|
||||||
|
style="-moz-animation-duration:3s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-cloud-2;-moz-animation-timing-function:linear;-webkit-animation-duration:3s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-cloud-2;-webkit-animation-timing-function:linear">
|
||||||
|
<path transform="translate(-20,-11)"
|
||||||
|
d="m47.7 35.4c0-4.6-3.7-8.2-8.2-8.2-1 0-1.9 0.2-2.8 0.5-0.3-3.4-3.1-6.2-6.6-6.2-3.7 0-6.7 3-6.7 6.7 0 0.8 0.2 1.6 0.4 2.3-0.3-0.1-0.7-0.1-1-0.1-3.7 0-6.7 3-6.7 6.7 0 3.6 2.9 6.6 6.5 6.7h17.2c4.4-0.5 7.9-4 7.9-8.4z"
|
||||||
|
fill="#57a0ee" stroke="#fff" stroke-linejoin="round" stroke-width="1.2" />
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-1"
|
||||||
|
style="-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(3,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-2"
|
||||||
|
style="-moz-animation-delay:1.2s;-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow;-moz-animation-timing-function:linear;-ms-animation-delay:1.2s;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow;-ms-animation-timing-function:linear;-webkit-animation-delay:1.2s;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(11,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g class="am-weather-snow-3"
|
||||||
|
style="-moz-animation-duration:2s;-moz-animation-iteration-count:infinite;-moz-animation-name:am-weather-snow-reverse;-moz-animation-timing-function:linear;-ms-animation-duration:2s;-ms-animation-iteration-count:infinite;-ms-animation-name:am-weather-snow-reverse;-ms-animation-timing-function:linear;-webkit-animation-duration:2s;-webkit-animation-iteration-count:infinite;-webkit-animation-name:am-weather-snow-reverse;-webkit-animation-timing-function:linear">
|
||||||
|
<g transform="translate(20,28)" fill="none" stroke="#57a0ee" stroke-linecap="round">
|
||||||
|
<line transform="translate(0,9)" y1="-2.5" y2="2.5" stroke-width="1.2" />
|
||||||
|
<line transform="rotate(45,-10.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(90,-4.5,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
<line transform="rotate(135,-1.864,4.5)" y1="-2.5" y2="2.5" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 17 KiB |
@@ -1,5 +1,4 @@
|
|||||||
[GENERAL]
|
[GENERAL]
|
||||||
PORT = 3001 # Port to run the server on
|
|
||||||
SIMILARITY_MEASURE = "cosine" # "cosine" or "dot"
|
SIMILARITY_MEASURE = "cosine" # "cosine" or "dot"
|
||||||
KEEP_ALIVE = "5m" # How long to keep Ollama models loaded into memory. (Instead of using -1 use "-1m")
|
KEEP_ALIVE = "5m" # How long to keep Ollama models loaded into memory. (Instead of using -1 use "-1m")
|
||||||
|
|
||||||
@@ -18,9 +17,16 @@ API_KEY = ""
|
|||||||
[MODELS.CUSTOM_OPENAI]
|
[MODELS.CUSTOM_OPENAI]
|
||||||
API_KEY = ""
|
API_KEY = ""
|
||||||
API_URL = ""
|
API_URL = ""
|
||||||
|
MODEL_NAME = ""
|
||||||
|
|
||||||
[MODELS.OLLAMA]
|
[MODELS.OLLAMA]
|
||||||
API_URL = "" # Ollama API URL - http://host.docker.internal:11434
|
API_URL = "" # Ollama API URL - http://host.docker.internal:11434
|
||||||
|
|
||||||
|
[MODELS.DEEPSEEK]
|
||||||
|
API_KEY = ""
|
||||||
|
|
||||||
|
[MODELS.LM_STUDIO]
|
||||||
|
API_URL = "" # LM Studio API URL - http://host.docker.internal:1234
|
||||||
|
|
||||||
[API_ENDPOINTS]
|
[API_ENDPOINTS]
|
||||||
SEARXNG = "http://localhost:32768" # SearxNG API URL
|
SEARXNG = "" # SearxNG API URL - http://localhost:32768
|
||||||
|
38
src/app.ts
@@ -1,38 +0,0 @@
|
|||||||
import { startWebSocketServer } from './websocket';
|
|
||||||
import express from 'express';
|
|
||||||
import cors from 'cors';
|
|
||||||
import http from 'http';
|
|
||||||
import routes from './routes';
|
|
||||||
import { getPort } from './config';
|
|
||||||
import logger from './utils/logger';
|
|
||||||
|
|
||||||
const port = getPort();
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
const server = http.createServer(app);
|
|
||||||
|
|
||||||
const corsOptions = {
|
|
||||||
origin: '*',
|
|
||||||
};
|
|
||||||
|
|
||||||
app.use(cors(corsOptions));
|
|
||||||
app.use(express.json());
|
|
||||||
|
|
||||||
app.use('/api', routes);
|
|
||||||
app.get('/api', (_, res) => {
|
|
||||||
res.status(200).json({ status: 'ok' });
|
|
||||||
});
|
|
||||||
|
|
||||||
server.listen(port, () => {
|
|
||||||
logger.info(`Server is running on port ${port}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
startWebSocketServer(server);
|
|
||||||
|
|
||||||
process.on('uncaughtException', (err, origin) => {
|
|
||||||
logger.error(`Uncaught Exception at ${origin}: ${err}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason, promise) => {
|
|
||||||
logger.error(`Unhandled Rejection at: ${promise}, reason: ${reason}`);
|
|
||||||
});
|
|
306
src/app/api/chat/route.ts
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
import prompts from '@/lib/prompts';
|
||||||
|
import MetaSearchAgent from '@/lib/search/metaSearchAgent';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
|
||||||
|
import { EventEmitter } from 'stream';
|
||||||
|
import {
|
||||||
|
chatModelProviders,
|
||||||
|
embeddingModelProviders,
|
||||||
|
getAvailableChatModelProviders,
|
||||||
|
getAvailableEmbeddingModelProviders,
|
||||||
|
} from '@/lib/providers';
|
||||||
|
import db from '@/lib/db';
|
||||||
|
import { chats, messages as messagesSchema } from '@/lib/db/schema';
|
||||||
|
import { and, eq, gt } from 'drizzle-orm';
|
||||||
|
import { getFileDetails } from '@/lib/utils/files';
|
||||||
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||||
|
import { ChatOpenAI } from '@langchain/openai';
|
||||||
|
import {
|
||||||
|
getCustomOpenaiApiKey,
|
||||||
|
getCustomOpenaiApiUrl,
|
||||||
|
getCustomOpenaiModelName,
|
||||||
|
} from '@/lib/config';
|
||||||
|
import { searchHandlers } from '@/lib/search';
|
||||||
|
|
||||||
|
export const runtime = 'nodejs';
|
||||||
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
|
type Message = {
|
||||||
|
messageId: string;
|
||||||
|
chatId: string;
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ChatModel = {
|
||||||
|
provider: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type EmbeddingModel = {
|
||||||
|
provider: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Body = {
|
||||||
|
message: Message;
|
||||||
|
optimizationMode: 'speed' | 'balanced' | 'quality';
|
||||||
|
focusMode: string;
|
||||||
|
history: Array<[string, string]>;
|
||||||
|
files: Array<string>;
|
||||||
|
chatModel: ChatModel;
|
||||||
|
embeddingModel: EmbeddingModel;
|
||||||
|
systemInstructions: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEmitterEvents = async (
|
||||||
|
stream: EventEmitter,
|
||||||
|
writer: WritableStreamDefaultWriter,
|
||||||
|
encoder: TextEncoder,
|
||||||
|
aiMessageId: string,
|
||||||
|
chatId: string,
|
||||||
|
) => {
|
||||||
|
let recievedMessage = '';
|
||||||
|
let sources: any[] = [];
|
||||||
|
|
||||||
|
stream.on('data', (data) => {
|
||||||
|
const parsedData = JSON.parse(data);
|
||||||
|
if (parsedData.type === 'response') {
|
||||||
|
writer.write(
|
||||||
|
encoder.encode(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'message',
|
||||||
|
data: parsedData.data,
|
||||||
|
messageId: aiMessageId,
|
||||||
|
}) + '\n',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
recievedMessage += parsedData.data;
|
||||||
|
} else if (parsedData.type === 'sources') {
|
||||||
|
writer.write(
|
||||||
|
encoder.encode(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'sources',
|
||||||
|
data: parsedData.data,
|
||||||
|
messageId: aiMessageId,
|
||||||
|
}) + '\n',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
sources = parsedData.data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
stream.on('end', () => {
|
||||||
|
writer.write(
|
||||||
|
encoder.encode(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'messageEnd',
|
||||||
|
messageId: aiMessageId,
|
||||||
|
}) + '\n',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
writer.close();
|
||||||
|
|
||||||
|
db.insert(messagesSchema)
|
||||||
|
.values({
|
||||||
|
content: recievedMessage,
|
||||||
|
chatId: chatId,
|
||||||
|
messageId: aiMessageId,
|
||||||
|
role: 'assistant',
|
||||||
|
metadata: JSON.stringify({
|
||||||
|
createdAt: new Date(),
|
||||||
|
...(sources && sources.length > 0 && { sources }),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
});
|
||||||
|
stream.on('error', (data) => {
|
||||||
|
const parsedData = JSON.parse(data);
|
||||||
|
writer.write(
|
||||||
|
encoder.encode(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'error',
|
||||||
|
data: parsedData.data,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
writer.close();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleHistorySave = async (
|
||||||
|
message: Message,
|
||||||
|
humanMessageId: string,
|
||||||
|
focusMode: string,
|
||||||
|
files: string[],
|
||||||
|
) => {
|
||||||
|
const chat = await db.query.chats.findFirst({
|
||||||
|
where: eq(chats.id, message.chatId),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!chat) {
|
||||||
|
await db
|
||||||
|
.insert(chats)
|
||||||
|
.values({
|
||||||
|
id: message.chatId,
|
||||||
|
title: message.content,
|
||||||
|
createdAt: new Date().toString(),
|
||||||
|
focusMode: focusMode,
|
||||||
|
files: files.map(getFileDetails),
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageExists = await db.query.messages.findFirst({
|
||||||
|
where: eq(messagesSchema.messageId, humanMessageId),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!messageExists) {
|
||||||
|
await db
|
||||||
|
.insert(messagesSchema)
|
||||||
|
.values({
|
||||||
|
content: message.content,
|
||||||
|
chatId: message.chatId,
|
||||||
|
messageId: humanMessageId,
|
||||||
|
role: 'user',
|
||||||
|
metadata: JSON.stringify({
|
||||||
|
createdAt: new Date(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
} else {
|
||||||
|
await db
|
||||||
|
.delete(messagesSchema)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
gt(messagesSchema.id, messageExists.id),
|
||||||
|
eq(messagesSchema.chatId, message.chatId),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const POST = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const body = (await req.json()) as Body;
|
||||||
|
const { message } = body;
|
||||||
|
|
||||||
|
if (message.content === '') {
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Please provide a message to process',
|
||||||
|
},
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [chatModelProviders, embeddingModelProviders] = await Promise.all([
|
||||||
|
getAvailableChatModelProviders(),
|
||||||
|
getAvailableEmbeddingModelProviders(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const chatModelProvider =
|
||||||
|
chatModelProviders[
|
||||||
|
body.chatModel?.provider || Object.keys(chatModelProviders)[0]
|
||||||
|
];
|
||||||
|
const chatModel =
|
||||||
|
chatModelProvider[
|
||||||
|
body.chatModel?.name || Object.keys(chatModelProvider)[0]
|
||||||
|
];
|
||||||
|
|
||||||
|
const embeddingProvider =
|
||||||
|
embeddingModelProviders[
|
||||||
|
body.embeddingModel?.provider || Object.keys(embeddingModelProviders)[0]
|
||||||
|
];
|
||||||
|
const embeddingModel =
|
||||||
|
embeddingProvider[
|
||||||
|
body.embeddingModel?.name || Object.keys(embeddingProvider)[0]
|
||||||
|
];
|
||||||
|
|
||||||
|
let llm: BaseChatModel | undefined;
|
||||||
|
let embedding = embeddingModel.model;
|
||||||
|
|
||||||
|
if (body.chatModel?.provider === 'custom_openai') {
|
||||||
|
llm = new ChatOpenAI({
|
||||||
|
openAIApiKey: getCustomOpenaiApiKey(),
|
||||||
|
modelName: getCustomOpenaiModelName(),
|
||||||
|
temperature: 0.7,
|
||||||
|
configuration: {
|
||||||
|
baseURL: getCustomOpenaiApiUrl(),
|
||||||
|
},
|
||||||
|
}) as unknown as BaseChatModel;
|
||||||
|
} else if (chatModelProvider && chatModel) {
|
||||||
|
llm = chatModel.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!llm) {
|
||||||
|
return Response.json({ error: 'Invalid chat model' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!embedding) {
|
||||||
|
return Response.json(
|
||||||
|
{ error: 'Invalid embedding model' },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const humanMessageId =
|
||||||
|
message.messageId ?? crypto.randomBytes(7).toString('hex');
|
||||||
|
const aiMessageId = crypto.randomBytes(7).toString('hex');
|
||||||
|
|
||||||
|
const history: BaseMessage[] = body.history.map((msg) => {
|
||||||
|
if (msg[0] === 'human') {
|
||||||
|
return new HumanMessage({
|
||||||
|
content: msg[1],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new AIMessage({
|
||||||
|
content: msg[1],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const handler = searchHandlers[body.focusMode];
|
||||||
|
|
||||||
|
if (!handler) {
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Invalid focus mode',
|
||||||
|
},
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const stream = await handler.searchAndAnswer(
|
||||||
|
message.content,
|
||||||
|
history,
|
||||||
|
llm,
|
||||||
|
embedding,
|
||||||
|
body.optimizationMode,
|
||||||
|
body.files,
|
||||||
|
body.systemInstructions,
|
||||||
|
);
|
||||||
|
|
||||||
|
const responseStream = new TransformStream();
|
||||||
|
const writer = responseStream.writable.getWriter();
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
|
handleEmitterEvents(stream, writer, encoder, aiMessageId, message.chatId);
|
||||||
|
handleHistorySave(message, humanMessageId, body.focusMode, body.files);
|
||||||
|
|
||||||
|
return new Response(responseStream.readable, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/event-stream',
|
||||||
|
Connection: 'keep-alive',
|
||||||
|
'Cache-Control': 'no-cache, no-transform',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error('An error occurred while processing chat request:', err);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error occurred while processing chat request' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
69
src/app/api/chats/[id]/route.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import db from '@/lib/db';
|
||||||
|
import { chats, messages } from '@/lib/db/schema';
|
||||||
|
import { eq } from 'drizzle-orm';
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: Request,
|
||||||
|
{ params }: { params: Promise<{ id: string }> },
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const { id } = await params;
|
||||||
|
|
||||||
|
const chatExists = await db.query.chats.findFirst({
|
||||||
|
where: eq(chats.id, id),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!chatExists) {
|
||||||
|
return Response.json({ message: 'Chat not found' }, { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const chatMessages = await db.query.messages.findMany({
|
||||||
|
where: eq(messages.chatId, id),
|
||||||
|
});
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
chat: chatExists,
|
||||||
|
messages: chatMessages,
|
||||||
|
},
|
||||||
|
{ status: 200 },
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in getting chat by id: ', err);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error has occurred.' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DELETE = async (
|
||||||
|
req: Request,
|
||||||
|
{ params }: { params: Promise<{ id: string }> },
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const { id } = await params;
|
||||||
|
|
||||||
|
const chatExists = await db.query.chats.findFirst({
|
||||||
|
where: eq(chats.id, id),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!chatExists) {
|
||||||
|
return Response.json({ message: 'Chat not found' }, { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.delete(chats).where(eq(chats.id, id)).execute();
|
||||||
|
await db.delete(messages).where(eq(messages.chatId, id)).execute();
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'Chat deleted successfully' },
|
||||||
|
{ status: 200 },
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in deleting chat by id: ', err);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error has occurred.' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
15
src/app/api/chats/route.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import db from '@/lib/db';
|
||||||
|
|
||||||
|
export const GET = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
let chats = await db.query.chats.findMany();
|
||||||
|
chats = chats.reverse();
|
||||||
|
return Response.json({ chats: chats }, { status: 200 });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in getting chats: ', err);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error has occurred.' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
119
src/app/api/config/route.ts
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import {
|
||||||
|
getAnthropicApiKey,
|
||||||
|
getCustomOpenaiApiKey,
|
||||||
|
getCustomOpenaiApiUrl,
|
||||||
|
getCustomOpenaiModelName,
|
||||||
|
getGeminiApiKey,
|
||||||
|
getGroqApiKey,
|
||||||
|
getOllamaApiEndpoint,
|
||||||
|
getOpenaiApiKey,
|
||||||
|
getDeepseekApiKey,
|
||||||
|
getLMStudioApiEndpoint,
|
||||||
|
updateConfig,
|
||||||
|
} from '@/lib/config';
|
||||||
|
import {
|
||||||
|
getAvailableChatModelProviders,
|
||||||
|
getAvailableEmbeddingModelProviders,
|
||||||
|
} from '@/lib/providers';
|
||||||
|
|
||||||
|
export const GET = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const config: Record<string, any> = {};
|
||||||
|
|
||||||
|
const [chatModelProviders, embeddingModelProviders] = await Promise.all([
|
||||||
|
getAvailableChatModelProviders(),
|
||||||
|
getAvailableEmbeddingModelProviders(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
config['chatModelProviders'] = {};
|
||||||
|
config['embeddingModelProviders'] = {};
|
||||||
|
|
||||||
|
for (const provider in chatModelProviders) {
|
||||||
|
config['chatModelProviders'][provider] = Object.keys(
|
||||||
|
chatModelProviders[provider],
|
||||||
|
).map((model) => {
|
||||||
|
return {
|
||||||
|
name: model,
|
||||||
|
displayName: chatModelProviders[provider][model].displayName,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const provider in embeddingModelProviders) {
|
||||||
|
config['embeddingModelProviders'][provider] = Object.keys(
|
||||||
|
embeddingModelProviders[provider],
|
||||||
|
).map((model) => {
|
||||||
|
return {
|
||||||
|
name: model,
|
||||||
|
displayName: embeddingModelProviders[provider][model].displayName,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
config['openaiApiKey'] = getOpenaiApiKey();
|
||||||
|
config['ollamaApiUrl'] = getOllamaApiEndpoint();
|
||||||
|
config['lmStudioApiUrl'] = getLMStudioApiEndpoint();
|
||||||
|
config['anthropicApiKey'] = getAnthropicApiKey();
|
||||||
|
config['groqApiKey'] = getGroqApiKey();
|
||||||
|
config['geminiApiKey'] = getGeminiApiKey();
|
||||||
|
config['deepseekApiKey'] = getDeepseekApiKey();
|
||||||
|
config['customOpenaiApiUrl'] = getCustomOpenaiApiUrl();
|
||||||
|
config['customOpenaiApiKey'] = getCustomOpenaiApiKey();
|
||||||
|
config['customOpenaiModelName'] = getCustomOpenaiModelName();
|
||||||
|
|
||||||
|
return Response.json({ ...config }, { status: 200 });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('An error occurred while getting config:', err);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error occurred while getting config' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const POST = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const config = await req.json();
|
||||||
|
|
||||||
|
const updatedConfig = {
|
||||||
|
MODELS: {
|
||||||
|
OPENAI: {
|
||||||
|
API_KEY: config.openaiApiKey,
|
||||||
|
},
|
||||||
|
GROQ: {
|
||||||
|
API_KEY: config.groqApiKey,
|
||||||
|
},
|
||||||
|
ANTHROPIC: {
|
||||||
|
API_KEY: config.anthropicApiKey,
|
||||||
|
},
|
||||||
|
GEMINI: {
|
||||||
|
API_KEY: config.geminiApiKey,
|
||||||
|
},
|
||||||
|
OLLAMA: {
|
||||||
|
API_URL: config.ollamaApiUrl,
|
||||||
|
},
|
||||||
|
DEEPSEEK: {
|
||||||
|
API_KEY: config.deepseekApiKey,
|
||||||
|
},
|
||||||
|
LM_STUDIO: {
|
||||||
|
API_URL: config.lmStudioApiUrl,
|
||||||
|
},
|
||||||
|
CUSTOM_OPENAI: {
|
||||||
|
API_URL: config.customOpenaiApiUrl,
|
||||||
|
API_KEY: config.customOpenaiApiKey,
|
||||||
|
MODEL_NAME: config.customOpenaiModelName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
updateConfig(updatedConfig);
|
||||||
|
|
||||||
|
return Response.json({ message: 'Config updated' }, { status: 200 });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('An error occurred while updating config:', err);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error occurred while updating config' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
76
src/app/api/discover/route.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import { searchSearxng } from '@/lib/searxng';
|
||||||
|
|
||||||
|
const articleWebsites = [
|
||||||
|
'yahoo.com',
|
||||||
|
'www.exchangewire.com',
|
||||||
|
'businessinsider.com',
|
||||||
|
/* 'wired.com',
|
||||||
|
'mashable.com',
|
||||||
|
'theverge.com',
|
||||||
|
'gizmodo.com',
|
||||||
|
'cnet.com',
|
||||||
|
'venturebeat.com', */
|
||||||
|
];
|
||||||
|
|
||||||
|
const topics = ['AI', 'tech']; /* TODO: Add UI to customize this */
|
||||||
|
|
||||||
|
export const GET = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const params = new URL(req.url).searchParams;
|
||||||
|
const mode: 'normal' | 'preview' =
|
||||||
|
(params.get('mode') as 'normal' | 'preview') || 'normal';
|
||||||
|
|
||||||
|
let data = [];
|
||||||
|
|
||||||
|
if (mode === 'normal') {
|
||||||
|
data = (
|
||||||
|
await Promise.all([
|
||||||
|
...new Array(articleWebsites.length * topics.length)
|
||||||
|
.fill(0)
|
||||||
|
.map(async (_, i) => {
|
||||||
|
return (
|
||||||
|
await searchSearxng(
|
||||||
|
`site:${articleWebsites[i % articleWebsites.length]} ${
|
||||||
|
topics[i % topics.length]
|
||||||
|
}`,
|
||||||
|
{
|
||||||
|
engines: ['bing news'],
|
||||||
|
pageno: 1,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
).results;
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
.map((result) => result)
|
||||||
|
.flat()
|
||||||
|
.sort(() => Math.random() - 0.5);
|
||||||
|
} else {
|
||||||
|
data = (
|
||||||
|
await searchSearxng(
|
||||||
|
`site:${articleWebsites[Math.floor(Math.random() * articleWebsites.length)]} ${topics[Math.floor(Math.random() * topics.length)]}`,
|
||||||
|
{ engines: ['bing news'], pageno: 1 },
|
||||||
|
)
|
||||||
|
).results;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
blogs: data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`An error occurred in discover route: ${err}`);
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'An error has occurred',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 500,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
83
src/app/api/images/route.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import handleImageSearch from '@/lib/chains/imageSearchAgent';
|
||||||
|
import {
|
||||||
|
getCustomOpenaiApiKey,
|
||||||
|
getCustomOpenaiApiUrl,
|
||||||
|
getCustomOpenaiModelName,
|
||||||
|
} from '@/lib/config';
|
||||||
|
import { getAvailableChatModelProviders } from '@/lib/providers';
|
||||||
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||||
|
import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
|
||||||
|
import { ChatOpenAI } from '@langchain/openai';
|
||||||
|
|
||||||
|
interface ChatModel {
|
||||||
|
provider: string;
|
||||||
|
model: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImageSearchBody {
|
||||||
|
query: string;
|
||||||
|
chatHistory: any[];
|
||||||
|
chatModel?: ChatModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const body: ImageSearchBody = await req.json();
|
||||||
|
|
||||||
|
const chatHistory = body.chatHistory
|
||||||
|
.map((msg: any) => {
|
||||||
|
if (msg.role === 'user') {
|
||||||
|
return new HumanMessage(msg.content);
|
||||||
|
} else if (msg.role === 'assistant') {
|
||||||
|
return new AIMessage(msg.content);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((msg) => msg !== undefined) as BaseMessage[];
|
||||||
|
|
||||||
|
const chatModelProviders = await getAvailableChatModelProviders();
|
||||||
|
|
||||||
|
const chatModelProvider =
|
||||||
|
chatModelProviders[
|
||||||
|
body.chatModel?.provider || Object.keys(chatModelProviders)[0]
|
||||||
|
];
|
||||||
|
const chatModel =
|
||||||
|
chatModelProvider[
|
||||||
|
body.chatModel?.model || Object.keys(chatModelProvider)[0]
|
||||||
|
];
|
||||||
|
|
||||||
|
let llm: BaseChatModel | undefined;
|
||||||
|
|
||||||
|
if (body.chatModel?.provider === 'custom_openai') {
|
||||||
|
llm = new ChatOpenAI({
|
||||||
|
openAIApiKey: getCustomOpenaiApiKey(),
|
||||||
|
modelName: getCustomOpenaiModelName(),
|
||||||
|
temperature: 0.7,
|
||||||
|
configuration: {
|
||||||
|
baseURL: getCustomOpenaiApiUrl(),
|
||||||
|
},
|
||||||
|
}) as unknown as BaseChatModel;
|
||||||
|
} else if (chatModelProvider && chatModel) {
|
||||||
|
llm = chatModel.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!llm) {
|
||||||
|
return Response.json({ error: 'Invalid chat model' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const images = await handleImageSearch(
|
||||||
|
{
|
||||||
|
chat_history: chatHistory,
|
||||||
|
query: body.query,
|
||||||
|
},
|
||||||
|
llm,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Response.json({ images }, { status: 200 });
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`An error occurred while searching images: ${err}`);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error occurred while searching images' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
47
src/app/api/models/route.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import {
|
||||||
|
getAvailableChatModelProviders,
|
||||||
|
getAvailableEmbeddingModelProviders,
|
||||||
|
} from '@/lib/providers';
|
||||||
|
|
||||||
|
export const GET = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const [chatModelProviders, embeddingModelProviders] = await Promise.all([
|
||||||
|
getAvailableChatModelProviders(),
|
||||||
|
getAvailableEmbeddingModelProviders(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Object.keys(chatModelProviders).forEach((provider) => {
|
||||||
|
Object.keys(chatModelProviders[provider]).forEach((model) => {
|
||||||
|
delete (chatModelProviders[provider][model] as { model?: unknown })
|
||||||
|
.model;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(embeddingModelProviders).forEach((provider) => {
|
||||||
|
Object.keys(embeddingModelProviders[provider]).forEach((model) => {
|
||||||
|
delete (embeddingModelProviders[provider][model] as { model?: unknown })
|
||||||
|
.model;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
chatModelProviders,
|
||||||
|
embeddingModelProviders,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('An error occurred while fetching models', err);
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'An error has occurred.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 500,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
270
src/app/api/search/route.ts
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||||
|
import type { Embeddings } from '@langchain/core/embeddings';
|
||||||
|
import { ChatOpenAI } from '@langchain/openai';
|
||||||
|
import {
|
||||||
|
getAvailableChatModelProviders,
|
||||||
|
getAvailableEmbeddingModelProviders,
|
||||||
|
} from '@/lib/providers';
|
||||||
|
import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
|
||||||
|
import { MetaSearchAgentType } from '@/lib/search/metaSearchAgent';
|
||||||
|
import {
|
||||||
|
getCustomOpenaiApiKey,
|
||||||
|
getCustomOpenaiApiUrl,
|
||||||
|
getCustomOpenaiModelName,
|
||||||
|
} from '@/lib/config';
|
||||||
|
import { searchHandlers } from '@/lib/search';
|
||||||
|
|
||||||
|
interface chatModel {
|
||||||
|
provider: string;
|
||||||
|
name: string;
|
||||||
|
customOpenAIKey?: string;
|
||||||
|
customOpenAIBaseURL?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface embeddingModel {
|
||||||
|
provider: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChatRequestBody {
|
||||||
|
optimizationMode: 'speed' | 'balanced';
|
||||||
|
focusMode: string;
|
||||||
|
chatModel?: chatModel;
|
||||||
|
embeddingModel?: embeddingModel;
|
||||||
|
query: string;
|
||||||
|
history: Array<[string, string]>;
|
||||||
|
stream?: boolean;
|
||||||
|
systemInstructions?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const body: ChatRequestBody = await req.json();
|
||||||
|
|
||||||
|
if (!body.focusMode || !body.query) {
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'Missing focus mode or query' },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.history = body.history || [];
|
||||||
|
body.optimizationMode = body.optimizationMode || 'balanced';
|
||||||
|
body.stream = body.stream || false;
|
||||||
|
|
||||||
|
const history: BaseMessage[] = body.history.map((msg) => {
|
||||||
|
return msg[0] === 'human'
|
||||||
|
? new HumanMessage({ content: msg[1] })
|
||||||
|
: new AIMessage({ content: msg[1] });
|
||||||
|
});
|
||||||
|
|
||||||
|
const [chatModelProviders, embeddingModelProviders] = await Promise.all([
|
||||||
|
getAvailableChatModelProviders(),
|
||||||
|
getAvailableEmbeddingModelProviders(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const chatModelProvider =
|
||||||
|
body.chatModel?.provider || Object.keys(chatModelProviders)[0];
|
||||||
|
const chatModel =
|
||||||
|
body.chatModel?.name ||
|
||||||
|
Object.keys(chatModelProviders[chatModelProvider])[0];
|
||||||
|
|
||||||
|
const embeddingModelProvider =
|
||||||
|
body.embeddingModel?.provider || Object.keys(embeddingModelProviders)[0];
|
||||||
|
const embeddingModel =
|
||||||
|
body.embeddingModel?.name ||
|
||||||
|
Object.keys(embeddingModelProviders[embeddingModelProvider])[0];
|
||||||
|
|
||||||
|
let llm: BaseChatModel | undefined;
|
||||||
|
let embeddings: Embeddings | undefined;
|
||||||
|
|
||||||
|
if (body.chatModel?.provider === 'custom_openai') {
|
||||||
|
llm = new ChatOpenAI({
|
||||||
|
modelName: body.chatModel?.name || getCustomOpenaiModelName(),
|
||||||
|
openAIApiKey:
|
||||||
|
body.chatModel?.customOpenAIKey || getCustomOpenaiApiKey(),
|
||||||
|
temperature: 0.7,
|
||||||
|
configuration: {
|
||||||
|
baseURL:
|
||||||
|
body.chatModel?.customOpenAIBaseURL || getCustomOpenaiApiUrl(),
|
||||||
|
},
|
||||||
|
}) as unknown as BaseChatModel;
|
||||||
|
} else if (
|
||||||
|
chatModelProviders[chatModelProvider] &&
|
||||||
|
chatModelProviders[chatModelProvider][chatModel]
|
||||||
|
) {
|
||||||
|
llm = chatModelProviders[chatModelProvider][chatModel]
|
||||||
|
.model as unknown as BaseChatModel | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
embeddingModelProviders[embeddingModelProvider] &&
|
||||||
|
embeddingModelProviders[embeddingModelProvider][embeddingModel]
|
||||||
|
) {
|
||||||
|
embeddings = embeddingModelProviders[embeddingModelProvider][
|
||||||
|
embeddingModel
|
||||||
|
].model as Embeddings | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!llm || !embeddings) {
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'Invalid model selected' },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchHandler: MetaSearchAgentType = searchHandlers[body.focusMode];
|
||||||
|
|
||||||
|
if (!searchHandler) {
|
||||||
|
return Response.json({ message: 'Invalid focus mode' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const emitter = await searchHandler.searchAndAnswer(
|
||||||
|
body.query,
|
||||||
|
history,
|
||||||
|
llm,
|
||||||
|
embeddings,
|
||||||
|
body.optimizationMode,
|
||||||
|
[],
|
||||||
|
body.systemInstructions || '',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!body.stream) {
|
||||||
|
return new Promise(
|
||||||
|
(
|
||||||
|
resolve: (value: Response) => void,
|
||||||
|
reject: (value: Response) => void,
|
||||||
|
) => {
|
||||||
|
let message = '';
|
||||||
|
let sources: any[] = [];
|
||||||
|
|
||||||
|
emitter.on('data', (data: string) => {
|
||||||
|
try {
|
||||||
|
const parsedData = JSON.parse(data);
|
||||||
|
if (parsedData.type === 'response') {
|
||||||
|
message += parsedData.data;
|
||||||
|
} else if (parsedData.type === 'sources') {
|
||||||
|
sources = parsedData.data;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
reject(
|
||||||
|
Response.json(
|
||||||
|
{ message: 'Error parsing data' },
|
||||||
|
{ status: 500 },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.on('end', () => {
|
||||||
|
resolve(Response.json({ message, sources }, { status: 200 }));
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.on('error', (error: any) => {
|
||||||
|
reject(
|
||||||
|
Response.json(
|
||||||
|
{ message: 'Search error', error },
|
||||||
|
{ status: 500 },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
|
const abortController = new AbortController();
|
||||||
|
const { signal } = abortController;
|
||||||
|
|
||||||
|
const stream = new ReadableStream({
|
||||||
|
start(controller) {
|
||||||
|
let sources: any[] = [];
|
||||||
|
|
||||||
|
controller.enqueue(
|
||||||
|
encoder.encode(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'init',
|
||||||
|
data: 'Stream connected',
|
||||||
|
}) + '\n',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
signal.addEventListener('abort', () => {
|
||||||
|
emitter.removeAllListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
controller.close();
|
||||||
|
} catch (error) {}
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.on('data', (data: string) => {
|
||||||
|
if (signal.aborted) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsedData = JSON.parse(data);
|
||||||
|
|
||||||
|
if (parsedData.type === 'response') {
|
||||||
|
controller.enqueue(
|
||||||
|
encoder.encode(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'response',
|
||||||
|
data: parsedData.data,
|
||||||
|
}) + '\n',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (parsedData.type === 'sources') {
|
||||||
|
sources = parsedData.data;
|
||||||
|
controller.enqueue(
|
||||||
|
encoder.encode(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'sources',
|
||||||
|
data: sources,
|
||||||
|
}) + '\n',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
controller.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.on('end', () => {
|
||||||
|
if (signal.aborted) return;
|
||||||
|
|
||||||
|
controller.enqueue(
|
||||||
|
encoder.encode(
|
||||||
|
JSON.stringify({
|
||||||
|
type: 'done',
|
||||||
|
}) + '\n',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
controller.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.on('error', (error: any) => {
|
||||||
|
if (signal.aborted) return;
|
||||||
|
|
||||||
|
controller.error(error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
cancel() {
|
||||||
|
abortController.abort();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(stream, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/event-stream',
|
||||||
|
'Cache-Control': 'no-cache, no-transform',
|
||||||
|
Connection: 'keep-alive',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error(`Error in getting search results: ${err.message}`);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error has occurred.' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
81
src/app/api/suggestions/route.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import generateSuggestions from '@/lib/chains/suggestionGeneratorAgent';
|
||||||
|
import {
|
||||||
|
getCustomOpenaiApiKey,
|
||||||
|
getCustomOpenaiApiUrl,
|
||||||
|
getCustomOpenaiModelName,
|
||||||
|
} from '@/lib/config';
|
||||||
|
import { getAvailableChatModelProviders } from '@/lib/providers';
|
||||||
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||||
|
import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
|
||||||
|
import { ChatOpenAI } from '@langchain/openai';
|
||||||
|
|
||||||
|
interface ChatModel {
|
||||||
|
provider: string;
|
||||||
|
model: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SuggestionsGenerationBody {
|
||||||
|
chatHistory: any[];
|
||||||
|
chatModel?: ChatModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const body: SuggestionsGenerationBody = await req.json();
|
||||||
|
|
||||||
|
const chatHistory = body.chatHistory
|
||||||
|
.map((msg: any) => {
|
||||||
|
if (msg.role === 'user') {
|
||||||
|
return new HumanMessage(msg.content);
|
||||||
|
} else if (msg.role === 'assistant') {
|
||||||
|
return new AIMessage(msg.content);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((msg) => msg !== undefined) as BaseMessage[];
|
||||||
|
|
||||||
|
const chatModelProviders = await getAvailableChatModelProviders();
|
||||||
|
|
||||||
|
const chatModelProvider =
|
||||||
|
chatModelProviders[
|
||||||
|
body.chatModel?.provider || Object.keys(chatModelProviders)[0]
|
||||||
|
];
|
||||||
|
const chatModel =
|
||||||
|
chatModelProvider[
|
||||||
|
body.chatModel?.model || Object.keys(chatModelProvider)[0]
|
||||||
|
];
|
||||||
|
|
||||||
|
let llm: BaseChatModel | undefined;
|
||||||
|
|
||||||
|
if (body.chatModel?.provider === 'custom_openai') {
|
||||||
|
llm = new ChatOpenAI({
|
||||||
|
openAIApiKey: getCustomOpenaiApiKey(),
|
||||||
|
modelName: getCustomOpenaiModelName(),
|
||||||
|
temperature: 0.7,
|
||||||
|
configuration: {
|
||||||
|
baseURL: getCustomOpenaiApiUrl(),
|
||||||
|
},
|
||||||
|
}) as unknown as BaseChatModel;
|
||||||
|
} else if (chatModelProvider && chatModel) {
|
||||||
|
llm = chatModel.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!llm) {
|
||||||
|
return Response.json({ error: 'Invalid chat model' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const suggestions = await generateSuggestions(
|
||||||
|
{
|
||||||
|
chat_history: chatHistory,
|
||||||
|
},
|
||||||
|
llm,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Response.json({ suggestions }, { status: 200 });
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`An error occurred while generating suggestions: ${err}`);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error occurred while generating suggestions' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
134
src/app/api/uploads/route.ts
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
import { getAvailableEmbeddingModelProviders } from '@/lib/providers';
|
||||||
|
import { PDFLoader } from '@langchain/community/document_loaders/fs/pdf';
|
||||||
|
import { DocxLoader } from '@langchain/community/document_loaders/fs/docx';
|
||||||
|
import { RecursiveCharacterTextSplitter } from '@langchain/textsplitters';
|
||||||
|
import { Document } from 'langchain/document';
|
||||||
|
|
||||||
|
interface FileRes {
|
||||||
|
fileName: string;
|
||||||
|
fileExtension: string;
|
||||||
|
fileId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadDir = path.join(process.cwd(), 'uploads');
|
||||||
|
|
||||||
|
if (!fs.existsSync(uploadDir)) {
|
||||||
|
fs.mkdirSync(uploadDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const splitter = new RecursiveCharacterTextSplitter({
|
||||||
|
chunkSize: 500,
|
||||||
|
chunkOverlap: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
try {
|
||||||
|
const formData = await req.formData();
|
||||||
|
|
||||||
|
const files = formData.getAll('files') as File[];
|
||||||
|
const embedding_model = formData.get('embedding_model');
|
||||||
|
const embedding_model_provider = formData.get('embedding_model_provider');
|
||||||
|
|
||||||
|
if (!embedding_model || !embedding_model_provider) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ message: 'Missing embedding model or provider' },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const embeddingModels = await getAvailableEmbeddingModelProviders();
|
||||||
|
const provider =
|
||||||
|
embedding_model_provider ?? Object.keys(embeddingModels)[0];
|
||||||
|
const embeddingModel =
|
||||||
|
embedding_model ?? Object.keys(embeddingModels[provider as string])[0];
|
||||||
|
|
||||||
|
let embeddingsModel =
|
||||||
|
embeddingModels[provider as string]?.[embeddingModel as string]?.model;
|
||||||
|
if (!embeddingsModel) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ message: 'Invalid embedding model selected' },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const processedFiles: FileRes[] = [];
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
files.map(async (file: any) => {
|
||||||
|
const fileExtension = file.name.split('.').pop();
|
||||||
|
if (!['pdf', 'docx', 'txt'].includes(fileExtension!)) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ message: 'File type not supported' },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueFileName = `${crypto.randomBytes(16).toString('hex')}.${fileExtension}`;
|
||||||
|
const filePath = path.join(uploadDir, uniqueFileName);
|
||||||
|
|
||||||
|
const buffer = Buffer.from(await file.arrayBuffer());
|
||||||
|
fs.writeFileSync(filePath, new Uint8Array(buffer));
|
||||||
|
|
||||||
|
let docs: any[] = [];
|
||||||
|
if (fileExtension === 'pdf') {
|
||||||
|
const loader = new PDFLoader(filePath);
|
||||||
|
docs = await loader.load();
|
||||||
|
} else if (fileExtension === 'docx') {
|
||||||
|
const loader = new DocxLoader(filePath);
|
||||||
|
docs = await loader.load();
|
||||||
|
} else if (fileExtension === 'txt') {
|
||||||
|
const text = fs.readFileSync(filePath, 'utf-8');
|
||||||
|
docs = [
|
||||||
|
new Document({ pageContent: text, metadata: { title: file.name } }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const splitted = await splitter.splitDocuments(docs);
|
||||||
|
|
||||||
|
const extractedDataPath = filePath.replace(/\.\w+$/, '-extracted.json');
|
||||||
|
fs.writeFileSync(
|
||||||
|
extractedDataPath,
|
||||||
|
JSON.stringify({
|
||||||
|
title: file.name,
|
||||||
|
contents: splitted.map((doc) => doc.pageContent),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const embeddings = await embeddingsModel.embedDocuments(
|
||||||
|
splitted.map((doc) => doc.pageContent),
|
||||||
|
);
|
||||||
|
const embeddingsDataPath = filePath.replace(
|
||||||
|
/\.\w+$/,
|
||||||
|
'-embeddings.json',
|
||||||
|
);
|
||||||
|
fs.writeFileSync(
|
||||||
|
embeddingsDataPath,
|
||||||
|
JSON.stringify({
|
||||||
|
title: file.name,
|
||||||
|
embeddings,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
processedFiles.push({
|
||||||
|
fileName: file.name,
|
||||||
|
fileExtension: fileExtension,
|
||||||
|
fileId: uniqueFileName.replace(/\.\w+$/, ''),
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
files: processedFiles,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error uploading file:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ message: 'An error has occurred.' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
83
src/app/api/videos/route.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import handleVideoSearch from '@/lib/chains/videoSearchAgent';
|
||||||
|
import {
|
||||||
|
getCustomOpenaiApiKey,
|
||||||
|
getCustomOpenaiApiUrl,
|
||||||
|
getCustomOpenaiModelName,
|
||||||
|
} from '@/lib/config';
|
||||||
|
import { getAvailableChatModelProviders } from '@/lib/providers';
|
||||||
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||||
|
import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
|
||||||
|
import { ChatOpenAI } from '@langchain/openai';
|
||||||
|
|
||||||
|
interface ChatModel {
|
||||||
|
provider: string;
|
||||||
|
model: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoSearchBody {
|
||||||
|
query: string;
|
||||||
|
chatHistory: any[];
|
||||||
|
chatModel?: ChatModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const body: VideoSearchBody = await req.json();
|
||||||
|
|
||||||
|
const chatHistory = body.chatHistory
|
||||||
|
.map((msg: any) => {
|
||||||
|
if (msg.role === 'user') {
|
||||||
|
return new HumanMessage(msg.content);
|
||||||
|
} else if (msg.role === 'assistant') {
|
||||||
|
return new AIMessage(msg.content);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((msg) => msg !== undefined) as BaseMessage[];
|
||||||
|
|
||||||
|
const chatModelProviders = await getAvailableChatModelProviders();
|
||||||
|
|
||||||
|
const chatModelProvider =
|
||||||
|
chatModelProviders[
|
||||||
|
body.chatModel?.provider || Object.keys(chatModelProviders)[0]
|
||||||
|
];
|
||||||
|
const chatModel =
|
||||||
|
chatModelProvider[
|
||||||
|
body.chatModel?.model || Object.keys(chatModelProvider)[0]
|
||||||
|
];
|
||||||
|
|
||||||
|
let llm: BaseChatModel | undefined;
|
||||||
|
|
||||||
|
if (body.chatModel?.provider === 'custom_openai') {
|
||||||
|
llm = new ChatOpenAI({
|
||||||
|
openAIApiKey: getCustomOpenaiApiKey(),
|
||||||
|
modelName: getCustomOpenaiModelName(),
|
||||||
|
temperature: 0.7,
|
||||||
|
configuration: {
|
||||||
|
baseURL: getCustomOpenaiApiUrl(),
|
||||||
|
},
|
||||||
|
}) as unknown as BaseChatModel;
|
||||||
|
} else if (chatModelProvider && chatModel) {
|
||||||
|
llm = chatModel.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!llm) {
|
||||||
|
return Response.json({ error: 'Invalid chat model' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const videos = await handleVideoSearch(
|
||||||
|
{
|
||||||
|
chat_history: chatHistory,
|
||||||
|
query: body.query,
|
||||||
|
},
|
||||||
|
llm,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Response.json({ videos }, { status: 200 });
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`An error occurred while searching videos: ${err}`);
|
||||||
|
return Response.json(
|
||||||
|
{ message: 'An error occurred while searching videos' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
164
src/app/api/weather/route.ts
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
export const POST = async (req: Request) => {
|
||||||
|
try {
|
||||||
|
const body: { lat: number; lng: number } = await req.json();
|
||||||
|
|
||||||
|
if (!body.lat || !body.lng) {
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'Invalid request.',
|
||||||
|
},
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`https://api.open-meteo.com/v1/forecast?latitude=${body.lat}&longitude=${body.lng}¤t=weather_code,temperature_2m,is_day,relative_humidity_2m,wind_speed_10m&timezone=auto`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (data.error) {
|
||||||
|
console.error(`Error fetching weather data: ${data.reason}`);
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'An error has occurred.',
|
||||||
|
},
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const weather: {
|
||||||
|
temperature: number;
|
||||||
|
condition: string;
|
||||||
|
humidity: number;
|
||||||
|
windSpeed: number;
|
||||||
|
icon: string;
|
||||||
|
} = {
|
||||||
|
temperature: data.current.temperature_2m,
|
||||||
|
condition: '',
|
||||||
|
humidity: data.current.relative_humidity_2m,
|
||||||
|
windSpeed: data.current.wind_speed_10m,
|
||||||
|
icon: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
const code = data.current.weather_code;
|
||||||
|
const isDay = data.current.is_day === 1;
|
||||||
|
const dayOrNight = isDay ? 'day' : 'night';
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case 0:
|
||||||
|
weather.icon = `clear-${dayOrNight}`;
|
||||||
|
weather.condition = 'Clear';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
weather.condition = 'Mainly Clear';
|
||||||
|
case 2:
|
||||||
|
weather.condition = 'Partly Cloudy';
|
||||||
|
case 3:
|
||||||
|
weather.icon = `cloudy-1-${dayOrNight}`;
|
||||||
|
weather.condition = 'Cloudy';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 45:
|
||||||
|
weather.condition = 'Fog';
|
||||||
|
case 48:
|
||||||
|
weather.icon = `fog-${dayOrNight}`;
|
||||||
|
weather.condition = 'Fog';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 51:
|
||||||
|
weather.condition = 'Light Drizzle';
|
||||||
|
case 53:
|
||||||
|
weather.condition = 'Moderate Drizzle';
|
||||||
|
case 55:
|
||||||
|
weather.icon = `rainy-1-${dayOrNight}`;
|
||||||
|
weather.condition = 'Dense Drizzle';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 56:
|
||||||
|
weather.condition = 'Light Freezing Drizzle';
|
||||||
|
case 57:
|
||||||
|
weather.icon = `frost-${dayOrNight}`;
|
||||||
|
weather.condition = 'Dense Freezing Drizzle';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 61:
|
||||||
|
weather.condition = 'Slight Rain';
|
||||||
|
case 63:
|
||||||
|
weather.condition = 'Moderate Rain';
|
||||||
|
case 65:
|
||||||
|
weather.condition = 'Heavy Rain';
|
||||||
|
weather.icon = `rainy-2-${dayOrNight}`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 66:
|
||||||
|
weather.condition = 'Light Freezing Rain';
|
||||||
|
case 67:
|
||||||
|
weather.condition = 'Heavy Freezing Rain';
|
||||||
|
weather.icon = 'rain-and-sleet-mix';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 71:
|
||||||
|
weather.condition = 'Slight Snow Fall';
|
||||||
|
case 73:
|
||||||
|
weather.condition = 'Moderate Snow Fall';
|
||||||
|
case 75:
|
||||||
|
weather.condition = 'Heavy Snow Fall';
|
||||||
|
weather.icon = `snowy-2-${dayOrNight}`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 77:
|
||||||
|
weather.condition = 'Snow';
|
||||||
|
weather.icon = `snowy-1-${dayOrNight}`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 80:
|
||||||
|
weather.condition = 'Slight Rain Showers';
|
||||||
|
case 81:
|
||||||
|
weather.condition = 'Moderate Rain Showers';
|
||||||
|
case 82:
|
||||||
|
weather.condition = 'Heavy Rain Showers';
|
||||||
|
weather.icon = `rainy-3-${dayOrNight}`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 85:
|
||||||
|
weather.condition = 'Slight Snow Showers';
|
||||||
|
case 86:
|
||||||
|
weather.condition = 'Moderate Snow Showers';
|
||||||
|
case 87:
|
||||||
|
weather.condition = 'Heavy Snow Showers';
|
||||||
|
weather.icon = `snowy-3-${dayOrNight}`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 95:
|
||||||
|
weather.condition = 'Thunderstorm';
|
||||||
|
weather.icon = `scattered-thunderstorms-${dayOrNight}`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 96:
|
||||||
|
weather.condition = 'Thunderstorm with Slight Hail';
|
||||||
|
case 99:
|
||||||
|
weather.condition = 'Thunderstorm with Heavy Hail';
|
||||||
|
weather.icon = 'severe-thunderstorm';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
weather.icon = `clear-${dayOrNight}`;
|
||||||
|
weather.condition = 'Clear';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.json(weather);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('An error occurred while getting home widgets', err);
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
message: 'An error has occurred.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 500,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
9
src/app/c/[chatId]/page.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import ChatWindow from '@/components/ChatWindow';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Page = ({ params }: { params: Promise<{ chatId: string }> }) => {
|
||||||
|
const { chatId } = React.use(params);
|
||||||
|
return <ChatWindow id={chatId} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Page;
|
@@ -19,7 +19,7 @@ const Page = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/discover`, {
|
const res = await fetch(`/api/discover`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -21,7 +21,7 @@ const Page = () => {
|
|||||||
const fetchChats = async () => {
|
const fetchChats = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/chats`, {
|
const res = await fetch(`/api/chats`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
@@ -7,6 +7,7 @@ import { Switch } from '@headlessui/react';
|
|||||||
import ThemeSwitcher from '@/components/theme/Switcher';
|
import ThemeSwitcher from '@/components/theme/Switcher';
|
||||||
import { ImagesIcon, VideoIcon } from 'lucide-react';
|
import { ImagesIcon, VideoIcon } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { PROVIDER_METADATA } from '@/lib/providers';
|
||||||
|
|
||||||
interface SettingsType {
|
interface SettingsType {
|
||||||
chatModelProviders: {
|
chatModelProviders: {
|
||||||
@@ -20,6 +21,8 @@ interface SettingsType {
|
|||||||
anthropicApiKey: string;
|
anthropicApiKey: string;
|
||||||
geminiApiKey: string;
|
geminiApiKey: string;
|
||||||
ollamaApiUrl: string;
|
ollamaApiUrl: string;
|
||||||
|
lmStudioApiUrl: string;
|
||||||
|
deepseekApiKey: string;
|
||||||
customOpenaiApiKey: string;
|
customOpenaiApiKey: string;
|
||||||
customOpenaiApiUrl: string;
|
customOpenaiApiUrl: string;
|
||||||
customOpenaiModelName: string;
|
customOpenaiModelName: string;
|
||||||
@@ -54,6 +57,38 @@ const Input = ({ className, isSaving, onSave, ...restProps }: InputProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface TextareaProps extends React.InputHTMLAttributes<HTMLTextAreaElement> {
|
||||||
|
isSaving?: boolean;
|
||||||
|
onSave?: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Textarea = ({
|
||||||
|
className,
|
||||||
|
isSaving,
|
||||||
|
onSave,
|
||||||
|
...restProps
|
||||||
|
}: TextareaProps) => {
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<textarea
|
||||||
|
placeholder="Any special instructions for the LLM"
|
||||||
|
className="placeholder:text-sm text-sm w-full flex items-center justify-between p-3 bg-light-secondary dark:bg-dark-secondary rounded-lg hover:bg-light-200 dark:hover:bg-dark-200 transition-colors"
|
||||||
|
rows={4}
|
||||||
|
onBlur={(e) => onSave?.(e.target.value)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
{isSaving && (
|
||||||
|
<div className="absolute right-3 top-3">
|
||||||
|
<Loader2
|
||||||
|
size={16}
|
||||||
|
className="animate-spin text-black/70 dark:text-white/70"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const Select = ({
|
const Select = ({
|
||||||
className,
|
className,
|
||||||
options,
|
options,
|
||||||
@@ -108,15 +143,15 @@ const Page = () => {
|
|||||||
const [selectedEmbeddingModel, setSelectedEmbeddingModel] = useState<
|
const [selectedEmbeddingModel, setSelectedEmbeddingModel] = useState<
|
||||||
string | null
|
string | null
|
||||||
>(null);
|
>(null);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [automaticImageSearch, setAutomaticImageSearch] = useState(false);
|
const [automaticImageSearch, setAutomaticImageSearch] = useState(false);
|
||||||
const [automaticVideoSearch, setAutomaticVideoSearch] = useState(false);
|
const [automaticVideoSearch, setAutomaticVideoSearch] = useState(false);
|
||||||
|
const [systemInstructions, setSystemInstructions] = useState<string>('');
|
||||||
const [savingStates, setSavingStates] = useState<Record<string, boolean>>({});
|
const [savingStates, setSavingStates] = useState<Record<string, boolean>>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchConfig = async () => {
|
const fetchConfig = async () => {
|
||||||
setIsLoading(true);
|
const res = await fetch(`/api/config`, {
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/config`, {
|
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
@@ -172,6 +207,8 @@ const Page = () => {
|
|||||||
localStorage.getItem('autoVideoSearch') === 'true',
|
localStorage.getItem('autoVideoSearch') === 'true',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
setSystemInstructions(localStorage.getItem('systemInstructions')!);
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -187,16 +224,13 @@ const Page = () => {
|
|||||||
[key]: value,
|
[key]: value,
|
||||||
} as SettingsType;
|
} as SettingsType;
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(`/api/config`, {
|
||||||
`${process.env.NEXT_PUBLIC_API_URL}/config`,
|
method: 'POST',
|
||||||
{
|
headers: {
|
||||||
method: 'POST',
|
'Content-Type': 'application/json',
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(updatedConfig),
|
|
||||||
},
|
},
|
||||||
);
|
body: JSON.stringify(updatedConfig),
|
||||||
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Failed to update config');
|
throw new Error('Failed to update config');
|
||||||
@@ -208,7 +242,7 @@ const Page = () => {
|
|||||||
key.toLowerCase().includes('api') ||
|
key.toLowerCase().includes('api') ||
|
||||||
key.toLowerCase().includes('url')
|
key.toLowerCase().includes('url')
|
||||||
) {
|
) {
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/config`, {
|
const res = await fetch(`/api/config`, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
@@ -331,6 +365,8 @@ const Page = () => {
|
|||||||
localStorage.setItem('embeddingModelProvider', value);
|
localStorage.setItem('embeddingModelProvider', value);
|
||||||
} else if (key === 'embeddingModel') {
|
} else if (key === 'embeddingModel') {
|
||||||
localStorage.setItem('embeddingModel', value);
|
localStorage.setItem('embeddingModel', value);
|
||||||
|
} else if (key === 'systemInstructions') {
|
||||||
|
localStorage.setItem('systemInstructions', value);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to save:', err);
|
console.error('Failed to save:', err);
|
||||||
@@ -476,6 +512,19 @@ const Page = () => {
|
|||||||
</div>
|
</div>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
||||||
|
<SettingsSection title="System Instructions">
|
||||||
|
<div className="flex flex-col space-y-4">
|
||||||
|
<Textarea
|
||||||
|
value={systemInstructions}
|
||||||
|
isSaving={savingStates['systemInstructions']}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSystemInstructions(e.target.value);
|
||||||
|
}}
|
||||||
|
onSave={(value) => saveConfig('systemInstructions', value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</SettingsSection>
|
||||||
|
|
||||||
<SettingsSection title="Model Settings">
|
<SettingsSection title="Model Settings">
|
||||||
{config.chatModelProviders && (
|
{config.chatModelProviders && (
|
||||||
<div className="flex flex-col space-y-4">
|
<div className="flex flex-col space-y-4">
|
||||||
@@ -500,8 +549,9 @@ const Page = () => {
|
|||||||
(provider) => ({
|
(provider) => ({
|
||||||
value: provider,
|
value: provider,
|
||||||
label:
|
label:
|
||||||
|
(PROVIDER_METADATA as any)[provider]?.displayName ||
|
||||||
provider.charAt(0).toUpperCase() +
|
provider.charAt(0).toUpperCase() +
|
||||||
provider.slice(1),
|
provider.slice(1),
|
||||||
}),
|
}),
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -642,8 +692,9 @@ const Page = () => {
|
|||||||
(provider) => ({
|
(provider) => ({
|
||||||
value: provider,
|
value: provider,
|
||||||
label:
|
label:
|
||||||
|
(PROVIDER_METADATA as any)[provider]?.displayName ||
|
||||||
provider.charAt(0).toUpperCase() +
|
provider.charAt(0).toUpperCase() +
|
||||||
provider.slice(1),
|
provider.slice(1),
|
||||||
}),
|
}),
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -791,6 +842,44 @@ const Page = () => {
|
|||||||
onSave={(value) => saveConfig('geminiApiKey', value)}
|
onSave={(value) => saveConfig('geminiApiKey', value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col space-y-1">
|
||||||
|
<p className="text-black/70 dark:text-white/70 text-sm">
|
||||||
|
Deepseek API Key
|
||||||
|
</p>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
placeholder="Deepseek API Key"
|
||||||
|
value={config.deepseekApiKey}
|
||||||
|
isSaving={savingStates['deepseekApiKey']}
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfig((prev) => ({
|
||||||
|
...prev!,
|
||||||
|
deepseekApiKey: e.target.value,
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
onSave={(value) => saveConfig('deepseekApiKey', value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col space-y-1">
|
||||||
|
<p className="text-black/70 dark:text-white/70 text-sm">
|
||||||
|
LM Studio API URL
|
||||||
|
</p>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
placeholder="LM Studio API URL"
|
||||||
|
value={config.lmStudioApiUrl}
|
||||||
|
isSaving={savingStates['lmStudioApiUrl']}
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfig((prev) => ({
|
||||||
|
...prev!,
|
||||||
|
lmStudioApiUrl: e.target.value,
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
onSave={(value) => saveConfig('lmStudioApiUrl', value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
</div>
|
</div>
|
@@ -48,11 +48,17 @@ const Chat = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
messageEnd.current?.scrollIntoView({ behavior: 'smooth' });
|
const scroll = () => {
|
||||||
|
messageEnd.current?.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
};
|
||||||
|
|
||||||
if (messages.length === 1) {
|
if (messages.length === 1) {
|
||||||
document.title = `${messages[0].content.substring(0, 30)} - Perplexica`;
|
document.title = `${messages[0].content.substring(0, 30)} - Perplexica`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (messages[messages.length - 1]?.role == 'user') {
|
||||||
|
scroll();
|
||||||
|
}
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
return (
|
return (
|
@@ -29,280 +29,154 @@ export interface File {
|
|||||||
fileId: string;
|
fileId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useSocket = (
|
interface ChatModelProvider {
|
||||||
url: string,
|
name: string;
|
||||||
setIsWSReady: (ready: boolean) => void,
|
provider: string;
|
||||||
setError: (error: boolean) => void,
|
}
|
||||||
|
|
||||||
|
interface EmbeddingModelProvider {
|
||||||
|
name: string;
|
||||||
|
provider: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkConfig = async (
|
||||||
|
setChatModelProvider: (provider: ChatModelProvider) => void,
|
||||||
|
setEmbeddingModelProvider: (provider: EmbeddingModelProvider) => void,
|
||||||
|
setIsConfigReady: (ready: boolean) => void,
|
||||||
|
setHasError: (hasError: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const wsRef = useRef<WebSocket | null>(null);
|
try {
|
||||||
const reconnectTimeoutRef = useRef<NodeJS.Timeout>();
|
let chatModel = localStorage.getItem('chatModel');
|
||||||
const retryCountRef = useRef(0);
|
let chatModelProvider = localStorage.getItem('chatModelProvider');
|
||||||
const isCleaningUpRef = useRef(false);
|
let embeddingModel = localStorage.getItem('embeddingModel');
|
||||||
const MAX_RETRIES = 3;
|
let embeddingModelProvider = localStorage.getItem('embeddingModelProvider');
|
||||||
const INITIAL_BACKOFF = 1000; // 1 second
|
|
||||||
const isConnectionErrorRef = useRef(false);
|
|
||||||
|
|
||||||
const getBackoffDelay = (retryCount: number) => {
|
const autoImageSearch = localStorage.getItem('autoImageSearch');
|
||||||
return Math.min(INITIAL_BACKOFF * Math.pow(2, retryCount), 10000); // Cap at 10 seconds
|
const autoVideoSearch = localStorage.getItem('autoVideoSearch');
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
if (!autoImageSearch) {
|
||||||
const connectWs = async () => {
|
localStorage.setItem('autoImageSearch', 'true');
|
||||||
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
}
|
||||||
wsRef.current.close();
|
|
||||||
|
if (!autoVideoSearch) {
|
||||||
|
localStorage.setItem('autoVideoSearch', 'false');
|
||||||
|
}
|
||||||
|
|
||||||
|
const providers = await fetch(`/api/models`, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
}).then(async (res) => {
|
||||||
|
if (!res.ok)
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch models: ${res.status} ${res.statusText}`,
|
||||||
|
);
|
||||||
|
return res.json();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
!chatModel ||
|
||||||
|
!chatModelProvider ||
|
||||||
|
!embeddingModel ||
|
||||||
|
!embeddingModelProvider
|
||||||
|
) {
|
||||||
|
if (!chatModel || !chatModelProvider) {
|
||||||
|
const chatModelProviders = providers.chatModelProviders;
|
||||||
|
|
||||||
|
chatModelProvider =
|
||||||
|
chatModelProvider || Object.keys(chatModelProviders)[0];
|
||||||
|
|
||||||
|
chatModel = Object.keys(chatModelProviders[chatModelProvider])[0];
|
||||||
|
|
||||||
|
if (!chatModelProviders || Object.keys(chatModelProviders).length === 0)
|
||||||
|
return toast.error('No chat models available');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (!embeddingModel || !embeddingModelProvider) {
|
||||||
let chatModel = localStorage.getItem('chatModel');
|
const embeddingModelProviders = providers.embeddingModelProviders;
|
||||||
let chatModelProvider = localStorage.getItem('chatModelProvider');
|
|
||||||
let embeddingModel = localStorage.getItem('embeddingModel');
|
|
||||||
let embeddingModelProvider = localStorage.getItem(
|
|
||||||
'embeddingModelProvider',
|
|
||||||
);
|
|
||||||
|
|
||||||
const autoImageSearch = localStorage.getItem('autoImageSearch');
|
|
||||||
const autoVideoSearch = localStorage.getItem('autoVideoSearch');
|
|
||||||
|
|
||||||
if (!autoImageSearch) {
|
|
||||||
localStorage.setItem('autoImageSearch', 'true');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!autoVideoSearch) {
|
|
||||||
localStorage.setItem('autoVideoSearch', 'false');
|
|
||||||
}
|
|
||||||
|
|
||||||
const providers = await fetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_API_URL}/models`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
).then(async (res) => {
|
|
||||||
if (!res.ok)
|
|
||||||
throw new Error(
|
|
||||||
`Failed to fetch models: ${res.status} ${res.statusText}`,
|
|
||||||
);
|
|
||||||
return res.json();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!chatModel ||
|
!embeddingModelProviders ||
|
||||||
!chatModelProvider ||
|
Object.keys(embeddingModelProviders).length === 0
|
||||||
!embeddingModel ||
|
)
|
||||||
!embeddingModelProvider
|
return toast.error('No embedding models available');
|
||||||
) {
|
|
||||||
if (!chatModel || !chatModelProvider) {
|
|
||||||
const chatModelProviders = providers.chatModelProviders;
|
|
||||||
|
|
||||||
chatModelProvider =
|
embeddingModelProvider = Object.keys(embeddingModelProviders)[0];
|
||||||
chatModelProvider || Object.keys(chatModelProviders)[0];
|
embeddingModel = Object.keys(
|
||||||
|
embeddingModelProviders[embeddingModelProvider],
|
||||||
chatModel = Object.keys(chatModelProviders[chatModelProvider])[0];
|
)[0];
|
||||||
|
|
||||||
if (
|
|
||||||
!chatModelProviders ||
|
|
||||||
Object.keys(chatModelProviders).length === 0
|
|
||||||
)
|
|
||||||
return toast.error('No chat models available');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!embeddingModel || !embeddingModelProvider) {
|
|
||||||
const embeddingModelProviders = providers.embeddingModelProviders;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!embeddingModelProviders ||
|
|
||||||
Object.keys(embeddingModelProviders).length === 0
|
|
||||||
)
|
|
||||||
return toast.error('No embedding models available');
|
|
||||||
|
|
||||||
embeddingModelProvider = Object.keys(embeddingModelProviders)[0];
|
|
||||||
embeddingModel = Object.keys(
|
|
||||||
embeddingModelProviders[embeddingModelProvider],
|
|
||||||
)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem('chatModel', chatModel!);
|
|
||||||
localStorage.setItem('chatModelProvider', chatModelProvider);
|
|
||||||
localStorage.setItem('embeddingModel', embeddingModel!);
|
|
||||||
localStorage.setItem(
|
|
||||||
'embeddingModelProvider',
|
|
||||||
embeddingModelProvider,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
const chatModelProviders = providers.chatModelProviders;
|
|
||||||
const embeddingModelProviders = providers.embeddingModelProviders;
|
|
||||||
|
|
||||||
if (
|
|
||||||
Object.keys(chatModelProviders).length > 0 &&
|
|
||||||
!chatModelProviders[chatModelProvider]
|
|
||||||
) {
|
|
||||||
const chatModelProvidersKeys = Object.keys(chatModelProviders);
|
|
||||||
chatModelProvider =
|
|
||||||
chatModelProvidersKeys.find(
|
|
||||||
(key) => Object.keys(chatModelProviders[key]).length > 0,
|
|
||||||
) || chatModelProvidersKeys[0];
|
|
||||||
|
|
||||||
localStorage.setItem('chatModelProvider', chatModelProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
chatModelProvider &&
|
|
||||||
!chatModelProviders[chatModelProvider][chatModel]
|
|
||||||
) {
|
|
||||||
chatModel = Object.keys(
|
|
||||||
chatModelProviders[
|
|
||||||
Object.keys(chatModelProviders[chatModelProvider]).length > 0
|
|
||||||
? chatModelProvider
|
|
||||||
: Object.keys(chatModelProviders)[0]
|
|
||||||
],
|
|
||||||
)[0];
|
|
||||||
localStorage.setItem('chatModel', chatModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
Object.keys(embeddingModelProviders).length > 0 &&
|
|
||||||
!embeddingModelProviders[embeddingModelProvider]
|
|
||||||
) {
|
|
||||||
embeddingModelProvider = Object.keys(embeddingModelProviders)[0];
|
|
||||||
localStorage.setItem(
|
|
||||||
'embeddingModelProvider',
|
|
||||||
embeddingModelProvider,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
embeddingModelProvider &&
|
|
||||||
!embeddingModelProviders[embeddingModelProvider][embeddingModel]
|
|
||||||
) {
|
|
||||||
embeddingModel = Object.keys(
|
|
||||||
embeddingModelProviders[embeddingModelProvider],
|
|
||||||
)[0];
|
|
||||||
localStorage.setItem('embeddingModel', embeddingModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const wsURL = new URL(url);
|
|
||||||
const searchParams = new URLSearchParams({});
|
|
||||||
|
|
||||||
searchParams.append('chatModel', chatModel!);
|
|
||||||
searchParams.append('chatModelProvider', chatModelProvider);
|
|
||||||
|
|
||||||
if (chatModelProvider === 'custom_openai') {
|
|
||||||
searchParams.append(
|
|
||||||
'openAIApiKey',
|
|
||||||
localStorage.getItem('openAIApiKey')!,
|
|
||||||
);
|
|
||||||
searchParams.append(
|
|
||||||
'openAIBaseURL',
|
|
||||||
localStorage.getItem('openAIBaseURL')!,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
searchParams.append('embeddingModel', embeddingModel!);
|
|
||||||
searchParams.append('embeddingModelProvider', embeddingModelProvider);
|
|
||||||
|
|
||||||
wsURL.search = searchParams.toString();
|
|
||||||
|
|
||||||
const ws = new WebSocket(wsURL.toString());
|
|
||||||
wsRef.current = ws;
|
|
||||||
|
|
||||||
const timeoutId = setTimeout(() => {
|
|
||||||
if (ws.readyState !== 1) {
|
|
||||||
toast.error(
|
|
||||||
'Failed to connect to the server. Please try again later.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
ws.addEventListener('message', (e) => {
|
|
||||||
const data = JSON.parse(e.data);
|
|
||||||
if (data.type === 'signal' && data.data === 'open') {
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
if (ws.readyState === 1) {
|
|
||||||
setIsWSReady(true);
|
|
||||||
setError(false);
|
|
||||||
if (retryCountRef.current > 0) {
|
|
||||||
toast.success('Connection restored.');
|
|
||||||
}
|
|
||||||
retryCountRef.current = 0;
|
|
||||||
clearInterval(interval);
|
|
||||||
}
|
|
||||||
}, 5);
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
console.debug(new Date(), 'ws:connected');
|
|
||||||
}
|
|
||||||
if (data.type === 'error') {
|
|
||||||
isConnectionErrorRef.current = true;
|
|
||||||
setError(true);
|
|
||||||
toast.error(data.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.onerror = () => {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
setIsWSReady(false);
|
|
||||||
toast.error('WebSocket connection error.');
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.onclose = () => {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
setIsWSReady(false);
|
|
||||||
console.debug(new Date(), 'ws:disconnected');
|
|
||||||
if (!isCleaningUpRef.current && !isConnectionErrorRef.current) {
|
|
||||||
toast.error('Connection lost. Attempting to reconnect...');
|
|
||||||
attemptReconnect();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.debug(new Date(), 'ws:error', error);
|
|
||||||
setIsWSReady(false);
|
|
||||||
attemptReconnect();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const attemptReconnect = () => {
|
|
||||||
retryCountRef.current += 1;
|
|
||||||
|
|
||||||
if (retryCountRef.current > MAX_RETRIES) {
|
|
||||||
console.debug(new Date(), 'ws:max_retries');
|
|
||||||
setError(true);
|
|
||||||
toast.error(
|
|
||||||
'Unable to connect to server after multiple attempts. Please refresh the page to try again.',
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const backoffDelay = getBackoffDelay(retryCountRef.current);
|
localStorage.setItem('chatModel', chatModel!);
|
||||||
console.debug(
|
localStorage.setItem('chatModelProvider', chatModelProvider);
|
||||||
new Date(),
|
localStorage.setItem('embeddingModel', embeddingModel!);
|
||||||
`ws:retry attempt=${retryCountRef.current}/${MAX_RETRIES} delay=${backoffDelay}ms`,
|
localStorage.setItem('embeddingModelProvider', embeddingModelProvider);
|
||||||
);
|
} else {
|
||||||
|
const chatModelProviders = providers.chatModelProviders;
|
||||||
|
const embeddingModelProviders = providers.embeddingModelProviders;
|
||||||
|
|
||||||
if (reconnectTimeoutRef.current) {
|
if (
|
||||||
clearTimeout(reconnectTimeoutRef.current);
|
Object.keys(chatModelProviders).length > 0 &&
|
||||||
|
!chatModelProviders[chatModelProvider]
|
||||||
|
) {
|
||||||
|
const chatModelProvidersKeys = Object.keys(chatModelProviders);
|
||||||
|
chatModelProvider =
|
||||||
|
chatModelProvidersKeys.find(
|
||||||
|
(key) => Object.keys(chatModelProviders[key]).length > 0,
|
||||||
|
) || chatModelProvidersKeys[0];
|
||||||
|
|
||||||
|
localStorage.setItem('chatModelProvider', chatModelProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
reconnectTimeoutRef.current = setTimeout(() => {
|
if (
|
||||||
connectWs();
|
chatModelProvider &&
|
||||||
}, backoffDelay);
|
!chatModelProviders[chatModelProvider][chatModel]
|
||||||
};
|
) {
|
||||||
|
chatModel = Object.keys(
|
||||||
connectWs();
|
chatModelProviders[
|
||||||
|
Object.keys(chatModelProviders[chatModelProvider]).length > 0
|
||||||
return () => {
|
? chatModelProvider
|
||||||
if (reconnectTimeoutRef.current) {
|
: Object.keys(chatModelProviders)[0]
|
||||||
clearTimeout(reconnectTimeoutRef.current);
|
],
|
||||||
|
)[0];
|
||||||
|
localStorage.setItem('chatModel', chatModel);
|
||||||
}
|
}
|
||||||
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
||||||
wsRef.current.close();
|
|
||||||
isCleaningUpRef.current = true;
|
|
||||||
console.debug(new Date(), 'ws:cleanup');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [url, setIsWSReady, setError]);
|
|
||||||
|
|
||||||
return wsRef.current;
|
if (
|
||||||
|
Object.keys(embeddingModelProviders).length > 0 &&
|
||||||
|
!embeddingModelProviders[embeddingModelProvider]
|
||||||
|
) {
|
||||||
|
embeddingModelProvider = Object.keys(embeddingModelProviders)[0];
|
||||||
|
localStorage.setItem('embeddingModelProvider', embeddingModelProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
embeddingModelProvider &&
|
||||||
|
!embeddingModelProviders[embeddingModelProvider][embeddingModel]
|
||||||
|
) {
|
||||||
|
embeddingModel = Object.keys(
|
||||||
|
embeddingModelProviders[embeddingModelProvider],
|
||||||
|
)[0];
|
||||||
|
localStorage.setItem('embeddingModel', embeddingModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setChatModelProvider({
|
||||||
|
name: chatModel!,
|
||||||
|
provider: chatModelProvider,
|
||||||
|
});
|
||||||
|
|
||||||
|
setEmbeddingModelProvider({
|
||||||
|
name: embeddingModel!,
|
||||||
|
provider: embeddingModelProvider,
|
||||||
|
});
|
||||||
|
|
||||||
|
setIsConfigReady(true);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('An error occurred while checking the configuration:', err);
|
||||||
|
setIsConfigReady(false);
|
||||||
|
setHasError(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadMessages = async (
|
const loadMessages = async (
|
||||||
@@ -315,15 +189,12 @@ const loadMessages = async (
|
|||||||
setFiles: (files: File[]) => void,
|
setFiles: (files: File[]) => void,
|
||||||
setFileIds: (fileIds: string[]) => void,
|
setFileIds: (fileIds: string[]) => void,
|
||||||
) => {
|
) => {
|
||||||
const res = await fetch(
|
const res = await fetch(`/api/chats/${chatId}`, {
|
||||||
`${process.env.NEXT_PUBLIC_API_URL}/chats/${chatId}`,
|
method: 'GET',
|
||||||
{
|
headers: {
|
||||||
method: 'GET',
|
'Content-Type': 'application/json',
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
||||||
if (res.status === 404) {
|
if (res.status === 404) {
|
||||||
setNotFound(true);
|
setNotFound(true);
|
||||||
@@ -373,15 +244,32 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
const [chatId, setChatId] = useState<string | undefined>(id);
|
const [chatId, setChatId] = useState<string | undefined>(id);
|
||||||
const [newChatCreated, setNewChatCreated] = useState(false);
|
const [newChatCreated, setNewChatCreated] = useState(false);
|
||||||
|
|
||||||
|
const [chatModelProvider, setChatModelProvider] = useState<ChatModelProvider>(
|
||||||
|
{
|
||||||
|
name: '',
|
||||||
|
provider: '',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const [embeddingModelProvider, setEmbeddingModelProvider] =
|
||||||
|
useState<EmbeddingModelProvider>({
|
||||||
|
name: '',
|
||||||
|
provider: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const [isConfigReady, setIsConfigReady] = useState(false);
|
||||||
const [hasError, setHasError] = useState(false);
|
const [hasError, setHasError] = useState(false);
|
||||||
const [isReady, setIsReady] = useState(false);
|
const [isReady, setIsReady] = useState(false);
|
||||||
|
|
||||||
const [isWSReady, setIsWSReady] = useState(false);
|
useEffect(() => {
|
||||||
const ws = useSocket(
|
checkConfig(
|
||||||
process.env.NEXT_PUBLIC_WS_URL!,
|
setChatModelProvider,
|
||||||
setIsWSReady,
|
setEmbeddingModelProvider,
|
||||||
setHasError,
|
setIsConfigReady,
|
||||||
);
|
setHasError,
|
||||||
|
);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [messageAppeared, setMessageAppeared] = useState(false);
|
const [messageAppeared, setMessageAppeared] = useState(false);
|
||||||
@@ -399,8 +287,6 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
|
|
||||||
const [notFound, setNotFound] = useState(false);
|
const [notFound, setNotFound] = useState(false);
|
||||||
|
|
||||||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
chatId &&
|
chatId &&
|
||||||
@@ -426,16 +312,6 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
if (ws?.readyState === 1) {
|
|
||||||
ws.close();
|
|
||||||
console.debug(new Date(), 'ws:cleanup');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const messagesRef = useRef<Message[]>([]);
|
const messagesRef = useRef<Message[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -443,18 +319,18 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isMessagesLoaded && isWSReady) {
|
if (isMessagesLoaded && isConfigReady) {
|
||||||
setIsReady(true);
|
setIsReady(true);
|
||||||
console.debug(new Date(), 'app:ready');
|
console.debug(new Date(), 'app:ready');
|
||||||
} else {
|
} else {
|
||||||
setIsReady(false);
|
setIsReady(false);
|
||||||
}
|
}
|
||||||
}, [isMessagesLoaded, isWSReady]);
|
}, [isMessagesLoaded, isConfigReady]);
|
||||||
|
|
||||||
const sendMessage = async (message: string, messageId?: string) => {
|
const sendMessage = async (message: string, messageId?: string) => {
|
||||||
if (loading) return;
|
if (loading) return;
|
||||||
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
if (!isConfigReady) {
|
||||||
toast.error('Cannot send message while disconnected');
|
toast.error('Cannot send message before the configuration is ready');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,21 +343,6 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
|
|
||||||
messageId = messageId ?? crypto.randomBytes(7).toString('hex');
|
messageId = messageId ?? crypto.randomBytes(7).toString('hex');
|
||||||
|
|
||||||
ws.send(
|
|
||||||
JSON.stringify({
|
|
||||||
type: 'message',
|
|
||||||
message: {
|
|
||||||
messageId: messageId,
|
|
||||||
chatId: chatId!,
|
|
||||||
content: message,
|
|
||||||
},
|
|
||||||
files: fileIds,
|
|
||||||
focusMode: focusMode,
|
|
||||||
optimizationMode: optimizationMode,
|
|
||||||
history: [...chatHistory, ['human', message]],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
setMessages((prevMessages) => [
|
setMessages((prevMessages) => [
|
||||||
...prevMessages,
|
...prevMessages,
|
||||||
{
|
{
|
||||||
@@ -493,9 +354,7 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const messageHandler = async (e: MessageEvent) => {
|
const messageHandler = async (data: any) => {
|
||||||
const data = JSON.parse(e.data);
|
|
||||||
|
|
||||||
if (data.type === 'error') {
|
if (data.type === 'error') {
|
||||||
toast.error(data.data);
|
toast.error(data.data);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -558,11 +417,25 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
['assistant', recievedMessage],
|
['assistant', recievedMessage],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
ws?.removeEventListener('message', messageHandler);
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
const lastMsg = messagesRef.current[messagesRef.current.length - 1];
|
const lastMsg = messagesRef.current[messagesRef.current.length - 1];
|
||||||
|
|
||||||
|
const autoImageSearch = localStorage.getItem('autoImageSearch');
|
||||||
|
const autoVideoSearch = localStorage.getItem('autoVideoSearch');
|
||||||
|
|
||||||
|
if (autoImageSearch === 'true') {
|
||||||
|
document
|
||||||
|
.getElementById(`search-images-${lastMsg.messageId}`)
|
||||||
|
?.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoVideoSearch === 'true') {
|
||||||
|
document
|
||||||
|
.getElementById(`search-videos-${lastMsg.messageId}`)
|
||||||
|
?.click();
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
lastMsg.role === 'assistant' &&
|
lastMsg.role === 'assistant' &&
|
||||||
lastMsg.sources &&
|
lastMsg.sources &&
|
||||||
@@ -579,21 +452,63 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const autoImageSearch = localStorage.getItem('autoImageSearch');
|
|
||||||
const autoVideoSearch = localStorage.getItem('autoVideoSearch');
|
|
||||||
|
|
||||||
if (autoImageSearch === 'true') {
|
|
||||||
document.getElementById('search-images')?.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (autoVideoSearch === 'true') {
|
|
||||||
document.getElementById('search-videos')?.click();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ws?.addEventListener('message', messageHandler);
|
const res = await fetch('/api/chat', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
content: message,
|
||||||
|
message: {
|
||||||
|
messageId: messageId,
|
||||||
|
chatId: chatId!,
|
||||||
|
content: message,
|
||||||
|
},
|
||||||
|
chatId: chatId!,
|
||||||
|
files: fileIds,
|
||||||
|
focusMode: focusMode,
|
||||||
|
optimizationMode: optimizationMode,
|
||||||
|
history: chatHistory,
|
||||||
|
chatModel: {
|
||||||
|
name: chatModelProvider.name,
|
||||||
|
provider: chatModelProvider.provider,
|
||||||
|
},
|
||||||
|
embeddingModel: {
|
||||||
|
name: embeddingModelProvider.name,
|
||||||
|
provider: embeddingModelProvider.provider,
|
||||||
|
},
|
||||||
|
systemInstructions: localStorage.getItem('systemInstructions'),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.body) throw new Error('No response body');
|
||||||
|
|
||||||
|
const reader = res.body?.getReader();
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
|
||||||
|
let partialChunk = '';
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
|
||||||
|
partialChunk += decoder.decode(value, { stream: true });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const messages = partialChunk.split('\n');
|
||||||
|
for (const msg of messages) {
|
||||||
|
if (!msg.trim()) continue;
|
||||||
|
const json = JSON.parse(msg);
|
||||||
|
messageHandler(json);
|
||||||
|
}
|
||||||
|
partialChunk = '';
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Incomplete JSON, waiting for next chunk...');
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const rewrite = (messageId: string) => {
|
const rewrite = (messageId: string) => {
|
||||||
@@ -614,11 +529,11 @@ const ChatWindow = ({ id }: { id?: string }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isReady && initialMessage && ws?.readyState === 1) {
|
if (isReady && initialMessage && isConfigReady) {
|
||||||
sendMessage(initialMessage);
|
sendMessage(initialMessage);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [ws?.readyState, isReady, initialMessage, isWSReady]);
|
}, [isConfigReady, isReady, initialMessage]);
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
return (
|
return (
|
@@ -29,15 +29,12 @@ const DeleteChat = ({
|
|||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await fetch(
|
const res = await fetch(`/api/chats/${chatId}`, {
|
||||||
`${process.env.NEXT_PUBLIC_API_URL}/chats/${chatId}`,
|
method: 'DELETE',
|
||||||
{
|
headers: {
|
||||||
method: 'DELETE',
|
'Content-Type': 'application/json',
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
);
|
});
|
||||||
|
|
||||||
if (res.status != 200) {
|
if (res.status != 200) {
|
||||||
throw new Error('Failed to delete chat');
|
throw new Error('Failed to delete chat');
|
@@ -1,8 +1,10 @@
|
|||||||
import { Settings } from 'lucide-react';
|
import { Settings } from 'lucide-react';
|
||||||
import EmptyChatMessageInput from './EmptyChatMessageInput';
|
import EmptyChatMessageInput from './EmptyChatMessageInput';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { File } from './ChatWindow';
|
import { File } from './ChatWindow';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import WeatherWidget from './WeatherWidget';
|
||||||
|
import NewsArticleWidget from './NewsArticleWidget';
|
||||||
|
|
||||||
const EmptyChat = ({
|
const EmptyChat = ({
|
||||||
sendMessage,
|
sendMessage,
|
||||||
@@ -25,8 +27,6 @@ const EmptyChat = ({
|
|||||||
files: File[];
|
files: File[];
|
||||||
setFiles: (files: File[]) => void;
|
setFiles: (files: File[]) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="absolute w-full flex flex-row items-center justify-end mr-5 mt-5">
|
<div className="absolute w-full flex flex-row items-center justify-end mr-5 mt-5">
|
||||||
@@ -49,6 +49,14 @@ const EmptyChat = ({
|
|||||||
files={files}
|
files={files}
|
||||||
setFiles={setFiles}
|
setFiles={setFiles}
|
||||||
/>
|
/>
|
||||||
|
<div className="flex flex-col w-full gap-4 mt-2 sm:flex-row sm:justify-center">
|
||||||
|
<div className="flex-1 max-w-xs">
|
||||||
|
<WeatherWidget />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 max-w-xs">
|
||||||
|
<NewsArticleWidget />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
@@ -12,13 +12,18 @@ import {
|
|||||||
Layers3,
|
Layers3,
|
||||||
Plus,
|
Plus,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import Markdown from 'markdown-to-jsx';
|
import Markdown, { MarkdownToJSX } from 'markdown-to-jsx';
|
||||||
import Copy from './MessageActions/Copy';
|
import Copy from './MessageActions/Copy';
|
||||||
import Rewrite from './MessageActions/Rewrite';
|
import Rewrite from './MessageActions/Rewrite';
|
||||||
import MessageSources from './MessageSources';
|
import MessageSources from './MessageSources';
|
||||||
import SearchImages from './SearchImages';
|
import SearchImages from './SearchImages';
|
||||||
import SearchVideos from './SearchVideos';
|
import SearchVideos from './SearchVideos';
|
||||||
import { useSpeech } from 'react-text-to-speech';
|
import { useSpeech } from 'react-text-to-speech';
|
||||||
|
import ThinkBox from './ThinkBox';
|
||||||
|
|
||||||
|
const ThinkTagProcessor = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
return <ThinkBox content={children as string} />;
|
||||||
|
};
|
||||||
|
|
||||||
const MessageBox = ({
|
const MessageBox = ({
|
||||||
message,
|
message,
|
||||||
@@ -43,32 +48,83 @@ const MessageBox = ({
|
|||||||
const [speechMessage, setSpeechMessage] = useState(message.content);
|
const [speechMessage, setSpeechMessage] = useState(message.content);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const citationRegex = /\[([^\]]+)\]/g;
|
||||||
const regex = /\[(\d+)\]/g;
|
const regex = /\[(\d+)\]/g;
|
||||||
|
let processedMessage = message.content;
|
||||||
|
|
||||||
|
if (message.role === 'assistant' && message.content.includes('<think>')) {
|
||||||
|
const openThinkTag = processedMessage.match(/<think>/g)?.length || 0;
|
||||||
|
const closeThinkTag = processedMessage.match(/<\/think>/g)?.length || 0;
|
||||||
|
|
||||||
|
if (openThinkTag > closeThinkTag) {
|
||||||
|
processedMessage += '</think> <a> </a>'; // The extra <a> </a> is to prevent the the think component from looking bad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
message.role === 'assistant' &&
|
message.role === 'assistant' &&
|
||||||
message?.sources &&
|
message?.sources &&
|
||||||
message.sources.length > 0
|
message.sources.length > 0
|
||||||
) {
|
) {
|
||||||
return setParsedMessage(
|
setParsedMessage(
|
||||||
message.content.replace(
|
processedMessage.replace(
|
||||||
regex,
|
citationRegex,
|
||||||
(_, number) =>
|
(_, capturedContent: string) => {
|
||||||
`<a href="${message.sources?.[number - 1]?.metadata?.url}" target="_blank" className="bg-light-secondary dark:bg-dark-secondary px-1 rounded ml-1 no-underline text-xs text-black/70 dark:text-white/70 relative">${number}</a>`,
|
const numbers = capturedContent
|
||||||
|
.split(',')
|
||||||
|
.map((numStr) => numStr.trim());
|
||||||
|
|
||||||
|
const linksHtml = numbers
|
||||||
|
.map((numStr) => {
|
||||||
|
const number = parseInt(numStr);
|
||||||
|
|
||||||
|
if (isNaN(number) || number <= 0) {
|
||||||
|
return `[${numStr}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = message.sources?.[number - 1];
|
||||||
|
const url = source?.metadata?.url;
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
return `<a href="${url}" target="_blank" className="bg-light-secondary dark:bg-dark-secondary px-1 rounded ml-1 no-underline text-xs text-black/70 dark:text-white/70 relative">${numStr}</a>`;
|
||||||
|
} else {
|
||||||
|
return `[${numStr}]`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
return linksHtml;
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
setSpeechMessage(message.content.replace(regex, ''));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSpeechMessage(message.content.replace(regex, ''));
|
setSpeechMessage(message.content.replace(regex, ''));
|
||||||
setParsedMessage(message.content);
|
setParsedMessage(processedMessage);
|
||||||
}, [message.content, message.sources, message.role]);
|
}, [message.content, message.sources, message.role]);
|
||||||
|
|
||||||
const { speechStatus, start, stop } = useSpeech({ text: speechMessage });
|
const { speechStatus, start, stop } = useSpeech({ text: speechMessage });
|
||||||
|
|
||||||
|
const markdownOverrides: MarkdownToJSX.Options = {
|
||||||
|
overrides: {
|
||||||
|
think: {
|
||||||
|
component: ThinkTagProcessor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{message.role === 'user' && (
|
{message.role === 'user' && (
|
||||||
<div className={cn('w-full', messageIndex === 0 ? 'pt-16' : 'pt-8', 'break-words')}>
|
<div
|
||||||
|
className={cn(
|
||||||
|
'w-full',
|
||||||
|
messageIndex === 0 ? 'pt-16' : 'pt-8',
|
||||||
|
'break-words',
|
||||||
|
)}
|
||||||
|
>
|
||||||
<h2 className="text-black dark:text-white font-medium text-3xl lg:w-9/12">
|
<h2 className="text-black dark:text-white font-medium text-3xl lg:w-9/12">
|
||||||
{message.content}
|
{message.content}
|
||||||
</h2>
|
</h2>
|
||||||
@@ -105,11 +161,13 @@ const MessageBox = ({
|
|||||||
Answer
|
Answer
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Markdown
|
<Markdown
|
||||||
className={cn(
|
className={cn(
|
||||||
'prose prose-h1:mb-3 prose-h2:mb-2 prose-h2:mt-6 prose-h2:font-[800] prose-h3:mt-4 prose-h3:mb-1.5 prose-h3:font-[600] dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 font-[400]',
|
'prose prose-h1:mb-3 prose-h2:mb-2 prose-h2:mt-6 prose-h2:font-[800] prose-h3:mt-4 prose-h3:mb-1.5 prose-h3:font-[600] dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 font-[400]',
|
||||||
'max-w-none break-words text-black dark:text-white',
|
'max-w-none break-words text-black dark:text-white',
|
||||||
)}
|
)}
|
||||||
|
options={markdownOverrides}
|
||||||
>
|
>
|
||||||
{parsedMessage}
|
{parsedMessage}
|
||||||
</Markdown>
|
</Markdown>
|
||||||
@@ -187,10 +245,12 @@ const MessageBox = ({
|
|||||||
<SearchImages
|
<SearchImages
|
||||||
query={history[messageIndex - 1].content}
|
query={history[messageIndex - 1].content}
|
||||||
chatHistory={history.slice(0, messageIndex - 1)}
|
chatHistory={history.slice(0, messageIndex - 1)}
|
||||||
|
messageId={message.messageId}
|
||||||
/>
|
/>
|
||||||
<SearchVideos
|
<SearchVideos
|
||||||
chatHistory={history.slice(0, messageIndex - 1)}
|
chatHistory={history.slice(0, messageIndex - 1)}
|
||||||
query={history[messageIndex - 1].content}
|
query={history[messageIndex - 1].content}
|
||||||
|
messageId={message.messageId}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@@ -41,7 +41,7 @@ const Attach = ({
|
|||||||
data.append('embedding_model_provider', embeddingModelProvider!);
|
data.append('embedding_model_provider', embeddingModelProvider!);
|
||||||
data.append('embedding_model', embeddingModel!);
|
data.append('embedding_model', embeddingModel!);
|
||||||
|
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/uploads`, {
|
const res = await fetch(`/api/uploads`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: data,
|
body: data,
|
||||||
});
|
});
|
@@ -39,7 +39,7 @@ const AttachSmall = ({
|
|||||||
data.append('embedding_model_provider', embeddingModelProvider!);
|
data.append('embedding_model_provider', embeddingModelProvider!);
|
||||||
data.append('embedding_model', embeddingModel!);
|
data.append('embedding_model', embeddingModel!);
|
||||||
|
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/uploads`, {
|
const res = await fetch(`/api/uploads`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: data,
|
body: data,
|
||||||
});
|
});
|
@@ -45,25 +45,13 @@ const focusModes = [
|
|||||||
key: 'youtubeSearch',
|
key: 'youtubeSearch',
|
||||||
title: 'Youtube',
|
title: 'Youtube',
|
||||||
description: 'Search and watch videos',
|
description: 'Search and watch videos',
|
||||||
icon: (
|
icon: <SiYoutube className="h-5 w-auto mr-0.5" />,
|
||||||
<SiYoutube
|
|
||||||
className="h-5 w-auto mr-0.5"
|
|
||||||
onPointerEnterCapture={undefined}
|
|
||||||
onPointerLeaveCapture={undefined}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'redditSearch',
|
key: 'redditSearch',
|
||||||
title: 'Reddit',
|
title: 'Reddit',
|
||||||
description: 'Search for discussions and opinions',
|
description: 'Search for discussions and opinions',
|
||||||
icon: (
|
icon: <SiReddit className="h-5 w-auto mr-0.5" />,
|
||||||
<SiReddit
|
|
||||||
className="h-5 w-auto mr-0.5"
|
|
||||||
onPointerEnterCapture={undefined}
|
|
||||||
onPointerLeaveCapture={undefined}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@@ -69,11 +69,15 @@ const MessageSources = ({ sources }: { sources: Document[] }) => {
|
|||||||
<div className="flex flex-row items-center space-x-1">
|
<div className="flex flex-row items-center space-x-1">
|
||||||
{sources.slice(3, 6).map((source, i) => {
|
{sources.slice(3, 6).map((source, i) => {
|
||||||
return source.metadata.url === 'File' ? (
|
return source.metadata.url === 'File' ? (
|
||||||
<div className="bg-dark-200 hover:bg-dark-100 transition duration-200 flex items-center justify-center w-6 h-6 rounded-full">
|
<div
|
||||||
|
key={i}
|
||||||
|
className="bg-dark-200 hover:bg-dark-100 transition duration-200 flex items-center justify-center w-6 h-6 rounded-full"
|
||||||
|
>
|
||||||
<File size={12} className="text-white/70" />
|
<File size={12} className="text-white/70" />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<img
|
<img
|
||||||
|
key={i}
|
||||||
src={`https://s2.googleusercontent.com/s2/favicons?domain_url=${source.metadata.url}`}
|
src={`https://s2.googleusercontent.com/s2/favicons?domain_url=${source.metadata.url}`}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
215
src/components/Navbar.tsx
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
import { Clock, Edit, Share, Trash, FileText, FileDown } from 'lucide-react';
|
||||||
|
import { Message } from './ChatWindow';
|
||||||
|
import { useEffect, useState, Fragment } from 'react';
|
||||||
|
import { formatTimeDifference } from '@/lib/utils';
|
||||||
|
import DeleteChat from './DeleteChat';
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverButton,
|
||||||
|
PopoverPanel,
|
||||||
|
Transition,
|
||||||
|
} from '@headlessui/react';
|
||||||
|
import jsPDF from 'jspdf';
|
||||||
|
|
||||||
|
const downloadFile = (filename: string, content: string, type: string) => {
|
||||||
|
const blob = new Blob([content], { type });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = filename;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
setTimeout(() => {
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportAsMarkdown = (messages: Message[], title: string) => {
|
||||||
|
const date = new Date(messages[0]?.createdAt || Date.now()).toLocaleString();
|
||||||
|
let md = `# 💬 Chat Export: ${title}\n\n`;
|
||||||
|
md += `*Exported on: ${date}*\n\n---\n`;
|
||||||
|
messages.forEach((msg, idx) => {
|
||||||
|
md += `\n---\n`;
|
||||||
|
md += `**${msg.role === 'user' ? '🧑 User' : '🤖 Assistant'}**
|
||||||
|
`;
|
||||||
|
md += `*${new Date(msg.createdAt).toLocaleString()}*\n\n`;
|
||||||
|
md += `> ${msg.content.replace(/\n/g, '\n> ')}\n`;
|
||||||
|
if (msg.sources && msg.sources.length > 0) {
|
||||||
|
md += `\n**Citations:**\n`;
|
||||||
|
msg.sources.forEach((src: any, i: number) => {
|
||||||
|
const url = src.metadata?.url || '';
|
||||||
|
md += `- [${i + 1}] [${url}](${url})\n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
md += '\n---\n';
|
||||||
|
downloadFile(`${title || 'chat'}.md`, md, 'text/markdown');
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportAsPDF = (messages: Message[], title: string) => {
|
||||||
|
const doc = new jsPDF();
|
||||||
|
const date = new Date(messages[0]?.createdAt || Date.now()).toLocaleString();
|
||||||
|
let y = 15;
|
||||||
|
const pageHeight = doc.internal.pageSize.height;
|
||||||
|
doc.setFontSize(18);
|
||||||
|
doc.text(`Chat Export: ${title}`, 10, y);
|
||||||
|
y += 8;
|
||||||
|
doc.setFontSize(11);
|
||||||
|
doc.setTextColor(100);
|
||||||
|
doc.text(`Exported on: ${date}`, 10, y);
|
||||||
|
y += 8;
|
||||||
|
doc.setDrawColor(200);
|
||||||
|
doc.line(10, y, 200, y);
|
||||||
|
y += 6;
|
||||||
|
doc.setTextColor(30);
|
||||||
|
messages.forEach((msg, idx) => {
|
||||||
|
if (y > pageHeight - 30) {
|
||||||
|
doc.addPage();
|
||||||
|
y = 15;
|
||||||
|
}
|
||||||
|
doc.setFont('helvetica', 'bold');
|
||||||
|
doc.text(`${msg.role === 'user' ? 'User' : 'Assistant'}`, 10, y);
|
||||||
|
doc.setFont('helvetica', 'normal');
|
||||||
|
doc.setFontSize(10);
|
||||||
|
doc.setTextColor(120);
|
||||||
|
doc.text(`${new Date(msg.createdAt).toLocaleString()}`, 40, y);
|
||||||
|
y += 6;
|
||||||
|
doc.setTextColor(30);
|
||||||
|
doc.setFontSize(12);
|
||||||
|
const lines = doc.splitTextToSize(msg.content, 180);
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
if (y > pageHeight - 20) {
|
||||||
|
doc.addPage();
|
||||||
|
y = 15;
|
||||||
|
}
|
||||||
|
doc.text(lines[i], 12, y);
|
||||||
|
y += 6;
|
||||||
|
}
|
||||||
|
if (msg.sources && msg.sources.length > 0) {
|
||||||
|
doc.setFontSize(11);
|
||||||
|
doc.setTextColor(80);
|
||||||
|
if (y > pageHeight - 20) {
|
||||||
|
doc.addPage();
|
||||||
|
y = 15;
|
||||||
|
}
|
||||||
|
doc.text('Citations:', 12, y);
|
||||||
|
y += 5;
|
||||||
|
msg.sources.forEach((src: any, i: number) => {
|
||||||
|
const url = src.metadata?.url || '';
|
||||||
|
if (y > pageHeight - 15) {
|
||||||
|
doc.addPage();
|
||||||
|
y = 15;
|
||||||
|
}
|
||||||
|
doc.text(`- [${i + 1}] ${url}`, 15, y);
|
||||||
|
y += 5;
|
||||||
|
});
|
||||||
|
doc.setTextColor(30);
|
||||||
|
}
|
||||||
|
y += 6;
|
||||||
|
doc.setDrawColor(230);
|
||||||
|
if (y > pageHeight - 10) {
|
||||||
|
doc.addPage();
|
||||||
|
y = 15;
|
||||||
|
}
|
||||||
|
doc.line(10, y, 200, y);
|
||||||
|
y += 4;
|
||||||
|
});
|
||||||
|
doc.save(`${title || 'chat'}.pdf`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Navbar = ({
|
||||||
|
chatId,
|
||||||
|
messages,
|
||||||
|
}: {
|
||||||
|
messages: Message[];
|
||||||
|
chatId: string;
|
||||||
|
}) => {
|
||||||
|
const [title, setTitle] = useState<string>('');
|
||||||
|
const [timeAgo, setTimeAgo] = useState<string>('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (messages.length > 0) {
|
||||||
|
const newTitle =
|
||||||
|
messages[0].content.length > 20
|
||||||
|
? `${messages[0].content.substring(0, 20).trim()}...`
|
||||||
|
: messages[0].content;
|
||||||
|
setTitle(newTitle);
|
||||||
|
const newTimeAgo = formatTimeDifference(
|
||||||
|
new Date(),
|
||||||
|
messages[0].createdAt,
|
||||||
|
);
|
||||||
|
setTimeAgo(newTimeAgo);
|
||||||
|
}
|
||||||
|
}, [messages]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
if (messages.length > 0) {
|
||||||
|
const newTimeAgo = formatTimeDifference(
|
||||||
|
new Date(),
|
||||||
|
messages[0].createdAt,
|
||||||
|
);
|
||||||
|
setTimeAgo(newTimeAgo);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => clearInterval(intervalId);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed z-40 top-0 left-0 right-0 px-4 lg:pl-[104px] lg:pr-6 lg:px-8 flex flex-row items-center justify-between w-full py-4 text-sm text-black dark:text-white/70 border-b bg-light-primary dark:bg-dark-primary border-light-100 dark:border-dark-200">
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
className="active:scale-95 transition duration-100 cursor-pointer lg:hidden"
|
||||||
|
>
|
||||||
|
<Edit size={17} />
|
||||||
|
</a>
|
||||||
|
<div className="hidden lg:flex flex-row items-center justify-center space-x-2">
|
||||||
|
<Clock size={17} />
|
||||||
|
<p className="text-xs">{timeAgo} ago</p>
|
||||||
|
</div>
|
||||||
|
<p className="hidden lg:flex">{title}</p>
|
||||||
|
|
||||||
|
<div className="flex flex-row items-center space-x-4">
|
||||||
|
<Popover className="relative">
|
||||||
|
<PopoverButton className="active:scale-95 transition duration-100 cursor-pointer p-2 rounded-full hover:bg-light-secondary dark:hover:bg-dark-secondary">
|
||||||
|
<Share size={17} />
|
||||||
|
</PopoverButton>
|
||||||
|
<Transition
|
||||||
|
as={Fragment}
|
||||||
|
enter="transition ease-out duration-100"
|
||||||
|
enterFrom="opacity-0 translate-y-1"
|
||||||
|
enterTo="opacity-100 translate-y-0"
|
||||||
|
leave="transition ease-in duration-75"
|
||||||
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
|
leaveTo="opacity-0 translate-y-1"
|
||||||
|
>
|
||||||
|
<PopoverPanel className="absolute right-0 mt-2 w-64 rounded-xl shadow-xl bg-light-primary dark:bg-dark-primary border border-light-200 dark:border-dark-200 z-50">
|
||||||
|
<div className="flex flex-col py-3 px-3 gap-2">
|
||||||
|
<button
|
||||||
|
className="flex items-center gap-2 px-4 py-2 text-left hover:bg-light-secondary dark:hover:bg-dark-secondary transition-colors text-black dark:text-white rounded-lg font-medium"
|
||||||
|
onClick={() => exportAsMarkdown(messages, title || '')}
|
||||||
|
>
|
||||||
|
<FileText size={17} className="text-[#24A0ED]" />
|
||||||
|
Export as Markdown
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="flex items-center gap-2 px-4 py-2 text-left hover:bg-light-secondary dark:hover:bg-dark-secondary transition-colors text-black dark:text-white rounded-lg font-medium"
|
||||||
|
onClick={() => exportAsPDF(messages, title || '')}
|
||||||
|
>
|
||||||
|
<FileDown size={17} className="text-[#24A0ED]" />
|
||||||
|
Export as PDF
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</PopoverPanel>
|
||||||
|
</Transition>
|
||||||
|
</Popover>
|
||||||
|
<DeleteChat redirect chatId={chatId} chats={[]} setChats={() => {}} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Navbar;
|
71
src/components/NewsArticleWidget.tsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
interface Article {
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
url: string;
|
||||||
|
thumbnail: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NewsArticleWidget = () => {
|
||||||
|
const [article, setArticle] = useState<Article | null>(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/api/discover?mode=preview')
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
const articles = (data.blogs || []).filter((a: Article) => a.thumbnail);
|
||||||
|
setArticle(articles[Math.floor(Math.random() * articles.length)]);
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setError(true);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-light-secondary dark:bg-dark-secondary rounded-xl border border-light-200 dark:border-dark-200 shadow-sm flex flex-row items-center w-full h-24 min-h-[96px] max-h-[96px] px-3 py-2 gap-3 overflow-hidden">
|
||||||
|
{loading ? (
|
||||||
|
<>
|
||||||
|
<div className="animate-pulse flex flex-row items-center w-full h-full">
|
||||||
|
<div className="rounded-lg w-16 min-w-16 max-w-16 h-16 min-h-16 max-h-16 bg-light-200 dark:bg-dark-200 mr-3" />
|
||||||
|
<div className="flex flex-col justify-center flex-1 h-full w-0 gap-2">
|
||||||
|
<div className="h-4 w-3/4 rounded bg-light-200 dark:bg-dark-200" />
|
||||||
|
<div className="h-3 w-1/2 rounded bg-light-200 dark:bg-dark-200" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : error ? (
|
||||||
|
<div className="w-full text-xs text-red-400">Could not load news.</div>
|
||||||
|
) : article ? (
|
||||||
|
<a
|
||||||
|
href={`/?q=Summary: ${article.url}`}
|
||||||
|
className="flex flex-row items-center w-full h-full group"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
className="object-cover rounded-lg w-16 min-w-16 max-w-16 h-16 min-h-16 max-h-16 border border-light-200 dark:border-dark-200 bg-light-200 dark:bg-dark-200 group-hover:opacity-90 transition"
|
||||||
|
src={
|
||||||
|
new URL(article.thumbnail).origin +
|
||||||
|
new URL(article.thumbnail).pathname +
|
||||||
|
`?id=${new URL(article.thumbnail).searchParams.get('id')}`
|
||||||
|
}
|
||||||
|
alt={article.title}
|
||||||
|
/>
|
||||||
|
<div className="flex flex-col justify-center flex-1 h-full pl-3 w-0">
|
||||||
|
<div className="font-bold text-xs text-black dark:text-white leading-tight truncate overflow-hidden whitespace-nowrap">
|
||||||
|
{article.title}
|
||||||
|
</div>
|
||||||
|
<p className="text-black/70 dark:text-white/70 text-xs leading-snug truncate overflow-hidden whitespace-nowrap">
|
||||||
|
{article.content}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NewsArticleWidget;
|
@@ -14,9 +14,11 @@ type Image = {
|
|||||||
const SearchImages = ({
|
const SearchImages = ({
|
||||||
query,
|
query,
|
||||||
chatHistory,
|
chatHistory,
|
||||||
|
messageId,
|
||||||
}: {
|
}: {
|
||||||
query: string;
|
query: string;
|
||||||
chatHistory: Message[];
|
chatHistory: Message[];
|
||||||
|
messageId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const [images, setImages] = useState<Image[] | null>(null);
|
const [images, setImages] = useState<Image[] | null>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -27,7 +29,7 @@ const SearchImages = ({
|
|||||||
<>
|
<>
|
||||||
{!loading && images === null && (
|
{!loading && images === null && (
|
||||||
<button
|
<button
|
||||||
id="search-images"
|
id={`search-images-${messageId}`}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
@@ -37,27 +39,24 @@ const SearchImages = ({
|
|||||||
const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL');
|
const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL');
|
||||||
const customOpenAIKey = localStorage.getItem('openAIApiKey');
|
const customOpenAIKey = localStorage.getItem('openAIApiKey');
|
||||||
|
|
||||||
const res = await fetch(
|
const res = await fetch(`/api/images`, {
|
||||||
`${process.env.NEXT_PUBLIC_API_URL}/images`,
|
method: 'POST',
|
||||||
{
|
headers: {
|
||||||
method: 'POST',
|
'Content-Type': 'application/json',
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: query,
|
|
||||||
chatHistory: chatHistory,
|
|
||||||
chatModel: {
|
|
||||||
provider: chatModelProvider,
|
|
||||||
model: chatModel,
|
|
||||||
...(chatModelProvider === 'custom_openai' && {
|
|
||||||
customOpenAIBaseURL: customOpenAIBaseURL,
|
|
||||||
customOpenAIKey: customOpenAIKey,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
);
|
body: JSON.stringify({
|
||||||
|
query: query,
|
||||||
|
chatHistory: chatHistory,
|
||||||
|
chatModel: {
|
||||||
|
provider: chatModelProvider,
|
||||||
|
model: chatModel,
|
||||||
|
...(chatModelProvider === 'custom_openai' && {
|
||||||
|
customOpenAIBaseURL: customOpenAIBaseURL,
|
||||||
|
customOpenAIKey: customOpenAIKey,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
@@ -27,9 +27,11 @@ declare module 'yet-another-react-lightbox' {
|
|||||||
const Searchvideos = ({
|
const Searchvideos = ({
|
||||||
query,
|
query,
|
||||||
chatHistory,
|
chatHistory,
|
||||||
|
messageId,
|
||||||
}: {
|
}: {
|
||||||
query: string;
|
query: string;
|
||||||
chatHistory: Message[];
|
chatHistory: Message[];
|
||||||
|
messageId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const [videos, setVideos] = useState<Video[] | null>(null);
|
const [videos, setVideos] = useState<Video[] | null>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -42,7 +44,7 @@ const Searchvideos = ({
|
|||||||
<>
|
<>
|
||||||
{!loading && videos === null && (
|
{!loading && videos === null && (
|
||||||
<button
|
<button
|
||||||
id="search-videos"
|
id={`search-videos-${messageId}`}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
@@ -52,27 +54,24 @@ const Searchvideos = ({
|
|||||||
const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL');
|
const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL');
|
||||||
const customOpenAIKey = localStorage.getItem('openAIApiKey');
|
const customOpenAIKey = localStorage.getItem('openAIApiKey');
|
||||||
|
|
||||||
const res = await fetch(
|
const res = await fetch(`/api/videos`, {
|
||||||
`${process.env.NEXT_PUBLIC_API_URL}/videos`,
|
method: 'POST',
|
||||||
{
|
headers: {
|
||||||
method: 'POST',
|
'Content-Type': 'application/json',
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
query: query,
|
|
||||||
chatHistory: chatHistory,
|
|
||||||
chatModel: {
|
|
||||||
provider: chatModelProvider,
|
|
||||||
model: chatModel,
|
|
||||||
...(chatModelProvider === 'custom_openai' && {
|
|
||||||
customOpenAIBaseURL: customOpenAIBaseURL,
|
|
||||||
customOpenAIKey: customOpenAIKey,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
);
|
body: JSON.stringify({
|
||||||
|
query: query,
|
||||||
|
chatHistory: chatHistory,
|
||||||
|
chatModel: {
|
||||||
|
provider: chatModelProvider,
|
||||||
|
model: chatModel,
|
||||||
|
...(chatModelProvider === 'custom_openai' && {
|
||||||
|
customOpenAIBaseURL: customOpenAIBaseURL,
|
||||||
|
customOpenAIKey: customOpenAIKey,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
@@ -16,8 +16,6 @@ const VerticalIconContainer = ({ children }: { children: ReactNode }) => {
|
|||||||
const Sidebar = ({ children }: { children: React.ReactNode }) => {
|
const Sidebar = ({ children }: { children: React.ReactNode }) => {
|
||||||
const segments = useSelectedLayoutSegments();
|
const segments = useSelectedLayoutSegments();
|
||||||
|
|
||||||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
|
||||||
|
|
||||||
const navLinks = [
|
const navLinks = [
|
||||||
{
|
{
|
||||||
icon: Home,
|
icon: Home,
|
43
src/components/ThinkBox.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { ChevronDown, ChevronUp, BrainCircuit } from 'lucide-react';
|
||||||
|
|
||||||
|
interface ThinkBoxProps {
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThinkBox = ({ content }: ThinkBoxProps) => {
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="my-4 bg-light-secondary/50 dark:bg-dark-secondary/50 rounded-xl border border-light-200 dark:border-dark-200 overflow-hidden">
|
||||||
|
<button
|
||||||
|
onClick={() => setIsExpanded(!isExpanded)}
|
||||||
|
className="w-full flex items-center justify-between px-4 py-1 text-black/90 dark:text-white/90 hover:bg-light-200 dark:hover:bg-dark-200 transition duration-200"
|
||||||
|
>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<BrainCircuit
|
||||||
|
size={20}
|
||||||
|
className="text-[#9C27B0] dark:text-[#CE93D8]"
|
||||||
|
/>
|
||||||
|
<p className="font-medium text-sm">Thinking Process</p>
|
||||||
|
</div>
|
||||||
|
{isExpanded ? (
|
||||||
|
<ChevronUp size={18} className="text-black/70 dark:text-white/70" />
|
||||||
|
) : (
|
||||||
|
<ChevronDown size={18} className="text-black/70 dark:text-white/70" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{isExpanded && (
|
||||||
|
<div className="px-4 py-3 text-black/80 dark:text-white/80 text-sm border-t border-light-200 dark:border-dark-200 bg-light-100/50 dark:bg-dark-100/50 whitespace-pre-wrap">
|
||||||
|
{content}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ThinkBox;
|
145
src/components/WeatherWidget.tsx
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
import { Cloud, Sun, CloudRain, CloudSnow, Wind } from 'lucide-react';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
const WeatherWidget = () => {
|
||||||
|
const [data, setData] = useState({
|
||||||
|
temperature: 0,
|
||||||
|
condition: '',
|
||||||
|
location: '',
|
||||||
|
humidity: 0,
|
||||||
|
windSpeed: 0,
|
||||||
|
icon: '',
|
||||||
|
});
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const getApproxLocation = async () => {
|
||||||
|
const res = await fetch('https://ipwhois.app/json/');
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
return {
|
||||||
|
latitude: data.latitude,
|
||||||
|
longitude: data.longitude,
|
||||||
|
city: data.city,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLocation = async (
|
||||||
|
callback: (location: {
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
city: string;
|
||||||
|
}) => void,
|
||||||
|
) => {
|
||||||
|
/*
|
||||||
|
// Geolocation doesn't give city so we'll country using ipapi for now
|
||||||
|
if (navigator.geolocation) {
|
||||||
|
const result = await navigator.permissions.query({
|
||||||
|
name: 'geolocation',
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result.state === 'granted') {
|
||||||
|
navigator.geolocation.getCurrentPosition(position => {
|
||||||
|
callback({
|
||||||
|
latitude: position.coords.latitude,
|
||||||
|
longitude: position.coords.longitude,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else if (result.state === 'prompt') {
|
||||||
|
callback(await getApproxLocation())
|
||||||
|
navigator.geolocation.getCurrentPosition(position => {})
|
||||||
|
} else if (result.state === 'denied') {
|
||||||
|
callback(await getApproxLocation())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback(await getApproxLocation())
|
||||||
|
} */
|
||||||
|
callback(await getApproxLocation());
|
||||||
|
};
|
||||||
|
|
||||||
|
getLocation(async (location) => {
|
||||||
|
const res = await fetch(`/api/weather`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
lat: location.latitude,
|
||||||
|
lng: location.longitude,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (res.status !== 200) {
|
||||||
|
console.error('Error fetching weather data');
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setData({
|
||||||
|
temperature: data.temperature,
|
||||||
|
condition: data.condition,
|
||||||
|
location: location.city,
|
||||||
|
humidity: data.humidity,
|
||||||
|
windSpeed: data.windSpeed,
|
||||||
|
icon: data.icon,
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-light-secondary dark:bg-dark-secondary rounded-xl border border-light-200 dark:border-dark-200 shadow-sm flex flex-row items-center w-full h-24 min-h-[96px] max-h-[96px] px-3 py-2 gap-3">
|
||||||
|
{loading ? (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-col items-center justify-center w-16 min-w-16 max-w-16 h-full animate-pulse">
|
||||||
|
<div className="h-10 w-10 rounded-full bg-light-200 dark:bg-dark-200 mb-2" />
|
||||||
|
<div className="h-4 w-10 rounded bg-light-200 dark:bg-dark-200" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col justify-between flex-1 h-full py-1 animate-pulse">
|
||||||
|
<div className="flex flex-row items-center justify-between">
|
||||||
|
<div className="h-3 w-20 rounded bg-light-200 dark:bg-dark-200" />
|
||||||
|
<div className="h-3 w-12 rounded bg-light-200 dark:bg-dark-200" />
|
||||||
|
</div>
|
||||||
|
<div className="h-3 w-16 rounded bg-light-200 dark:bg-dark-200 mt-1" />
|
||||||
|
<div className="flex flex-row justify-between w-full mt-auto pt-1 border-t border-light-200 dark:border-dark-200">
|
||||||
|
<div className="h-3 w-16 rounded bg-light-200 dark:bg-dark-200" />
|
||||||
|
<div className="h-3 w-8 rounded bg-light-200 dark:bg-dark-200" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="flex flex-col items-center justify-center w-16 min-w-16 max-w-16 h-full">
|
||||||
|
<img
|
||||||
|
src={`/weather-ico/${data.icon}.svg`}
|
||||||
|
alt={data.condition}
|
||||||
|
className="h-10 w-auto"
|
||||||
|
/>
|
||||||
|
<span className="text-base font-semibold text-black dark:text-white">
|
||||||
|
{data.temperature}°C
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col justify-between flex-1 h-full py-1">
|
||||||
|
<div className="flex flex-row items-center justify-between">
|
||||||
|
<span className="text-xs font-medium text-black dark:text-white">
|
||||||
|
{data.location}
|
||||||
|
</span>
|
||||||
|
<span className="flex items-center text-xs text-black/60 dark:text-white/60">
|
||||||
|
<Wind className="w-3 h-3 mr-1" />
|
||||||
|
{data.windSpeed} km/h
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs text-black/60 dark:text-white/60 mt-1">
|
||||||
|
{data.condition}
|
||||||
|
</span>
|
||||||
|
<div className="flex flex-row justify-between w-full mt-auto pt-1 border-t border-light-200 dark:border-dark-200 text-xs text-black/60 dark:text-white/60">
|
||||||
|
<span>Humidity: {data.humidity}%</span>
|
||||||
|
<span>Now</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WeatherWidget;
|
@@ -7,7 +7,7 @@ export const getSuggestions = async (chatHisory: Message[]) => {
|
|||||||
const customOpenAIKey = localStorage.getItem('openAIApiKey');
|
const customOpenAIKey = localStorage.getItem('openAIApiKey');
|
||||||
const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL');
|
const customOpenAIBaseURL = localStorage.getItem('openAIBaseURL');
|
||||||
|
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/suggestions`, {
|
const res = await fetch(`/api/suggestions`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
@@ -7,7 +7,7 @@ import { PromptTemplate } from '@langchain/core/prompts';
|
|||||||
import formatChatHistoryAsString from '../utils/formatHistory';
|
import formatChatHistoryAsString from '../utils/formatHistory';
|
||||||
import { BaseMessage } from '@langchain/core/messages';
|
import { BaseMessage } from '@langchain/core/messages';
|
||||||
import { StringOutputParser } from '@langchain/core/output_parsers';
|
import { StringOutputParser } from '@langchain/core/output_parsers';
|
||||||
import { searchSearxng } from '../lib/searxng';
|
import { searchSearxng } from '../searxng';
|
||||||
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||||
|
|
||||||
const imageSearchChainPrompt = `
|
const imageSearchChainPrompt = `
|
||||||
@@ -36,6 +36,12 @@ type ImageSearchChainInput = {
|
|||||||
query: string;
|
query: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface ImageSearchResult {
|
||||||
|
img_src: string;
|
||||||
|
url: string;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
const strParser = new StringOutputParser();
|
const strParser = new StringOutputParser();
|
||||||
|
|
||||||
const createImageSearchChain = (llm: BaseChatModel) => {
|
const createImageSearchChain = (llm: BaseChatModel) => {
|
||||||
@@ -52,11 +58,13 @@ const createImageSearchChain = (llm: BaseChatModel) => {
|
|||||||
llm,
|
llm,
|
||||||
strParser,
|
strParser,
|
||||||
RunnableLambda.from(async (input: string) => {
|
RunnableLambda.from(async (input: string) => {
|
||||||
|
input = input.replace(/<think>.*?<\/think>/g, '');
|
||||||
|
|
||||||
const res = await searchSearxng(input, {
|
const res = await searchSearxng(input, {
|
||||||
engines: ['bing images', 'google images'],
|
engines: ['bing images', 'google images'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const images = [];
|
const images: ImageSearchResult[] = [];
|
||||||
|
|
||||||
res.results.forEach((result) => {
|
res.results.forEach((result) => {
|
||||||
if (result.img_src && result.url && result.title) {
|
if (result.img_src && result.url && result.title) {
|