Compare commits

..

2 Commits

Author SHA1 Message Date
sjiampojamarn
fec42d1927 Merge 8097610baf into e226645bc7 2025-04-06 12:40:20 +02:00
sjiampojamarn
8097610baf Adding user session for history 2025-04-05 17:43:04 -07:00
94 changed files with 1505 additions and 8986 deletions

View File

2
.gitignore vendored
View File

@@ -37,5 +37,3 @@ Thumbs.db
# Db # Db
db.sqlite db.sqlite
/searxng /searxng
certificates

View File

@@ -16,7 +16,7 @@
<hr/> <hr/>
[![Discord](https://dcbadge.limes.pink/api/server/26aArMy8tT?style=flat)](https://discord.gg/26aArMy8tT) [![Discord](https://dcbadge.vercel.app/api/server/26aArMy8tT?style=flat&compact=true)](https://discord.gg/26aArMy8tT)
![preview](.assets/perplexica-screenshot.png?) ![preview](.assets/perplexica-screenshot.png?)
@@ -53,7 +53,7 @@ Want to know more about its architecture and how it works? You can read it [here
## Features ## Features
- **Local LLMs**: You can utilize local LLMs such as Qwen, DeepSeek, Llama, and Mistral. - **Local LLMs**: You can make use local LLMs such as Llama3 and Mixtral using Ollama.
- **Two Main Modes:** - **Two Main Modes:**
- **Copilot Mode:** (In development) Boosts search by generating different queries to find more relevant internet sources. Like normal search instead of just using the context by SearxNG, it visits the top matches and tries to find relevant sources to the user's query directly from the page. - **Copilot Mode:** (In development) Boosts search by generating different queries to find more relevant internet sources. Like normal search instead of just using the context by SearxNG, it visits the top matches and tries to find relevant sources to the user's query directly from the page.
- **Normal Mode:** Processes your query and performs a web search. - **Normal Mode:** Processes your query and performs a web search.
@@ -87,13 +87,9 @@ There are mainly 2 ways of installing Perplexica - With Docker, Without Docker.
4. Rename the `sample.config.toml` file to `config.toml`. For Docker setups, you need only fill in the following fields: 4. Rename the `sample.config.toml` file to `config.toml`. For Docker setups, you need only fill in the following fields:
- `OPENAI`: Your OpenAI API key. **You only need to fill this if you wish to use OpenAI's models**. - `OPENAI`: Your OpenAI API key. **You only need to fill this if you wish to use OpenAI's models**.
- `CUSTOM_OPENAI`: Your OpenAI-API-compliant local server URL, model name, and API key. You should run your local server with host set to `0.0.0.0`, take note of which port number it is running on, and then use that port number to set `API_URL = http://host.docker.internal:PORT_NUMBER`. You must specify the model name, such as `MODEL_NAME = "unsloth/DeepSeek-R1-0528-Qwen3-8B-GGUF:Q4_K_XL"`. Finally, set `API_KEY` to the appropriate value. If you have not defined an API key, just put anything you want in-between the quotation marks: `API_KEY = "whatever-you-want-but-not-blank"` **You only need to configure these settings if you want to use a local OpenAI-compliant server, such as Llama.cpp's [`llama-server`](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md)**.
- `OLLAMA`: Your Ollama API URL. You should enter it as `http://host.docker.internal:PORT_NUMBER`. If you installed Ollama on port 11434, use `http://host.docker.internal:11434`. For other ports, adjust accordingly. **You need to fill this if you wish to use Ollama's models instead of OpenAI's**. - `OLLAMA`: Your Ollama API URL. You should enter it as `http://host.docker.internal:PORT_NUMBER`. If you installed Ollama on port 11434, use `http://host.docker.internal:11434`. For other ports, adjust accordingly. **You need to fill this if you wish to use Ollama's models instead of OpenAI's**.
- `GROQ`: Your Groq API key. **You only need to fill this if you wish to use Groq's hosted models**. - `GROQ`: Your Groq API key. **You only need to fill this if you wish to use Groq's hosted models**.
- `ANTHROPIC`: Your Anthropic API key. **You only need to fill this if you wish to use Anthropic models**. - `ANTHROPIC`: Your Anthropic API key. **You only need to fill this if you wish to use Anthropic models**.
- `Gemini`: Your Gemini API key. **You only need to fill this if you wish to use Google's models**.
- `DEEPSEEK`: Your Deepseek API key. **Only needed if you want Deepseek models.**
- `AIMLAPI`: Your AI/ML API key. **Only needed if you want to use AI/ML API models and embeddings.**
**Note**: You can change these after starting Perplexica from the settings dialog. **Note**: You can change these after starting Perplexica from the settings dialog.
@@ -115,23 +111,13 @@ There are mainly 2 ways of installing Perplexica - With Docker, Without Docker.
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. After populating the configuration run `npm i`. 3. After populating the configuration run `npm i`.
4. Install the dependencies and then execute `npm run build`. 4. Install the dependencies and then execute `npm run build`.
5. Finally, start the app by running `npm run start` 5. Finally, start the app by running `npm rum start`
**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 updating, etc. See the [installation documentation](https://github.com/ItzCrazyKns/Perplexica/tree/master/docs/installation) for more information like updating, etc.
### Troubleshooting ### Ollama Connection Errors
#### Local OpenAI-API-Compliant Servers
If Perplexica tells you that you haven't configured any chat model providers, ensure that:
1. Your server is running on `0.0.0.0` (not `127.0.0.1`) and on the same port you put in the API URL.
2. You have specified the correct model name loaded by your local LLM server.
3. You have specified the correct API key, or if one is not defined, you have put *something* in the API key field and not left it empty.
#### Ollama Connection Errors
If you're encountering an Ollama connection error, it is likely due to the backend being unable to connect to Ollama's API. To fix this issue you can: If you're encountering an Ollama connection error, it is likely due to the backend being unable to connect to Ollama's API. To fix this issue you can:
@@ -146,7 +132,7 @@ If you're encountering an Ollama connection error, it is likely due to the backe
3. **Linux Users - Expose Ollama to Network:** 3. **Linux Users - Expose Ollama to Network:**
- Inside `/etc/systemd/system/ollama.service`, you need to add `Environment="OLLAMA_HOST=0.0.0.0:11434"`. (Change the port number if you are using a different one.) Then reload the systemd manager configuration with `systemctl daemon-reload`, and restart Ollama by `systemctl restart ollama`. For more information see [Ollama docs](https://github.com/ollama/ollama/blob/main/docs/faq.md#setting-environment-variables-on-linux) - Inside `/etc/systemd/system/ollama.service`, you need to add `Environment="OLLAMA_HOST=0.0.0.0"`. Then restart Ollama by `systemctl restart ollama`. For more information see [Ollama docs](https://github.com/ollama/ollama/blob/main/docs/faq.md#setting-environment-variables-on-linux)
- Ensure that the port (default is 11434) is not blocked by your firewall. - Ensure that the port (default is 11434) is not blocked by your firewall.
@@ -173,7 +159,6 @@ Perplexica runs on Next.js and handles all API requests. It works right away on
[![Deploy to Sealos](https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg)](https://usw.sealos.io/?openapp=system-template%3FtemplateName%3Dperplexica) [![Deploy to Sealos](https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg)](https://usw.sealos.io/?openapp=system-template%3FtemplateName%3Dperplexica)
[![Deploy to RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploylobe.svg)](https://repocloud.io/details/?app_id=267) [![Deploy to RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploylobe.svg)](https://repocloud.io/details/?app_id=267)
[![Run on ClawCloud](https://raw.githubusercontent.com/ClawCloud/Run-Template/refs/heads/main/Run-on-ClawCloud.svg)](https://template.run.claw.cloud/?referralCode=U11MRQ8U9RM4&openapp=system-fastdeploy%3FtemplateName%3Dperplexica)
## Upcoming Features ## Upcoming Features

View File

@@ -12,9 +12,6 @@ COPY public ./public
RUN mkdir -p /home/perplexica/data RUN mkdir -p /home/perplexica/data
RUN yarn build RUN yarn build
RUN yarn add --dev @vercel/ncc
RUN yarn ncc build ./src/lib/db/migrate.ts -o migrator
FROM node:20.18.0-slim FROM node:20.18.0-slim
WORKDIR /home/perplexica WORKDIR /home/perplexica
@@ -24,12 +21,7 @@ COPY --from=builder /home/perplexica/.next/static ./public/_next/static
COPY --from=builder /home/perplexica/.next/standalone ./ COPY --from=builder /home/perplexica/.next/standalone ./
COPY --from=builder /home/perplexica/data ./data 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 RUN mkdir /home/perplexica/uploads
COPY entrypoint.sh ./entrypoint.sh CMD ["node", "server.js"]
RUN chmod +x ./entrypoint.sh
CMD ["./entrypoint.sh"]

View File

@@ -16,7 +16,6 @@ services:
dockerfile: app.dockerfile dockerfile: app.dockerfile
environment: environment:
- SEARXNG_API_URL=http://searxng:8080 - SEARXNG_API_URL=http://searxng:8080
- DATA_DIR=/home/perplexica
ports: ports:
- 3000:3000 - 3000:3000
networks: networks:

View File

@@ -41,6 +41,6 @@ To update Perplexica to the latest version, follow these steps:
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. After populating the configuration run `npm i`.
5. Install the dependencies and then execute `npm run build`. 5. Install the dependencies and then execute `npm run build`.
6. Finally, start the app by running `npm run start` 6. Finally, start the app by running `npm rum start`
--- ---

View File

@@ -1,11 +1,10 @@
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/lib/db/schema.ts', schema: './src/lib/db/schema.ts',
out: './drizzle', out: './drizzle',
dbCredentials: { dbCredentials: {
url: path.join(process.cwd(), 'data', 'db.sqlite'), url: './data/db.sqlite',
}, },
}); });

View File

@@ -1,16 +0,0 @@
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
);

View File

@@ -1,116 +0,0 @@
{
"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": {}
}
}

View File

@@ -1,13 +0,0 @@
{
"version": "7",
"dialect": "sqlite",
"entries": [
{
"idx": 0,
"version": "6",
"when": 1748405503809,
"tag": "0000_fuzzy_randall",
"breakpoints": true
}
]
}

View File

@@ -1,6 +0,0 @@
#!/bin/sh
set -e
node migrate.js
exec node server.js

View File

@@ -1,6 +1,6 @@
{ {
"name": "perplexica-frontend", "name": "perplexica-frontend",
"version": "1.11.0-rc2", "version": "1.10.1",
"license": "MIT", "license": "MIT",
"author": "ItzCrazyKns", "author": "ItzCrazyKns",
"scripts": { "scripts": {
@@ -15,13 +15,11 @@
"@headlessui/react": "^2.2.0", "@headlessui/react": "^2.2.0",
"@iarna/toml": "^2.2.5", "@iarna/toml": "^2.2.5",
"@icons-pack/react-simple-icons": "^12.3.0", "@icons-pack/react-simple-icons": "^12.3.0",
"@langchain/anthropic": "^0.3.24", "@langchain/anthropic": "^0.3.15",
"@langchain/community": "^0.3.49", "@langchain/community": "^0.3.36",
"@langchain/core": "^0.3.66", "@langchain/core": "^0.3.42",
"@langchain/google-genai": "^0.2.15", "@langchain/google-genai": "^0.1.12",
"@langchain/groq": "^0.2.3", "@langchain/openai": "^0.0.25",
"@langchain/ollama": "^0.2.3",
"@langchain/openai": "^0.6.2",
"@langchain/textsplitters": "^0.1.0", "@langchain/textsplitters": "^0.1.0",
"@tailwindcss/typography": "^0.5.12", "@tailwindcss/typography": "^0.5.12",
"@xenova/transformers": "^2.17.2", "@xenova/transformers": "^2.17.2",
@@ -32,10 +30,8 @@
"compute-dot": "^1.1.0", "compute-dot": "^1.1.0",
"drizzle-orm": "^0.40.1", "drizzle-orm": "^0.40.1",
"html-to-text": "^9.0.5", "html-to-text": "^9.0.5",
"jspdf": "^3.0.1", "langchain": "^0.1.30",
"langchain": "^0.3.30",
"lucide-react": "^0.363.0", "lucide-react": "^0.363.0",
"mammoth": "^1.9.1",
"markdown-to-jsx": "^7.7.2", "markdown-to-jsx": "^7.7.2",
"next": "^15.2.2", "next": "^15.2.2",
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
@@ -53,7 +49,6 @@
"devDependencies": { "devDependencies": {
"@types/better-sqlite3": "^7.6.12", "@types/better-sqlite3": "^7.6.12",
"@types/html-to-text": "^9.0.4", "@types/html-to-text": "^9.0.4",
"@types/jspdf": "^2.0.0",
"@types/node": "^20", "@types/node": "^20",
"@types/pdf-parse": "^1.1.4", "@types/pdf-parse": "^1.1.4",
"@types/react": "^18", "@types/react": "^18",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 627 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

View File

@@ -1,131 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -1,159 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -1,178 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -1,206 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -1,244 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -1,309 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,204 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -1,269 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,141 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -1,179 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -1,243 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1,204 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 8.8 KiB

View File

@@ -1,256 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,206 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 9.3 KiB

View File

@@ -1,270 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,374 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,283 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,307 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,241 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 9.6 KiB

View File

@@ -1,269 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,273 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,301 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,334 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,361 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -25,11 +25,5 @@ API_URL = "" # Ollama API URL - http://host.docker.internal:11434
[MODELS.DEEPSEEK] [MODELS.DEEPSEEK]
API_KEY = "" API_KEY = ""
[MODELS.AIMLAPI]
API_KEY = "" # Required to use AI/ML API chat and embedding models
[MODELS.LM_STUDIO]
API_URL = "" # LM Studio API URL - http://host.docker.internal:1234
[API_ENDPOINTS] [API_ENDPOINTS]
SEARXNG = "" # SearxNG API URL - http://localhost:32768 SEARXNG = "" # SearxNG API URL - http://localhost:32768

View File

@@ -1,7 +1,11 @@
import prompts from '@/lib/prompts';
import MetaSearchAgent from '@/lib/search/metaSearchAgent';
import crypto from 'crypto'; import crypto from 'crypto';
import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages'; import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
import { EventEmitter } from 'stream'; import { EventEmitter } from 'stream';
import { import {
chatModelProviders,
embeddingModelProviders,
getAvailableChatModelProviders, getAvailableChatModelProviders,
getAvailableEmbeddingModelProviders, getAvailableEmbeddingModelProviders,
} from '@/lib/providers'; } from '@/lib/providers';
@@ -25,6 +29,7 @@ type Message = {
messageId: string; messageId: string;
chatId: string; chatId: string;
content: string; content: string;
userSessionId: string;
}; };
type ChatModel = { type ChatModel = {
@@ -134,8 +139,7 @@ const handleHistorySave = async (
where: eq(chats.id, message.chatId), where: eq(chats.id, message.chatId),
}); });
const fileData = files.map(getFileDetails); let currentDate = new Date();
if (!chat) { if (!chat) {
await db await db
.insert(chats) .insert(chats)
@@ -144,15 +148,11 @@ const handleHistorySave = async (
title: message.content, title: message.content,
createdAt: new Date().toString(), createdAt: new Date().toString(),
focusMode: focusMode, focusMode: focusMode,
files: fileData, files: files.map(getFileDetails),
userSessionId: message.userSessionId,
timestamp: currentDate.toISOString(),
}) })
.execute(); .execute();
} else if (JSON.stringify(chat.files ?? []) != JSON.stringify(fileData)) {
db.update(chats)
.set({
files: files.map(getFileDetails),
})
.where(eq(chats.id, message.chatId));
} }
const messageExists = await db.query.messages.findFirst({ const messageExists = await db.query.messages.findFirst({
@@ -227,7 +227,7 @@ export const POST = async (req: Request) => {
if (body.chatModel?.provider === 'custom_openai') { if (body.chatModel?.provider === 'custom_openai') {
llm = new ChatOpenAI({ llm = new ChatOpenAI({
apiKey: getCustomOpenaiApiKey(), openAIApiKey: getCustomOpenaiApiKey(),
modelName: getCustomOpenaiModelName(), modelName: getCustomOpenaiModelName(),
temperature: 0.7, temperature: 0.7,
configuration: { configuration: {

View File

@@ -1,10 +1,47 @@
import db from '@/lib/db'; import db from '@/lib/db';
import { chats } from '@/lib/db/schema';
import { eq, sql} from 'drizzle-orm';
export const GET = async (req: Request) => { export const GET = async (req: Request) => {
try { try {
let chats = await db.query.chats.findMany(); // get header from request
chats = chats.reverse(); const headers = await req.headers;
return Response.json({ chats: chats }, { status: 200 }); let userSessionId = headers.get('user-session-id')?.toString() ?? '';
if (userSessionId == '') {
return Response.json({ chats: {} }, { status: 200 });
}
let chatsRes = await db.query.chats.findMany({
where: eq(chats.userSessionId, userSessionId),
});
chatsRes = chatsRes.reverse();
// Keep only the latest 20 records in the database. Delete older records.
let maxRecordLimit = 20;
if (chatsRes.length > maxRecordLimit) {
const deleteChatsQuery = sql`DELETE FROM chats
WHERE userSessionId = ${userSessionId} AND (
timestamp IS NULL OR
timestamp NOT in (
SELECT timestamp FROM chats
WHERE userSessionId = ${userSessionId}
ORDER BY timestamp DESC
LIMIT ${maxRecordLimit}
)
)
`;
await db.run(deleteChatsQuery);
// Delete messages that no longer link with the chat from the database.
const deleteMessagesQuery = sql`DELETE FROM messages
WHERE chatId NOT IN (
SELECT id FROM chats
)
`;
await db.run(deleteMessagesQuery);
}
return Response.json({ chats: chatsRes }, { status: 200 });
} catch (err) { } catch (err) {
console.error('Error in getting chats: ', err); console.error('Error in getting chats: ', err);
return Response.json( return Response.json(

View File

@@ -8,10 +8,7 @@ import {
getOllamaApiEndpoint, getOllamaApiEndpoint,
getOpenaiApiKey, getOpenaiApiKey,
getDeepseekApiKey, getDeepseekApiKey,
getAimlApiKey,
getLMStudioApiEndpoint,
updateConfig, updateConfig,
getOllamaApiKey,
} from '@/lib/config'; } from '@/lib/config';
import { import {
getAvailableChatModelProviders, getAvailableChatModelProviders,
@@ -54,13 +51,10 @@ export const GET = async (req: Request) => {
config['openaiApiKey'] = getOpenaiApiKey(); config['openaiApiKey'] = getOpenaiApiKey();
config['ollamaApiUrl'] = getOllamaApiEndpoint(); config['ollamaApiUrl'] = getOllamaApiEndpoint();
config['ollamaApiKey'] = getOllamaApiKey();
config['lmStudioApiUrl'] = getLMStudioApiEndpoint();
config['anthropicApiKey'] = getAnthropicApiKey(); config['anthropicApiKey'] = getAnthropicApiKey();
config['groqApiKey'] = getGroqApiKey(); config['groqApiKey'] = getGroqApiKey();
config['geminiApiKey'] = getGeminiApiKey(); config['geminiApiKey'] = getGeminiApiKey();
config['deepseekApiKey'] = getDeepseekApiKey(); config['deepseekApiKey'] = getDeepseekApiKey();
config['aimlApiKey'] = getAimlApiKey();
config['customOpenaiApiUrl'] = getCustomOpenaiApiUrl(); config['customOpenaiApiUrl'] = getCustomOpenaiApiUrl();
config['customOpenaiApiKey'] = getCustomOpenaiApiKey(); config['customOpenaiApiKey'] = getCustomOpenaiApiKey();
config['customOpenaiModelName'] = getCustomOpenaiModelName(); config['customOpenaiModelName'] = getCustomOpenaiModelName();
@@ -95,17 +89,10 @@ export const POST = async (req: Request) => {
}, },
OLLAMA: { OLLAMA: {
API_URL: config.ollamaApiUrl, API_URL: config.ollamaApiUrl,
API_KEY: config.ollamaApiKey,
}, },
DEEPSEEK: { DEEPSEEK: {
API_KEY: config.deepseekApiKey, API_KEY: config.deepseekApiKey,
}, },
AIMLAPI: {
API_KEY: config.aimlApiKey,
},
LM_STUDIO: {
API_URL: config.lmStudioApiUrl,
},
CUSTOM_OPENAI: { CUSTOM_OPENAI: {
API_URL: config.customOpenaiApiUrl, API_URL: config.customOpenaiApiUrl,
API_KEY: config.customOpenaiApiKey, API_KEY: config.customOpenaiApiKey,

View File

@@ -1,80 +1,43 @@
import { searchSearxng } from '@/lib/searxng'; import { searchSearxng } from '@/lib/searxng';
const websitesForTopic = { const articleWebsites = [
tech: { 'yahoo.com',
query: ['technology news', 'latest tech', 'AI', 'science and innovation'], 'www.exchangewire.com',
links: ['techcrunch.com', 'wired.com', 'theverge.com'], 'businessinsider.com',
}, /* 'wired.com',
finance: { 'mashable.com',
query: ['finance news', 'economy', 'stock market', 'investing'], 'theverge.com',
links: ['bloomberg.com', 'cnbc.com', 'marketwatch.com'], 'gizmodo.com',
}, 'cnet.com',
art: { 'venturebeat.com', */
query: ['art news', 'culture', 'modern art', 'cultural events'], ];
links: ['artnews.com', 'hyperallergic.com', 'theartnewspaper.com'],
},
sports: {
query: ['sports news', 'latest sports', 'cricket football tennis'],
links: ['espn.com', 'bbc.com/sport', 'skysports.com'],
},
entertainment: {
query: ['entertainment news', 'movies', 'TV shows', 'celebrities'],
links: ['hollywoodreporter.com', 'variety.com', 'deadline.com'],
},
};
type Topic = keyof typeof websitesForTopic; const topics = ['AI', 'tech']; /* TODO: Add UI to customize this */
export const GET = async (req: Request) => { export const GET = async (req: Request) => {
try { try {
const params = new URL(req.url).searchParams; const data = (
await Promise.all([
const mode: 'normal' | 'preview' = ...new Array(articleWebsites.length * topics.length)
(params.get('mode') as 'normal' | 'preview') || 'normal'; .fill(0)
const topic: Topic = (params.get('topic') as Topic) || 'tech'; .map(async (_, i) => {
const selectedTopic = websitesForTopic[topic];
let data = [];
if (mode === 'normal') {
const seenUrls = new Set();
data = (
await Promise.all(
selectedTopic.links.flatMap((link) =>
selectedTopic.query.map(async (query) => {
return ( return (
await searchSearxng(`site:${link} ${query}`, {
engines: ['bing news'],
pageno: 1,
language: 'en',
})
).results;
}),
),
)
)
.flat()
.filter((item) => {
const url = item.url?.toLowerCase().trim();
if (seenUrls.has(url)) return false;
seenUrls.add(url);
return true;
})
.sort(() => Math.random() - 0.5);
} else {
data = (
await searchSearxng( await searchSearxng(
`site:${selectedTopic.links[Math.floor(Math.random() * selectedTopic.links.length)]} ${selectedTopic.query[Math.floor(Math.random() * selectedTopic.query.length)]}`, `site:${articleWebsites[i % articleWebsites.length]} ${
topics[i % topics.length]
}`,
{ {
engines: ['bing news'], engines: ['bing news'],
pageno: 1, pageno: 1,
language: 'en',
}, },
) )
).results; ).results;
} }),
])
)
.map((result) => result)
.flat()
.sort(() => Math.random() - 0.5);
return Response.json( return Response.json(
{ {

View File

@@ -49,7 +49,7 @@ export const POST = async (req: Request) => {
if (body.chatModel?.provider === 'custom_openai') { if (body.chatModel?.provider === 'custom_openai') {
llm = new ChatOpenAI({ llm = new ChatOpenAI({
apiKey: getCustomOpenaiApiKey(), openAIApiKey: getCustomOpenaiApiKey(),
modelName: getCustomOpenaiModelName(), modelName: getCustomOpenaiModelName(),
temperature: 0.7, temperature: 0.7,
configuration: { configuration: {

View File

@@ -81,7 +81,8 @@ export const POST = async (req: Request) => {
if (body.chatModel?.provider === 'custom_openai') { if (body.chatModel?.provider === 'custom_openai') {
llm = new ChatOpenAI({ llm = new ChatOpenAI({
modelName: body.chatModel?.name || getCustomOpenaiModelName(), modelName: body.chatModel?.name || getCustomOpenaiModelName(),
apiKey: body.chatModel?.customOpenAIKey || getCustomOpenaiApiKey(), openAIApiKey:
body.chatModel?.customOpenAIKey || getCustomOpenaiApiKey(),
temperature: 0.7, temperature: 0.7,
configuration: { configuration: {
baseURL: baseURL:

View File

@@ -48,7 +48,7 @@ export const POST = async (req: Request) => {
if (body.chatModel?.provider === 'custom_openai') { if (body.chatModel?.provider === 'custom_openai') {
llm = new ChatOpenAI({ llm = new ChatOpenAI({
apiKey: getCustomOpenaiApiKey(), openAIApiKey: getCustomOpenaiApiKey(),
modelName: getCustomOpenaiModelName(), modelName: getCustomOpenaiModelName(),
temperature: 0.7, temperature: 0.7,
configuration: { configuration: {

View File

@@ -49,7 +49,7 @@ export const POST = async (req: Request) => {
if (body.chatModel?.provider === 'custom_openai') { if (body.chatModel?.provider === 'custom_openai') {
llm = new ChatOpenAI({ llm = new ChatOpenAI({
apiKey: getCustomOpenaiApiKey(), openAIApiKey: getCustomOpenaiApiKey(),
modelName: getCustomOpenaiModelName(), modelName: getCustomOpenaiModelName(),
temperature: 0.7, temperature: 0.7,
configuration: { configuration: {

View File

@@ -1,174 +0,0 @@
export const POST = async (req: Request) => {
try {
const body: {
lat: number;
lng: number;
measureUnit: 'Imperial' | 'Metric';
} = 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}&current=weather_code,temperature_2m,is_day,relative_humidity_2m,wind_speed_10m&timezone=auto${
body.measureUnit === 'Metric' ? '' : '&temperature_unit=fahrenheit'
}${body.measureUnit === 'Metric' ? '' : '&wind_speed_unit=mph'}`,
);
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;
temperatureUnit: 'C' | 'F';
windSpeedUnit: 'm/s' | 'mph';
} = {
temperature: data.current.temperature_2m,
condition: '',
humidity: data.current.relative_humidity_2m,
windSpeed: data.current.wind_speed_10m,
icon: '',
temperatureUnit: body.measureUnit === 'Metric' ? 'C' : 'F',
windSpeedUnit: body.measureUnit === 'Metric' ? 'm/s' : 'mph',
};
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,
},
);
}
};

View File

@@ -1,17 +1,9 @@
'use client';
import ChatWindow from '@/components/ChatWindow'; import ChatWindow from '@/components/ChatWindow';
import { useParams } from 'next/navigation';
import React from 'react'; import React from 'react';
import { ChatProvider } from '@/lib/hooks/useChat';
const Page = () => { const Page = ({ params }: { params: Promise<{ chatId: string }> }) => {
const { chatId }: { chatId: string } = useParams(); const { chatId } = React.use(params);
return ( return <ChatWindow id={chatId} />;
<ChatProvider id={chatId}>
<ChatWindow />
</ChatProvider>
);
}; };
export default Page; export default Page;

View File

@@ -4,7 +4,6 @@ import { Search } from 'lucide-react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import Link from 'next/link'; import Link from 'next/link';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { cn } from '@/lib/utils';
interface Discover { interface Discover {
title: string; title: string;
@@ -13,38 +12,14 @@ interface Discover {
thumbnail: string; thumbnail: string;
} }
const topics: { key: string; display: string }[] = [
{
display: 'Tech & Science',
key: 'tech',
},
{
display: 'Finance',
key: 'finance',
},
{
display: 'Art & Culture',
key: 'art',
},
{
display: 'Sports',
key: 'sports',
},
{
display: 'Entertainment',
key: 'entertainment',
},
];
const Page = () => { const Page = () => {
const [discover, setDiscover] = useState<Discover[] | null>(null); const [discover, setDiscover] = useState<Discover[] | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [activeTopic, setActiveTopic] = useState<string>(topics[0].key);
const fetchArticles = async (topic: string) => { useEffect(() => {
setLoading(true); const fetchData = async () => {
try { try {
const res = await fetch(`/api/discover?topic=${topic}`, { const res = await fetch(`/api/discover`, {
method: 'GET', method: 'GET',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -68,39 +43,10 @@ const Page = () => {
} }
}; };
useEffect(() => { fetchData();
fetchArticles(activeTopic); }, []);
}, [activeTopic]);
return ( return loading ? (
<>
<div>
<div className="flex flex-col pt-4">
<div className="flex items-center">
<Search />
<h1 className="text-3xl font-medium p-2">Discover</h1>
</div>
<hr className="border-t border-[#2B2C2C] my-4 w-full" />
</div>
<div className="flex flex-row items-center space-x-2 overflow-x-auto">
{topics.map((t, i) => (
<div
key={i}
className={cn(
'border-[0.1px] rounded-full text-sm px-3 py-1 text-nowrap transition duration-200 cursor-pointer',
activeTopic === t.key
? 'text-cyan-300 bg-cyan-300/30 border-cyan-300/60'
: 'border-black/30 dark:border-white/30 text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white hover:border-black/40 dark:hover:border-white/40 hover:bg-black/5 dark:hover:bg-white/5',
)}
onClick={() => setActiveTopic(t.key)}
>
<span>{t.display}</span>
</div>
))}
</div>
{loading ? (
<div className="flex flex-row items-center justify-center min-h-screen"> <div className="flex flex-row items-center justify-center min-h-screen">
<svg <svg
aria-hidden="true" aria-hidden="true"
@@ -120,7 +66,17 @@ const Page = () => {
</svg> </svg>
</div> </div>
) : ( ) : (
<div className="grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-4 pb-28 pt-5 lg:pb-8 w-full justify-items-center lg:justify-items-start"> <>
<div>
<div className="flex flex-col pt-4">
<div className="flex items-center">
<Search />
<h1 className="text-3xl font-medium p-2">Discover</h1>
</div>
<hr className="border-t border-[#2B2C2C] my-4 w-full" />
</div>
<div className="grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-4 pb-28 lg:pb-8 w-full justify-items-center lg:justify-items-start">
{discover && {discover &&
discover?.map((item, i) => ( discover?.map((item, i) => (
<Link <Link
@@ -149,7 +105,6 @@ const Page = () => {
</Link> </Link>
))} ))}
</div> </div>
)}
</div> </div>
</> </>
); );

View File

@@ -11,11 +11,3 @@
display: none; display: none;
} }
} }
@media screen and (-webkit-min-device-pixel-ratio: 0) {
select,
textarea,
input {
font-size: 16px !important;
}
}

View File

@@ -1,5 +1,6 @@
'use client'; 'use client';
import crypto from 'crypto';
import DeleteChat from '@/components/DeleteChat'; import DeleteChat from '@/components/DeleteChat';
import { cn, formatTimeDifference } from '@/lib/utils'; import { cn, formatTimeDifference } from '@/lib/utils';
import { BookOpenText, ClockIcon, Delete, ScanEye } from 'lucide-react'; import { BookOpenText, ClockIcon, Delete, ScanEye } from 'lucide-react';
@@ -21,10 +22,17 @@ const Page = () => {
const fetchChats = async () => { const fetchChats = async () => {
setLoading(true); setLoading(true);
let userSessionId = localStorage.getItem('userSessionId');
if (!userSessionId) {
userSessionId = crypto.randomBytes(20).toString('hex');
localStorage.setItem('userSessionId', userSessionId)
}
const res = await fetch(`/api/chats`, { const res = await fetch(`/api/chats`, {
method: 'GET', method: 'GET',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'user-session-id': userSessionId!,
}, },
}); });

View File

@@ -1,54 +0,0 @@
import type { MetadataRoute } from 'next';
export default function manifest(): MetadataRoute.Manifest {
return {
name: 'Perplexica - Chat with the internet',
short_name: 'Perplexica',
description:
'Perplexica is an AI powered chatbot that is connected to the internet.',
start_url: '/',
display: 'standalone',
background_color: '#0a0a0a',
theme_color: '#0a0a0a',
screenshots: [
{
src: '/screenshots/p1.png',
form_factor: 'wide',
sizes: '2560x1600',
},
{
src: '/screenshots/p2.png',
form_factor: 'wide',
sizes: '2560x1600',
},
{
src: '/screenshots/p1_small.png',
form_factor: 'narrow',
sizes: '828x1792',
},
{
src: '/screenshots/p2_small.png',
form_factor: 'narrow',
sizes: '828x1792',
},
],
icons: [
{
src: '/icon-50.png',
sizes: '50x50',
type: 'image/png' as const,
},
{
src: '/icon-100.png',
sizes: '100x100',
type: 'image/png',
},
{
src: '/icon.png',
sizes: '440x440',
type: 'image/png',
purpose: 'any',
},
],
};
}

View File

@@ -1,5 +1,4 @@
import ChatWindow from '@/components/ChatWindow'; import ChatWindow from '@/components/ChatWindow';
import { ChatProvider } from '@/lib/hooks/useChat';
import { Metadata } from 'next'; import { Metadata } from 'next';
import { Suspense } from 'react'; import { Suspense } from 'react';
@@ -12,9 +11,7 @@ const Home = () => {
return ( return (
<div> <div>
<Suspense> <Suspense>
<ChatProvider>
<ChatWindow /> <ChatWindow />
</ChatProvider>
</Suspense> </Suspense>
</div> </div>
); );

View File

@@ -7,7 +7,6 @@ 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: {
@@ -21,10 +20,7 @@ interface SettingsType {
anthropicApiKey: string; anthropicApiKey: string;
geminiApiKey: string; geminiApiKey: string;
ollamaApiUrl: string; ollamaApiUrl: string;
ollamaApiKey: string;
lmStudioApiUrl: string;
deepseekApiKey: string; deepseekApiKey: string;
aimlApiKey: string;
customOpenaiApiKey: string; customOpenaiApiKey: string;
customOpenaiApiUrl: string; customOpenaiApiUrl: string;
customOpenaiModelName: string; customOpenaiModelName: string;
@@ -145,17 +141,15 @@ const Page = () => {
const [selectedEmbeddingModel, setSelectedEmbeddingModel] = useState< const [selectedEmbeddingModel, setSelectedEmbeddingModel] = useState<
string | null string | null
>(null); >(null);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(false);
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 [systemInstructions, setSystemInstructions] = useState<string>('');
const [measureUnit, setMeasureUnit] = useState<'Imperial' | 'Metric'>(
'Metric',
);
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(`/api/config`, {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -214,10 +208,6 @@ const Page = () => {
setSystemInstructions(localStorage.getItem('systemInstructions')!); setSystemInstructions(localStorage.getItem('systemInstructions')!);
setMeasureUnit(
localStorage.getItem('measureUnit')! as 'Imperial' | 'Metric',
);
setIsLoading(false); setIsLoading(false);
}; };
@@ -376,8 +366,6 @@ const Page = () => {
localStorage.setItem('embeddingModel', value); localStorage.setItem('embeddingModel', value);
} else if (key === 'systemInstructions') { } else if (key === 'systemInstructions') {
localStorage.setItem('systemInstructions', value); localStorage.setItem('systemInstructions', value);
} else if (key === 'measureUnit') {
localStorage.setItem('measureUnit', value.toString());
} }
} catch (err) { } catch (err) {
console.error('Failed to save:', err); console.error('Failed to save:', err);
@@ -426,35 +414,13 @@ const Page = () => {
) : ( ) : (
config && ( config && (
<div className="flex flex-col space-y-6 pb-28 lg:pb-8"> <div className="flex flex-col space-y-6 pb-28 lg:pb-8">
<SettingsSection title="Preferences"> <SettingsSection title="Appearance">
<div className="flex flex-col space-y-1"> <div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm"> <p className="text-black/70 dark:text-white/70 text-sm">
Theme Theme
</p> </p>
<ThemeSwitcher /> <ThemeSwitcher />
</div> </div>
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
Measurement Units
</p>
<Select
value={measureUnit ?? undefined}
onChange={(e) => {
setMeasureUnit(e.target.value as 'Imperial' | 'Metric');
saveConfig('measureUnit', e.target.value);
}}
options={[
{
label: 'Metric',
value: 'Metric',
},
{
label: 'Imperial',
value: 'Imperial',
},
]}
/>
</div>
</SettingsSection> </SettingsSection>
<SettingsSection title="Automatic Search"> <SettingsSection title="Automatic Search">
@@ -548,7 +514,7 @@ const Page = () => {
<SettingsSection title="System Instructions"> <SettingsSection title="System Instructions">
<div className="flex flex-col space-y-4"> <div className="flex flex-col space-y-4">
<Textarea <Textarea
value={systemInstructions ?? undefined} value={systemInstructions}
isSaving={savingStates['systemInstructions']} isSaving={savingStates['systemInstructions']}
onChange={(e) => { onChange={(e) => {
setSystemInstructions(e.target.value); setSystemInstructions(e.target.value);
@@ -582,7 +548,6 @@ 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),
}), }),
@@ -725,7 +690,6 @@ 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),
}), }),
@@ -819,25 +783,6 @@ const Page = () => {
/> />
</div> </div>
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
Ollama API Key (Can be left blank)
</p>
<Input
type="text"
placeholder="Ollama API Key"
value={config.ollamaApiKey}
isSaving={savingStates['ollamaApiKey']}
onChange={(e) => {
setConfig((prev) => ({
...prev!,
ollamaApiKey: e.target.value,
}));
}}
onSave={(value) => saveConfig('ollamaApiKey', value)}
/>
</div>
<div className="flex flex-col space-y-1"> <div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm"> <p className="text-black/70 dark:text-white/70 text-sm">
GROQ API Key GROQ API Key
@@ -913,44 +858,6 @@ const Page = () => {
onSave={(value) => saveConfig('deepseekApiKey', value)} onSave={(value) => saveConfig('deepseekApiKey', value)}
/> />
</div> </div>
<div className="flex flex-col space-y-1">
<p className="text-black/70 dark:text-white/70 text-sm">
AI/ML API Key
</p>
<Input
type="text"
placeholder="AI/ML API Key"
value={config.aimlApiKey}
isSaving={savingStates['aimlApiKey']}
onChange={(e) => {
setConfig((prev) => ({
...prev!,
aimlApiKey: e.target.value,
}));
}}
onSave={(value) => saveConfig('aimlApiKey', 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>

View File

@@ -5,11 +5,28 @@ import MessageInput from './MessageInput';
import { File, Message } from './ChatWindow'; import { File, Message } from './ChatWindow';
import MessageBox from './MessageBox'; import MessageBox from './MessageBox';
import MessageBoxLoading from './MessageBoxLoading'; import MessageBoxLoading from './MessageBoxLoading';
import { useChat } from '@/lib/hooks/useChat';
const Chat = () => {
const { messages, loading, messageAppeared } = useChat();
const Chat = ({
loading,
messages,
sendMessage,
messageAppeared,
rewrite,
fileIds,
setFileIds,
files,
setFiles,
}: {
messages: Message[];
sendMessage: (message: string) => void;
loading: boolean;
messageAppeared: boolean;
rewrite: (messageId: string) => void;
fileIds: string[];
setFileIds: (fileIds: string[]) => void;
files: File[];
setFiles: (files: File[]) => void;
}) => {
const [dividerWidth, setDividerWidth] = useState(0); const [dividerWidth, setDividerWidth] = useState(0);
const dividerRef = useRef<HTMLDivElement | null>(null); const dividerRef = useRef<HTMLDivElement | null>(null);
const messageEnd = useRef<HTMLDivElement | null>(null); const messageEnd = useRef<HTMLDivElement | null>(null);
@@ -55,8 +72,12 @@ const Chat = () => {
key={i} key={i}
message={msg} message={msg}
messageIndex={i} messageIndex={i}
history={messages}
loading={loading}
dividerRef={isLast ? dividerRef : undefined} dividerRef={isLast ? dividerRef : undefined}
isLast={isLast} isLast={isLast}
rewrite={rewrite}
sendMessage={sendMessage}
/> />
{!isLast && msg.role === 'assistant' && ( {!isLast && msg.role === 'assistant' && (
<div className="h-px w-full bg-light-secondary dark:bg-dark-secondary" /> <div className="h-px w-full bg-light-secondary dark:bg-dark-secondary" />
@@ -71,7 +92,14 @@ const Chat = () => {
className="bottom-24 lg:bottom-10 fixed z-40" className="bottom-24 lg:bottom-10 fixed z-40"
style={{ width: dividerWidth }} style={{ width: dividerWidth }}
> >
<MessageInput /> <MessageInput
loading={loading}
sendMessage={sendMessage}
fileIds={fileIds}
setFileIds={setFileIds}
files={files}
setFiles={setFiles}
/>
</div> </div>
)} )}
</div> </div>

View File

@@ -1,13 +1,17 @@
'use client'; 'use client';
import { useEffect, useRef, useState } from 'react';
import { Document } from '@langchain/core/documents'; import { Document } from '@langchain/core/documents';
import Navbar from './Navbar'; import Navbar from './Navbar';
import Chat from './Chat'; import Chat from './Chat';
import EmptyChat from './EmptyChat'; import EmptyChat from './EmptyChat';
import crypto from 'crypto';
import { toast } from 'sonner';
import { useSearchParams } from 'next/navigation';
import { getSuggestions } from '@/lib/actions';
import { Settings } from 'lucide-react'; import { Settings } from 'lucide-react';
import Link from 'next/link'; import Link from 'next/link';
import NextError from 'next/error'; import NextError from 'next/error';
import { useChat } from '@/lib/hooks/useChat';
export type Message = { export type Message = {
messageId: string; messageId: string;
@@ -25,8 +29,520 @@ export interface File {
fileId: string; fileId: string;
} }
const ChatWindow = () => { interface ChatModelProvider {
const { hasError, isReady, notFound, messages } = useChat(); name: string;
provider: string;
}
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,
) => {
try {
let chatModel = localStorage.getItem('chatModel');
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(`/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');
}
if (!embeddingModel || !embeddingModelProvider) {
const embeddingModelProviders = providers.embeddingModelProviders;
let userSessionId = localStorage.getItem('userSessionId');
if (!userSessionId) {
userSessionId = crypto.randomBytes(20).toString('hex');
localStorage.setItem('userSessionId', userSessionId!)
}
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);
}
}
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 (
chatId: string,
setMessages: (messages: Message[]) => void,
setIsMessagesLoaded: (loaded: boolean) => void,
setChatHistory: (history: [string, string][]) => void,
setFocusMode: (mode: string) => void,
setNotFound: (notFound: boolean) => void,
setFiles: (files: File[]) => void,
setFileIds: (fileIds: string[]) => void,
) => {
const res = await fetch(`/api/chats/${chatId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (res.status === 404) {
setNotFound(true);
setIsMessagesLoaded(true);
return;
}
const data = await res.json();
const messages = data.messages.map((msg: any) => {
return {
...msg,
...JSON.parse(msg.metadata),
};
}) as Message[];
setMessages(messages);
const history = messages.map((msg) => {
return [msg.role, msg.content];
}) as [string, string][];
console.debug(new Date(), 'app:messages_loaded');
document.title = messages[0].content;
const files = data.chat.files.map((file: any) => {
return {
fileName: file.name,
fileExtension: file.name.split('.').pop(),
fileId: file.fileId,
};
});
setFiles(files);
setFileIds(files.map((file: File) => file.fileId));
setChatHistory(history);
setFocusMode(data.chat.focusMode);
setIsMessagesLoaded(true);
};
const ChatWindow = ({ id }: { id?: string }) => {
const searchParams = useSearchParams();
const initialMessage = searchParams.get('q');
const [chatId, setChatId] = useState<string | undefined>(id);
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 [isReady, setIsReady] = useState(false);
useEffect(() => {
checkConfig(
setChatModelProvider,
setEmbeddingModelProvider,
setIsConfigReady,
setHasError,
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const [loading, setLoading] = useState(false);
const [messageAppeared, setMessageAppeared] = useState(false);
const [chatHistory, setChatHistory] = useState<[string, string][]>([]);
const [messages, setMessages] = useState<Message[]>([]);
const [files, setFiles] = useState<File[]>([]);
const [fileIds, setFileIds] = useState<string[]>([]);
const [focusMode, setFocusMode] = useState('webSearch');
const [optimizationMode, setOptimizationMode] = useState('speed');
const [isMessagesLoaded, setIsMessagesLoaded] = useState(false);
const [notFound, setNotFound] = useState(false);
useEffect(() => {
if (
chatId &&
!newChatCreated &&
!isMessagesLoaded &&
messages.length === 0
) {
loadMessages(
chatId,
setMessages,
setIsMessagesLoaded,
setChatHistory,
setFocusMode,
setNotFound,
setFiles,
setFileIds,
);
} else if (!chatId) {
setNewChatCreated(true);
setIsMessagesLoaded(true);
setChatId(crypto.randomBytes(20).toString('hex'));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const messagesRef = useRef<Message[]>([]);
useEffect(() => {
messagesRef.current = messages;
}, [messages]);
useEffect(() => {
if (isMessagesLoaded && isConfigReady) {
setIsReady(true);
console.debug(new Date(), 'app:ready');
} else {
setIsReady(false);
}
}, [isMessagesLoaded, isConfigReady]);
const sendMessage = async (message: string, messageId?: string) => {
if (loading) return;
if (!isConfigReady) {
toast.error('Cannot send message before the configuration is ready');
return;
}
setLoading(true);
setMessageAppeared(false);
let sources: Document[] | undefined = undefined;
let recievedMessage = '';
let added = false;
messageId = messageId ?? crypto.randomBytes(7).toString('hex');
let userSessionId = localStorage.getItem('userSessionId');
setMessages((prevMessages) => [
...prevMessages,
{
content: message,
messageId: messageId,
chatId: chatId!,
role: 'user',
createdAt: new Date(),
},
]);
const messageHandler = async (data: any) => {
if (data.type === 'error') {
toast.error(data.data);
setLoading(false);
return;
}
if (data.type === 'sources') {
sources = data.data;
if (!added) {
setMessages((prevMessages) => [
...prevMessages,
{
content: '',
messageId: data.messageId,
chatId: chatId!,
role: 'assistant',
sources: sources,
createdAt: new Date(),
},
]);
added = true;
}
setMessageAppeared(true);
}
if (data.type === 'message') {
if (!added) {
setMessages((prevMessages) => [
...prevMessages,
{
content: data.data,
messageId: data.messageId,
chatId: chatId!,
role: 'assistant',
sources: sources,
createdAt: new Date(),
},
]);
added = true;
}
setMessages((prev) =>
prev.map((message) => {
if (message.messageId === data.messageId) {
return { ...message, content: message.content + data.data };
}
return message;
}),
);
recievedMessage += data.data;
setMessageAppeared(true);
}
if (data.type === 'messageEnd') {
setChatHistory((prevHistory) => [
...prevHistory,
['human', message],
['assistant', recievedMessage],
]);
setLoading(false);
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 (
lastMsg.role === 'assistant' &&
lastMsg.sources &&
lastMsg.sources.length > 0 &&
!lastMsg.suggestions
) {
const suggestions = await getSuggestions(messagesRef.current);
setMessages((prev) =>
prev.map((msg) => {
if (msg.messageId === lastMsg.messageId) {
return { ...msg, suggestions: suggestions };
}
return msg;
}),
);
}
}
};
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,
userSessionId: userSessionId,
},
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 index = messages.findIndex((msg) => msg.messageId === messageId);
if (index === -1) return;
const message = messages[index - 1];
setMessages((prev) => {
return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)];
});
setChatHistory((prev) => {
return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)];
});
sendMessage(message.content, message.messageId);
};
useEffect(() => {
if (isReady && initialMessage && isConfigReady) {
sendMessage(initialMessage);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isConfigReady, isReady, initialMessage]);
if (hasError) { if (hasError) {
return ( return (
<div className="relative"> <div className="relative">
@@ -51,11 +567,31 @@ const ChatWindow = () => {
<div> <div>
{messages.length > 0 ? ( {messages.length > 0 ? (
<> <>
<Navbar /> <Navbar chatId={chatId!} messages={messages} />
<Chat /> <Chat
loading={loading}
messages={messages}
sendMessage={sendMessage}
messageAppeared={messageAppeared}
rewrite={rewrite}
fileIds={fileIds}
setFileIds={setFileIds}
files={files}
setFiles={setFiles}
/>
</> </>
) : ( ) : (
<EmptyChat /> <EmptyChat
sendMessage={sendMessage}
focusMode={focusMode}
setFocusMode={setFocusMode}
optimizationMode={optimizationMode}
setOptimizationMode={setOptimizationMode}
fileIds={fileIds}
setFileIds={setFileIds}
files={files}
setFiles={setFiles}
/>
)} )}
</div> </div>
) )

View File

@@ -1,11 +1,32 @@
import { Settings } from 'lucide-react'; import { Settings } from 'lucide-react';
import EmptyChatMessageInput from './EmptyChatMessageInput'; import EmptyChatMessageInput from './EmptyChatMessageInput';
import { 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,
focusMode,
setFocusMode,
optimizationMode,
setOptimizationMode,
fileIds,
setFileIds,
files,
setFiles,
}: {
sendMessage: (message: string) => void;
focusMode: string;
setFocusMode: (mode: string) => void;
optimizationMode: string;
setOptimizationMode: (mode: string) => void;
fileIds: string[];
setFileIds: (fileIds: string[]) => void;
files: File[];
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">
@@ -13,21 +34,21 @@ const EmptyChat = () => {
<Settings className="cursor-pointer lg:hidden" /> <Settings className="cursor-pointer lg:hidden" />
</Link> </Link>
</div> </div>
<div className="flex flex-col items-center justify-center min-h-screen max-w-screen-sm mx-auto p-2 space-y-4"> <div className="flex flex-col items-center justify-center min-h-screen max-w-screen-sm mx-auto p-2 space-y-8">
<div className="flex flex-col items-center justify-center w-full space-y-8">
<h2 className="text-black/70 dark:text-white/70 text-3xl font-medium -mt-8"> <h2 className="text-black/70 dark:text-white/70 text-3xl font-medium -mt-8">
Research begins here. Research begins here.
</h2> </h2>
<EmptyChatMessageInput /> <EmptyChatMessageInput
</div> sendMessage={sendMessage}
<div className="flex flex-col w-full gap-4 mt-2 sm:flex-row sm:justify-center"> focusMode={focusMode}
<div className="flex-1 w-full"> setFocusMode={setFocusMode}
<WeatherWidget /> optimizationMode={optimizationMode}
</div> setOptimizationMode={setOptimizationMode}
<div className="flex-1 w-full"> fileIds={fileIds}
<NewsArticleWidget /> setFileIds={setFileIds}
</div> files={files}
</div> setFiles={setFiles}
/>
</div> </div>
</div> </div>
); );

View File

@@ -1,15 +1,34 @@
import { ArrowRight } from 'lucide-react'; import { ArrowRight } from 'lucide-react';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import TextareaAutosize from 'react-textarea-autosize'; import TextareaAutosize from 'react-textarea-autosize';
import CopilotToggle from './MessageInputActions/Copilot';
import Focus from './MessageInputActions/Focus'; import Focus from './MessageInputActions/Focus';
import Optimization from './MessageInputActions/Optimization'; import Optimization from './MessageInputActions/Optimization';
import Attach from './MessageInputActions/Attach'; import Attach from './MessageInputActions/Attach';
import { useChat } from '@/lib/hooks/useChat'; import { File } from './ChatWindow';
const EmptyChatMessageInput = () => { const EmptyChatMessageInput = ({
const { sendMessage } = useChat(); sendMessage,
focusMode,
/* const [copilotEnabled, setCopilotEnabled] = useState(false); */ setFocusMode,
optimizationMode,
setOptimizationMode,
fileIds,
setFileIds,
files,
setFiles,
}: {
sendMessage: (message: string) => void;
focusMode: string;
setFocusMode: (mode: string) => void;
optimizationMode: string;
setOptimizationMode: (mode: string) => void;
fileIds: string[];
setFileIds: (fileIds: string[]) => void;
files: File[];
setFiles: (files: File[]) => void;
}) => {
const [copilotEnabled, setCopilotEnabled] = useState(false);
const [message, setMessage] = useState(''); const [message, setMessage] = useState('');
const inputRef = useRef<HTMLTextAreaElement | null>(null); const inputRef = useRef<HTMLTextAreaElement | null>(null);
@@ -65,11 +84,20 @@ const EmptyChatMessageInput = () => {
/> />
<div className="flex flex-row items-center justify-between mt-4"> <div className="flex flex-row items-center justify-between mt-4">
<div className="flex flex-row items-center space-x-2 lg:space-x-4"> <div className="flex flex-row items-center space-x-2 lg:space-x-4">
<Focus /> <Focus focusMode={focusMode} setFocusMode={setFocusMode} />
<Attach showText /> <Attach
fileIds={fileIds}
setFileIds={setFileIds}
files={files}
setFiles={setFiles}
showText
/>
</div> </div>
<div className="flex flex-row items-center space-x-1 sm:space-x-4"> <div className="flex flex-row items-center space-x-1 sm:space-x-4">
<Optimization /> <Optimization
optimizationMode={optimizationMode}
setOptimizationMode={setOptimizationMode}
/>
<button <button
disabled={message.trim().length === 0} disabled={message.trim().length === 0}
className="bg-[#24A0ED] text-white disabled:text-black/50 dark:disabled:text-white/50 disabled:bg-[#e0e0dc] dark:disabled:bg-[#ececec21] hover:bg-opacity-85 transition duration-100 rounded-full p-2" className="bg-[#24A0ED] text-white disabled:text-black/50 dark:disabled:text-white/50 disabled:bg-[#e0e0dc] dark:disabled:bg-[#ececec21] hover:bg-opacity-85 transition duration-100 rounded-full p-2"

View File

@@ -20,36 +20,32 @@ 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'; import ThinkBox from './ThinkBox';
import { useChat } from '@/lib/hooks/useChat';
const ThinkTagProcessor = ({ const ThinkTagProcessor = ({ children }: { children: React.ReactNode }) => {
children, return <ThinkBox content={children as string} />;
thinkingEnded,
}: {
children: React.ReactNode;
thinkingEnded: boolean;
}) => {
return (
<ThinkBox content={children as string} thinkingEnded={thinkingEnded} />
);
}; };
const MessageBox = ({ const MessageBox = ({
message, message,
messageIndex, messageIndex,
history,
loading,
dividerRef, dividerRef,
isLast, isLast,
rewrite,
sendMessage,
}: { }: {
message: Message; message: Message;
messageIndex: number; messageIndex: number;
history: Message[];
loading: boolean;
dividerRef?: MutableRefObject<HTMLDivElement | null>; dividerRef?: MutableRefObject<HTMLDivElement | null>;
isLast: boolean; isLast: boolean;
rewrite: (messageId: string) => void;
sendMessage: (message: string) => void;
}) => { }) => {
const { loading, messages: history, sendMessage, rewrite } = useChat();
const [parsedMessage, setParsedMessage] = useState(message.content); const [parsedMessage, setParsedMessage] = useState(message.content);
const [speechMessage, setSpeechMessage] = useState(message.content); const [speechMessage, setSpeechMessage] = useState(message.content);
const [thinkingEnded, setThinkingEnded] = useState(false);
useEffect(() => { useEffect(() => {
const citationRegex = /\[([^\]]+)\]/g; const citationRegex = /\[([^\]]+)\]/g;
@@ -65,10 +61,6 @@ const MessageBox = ({
} }
} }
if (message.role === 'assistant' && message.content.includes('</think>')) {
setThinkingEnded(true);
}
if ( if (
message.role === 'assistant' && message.role === 'assistant' &&
message?.sources && message?.sources &&
@@ -96,7 +88,7 @@ const MessageBox = ({
if (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>`; 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 { } else {
return ``; return `[${numStr}]`;
} }
}) })
.join(''); .join('');
@@ -105,15 +97,6 @@ const MessageBox = ({
}, },
), ),
); );
setSpeechMessage(message.content.replace(regex, ''));
return;
} else if (
message.role === 'assistant' &&
message?.sources &&
message.sources.length === 0
) {
setParsedMessage(processedMessage.replace(regex, ''));
setSpeechMessage(message.content.replace(regex, ''));
return; return;
} }
@@ -127,9 +110,6 @@ const MessageBox = ({
overrides: { overrides: {
think: { think: {
component: ThinkTagProcessor, component: ThinkTagProcessor,
props: {
thinkingEnded: thinkingEnded,
},
}, },
}, },
}; };

View File

@@ -6,11 +6,22 @@ import Attach from './MessageInputActions/Attach';
import CopilotToggle from './MessageInputActions/Copilot'; import CopilotToggle from './MessageInputActions/Copilot';
import { File } from './ChatWindow'; import { File } from './ChatWindow';
import AttachSmall from './MessageInputActions/AttachSmall'; import AttachSmall from './MessageInputActions/AttachSmall';
import { useChat } from '@/lib/hooks/useChat';
const MessageInput = () => {
const { loading, sendMessage } = useChat();
const MessageInput = ({
sendMessage,
loading,
fileIds,
setFileIds,
files,
setFiles,
}: {
sendMessage: (message: string) => void;
loading: boolean;
fileIds: string[];
setFileIds: (fileIds: string[]) => void;
files: File[];
setFiles: (files: File[]) => void;
}) => {
const [copilotEnabled, setCopilotEnabled] = useState(false); const [copilotEnabled, setCopilotEnabled] = useState(false);
const [message, setMessage] = useState(''); const [message, setMessage] = useState('');
const [textareaRows, setTextareaRows] = useState(1); const [textareaRows, setTextareaRows] = useState(1);
@@ -68,7 +79,14 @@ const MessageInput = () => {
mode === 'multi' ? 'flex-col rounded-lg' : 'flex-row rounded-full', mode === 'multi' ? 'flex-col rounded-lg' : 'flex-row rounded-full',
)} )}
> >
{mode === 'single' && <AttachSmall />} {mode === 'single' && (
<AttachSmall
fileIds={fileIds}
setFileIds={setFileIds}
files={files}
setFiles={setFiles}
/>
)}
<TextareaAutosize <TextareaAutosize
ref={inputRef} ref={inputRef}
value={message} value={message}
@@ -95,7 +113,12 @@ const MessageInput = () => {
)} )}
{mode === 'multi' && ( {mode === 'multi' && (
<div className="flex flex-row items-center justify-between w-full pt-2"> <div className="flex flex-row items-center justify-between w-full pt-2">
<AttachSmall /> <AttachSmall
fileIds={fileIds}
setFileIds={setFileIds}
files={files}
setFiles={setFiles}
/>
<div className="flex flex-row items-center space-x-4"> <div className="flex flex-row items-center space-x-4">
<CopilotToggle <CopilotToggle
copilotEnabled={copilotEnabled} copilotEnabled={copilotEnabled}

View File

@@ -7,11 +7,21 @@ import {
} from '@headlessui/react'; } from '@headlessui/react';
import { CopyPlus, File, LoaderCircle, Plus, Trash } from 'lucide-react'; import { CopyPlus, File, LoaderCircle, Plus, Trash } from 'lucide-react';
import { Fragment, useRef, useState } from 'react'; import { Fragment, useRef, useState } from 'react';
import { useChat } from '@/lib/hooks/useChat'; import { File as FileType } from '../ChatWindow';
const Attach = ({ showText }: { showText?: boolean }) => {
const { files, setFiles, setFileIds, fileIds } = useChat();
const Attach = ({
fileIds,
setFileIds,
showText,
files,
setFiles,
}: {
fileIds: string[];
setFileIds: (fileIds: string[]) => void;
showText?: boolean;
files: FileType[];
setFiles: (files: FileType[]) => void;
}) => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const fileInputRef = useRef<any>(); const fileInputRef = useRef<any>();
@@ -132,8 +142,8 @@ const Attach = ({ showText }: { showText?: boolean }) => {
key={i} key={i}
className="flex flex-row items-center justify-start w-full space-x-3 p-3" className="flex flex-row items-center justify-start w-full space-x-3 p-3"
> >
<div className="bg-light-100 dark:bg-dark-100 flex items-center justify-center w-10 h-10 rounded-md"> <div className="bg-dark-100 flex items-center justify-center w-10 h-10 rounded-md">
<File size={16} className="text-black/70 dark:text-white/70" /> <File size={16} className="text-white/70" />
</div> </div>
<p className="text-black/70 dark:text-white/70 text-sm"> <p className="text-black/70 dark:text-white/70 text-sm">
{file.fileName.length > 25 {file.fileName.length > 25

View File

@@ -8,11 +8,18 @@ import {
import { CopyPlus, File, LoaderCircle, Plus, Trash } from 'lucide-react'; import { CopyPlus, File, LoaderCircle, Plus, Trash } from 'lucide-react';
import { Fragment, useRef, useState } from 'react'; import { Fragment, useRef, useState } from 'react';
import { File as FileType } from '../ChatWindow'; import { File as FileType } from '../ChatWindow';
import { useChat } from '@/lib/hooks/useChat';
const AttachSmall = () => {
const { files, setFiles, setFileIds, fileIds } = useChat();
const AttachSmall = ({
fileIds,
setFileIds,
files,
setFiles,
}: {
fileIds: string[];
setFileIds: (fileIds: string[]) => void;
files: FileType[];
setFiles: (files: FileType[]) => void;
}) => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const fileInputRef = useRef<any>(); const fileInputRef = useRef<any>();
@@ -107,8 +114,8 @@ const AttachSmall = () => {
key={i} key={i}
className="flex flex-row items-center justify-start w-full space-x-3 p-3" className="flex flex-row items-center justify-start w-full space-x-3 p-3"
> >
<div className="bg-light-100 dark:bg-dark-100 flex items-center justify-center w-10 h-10 rounded-md"> <div className="bg-dark-100 flex items-center justify-center w-10 h-10 rounded-md">
<File size={16} className="text-black/70 dark:text-white/70" /> <File size={16} className="text-white/70" />
</div> </div>
<p className="text-black/70 dark:text-white/70 text-sm"> <p className="text-black/70 dark:text-white/70 text-sm">
{file.fileName.length > 25 {file.fileName.length > 25

View File

@@ -15,7 +15,6 @@ import {
} from '@headlessui/react'; } from '@headlessui/react';
import { SiReddit, SiYoutube } from '@icons-pack/react-simple-icons'; import { SiReddit, SiYoutube } from '@icons-pack/react-simple-icons';
import { Fragment } from 'react'; import { Fragment } from 'react';
import { useChat } from '@/lib/hooks/useChat';
const focusModes = [ const focusModes = [
{ {
@@ -56,9 +55,13 @@ const focusModes = [
}, },
]; ];
const Focus = () => { const Focus = ({
const { focusMode, setFocusMode } = useChat(); focusMode,
setFocusMode,
}: {
focusMode: string;
setFocusMode: (mode: string) => void;
}) => {
return ( return (
<Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg mt-[6.5px]"> <Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg mt-[6.5px]">
<PopoverButton <PopoverButton

View File

@@ -7,7 +7,6 @@ import {
Transition, Transition,
} from '@headlessui/react'; } from '@headlessui/react';
import { Fragment } from 'react'; import { Fragment } from 'react';
import { useChat } from '@/lib/hooks/useChat';
const OptimizationModes = [ const OptimizationModes = [
{ {
@@ -35,9 +34,13 @@ const OptimizationModes = [
}, },
]; ];
const Optimization = () => { const Optimization = ({
const { optimizationMode, setOptimizationMode } = useChat(); optimizationMode,
setOptimizationMode,
}: {
optimizationMode: string;
setOptimizationMode: (mode: string) => void;
}) => {
return ( return (
<Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg"> <Popover className="relative w-full max-w-[15rem] md:max-w-md lg:max-w-lg">
<PopoverButton <PopoverButton

View File

@@ -1,130 +1,19 @@
import { Clock, Edit, Share, Trash, FileText, FileDown } from 'lucide-react'; import { Clock, Edit, Share, Trash } from 'lucide-react';
import { Message } from './ChatWindow'; import { Message } from './ChatWindow';
import { useEffect, useState, Fragment } from 'react'; import { useEffect, useState } from 'react';
import { formatTimeDifference } from '@/lib/utils'; import { formatTimeDifference } from '@/lib/utils';
import DeleteChat from './DeleteChat'; import DeleteChat from './DeleteChat';
import {
Popover,
PopoverButton,
PopoverPanel,
Transition,
} from '@headlessui/react';
import jsPDF from 'jspdf';
import { useChat } from '@/lib/hooks/useChat';
const downloadFile = (filename: string, content: string, type: string) => { const Navbar = ({
const blob = new Blob([content], { type }); chatId,
const url = URL.createObjectURL(blob); messages,
const a = document.createElement('a'); }: {
a.href = url; messages: Message[];
a.download = filename; chatId: string;
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 = () => {
const [title, setTitle] = useState<string>(''); const [title, setTitle] = useState<string>('');
const [timeAgo, setTimeAgo] = useState<string>(''); const [timeAgo, setTimeAgo] = useState<string>('');
const { messages, chatId } = useChat();
useEffect(() => { useEffect(() => {
if (messages.length > 0) { if (messages.length > 0) {
const newTitle = const newTitle =
@@ -170,40 +59,11 @@ const Navbar = () => {
<p className="hidden lg:flex">{title}</p> <p className="hidden lg:flex">{title}</p>
<div className="flex flex-row items-center space-x-4"> <div className="flex flex-row items-center space-x-4">
<Popover className="relative"> <Share
<PopoverButton className="active:scale-95 transition duration-100 cursor-pointer p-2 rounded-full hover:bg-light-secondary dark:hover:bg-dark-secondary"> size={17}
<Share size={17} /> className="active:scale-95 transition duration-100 cursor-pointer"
</PopoverButton> />
<Transition <DeleteChat redirect chatId={chatId} chats={[]} setChats={() => {}} />
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>
</div> </div>
); );

View File

@@ -1,71 +0,0 @@
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;

View File

@@ -1,23 +1,15 @@
'use client'; 'use client';
import { useEffect, useState } from 'react'; import { useState } from 'react';
import { cn } from '@/lib/utils';
import { ChevronDown, ChevronUp, BrainCircuit } from 'lucide-react'; import { ChevronDown, ChevronUp, BrainCircuit } from 'lucide-react';
interface ThinkBoxProps { interface ThinkBoxProps {
content: string; content: string;
thinkingEnded: boolean;
} }
const ThinkBox = ({ content, thinkingEnded }: ThinkBoxProps) => { const ThinkBox = ({ content }: ThinkBoxProps) => {
const [isExpanded, setIsExpanded] = useState(true); const [isExpanded, setIsExpanded] = useState(false);
useEffect(() => {
if (thinkingEnded) {
setIsExpanded(false);
} else {
setIsExpanded(true);
}
}, [thinkingEnded]);
return ( 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"> <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">

View File

@@ -1,161 +0,0 @@
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: '',
temperatureUnit: 'C',
windSpeedUnit: 'm/s',
});
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,
) => {
if (navigator.geolocation) {
const result = await navigator.permissions.query({
name: 'geolocation',
});
if (result.state === 'granted') {
navigator.geolocation.getCurrentPosition(async (position) => {
const res = await fetch(
`https://api-bdc.io/data/reverse-geocode-client?latitude=${position.coords.latitude}&longitude=${position.coords.longitude}&localityLanguage=en`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
},
);
const data = await res.json();
callback({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
city: data.locality,
});
});
} else if (result.state === 'prompt') {
callback(await getApproxLocation());
navigator.geolocation.getCurrentPosition((position) => {});
} else if (result.state === 'denied') {
callback(await getApproxLocation());
}
} else {
callback(await getApproxLocation());
}
};
getLocation(async (location) => {
const res = await fetch(`/api/weather`, {
method: 'POST',
body: JSON.stringify({
lat: location.latitude,
lng: location.longitude,
measureUnit: localStorage.getItem('measureUnit') ?? 'Metric',
}),
});
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,
temperatureUnit: data.temperatureUnit,
windSpeedUnit: data.windSpeedUnit,
});
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}°{data.temperatureUnit}
</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} {data.windSpeedUnit}
</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;

View File

@@ -3,18 +3,32 @@ import {
RunnableMap, RunnableMap,
RunnableLambda, RunnableLambda,
} from '@langchain/core/runnables'; } from '@langchain/core/runnables';
import { ChatPromptTemplate } from '@langchain/core/prompts'; 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 '../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';
import LineOutputParser from '../outputParsers/lineOutputParser';
const imageSearchChainPrompt = ` const imageSearchChainPrompt = `
You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search the web for images. You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search the web for images.
You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation. You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation.
Output only the rephrased query wrapped in an XML <query> element. Do not include any explanation or additional text.
Example:
1. Follow up question: What is a cat?
Rephrased: A cat
2. Follow up question: What is a car? How does it works?
Rephrased: Car working
3. Follow up question: How does an AC work?
Rephrased: AC working
Conversation:
{chat_history}
Follow up question: {query}
Rephrased question:
`; `;
type ImageSearchChainInput = { type ImageSearchChainInput = {
@@ -40,39 +54,12 @@ const createImageSearchChain = (llm: BaseChatModel) => {
return input.query; return input.query;
}, },
}), }),
ChatPromptTemplate.fromMessages([ PromptTemplate.fromTemplate(imageSearchChainPrompt),
['system', imageSearchChainPrompt],
[
'user',
'<conversation>\n</conversation>\n<follow_up>\nWhat is a cat?\n</follow_up>',
],
['assistant', '<query>A cat</query>'],
[
'user',
'<conversation>\n</conversation>\n<follow_up>\nWhat is a car? How does it work?\n</follow_up>',
],
['assistant', '<query>Car working</query>'],
[
'user',
'<conversation>\n</conversation>\n<follow_up>\nHow does an AC work?\n</follow_up>',
],
['assistant', '<query>AC working</query>'],
[
'user',
'<conversation>{chat_history}</conversation>\n<follow_up>\n{query}\n</follow_up>',
],
]),
llm, llm,
strParser, strParser,
RunnableLambda.from(async (input: string) => { RunnableLambda.from(async (input: string) => {
const queryParser = new LineOutputParser({ input = input.replace(/<think>.*?<\/think>/g, '');
key: 'query',
});
return await queryParser.parse(input);
}),
RunnableLambda.from(async (input: string) => {
const res = await searchSearxng(input, { const res = await searchSearxng(input, {
engines: ['bing images', 'google images'], engines: ['bing images', 'google images'],
}); });

View File

@@ -3,18 +3,32 @@ import {
RunnableMap, RunnableMap,
RunnableLambda, RunnableLambda,
} from '@langchain/core/runnables'; } from '@langchain/core/runnables';
import { ChatPromptTemplate } from '@langchain/core/prompts'; 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 '../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';
import LineOutputParser from '../outputParsers/lineOutputParser';
const videoSearchChainPrompt = ` const VideoSearchChainPrompt = `
You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search Youtube for videos. You will be given a conversation below and a follow up question. You need to rephrase the follow-up question so it is a standalone question that can be used by the LLM to search Youtube for videos.
You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation. You need to make sure the rephrased question agrees with the conversation and is relevant to the conversation.
Output only the rephrased query wrapped in an XML <query> element. Do not include any explanation or additional text.
Example:
1. Follow up question: How does a car work?
Rephrased: How does a car work?
2. Follow up question: What is the theory of relativity?
Rephrased: What is theory of relativity
3. Follow up question: How does an AC work?
Rephrased: How does an AC work
Conversation:
{chat_history}
Follow up question: {query}
Rephrased question:
`; `;
type VideoSearchChainInput = { type VideoSearchChainInput = {
@@ -41,37 +55,12 @@ const createVideoSearchChain = (llm: BaseChatModel) => {
return input.query; return input.query;
}, },
}), }),
ChatPromptTemplate.fromMessages([ PromptTemplate.fromTemplate(VideoSearchChainPrompt),
['system', videoSearchChainPrompt],
[
'user',
'<conversation>\n</conversation>\n<follow_up>\nHow does a car work?\n</follow_up>',
],
['assistant', '<query>How does a car work?</query>'],
[
'user',
'<conversation>\n</conversation>\n<follow_up>\nWhat is the theory of relativity?\n</follow_up>',
],
['assistant', '<query>Theory of relativity</query>'],
[
'user',
'<conversation>\n</conversation>\n<follow_up>\nHow does an AC work?\n</follow_up>',
],
['assistant', '<query>AC working</query>'],
[
'user',
'<conversation>{chat_history}</conversation>\n<follow_up>\n{query}\n</follow_up>',
],
]),
llm, llm,
strParser, strParser,
RunnableLambda.from(async (input: string) => { RunnableLambda.from(async (input: string) => {
const queryParser = new LineOutputParser({ input = input.replace(/<think>.*?<\/think>/g, '');
key: 'query',
});
return await queryParser.parse(input);
}),
RunnableLambda.from(async (input: string) => {
const res = await searchSearxng(input, { const res = await searchSearxng(input, {
engines: ['youtube'], engines: ['youtube'],
}); });
@@ -103,8 +92,8 @@ const handleVideoSearch = (
input: VideoSearchChainInput, input: VideoSearchChainInput,
llm: BaseChatModel, llm: BaseChatModel,
) => { ) => {
const videoSearchChain = createVideoSearchChain(llm); const VideoSearchChain = createVideoSearchChain(llm);
return videoSearchChain.invoke(input); return VideoSearchChain.invoke(input);
}; };
export default handleVideoSearch; export default handleVideoSearch;

View File

@@ -1,14 +1,7 @@
import fs from 'fs';
import path from 'path';
import toml from '@iarna/toml'; import toml from '@iarna/toml';
// Use dynamic imports for Node.js modules to prevent client-side errors
let fs: any;
let path: any;
if (typeof window === 'undefined') {
// We're on the server
fs = require('fs');
path = require('path');
}
const configFileName = 'config.toml'; const configFileName = 'config.toml';
interface Config { interface Config {
@@ -31,17 +24,10 @@ interface Config {
}; };
OLLAMA: { OLLAMA: {
API_URL: string; API_URL: string;
API_KEY: string;
}; };
DEEPSEEK: { DEEPSEEK: {
API_KEY: string; API_KEY: string;
}; };
AIMLAPI: {
API_KEY: string;
};
LM_STUDIO: {
API_URL: string;
};
CUSTOM_OPENAI: { CUSTOM_OPENAI: {
API_URL: string; API_URL: string;
API_KEY: string; API_KEY: string;
@@ -57,17 +43,10 @@ type RecursivePartial<T> = {
[P in keyof T]?: RecursivePartial<T[P]>; [P in keyof T]?: RecursivePartial<T[P]>;
}; };
const loadConfig = () => { const loadConfig = () =>
// Server-side only toml.parse(
if (typeof window === 'undefined') {
return toml.parse(
fs.readFileSync(path.join(process.cwd(), `${configFileName}`), 'utf-8'), fs.readFileSync(path.join(process.cwd(), `${configFileName}`), 'utf-8'),
) as any as Config; ) as any as Config;
}
// Client-side fallback - settings will be loaded via API
return {} as Config;
};
export const getSimilarityMeasure = () => export const getSimilarityMeasure = () =>
loadConfig().GENERAL.SIMILARITY_MEASURE; loadConfig().GENERAL.SIMILARITY_MEASURE;
@@ -87,12 +66,8 @@ export const getSearxngApiEndpoint = () =>
export const getOllamaApiEndpoint = () => loadConfig().MODELS.OLLAMA.API_URL; export const getOllamaApiEndpoint = () => loadConfig().MODELS.OLLAMA.API_URL;
export const getOllamaApiKey = () => loadConfig().MODELS.OLLAMA.API_KEY;
export const getDeepseekApiKey = () => loadConfig().MODELS.DEEPSEEK.API_KEY; export const getDeepseekApiKey = () => loadConfig().MODELS.DEEPSEEK.API_KEY;
export const getAimlApiKey = () => loadConfig().MODELS.AIMLAPI.API_KEY;
export const getCustomOpenaiApiKey = () => export const getCustomOpenaiApiKey = () =>
loadConfig().MODELS.CUSTOM_OPENAI.API_KEY; loadConfig().MODELS.CUSTOM_OPENAI.API_KEY;
@@ -102,9 +77,6 @@ export const getCustomOpenaiApiUrl = () =>
export const getCustomOpenaiModelName = () => export const getCustomOpenaiModelName = () =>
loadConfig().MODELS.CUSTOM_OPENAI.MODEL_NAME; loadConfig().MODELS.CUSTOM_OPENAI.MODEL_NAME;
export const getLMStudioApiEndpoint = () =>
loadConfig().MODELS.LM_STUDIO.API_URL;
const mergeConfigs = (current: any, update: any): any => { const mergeConfigs = (current: any, update: any): any => {
if (update === null || update === undefined) { if (update === null || update === undefined) {
return current; return current;
@@ -137,13 +109,10 @@ const mergeConfigs = (current: any, update: any): any => {
}; };
export const updateConfig = (config: RecursivePartial<Config>) => { export const updateConfig = (config: RecursivePartial<Config>) => {
// Server-side only
if (typeof window === 'undefined') {
const currentConfig = loadConfig(); const currentConfig = loadConfig();
const mergedConfig = mergeConfigs(currentConfig, config); const mergedConfig = mergeConfigs(currentConfig, config);
fs.writeFileSync( fs.writeFileSync(
path.join(path.join(process.cwd(), `${configFileName}`)), path.join(path.join(process.cwd(), `${configFileName}`)),
toml.stringify(mergedConfig), toml.stringify(mergedConfig),
); );
}
}; };

View File

@@ -3,8 +3,7 @@ import Database from 'better-sqlite3';
import * as schema from './schema'; import * as schema from './schema';
import path from 'path'; import path from 'path';
const DATA_DIR = process.env.DATA_DIR || process.cwd(); const sqlite = new Database(path.join(process.cwd(), 'data/db.sqlite'));
const sqlite = new Database(path.join(DATA_DIR, './data/db.sqlite'));
const db = drizzle(sqlite, { const db = drizzle(sqlite, {
schema: schema, schema: schema,
}); });

View File

@@ -1,5 +0,0 @@
import db from './';
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
import path from 'path';
migrate(db, { migrationsFolder: path.join(process.cwd(), 'drizzle') });

View File

@@ -25,4 +25,6 @@ export const chats = sqliteTable('chats', {
files: text('files', { mode: 'json' }) files: text('files', { mode: 'json' })
.$type<File[]>() .$type<File[]>()
.default(sql`'[]'`), .default(sql`'[]'`),
userSessionId: text('userSessionId'),
timestamp: text('timestamp'),
}); });

View File

@@ -1,643 +0,0 @@
'use client';
import { Message } from '@/components/ChatWindow';
import { createContext, useContext, useEffect, useRef, useState } from 'react';
import crypto from 'crypto';
import { useSearchParams } from 'next/navigation';
import { toast } from 'sonner';
import { Document } from '@langchain/core/documents';
import { getSuggestions } from '../actions';
type ChatContext = {
messages: Message[];
chatHistory: [string, string][];
files: File[];
fileIds: string[];
focusMode: string;
chatId: string | undefined;
optimizationMode: string;
isMessagesLoaded: boolean;
loading: boolean;
notFound: boolean;
messageAppeared: boolean;
isReady: boolean;
hasError: boolean;
setOptimizationMode: (mode: string) => void;
setFocusMode: (mode: string) => void;
setFiles: (files: File[]) => void;
setFileIds: (fileIds: string[]) => void;
sendMessage: (
message: string,
messageId?: string,
rewrite?: boolean,
) => Promise<void>;
rewrite: (messageId: string) => void;
};
export interface File {
fileName: string;
fileExtension: string;
fileId: string;
}
interface ChatModelProvider {
name: string;
provider: string;
}
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,
) => {
try {
let chatModel = localStorage.getItem('chatModel');
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(`/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;
const chatModelProvidersKeys = Object.keys(chatModelProviders);
if (!chatModelProviders || chatModelProvidersKeys.length === 0) {
return toast.error('No chat models available');
} else {
chatModelProvider =
chatModelProvidersKeys.find(
(provider) =>
Object.keys(chatModelProviders[provider]).length > 0,
) || chatModelProvidersKeys[0];
}
if (
chatModelProvider === 'custom_openai' &&
Object.keys(chatModelProviders[chatModelProvider]).length === 0
) {
toast.error(
"Looks like you haven't configured any chat model providers. Please configure them from the settings page or the config file.",
);
return setHasError(true);
}
chatModel = Object.keys(chatModelProviders[chatModelProvider])[0];
}
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] ||
Object.keys(chatModelProviders[chatModelProvider]).length === 0)
) {
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]
) {
if (
chatModelProvider === 'custom_openai' &&
Object.keys(chatModelProviders[chatModelProvider]).length === 0
) {
toast.error(
"Looks like you haven't configured any chat model providers. Please configure them from the settings page or the config file.",
);
return setHasError(true);
}
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);
}
}
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 (
chatId: string,
setMessages: (messages: Message[]) => void,
setIsMessagesLoaded: (loaded: boolean) => void,
setChatHistory: (history: [string, string][]) => void,
setFocusMode: (mode: string) => void,
setNotFound: (notFound: boolean) => void,
setFiles: (files: File[]) => void,
setFileIds: (fileIds: string[]) => void,
) => {
const res = await fetch(`/api/chats/${chatId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (res.status === 404) {
setNotFound(true);
setIsMessagesLoaded(true);
return;
}
const data = await res.json();
const messages = data.messages.map((msg: any) => {
return {
...msg,
...JSON.parse(msg.metadata),
};
}) as Message[];
setMessages(messages);
const history = messages.map((msg) => {
return [msg.role, msg.content];
}) as [string, string][];
console.debug(new Date(), 'app:messages_loaded');
document.title = messages[0].content;
const files = data.chat.files.map((file: any) => {
return {
fileName: file.name,
fileExtension: file.name.split('.').pop(),
fileId: file.fileId,
};
});
setFiles(files);
setFileIds(files.map((file: File) => file.fileId));
setChatHistory(history);
setFocusMode(data.chat.focusMode);
setIsMessagesLoaded(true);
};
export const chatContext = createContext<ChatContext>({
chatHistory: [],
chatId: '',
fileIds: [],
files: [],
focusMode: '',
hasError: false,
isMessagesLoaded: false,
isReady: false,
loading: false,
messageAppeared: false,
messages: [],
notFound: false,
optimizationMode: '',
rewrite: () => {},
sendMessage: async () => {},
setFileIds: () => {},
setFiles: () => {},
setFocusMode: () => {},
setOptimizationMode: () => {},
});
export const ChatProvider = ({
children,
id,
}: {
children: React.ReactNode;
id?: string;
}) => {
const searchParams = useSearchParams();
const initialMessage = searchParams.get('q');
const [chatId, setChatId] = useState<string | undefined>(id);
const [newChatCreated, setNewChatCreated] = useState(false);
const [loading, setLoading] = useState(false);
const [messageAppeared, setMessageAppeared] = useState(false);
const [chatHistory, setChatHistory] = useState<[string, string][]>([]);
const [messages, setMessages] = useState<Message[]>([]);
const [files, setFiles] = useState<File[]>([]);
const [fileIds, setFileIds] = useState<string[]>([]);
const [focusMode, setFocusMode] = useState('webSearch');
const [optimizationMode, setOptimizationMode] = useState('speed');
const [isMessagesLoaded, setIsMessagesLoaded] = useState(false);
const [notFound, setNotFound] = 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 [isReady, setIsReady] = useState(false);
const messagesRef = useRef<Message[]>([]);
useEffect(() => {
checkConfig(
setChatModelProvider,
setEmbeddingModelProvider,
setIsConfigReady,
setHasError,
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (
chatId &&
!newChatCreated &&
!isMessagesLoaded &&
messages.length === 0
) {
loadMessages(
chatId,
setMessages,
setIsMessagesLoaded,
setChatHistory,
setFocusMode,
setNotFound,
setFiles,
setFileIds,
);
} else if (!chatId) {
setNewChatCreated(true);
setIsMessagesLoaded(true);
setChatId(crypto.randomBytes(20).toString('hex'));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
messagesRef.current = messages;
}, [messages]);
useEffect(() => {
if (isMessagesLoaded && isConfigReady) {
setIsReady(true);
console.debug(new Date(), 'app:ready');
} else {
setIsReady(false);
}
}, [isMessagesLoaded, isConfigReady]);
const rewrite = (messageId: string) => {
const index = messages.findIndex((msg) => msg.messageId === messageId);
if (index === -1) return;
const message = messages[index - 1];
setMessages((prev) => {
return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)];
});
setChatHistory((prev) => {
return [...prev.slice(0, messages.length > 2 ? index - 1 : 0)];
});
sendMessage(message.content, message.messageId, true);
};
useEffect(() => {
if (isReady && initialMessage && isConfigReady) {
if (!isConfigReady) {
toast.error('Cannot send message before the configuration is ready');
return;
}
sendMessage(initialMessage);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isConfigReady, isReady, initialMessage]);
const sendMessage: ChatContext['sendMessage'] = async (
message,
messageId,
rewrite = false,
) => {
if (loading) return;
setLoading(true);
setMessageAppeared(false);
let sources: Document[] | undefined = undefined;
let recievedMessage = '';
let added = false;
messageId = messageId ?? crypto.randomBytes(7).toString('hex');
setMessages((prevMessages) => [
...prevMessages,
{
content: message,
messageId: messageId,
chatId: chatId!,
role: 'user',
createdAt: new Date(),
},
]);
const messageHandler = async (data: any) => {
if (data.type === 'error') {
toast.error(data.data);
setLoading(false);
return;
}
if (data.type === 'sources') {
sources = data.data;
if (!added) {
setMessages((prevMessages) => [
...prevMessages,
{
content: '',
messageId: data.messageId,
chatId: chatId!,
role: 'assistant',
sources: sources,
createdAt: new Date(),
},
]);
added = true;
}
setMessageAppeared(true);
}
if (data.type === 'message') {
if (!added) {
setMessages((prevMessages) => [
...prevMessages,
{
content: data.data,
messageId: data.messageId,
chatId: chatId!,
role: 'assistant',
sources: sources,
createdAt: new Date(),
},
]);
added = true;
}
setMessages((prev) =>
prev.map((message) => {
if (message.messageId === data.messageId) {
return { ...message, content: message.content + data.data };
}
return message;
}),
);
recievedMessage += data.data;
setMessageAppeared(true);
}
if (data.type === 'messageEnd') {
setChatHistory((prevHistory) => [
...prevHistory,
['human', message],
['assistant', recievedMessage],
]);
setLoading(false);
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 (
lastMsg.role === 'assistant' &&
lastMsg.sources &&
lastMsg.sources.length > 0 &&
!lastMsg.suggestions
) {
const suggestions = await getSuggestions(messagesRef.current);
setMessages((prev) =>
prev.map((msg) => {
if (msg.messageId === lastMsg.messageId) {
return { ...msg, suggestions: suggestions };
}
return msg;
}),
);
}
}
};
const messageIndex = messages.findIndex((m) => m.messageId === messageId);
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: rewrite
? chatHistory.slice(0, messageIndex === -1 ? undefined : messageIndex)
: 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...');
}
}
};
return (
<chatContext.Provider
value={{
messages,
chatHistory,
files,
fileIds,
focusMode,
chatId,
hasError,
isMessagesLoaded,
isReady,
loading,
messageAppeared,
notFound,
optimizationMode,
setFileIds,
setFiles,
setFocusMode,
setOptimizationMode,
rewrite,
sendMessage,
}}
>
{children}
</chatContext.Provider>
);
};
export const useChat = () => {
const ctx = useContext(chatContext);
return ctx;
};

View File

@@ -1,94 +0,0 @@
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
import { getAimlApiKey } from '../config';
import { ChatModel, EmbeddingModel } from '.';
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Embeddings } from '@langchain/core/embeddings';
import axios from 'axios';
export const PROVIDER_INFO = {
key: 'aimlapi',
displayName: 'AI/ML API',
};
interface AimlApiModel {
id: string;
name?: string;
type?: string;
}
const API_URL = 'https://api.aimlapi.com';
export const loadAimlApiChatModels = async () => {
const apiKey = getAimlApiKey();
if (!apiKey) return {};
try {
const response = await axios.get(`${API_URL}/models`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
});
const chatModels: Record<string, ChatModel> = {};
response.data.data.forEach((model: AimlApiModel) => {
if (model.type === 'chat-completion') {
chatModels[model.id] = {
displayName: model.name || model.id,
model: new ChatOpenAI({
apiKey: apiKey,
modelName: model.id,
temperature: 0.7,
configuration: {
baseURL: API_URL,
},
}) as unknown as BaseChatModel,
};
}
});
return chatModels;
} catch (err) {
console.error(`Error loading AI/ML API models: ${err}`);
return {};
}
};
export const loadAimlApiEmbeddingModels = async () => {
const apiKey = getAimlApiKey();
if (!apiKey) return {};
try {
const response = await axios.get(`${API_URL}/models`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
});
const embeddingModels: Record<string, EmbeddingModel> = {};
response.data.data.forEach((model: AimlApiModel) => {
if (model.type === 'embedding') {
embeddingModels[model.id] = {
displayName: model.name || model.id,
model: new OpenAIEmbeddings({
apiKey: apiKey,
modelName: model.id,
configuration: {
baseURL: API_URL,
},
}) as unknown as Embeddings,
};
}
});
return embeddingModels;
} catch (err) {
console.error(`Error loading AI/ML API embeddings models: ${err}`);
return {};
}
};

View File

@@ -1,26 +1,9 @@
import { ChatAnthropic } from '@langchain/anthropic'; import { ChatAnthropic } from '@langchain/anthropic';
import { ChatModel } from '.'; import { ChatModel } from '.';
import { getAnthropicApiKey } from '../config'; import { getAnthropicApiKey } from '../config';
export const PROVIDER_INFO = {
key: 'anthropic',
displayName: 'Anthropic',
};
import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { BaseChatModel } from '@langchain/core/language_models/chat_models';
const anthropicChatModels: Record<string, string>[] = [ const anthropicChatModels: Record<string, string>[] = [
{
displayName: 'Claude 4.1 Opus',
key: 'claude-opus-4-1-20250805',
},
{
displayName: 'Claude 4 Opus',
key: 'claude-opus-4-20250514',
},
{
displayName: 'Claude 4 Sonnet',
key: 'claude-sonnet-4-20250514',
},
{ {
displayName: 'Claude 3.7 Sonnet', displayName: 'Claude 3.7 Sonnet',
key: 'claude-3-7-sonnet-20250219', key: 'claude-3-7-sonnet-20250219',

View File

@@ -3,11 +3,6 @@ import { getDeepseekApiKey } from '../config';
import { ChatModel } from '.'; import { ChatModel } from '.';
import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { BaseChatModel } from '@langchain/core/language_models/chat_models';
export const PROVIDER_INFO = {
key: 'deepseek',
displayName: 'Deepseek AI',
};
const deepseekChatModels: Record<string, string>[] = [ const deepseekChatModels: Record<string, string>[] = [
{ {
displayName: 'Deepseek Chat (Deepseek V3)', displayName: 'Deepseek Chat (Deepseek V3)',
@@ -31,7 +26,7 @@ export const loadDeepseekChatModels = async () => {
chatModels[model.key] = { chatModels[model.key] = {
displayName: model.displayName, displayName: model.displayName,
model: new ChatOpenAI({ model: new ChatOpenAI({
apiKey: deepseekApiKey, openAIApiKey: deepseekApiKey,
modelName: model.key, modelName: model.key,
temperature: 0.7, temperature: 0.7,
configuration: { configuration: {

View File

@@ -4,26 +4,13 @@ import {
} from '@langchain/google-genai'; } from '@langchain/google-genai';
import { getGeminiApiKey } from '../config'; import { getGeminiApiKey } from '../config';
import { ChatModel, EmbeddingModel } from '.'; import { ChatModel, EmbeddingModel } from '.';
export const PROVIDER_INFO = {
key: 'gemini',
displayName: 'Google Gemini',
};
import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Embeddings } from '@langchain/core/embeddings'; import { Embeddings } from '@langchain/core/embeddings';
const geminiChatModels: Record<string, string>[] = [ const geminiChatModels: Record<string, string>[] = [
{ {
displayName: 'Gemini 2.5 Flash', displayName: 'Gemini 2.5 Pro Experimental',
key: 'gemini-2.5-flash', key: 'gemini-2.5-pro-exp-03-25',
},
{
displayName: 'Gemini 2.5 Flash-Lite',
key: 'gemini-2.5-flash-lite',
},
{
displayName: 'Gemini 2.5 Pro',
key: 'gemini-2.5-pro',
}, },
{ {
displayName: 'Gemini 2.0 Flash', displayName: 'Gemini 2.0 Flash',
@@ -53,12 +40,8 @@ const geminiChatModels: Record<string, string>[] = [
const geminiEmbeddingModels: Record<string, string>[] = [ const geminiEmbeddingModels: Record<string, string>[] = [
{ {
displayName: 'Text Embedding 004', displayName: 'Gemini Embedding',
key: 'models/text-embedding-004', key: 'gemini-embedding-exp',
},
{
displayName: 'Embedding 001',
key: 'models/embedding-001',
}, },
]; ];
@@ -75,7 +58,7 @@ export const loadGeminiChatModels = async () => {
displayName: model.displayName, displayName: model.displayName,
model: new ChatGoogleGenerativeAI({ model: new ChatGoogleGenerativeAI({
apiKey: geminiApiKey, apiKey: geminiApiKey,
model: model.key, modelName: model.key,
temperature: 0.7, temperature: 0.7,
}) as unknown as BaseChatModel, }) as unknown as BaseChatModel,
}; };
@@ -108,7 +91,7 @@ export const loadGeminiEmbeddingModels = async () => {
return embeddingModels; return embeddingModels;
} catch (err) { } catch (err) {
console.error(`Error loading Gemini embeddings models: ${err}`); console.error(`Error loading OpenAI embeddings models: ${err}`);
return {}; return {};
} }
}; };

View File

@@ -1,37 +1,97 @@
import { ChatGroq } from '@langchain/groq'; import { ChatOpenAI } from '@langchain/openai';
import { getGroqApiKey } from '../config'; import { getGroqApiKey } from '../config';
import { ChatModel } from '.'; import { ChatModel } from '.';
export const PROVIDER_INFO = {
key: 'groq',
displayName: 'Groq',
};
import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { BaseChatModel } from '@langchain/core/language_models/chat_models';
const groqChatModels: Record<string, string>[] = [
{
displayName: 'Gemma2 9B IT',
key: 'gemma2-9b-it',
},
{
displayName: 'Llama 3.3 70B Versatile',
key: 'llama-3.3-70b-versatile',
},
{
displayName: 'Llama 3.1 8B Instant',
key: 'llama-3.1-8b-instant',
},
{
displayName: 'Llama3 70B 8192',
key: 'llama3-70b-8192',
},
{
displayName: 'Llama3 8B 8192',
key: 'llama3-8b-8192',
},
{
displayName: 'Mixtral 8x7B 32768',
key: 'mixtral-8x7b-32768',
},
{
displayName: 'Qwen QWQ 32B (Preview)',
key: 'qwen-qwq-32b',
},
{
displayName: 'Mistral Saba 24B (Preview)',
key: 'mistral-saba-24b',
},
{
displayName: 'Qwen 2.5 Coder 32B (Preview)',
key: 'qwen-2.5-coder-32b',
},
{
displayName: 'Qwen 2.5 32B (Preview)',
key: 'qwen-2.5-32b',
},
{
displayName: 'DeepSeek R1 Distill Qwen 32B (Preview)',
key: 'deepseek-r1-distill-qwen-32b',
},
{
displayName: 'DeepSeek R1 Distill Llama 70B (Preview)',
key: 'deepseek-r1-distill-llama-70b',
},
{
displayName: 'Llama 3.3 70B SpecDec (Preview)',
key: 'llama-3.3-70b-specdec',
},
{
displayName: 'Llama 3.2 1B Preview (Preview)',
key: 'llama-3.2-1b-preview',
},
{
displayName: 'Llama 3.2 3B Preview (Preview)',
key: 'llama-3.2-3b-preview',
},
{
displayName: 'Llama 3.2 11B Vision Preview (Preview)',
key: 'llama-3.2-11b-vision-preview',
},
{
displayName: 'Llama 3.2 90B Vision Preview (Preview)',
key: 'llama-3.2-90b-vision-preview',
},
];
export const loadGroqChatModels = async () => { export const loadGroqChatModels = async () => {
const groqApiKey = getGroqApiKey(); const groqApiKey = getGroqApiKey();
if (!groqApiKey) return {}; if (!groqApiKey) return {};
try { try {
const res = await fetch('https://api.groq.com/openai/v1/models', {
method: 'GET',
headers: {
Authorization: `bearer ${groqApiKey}`,
'Content-Type': 'application/json',
},
});
const groqChatModels = (await res.json()).data;
const chatModels: Record<string, ChatModel> = {}; const chatModels: Record<string, ChatModel> = {};
groqChatModels.forEach((model: any) => { groqChatModels.forEach((model) => {
chatModels[model.id] = { chatModels[model.key] = {
displayName: model.id, displayName: model.displayName,
model: new ChatGroq({ model: new ChatOpenAI({
apiKey: groqApiKey, openAIApiKey: groqApiKey,
model: model.id, modelName: model.key,
temperature: 0.7, temperature: 0.7,
configuration: {
baseURL: 'https://api.groq.com/openai/v1',
},
}) as unknown as BaseChatModel, }) as unknown as BaseChatModel,
}; };
}); });

View File

@@ -1,66 +1,18 @@
import { Embeddings } from '@langchain/core/embeddings'; import { Embeddings } from '@langchain/core/embeddings';
import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { import { loadOpenAIChatModels, loadOpenAIEmbeddingModels } from './openai';
loadOpenAIChatModels,
loadOpenAIEmbeddingModels,
PROVIDER_INFO as OpenAIInfo,
PROVIDER_INFO,
} from './openai';
import { import {
getCustomOpenaiApiKey, getCustomOpenaiApiKey,
getCustomOpenaiApiUrl, getCustomOpenaiApiUrl,
getCustomOpenaiModelName, getCustomOpenaiModelName,
} from '../config'; } from '../config';
import { ChatOpenAI } from '@langchain/openai'; import { ChatOpenAI } from '@langchain/openai';
import { import { loadOllamaChatModels, loadOllamaEmbeddingModels } from './ollama';
loadOllamaChatModels, import { loadGroqChatModels } from './groq';
loadOllamaEmbeddingModels, import { loadAnthropicChatModels } from './anthropic';
PROVIDER_INFO as OllamaInfo, import { loadGeminiChatModels, loadGeminiEmbeddingModels } from './gemini';
} from './ollama'; import { loadTransformersEmbeddingsModels } from './transformers';
import { loadGroqChatModels, PROVIDER_INFO as GroqInfo } from './groq'; import { loadDeepseekChatModels } from './deepseek';
import {
loadAnthropicChatModels,
PROVIDER_INFO as AnthropicInfo,
} from './anthropic';
import {
loadGeminiChatModels,
loadGeminiEmbeddingModels,
PROVIDER_INFO as GeminiInfo,
} from './gemini';
import {
loadTransformersEmbeddingsModels,
PROVIDER_INFO as TransformersInfo,
} from './transformers';
import {
loadDeepseekChatModels,
PROVIDER_INFO as DeepseekInfo,
} from './deepseek';
import {
loadAimlApiChatModels,
loadAimlApiEmbeddingModels,
PROVIDER_INFO as AimlApiInfo,
} from './aimlapi';
import {
loadLMStudioChatModels,
loadLMStudioEmbeddingsModels,
PROVIDER_INFO as LMStudioInfo,
} from './lmstudio';
export const PROVIDER_METADATA = {
openai: OpenAIInfo,
ollama: OllamaInfo,
groq: GroqInfo,
anthropic: AnthropicInfo,
gemini: GeminiInfo,
transformers: TransformersInfo,
deepseek: DeepseekInfo,
aimlapi: AimlApiInfo,
lmstudio: LMStudioInfo,
custom_openai: {
key: 'custom_openai',
displayName: 'Custom OpenAI',
},
};
export interface ChatModel { export interface ChatModel {
displayName: string; displayName: string;
@@ -82,8 +34,6 @@ export const chatModelProviders: Record<
anthropic: loadAnthropicChatModels, anthropic: loadAnthropicChatModels,
gemini: loadGeminiChatModels, gemini: loadGeminiChatModels,
deepseek: loadDeepseekChatModels, deepseek: loadDeepseekChatModels,
aimlapi: loadAimlApiChatModels,
lmstudio: loadLMStudioChatModels,
}; };
export const embeddingModelProviders: Record< export const embeddingModelProviders: Record<
@@ -94,8 +44,6 @@ export const embeddingModelProviders: Record<
ollama: loadOllamaEmbeddingModels, ollama: loadOllamaEmbeddingModels,
gemini: loadGeminiEmbeddingModels, gemini: loadGeminiEmbeddingModels,
transformers: loadTransformersEmbeddingsModels, transformers: loadTransformersEmbeddingsModels,
aimlapi: loadAimlApiEmbeddingModels,
lmstudio: loadLMStudioEmbeddingsModels,
}; };
export const getAvailableChatModelProviders = async () => { export const getAvailableChatModelProviders = async () => {
@@ -118,13 +66,9 @@ export const getAvailableChatModelProviders = async () => {
[customOpenAiModelName]: { [customOpenAiModelName]: {
displayName: customOpenAiModelName, displayName: customOpenAiModelName,
model: new ChatOpenAI({ model: new ChatOpenAI({
apiKey: customOpenAiApiKey, openAIApiKey: customOpenAiApiKey,
modelName: customOpenAiModelName, modelName: customOpenAiModelName,
...((() => { temperature: 0.7,
const temperatureRestrictedModels = ['gpt-5-nano','gpt-5','gpt-5-mini','o1', 'o3', 'o3-mini', 'o4-mini'];
const isTemperatureRestricted = temperatureRestrictedModels.some(restrictedModel => customOpenAiModelName.includes(restrictedModel));
return isTemperatureRestricted ? {} : { temperature: 0.7 };
})()),
configuration: { configuration: {
baseURL: customOpenAiApiUrl, baseURL: customOpenAiApiUrl,
}, },

View File

@@ -1,100 +0,0 @@
import { getKeepAlive, getLMStudioApiEndpoint } from '../config';
import axios from 'axios';
import { ChatModel, EmbeddingModel } from '.';
export const PROVIDER_INFO = {
key: 'lmstudio',
displayName: 'LM Studio',
};
import { ChatOpenAI } from '@langchain/openai';
import { OpenAIEmbeddings } from '@langchain/openai';
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Embeddings } from '@langchain/core/embeddings';
interface LMStudioModel {
id: string;
name?: string;
}
const ensureV1Endpoint = (endpoint: string): string =>
endpoint.endsWith('/v1') ? endpoint : `${endpoint}/v1`;
const checkServerAvailability = async (endpoint: string): Promise<boolean> => {
try {
await axios.get(`${ensureV1Endpoint(endpoint)}/models`, {
headers: { 'Content-Type': 'application/json' },
});
return true;
} catch {
return false;
}
};
export const loadLMStudioChatModels = async () => {
const endpoint = getLMStudioApiEndpoint();
if (!endpoint) return {};
if (!(await checkServerAvailability(endpoint))) return {};
try {
const response = await axios.get(`${ensureV1Endpoint(endpoint)}/models`, {
headers: { 'Content-Type': 'application/json' },
});
const chatModels: Record<string, ChatModel> = {};
response.data.data.forEach((model: LMStudioModel) => {
chatModels[model.id] = {
displayName: model.name || model.id,
model: new ChatOpenAI({
apiKey: 'lm-studio',
configuration: {
baseURL: ensureV1Endpoint(endpoint),
},
modelName: model.id,
temperature: 0.7,
streaming: true,
maxRetries: 3,
}) as unknown as BaseChatModel,
};
});
return chatModels;
} catch (err) {
console.error(`Error loading LM Studio models: ${err}`);
return {};
}
};
export const loadLMStudioEmbeddingsModels = async () => {
const endpoint = getLMStudioApiEndpoint();
if (!endpoint) return {};
if (!(await checkServerAvailability(endpoint))) return {};
try {
const response = await axios.get(`${ensureV1Endpoint(endpoint)}/models`, {
headers: { 'Content-Type': 'application/json' },
});
const embeddingsModels: Record<string, EmbeddingModel> = {};
response.data.data.forEach((model: LMStudioModel) => {
embeddingsModels[model.id] = {
displayName: model.name || model.id,
model: new OpenAIEmbeddings({
apiKey: 'lm-studio',
configuration: {
baseURL: ensureV1Endpoint(endpoint),
},
modelName: model.id,
}) as unknown as Embeddings,
};
});
return embeddingsModels;
} catch (err) {
console.error(`Error loading LM Studio embeddings model: ${err}`);
return {};
}
};

View File

@@ -1,17 +1,11 @@
import axios from 'axios'; import axios from 'axios';
import { getKeepAlive, getOllamaApiEndpoint, getOllamaApiKey } from '../config'; import { getKeepAlive, getOllamaApiEndpoint } from '../config';
import { ChatModel, EmbeddingModel } from '.'; import { ChatModel, EmbeddingModel } from '.';
import { ChatOllama } from '@langchain/community/chat_models/ollama';
export const PROVIDER_INFO = { import { OllamaEmbeddings } from '@langchain/community/embeddings/ollama';
key: 'ollama',
displayName: 'Ollama',
};
import { ChatOllama } from '@langchain/ollama';
import { OllamaEmbeddings } from '@langchain/ollama';
export const loadOllamaChatModels = async () => { export const loadOllamaChatModels = async () => {
const ollamaApiEndpoint = getOllamaApiEndpoint(); const ollamaApiEndpoint = getOllamaApiEndpoint();
const ollamaApiKey = getOllamaApiKey();
if (!ollamaApiEndpoint) return {}; if (!ollamaApiEndpoint) return {};
@@ -34,9 +28,6 @@ export const loadOllamaChatModels = async () => {
model: model.model, model: model.model,
temperature: 0.7, temperature: 0.7,
keepAlive: getKeepAlive(), keepAlive: getKeepAlive(),
...(ollamaApiKey
? { headers: { Authorization: `Bearer ${ollamaApiKey}` } }
: {}),
}), }),
}; };
}); });
@@ -50,7 +41,6 @@ export const loadOllamaChatModels = async () => {
export const loadOllamaEmbeddingModels = async () => { export const loadOllamaEmbeddingModels = async () => {
const ollamaApiEndpoint = getOllamaApiEndpoint(); const ollamaApiEndpoint = getOllamaApiEndpoint();
const ollamaApiKey = getOllamaApiKey();
if (!ollamaApiEndpoint) return {}; if (!ollamaApiEndpoint) return {};
@@ -71,9 +61,6 @@ export const loadOllamaEmbeddingModels = async () => {
model: new OllamaEmbeddings({ model: new OllamaEmbeddings({
baseUrl: ollamaApiEndpoint, baseUrl: ollamaApiEndpoint,
model: model.model, model: model.model,
...(ollamaApiKey
? { headers: { Authorization: `Bearer ${ollamaApiKey}` } }
: {}),
}), }),
}; };
}); });

View File

@@ -1,11 +1,6 @@
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai'; import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
import { getOpenaiApiKey } from '../config'; import { getOpenaiApiKey } from '../config';
import { ChatModel, EmbeddingModel } from '.'; import { ChatModel, EmbeddingModel } from '.';
export const PROVIDER_INFO = {
key: 'openai',
displayName: 'OpenAI',
};
import { BaseChatModel } from '@langchain/core/language_models/chat_models'; import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { Embeddings } from '@langchain/core/embeddings'; import { Embeddings } from '@langchain/core/embeddings';
@@ -26,54 +21,10 @@ const openaiChatModels: Record<string, string>[] = [
displayName: 'GPT-4 omni', displayName: 'GPT-4 omni',
key: 'gpt-4o', key: 'gpt-4o',
}, },
{
displayName: 'GPT-4o (2024-05-13)',
key: 'gpt-4o-2024-05-13',
},
{ {
displayName: 'GPT-4 omni mini', displayName: 'GPT-4 omni mini',
key: 'gpt-4o-mini', key: 'gpt-4o-mini',
}, },
{
displayName: 'GPT 4.1 nano',
key: 'gpt-4.1-nano',
},
{
displayName: 'GPT 4.1 mini',
key: 'gpt-4.1-mini',
},
{
displayName: 'GPT 4.1',
key: 'gpt-4.1',
},
{
displayName: 'GPT 5 nano',
key: 'gpt-5-nano',
},
{
displayName: 'GPT 5',
key: 'gpt-5',
},
{
displayName: 'GPT 5 Mini',
key: 'gpt-5-mini',
},
{
displayName: 'o1',
key: 'o1',
},
{
displayName: 'o3',
key: 'o3',
},
{
displayName: 'o3 Mini',
key: 'o3-mini',
},
{
displayName: 'o4 Mini',
key: 'o4-mini',
},
]; ];
const openaiEmbeddingModels: Record<string, string>[] = [ const openaiEmbeddingModels: Record<string, string>[] = [
@@ -96,23 +47,13 @@ export const loadOpenAIChatModels = async () => {
const chatModels: Record<string, ChatModel> = {}; const chatModels: Record<string, ChatModel> = {};
openaiChatModels.forEach((model) => { openaiChatModels.forEach((model) => {
// Models that only support temperature = 1
const temperatureRestrictedModels = ['gpt-5-nano','gpt-5','gpt-5-mini','o1', 'o3', 'o3-mini', 'o4-mini'];
const isTemperatureRestricted = temperatureRestrictedModels.some(restrictedModel => model.key.includes(restrictedModel));
const modelConfig: any = {
apiKey: openaiApiKey,
modelName: model.key,
};
// Only add temperature if the model supports it
if (!isTemperatureRestricted) {
modelConfig.temperature = 0.7;
}
chatModels[model.key] = { chatModels[model.key] = {
displayName: model.displayName, displayName: model.displayName,
model: new ChatOpenAI(modelConfig) as unknown as BaseChatModel, model: new ChatOpenAI({
openAIApiKey: openaiApiKey,
modelName: model.key,
temperature: 0.7,
}) as unknown as BaseChatModel,
}; };
}); });
@@ -135,7 +76,7 @@ export const loadOpenAIEmbeddingModels = async () => {
embeddingModels[model.key] = { embeddingModels[model.key] = {
displayName: model.displayName, displayName: model.displayName,
model: new OpenAIEmbeddings({ model: new OpenAIEmbeddings({
apiKey: openaiApiKey, openAIApiKey: openaiApiKey,
modelName: model.key, modelName: model.key,
}) as unknown as Embeddings, }) as unknown as Embeddings,
}; };

View File

@@ -1,10 +1,5 @@
import { HuggingFaceTransformersEmbeddings } from '../huggingfaceTransformer'; import { HuggingFaceTransformersEmbeddings } from '../huggingfaceTransformer';
export const PROVIDER_INFO = {
key: 'transformers',
displayName: 'Hugging Face',
};
export const loadTransformersEmbeddingsModels = async () => { export const loadTransformersEmbeddingsModels = async () => {
try { try {
const embeddingModels = { const embeddingModels = {

View File

@@ -64,7 +64,7 @@ export const getDocumentsFromLinks = async ({ links }: { links: string[] }) => {
const splittedText = await splitter.splitText(parsedText); const splittedText = await splitter.splitText(parsedText);
const title = res.data const title = res.data
.toString('utf8') .toString('utf8')
.match(/<title.*>(.*?)<\/title>/)?.[1]; .match(/<title>(.*?)<\/title>/)?.[1];
const linkDocs = splittedText.map((text) => { const linkDocs = splittedText.map((text) => {
return new Document({ return new Document({

View File

@@ -1,11 +1,8 @@
import { BaseMessage, isAIMessage } from '@langchain/core/messages'; import { BaseMessage } from '@langchain/core/messages';
const formatChatHistoryAsString = (history: BaseMessage[]) => { const formatChatHistoryAsString = (history: BaseMessage[]) => {
return history return history
.map( .map((message) => `${message._getType()}: ${message.content}`)
(message) =>
`${isAIMessage(message) ? 'AI' : 'User'}: ${message.content}`,
)
.join('\n'); .join('\n');
}; };

983
yarn.lock

File diff suppressed because it is too large Load Diff