forked from Archives/Athou_commafeed
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6de817f539 | ||
|
|
08a2746921 | ||
|
|
bc28727e39 | ||
|
|
eceaf3a98d | ||
|
|
4a8939e5e5 | ||
|
|
e90b80c641 | ||
|
|
2979600cc2 | ||
|
|
a2deef7f7f | ||
|
|
b5097d4fc3 | ||
|
|
f858eed150 | ||
|
|
bbdd712b01 | ||
|
|
c0875971e9 | ||
|
|
0199ebb6c3 | ||
|
|
c5763e2f8f | ||
|
|
5338ec0c34 | ||
|
|
8b5735f521 | ||
|
|
3d1a1cd033 | ||
|
|
b1b5eeb0e0 | ||
|
|
49e37587f9 | ||
|
|
01102ae973 | ||
|
|
e7931bf360 | ||
|
|
d095e4b35a |
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,5 +1,21 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [3.3.2]
|
||||||
|
|
||||||
|
- restore entry selection indicator (left orange border) that was lost with the mantine 6.x upgrade (3.3.0)
|
||||||
|
- add dividers to visually separate read-only information from forms on feed and category details pages
|
||||||
|
- reduced js bundle size by 10%
|
||||||
|
|
||||||
|
## [3.3.1]
|
||||||
|
|
||||||
|
- fix long feed names not being shortened to respect tree max width
|
||||||
|
|
||||||
|
## [3.3.0]
|
||||||
|
|
||||||
|
- there are now database changes, rolling back to 2.x will no longer be possible
|
||||||
|
- restore support for user custom CSS rules
|
||||||
|
- add support for user custom JS code that will be executed on page load
|
||||||
|
|
||||||
## [3.2.0]
|
## [3.2.0]
|
||||||
|
|
||||||
- restore the welcome page
|
- restore the welcome page
|
||||||
@@ -21,10 +37,10 @@
|
|||||||
## [3.0.1]
|
## [3.0.1]
|
||||||
|
|
||||||
- allow env variable substitution in config.yml
|
- allow env variable substitution in config.yml
|
||||||
- e.g. having a custom config.yml file with `app.session.path=${SOME_ENV_VAR}` will substitute `SOME_ENV_VAR` with
|
- e.g. having a custom config.yml file with `app.session.path=${SOME_ENV_VAR}` will substitute `SOME_ENV_VAR` with
|
||||||
its value
|
its value
|
||||||
- allow env variable prefixed with `CF_` to override config.yml properties
|
- allow env variable prefixed with `CF_` to override config.yml properties
|
||||||
- e.g. setting `CF_APP_ALLOWREGISTRATIONS=true` will set `app.allowRegistrations` to `true`
|
- e.g. setting `CF_APP_ALLOWREGISTRATIONS=true` will set `app.allowRegistrations` to `true`
|
||||||
|
|
||||||
## [3.0.0]
|
## [3.0.0]
|
||||||
|
|
||||||
@@ -131,4 +147,4 @@
|
|||||||
consumption and better overall performances.
|
consumption and better overall performances.
|
||||||
See the README on how to build CommaFeed from now on.
|
See the README on how to build CommaFeed from now on.
|
||||||
- CommaFeed should no longer fetch the same feed multiple times in a row
|
- CommaFeed should no longer fetch the same feed multiple times in a row
|
||||||
- Users can use their username or email to log in
|
- Users can use their username or email to log in
|
||||||
|
|||||||
@@ -48,10 +48,5 @@
|
|||||||
"sourceLocale": "en",
|
"sourceLocale": "en",
|
||||||
"fallbackLocales": {
|
"fallbackLocales": {
|
||||||
"default": "en"
|
"default": "en"
|
||||||
},
|
|
||||||
"extractBabelOptions": {
|
|
||||||
"presets": [
|
|
||||||
"@babel/preset-typescript"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||||
<link rel="manifest" href="manifest.json" />
|
<link rel="manifest" href="manifest.json" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<link rel="stylesheet" href="custom_css.css" />
|
||||||
<title>CommaFeed</title>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
</head>
|
<title>CommaFeed</title>
|
||||||
<body>
|
</head>
|
||||||
<div id="root"></div>
|
<body>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<div id="root"></div>
|
||||||
</body>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
<script src="custom_js.js"></script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
24168
commafeed-client/package-lock.json
generated
24168
commafeed-client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,83 +1,84 @@
|
|||||||
{
|
{
|
||||||
"name": "commafeed-client",
|
"name": "commafeed-client",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host",
|
"dev": "vite --host",
|
||||||
"dev:typescript": "tsc --watch",
|
"dev:typescript": "tsc --watch",
|
||||||
"build": "npm run i18n:compile && tsc && vite build",
|
"build": "npm run i18n:compile && tsc && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"test:ci": "vitest run",
|
"test:ci": "vitest run",
|
||||||
"eslint": "eslint --ext=.js,.jsx,.ts,.tsx src",
|
"eslint": "eslint --ext=.js,.jsx,.ts,.tsx src",
|
||||||
"i18n": "npm run i18n:extract && npm run i18n:compile",
|
"i18n": "npm run i18n:extract && npm run i18n:compile",
|
||||||
"i18n:extract": "lingui extract --clean",
|
"i18n:extract": "lingui extract --clean",
|
||||||
"i18n:compile": "lingui compile --typescript",
|
"i18n:compile": "lingui compile --typescript",
|
||||||
"postinstall": "npm run i18n:compile"
|
"postinstall": "npm run i18n:compile"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.10.5",
|
"@emotion/react": "^11.11.0",
|
||||||
"@fontsource/open-sans": "^4.5.14",
|
"@fontsource/open-sans": "^4.5.14",
|
||||||
"@lingui/core": "^3.17.0",
|
"@lingui/core": "^4.0.0",
|
||||||
"@lingui/macro": "^3.17.0",
|
"@lingui/macro": "^4.0.0",
|
||||||
"@lingui/react": "^3.17.0",
|
"@lingui/react": "^4.0.0",
|
||||||
"@mantine/core": "^5.10.3",
|
"@mantine/core": "^6.0.10",
|
||||||
"@mantine/form": "^5.10.3",
|
"@mantine/form": "^6.0.10",
|
||||||
"@mantine/hooks": "^5.10.3",
|
"@mantine/hooks": "^6.0.10",
|
||||||
"@mantine/modals": "^5.10.3",
|
"@mantine/modals": "^6.0.10",
|
||||||
"@mantine/notifications": "^5.10.3",
|
"@mantine/notifications": "^6.0.10",
|
||||||
"@mantine/spotlight": "^5.10.3",
|
"@mantine/spotlight": "^6.0.10",
|
||||||
"@mantine/styles": "^5.10.3",
|
"@mantine/styles": "^6.0.10",
|
||||||
"@reduxjs/toolkit": "^1.9.2",
|
"@reduxjs/toolkit": "^1.9.5",
|
||||||
"axios": "^1.3.2",
|
"axios": "^1.4.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"interweave": "^13.0.0",
|
"interweave": "^13.1.0",
|
||||||
"lodash": "^4.17.21",
|
"mousetrap": "^1.6.5",
|
||||||
"make-plural": "^7.2.0",
|
"react": "^18.2.0",
|
||||||
"mousetrap": "^1.6.5",
|
"react-async-hook": "^4.0.0",
|
||||||
"react": "^18.2.0",
|
"react-contexify": "^6.0.0",
|
||||||
"react-async-hook": "^4.0.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-contexify": "^6.0.0",
|
"react-ga4": "^2.1.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-icons": "^4.8.0",
|
||||||
"react-ga4": "^2.1.0",
|
"react-infinite-scroller": "^1.2.6",
|
||||||
"react-icons": "^4.7.1",
|
"react-redux": "^8.0.5",
|
||||||
"react-infinite-scroller": "^1.2.6",
|
"react-router-dom": "^6.11.1",
|
||||||
"react-redux": "^8.0.5",
|
"react-swipeable": "^7.0.0",
|
||||||
"react-router-dom": "^6.8.0",
|
"swagger-ui-react": "^4.18.3",
|
||||||
"react-swipeable": "^7.0.0",
|
"throttle-debounce": "^5.0.0",
|
||||||
"swagger-ui-react": "^4.15.5",
|
"tinycon": "^0.6.8",
|
||||||
"tinycon": "^0.6.8",
|
"use-local-storage": "^3.0.0",
|
||||||
"use-local-storage": "^3.0.0",
|
"websocket-heartbeat-js": "^1.1.2"
|
||||||
"websocket-heartbeat-js": "^1.1.1"
|
},
|
||||||
},
|
"devDependencies": {
|
||||||
"devDependencies": {
|
"@lingui/cli": "^4.0.0",
|
||||||
"@lingui/cli": "^3.17.0",
|
"@lingui/vite-plugin": "^4.0.0",
|
||||||
"@types/eslint": "^8.21.0",
|
"@types/eslint": "^8.37.0",
|
||||||
"@types/lodash": "^4.14.191",
|
"@types/mousetrap": "^1.6.11",
|
||||||
"@types/mousetrap": "^1.6.11",
|
"@types/react": "^18.2.6",
|
||||||
"@types/react": "^18.0.27",
|
"@types/react-dom": "^18.2.4",
|
||||||
"@types/react-dom": "^18.0.10",
|
"@types/react-infinite-scroller": "^1.2.3",
|
||||||
"@types/react-infinite-scroller": "^1.2.3",
|
"@types/swagger-ui-react": "^4.18.0",
|
||||||
"@types/swagger-ui-react": "^4.11.0",
|
"@types/throttle-debounce": "^5.0.0",
|
||||||
"@types/tinycon": "^0.6.3",
|
"@types/tinycon": "^0.6.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.50.0",
|
"@typescript-eslint/eslint-plugin": "^5.59.2",
|
||||||
"@typescript-eslint/parser": "^5.50.0",
|
"@typescript-eslint/parser": "^5.59.2",
|
||||||
"@vitejs/plugin-react": "^3.1.0",
|
"@vitejs/plugin-react": "^4.0.0",
|
||||||
"eslint": "^8.33.0",
|
"babel-plugin-macros": "^3.1.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint": "^8.40.0",
|
||||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-prettier": "^8.6.0",
|
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||||
"eslint-config-react-app": "^7.0.1",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-hooks": "^0.4.3",
|
"eslint-config-react-app": "^7.0.1",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-hooks": "^0.4.3",
|
||||||
"prettier": "^2.8.3",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"rollup-plugin-visualizer": "^5.9.0",
|
"prettier": "^2.8.8",
|
||||||
"typescript": "^4.9.5",
|
"rollup-plugin-visualizer": "^5.9.0",
|
||||||
"vite": "^4.1.1",
|
"typescript": "^5.0.4",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite": "^4.3.5",
|
||||||
"vite-tsconfig-paths": "^4.0.5",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vitest": "^0.28.4",
|
"vite-tsconfig-paths": "^4.2.0",
|
||||||
"vitest-mock-extended": "^1.0.9"
|
"vitest": "^0.31.0",
|
||||||
}
|
"vitest-mock-extended": "^1.1.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed</artifactId>
|
<artifactId>commafeed</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>commafeed-client</artifactId>
|
<artifactId>commafeed-client</artifactId>
|
||||||
<name>CommaFeed Client</name>
|
<name>CommaFeed Client</name>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { I18nProvider } from "@lingui/react"
|
|||||||
import { ColorScheme, ColorSchemeProvider, MantineProvider } from "@mantine/core"
|
import { ColorScheme, ColorSchemeProvider, MantineProvider } from "@mantine/core"
|
||||||
import { useColorScheme } from "@mantine/hooks"
|
import { useColorScheme } from "@mantine/hooks"
|
||||||
import { ModalsProvider } from "@mantine/modals"
|
import { ModalsProvider } from "@mantine/modals"
|
||||||
import { NotificationsProvider } from "@mantine/notifications"
|
import { Notifications } from "@mantine/notifications"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import { redirectTo } from "app/slices/redirect"
|
import { redirectTo } from "app/slices/redirect"
|
||||||
import { reloadServerInfos } from "app/slices/server"
|
import { reloadServerInfos } from "app/slices/server"
|
||||||
@@ -26,12 +26,12 @@ import { TagDetailsPage } from "pages/app/TagDetailsPage"
|
|||||||
import { LoginPage } from "pages/auth/LoginPage"
|
import { LoginPage } from "pages/auth/LoginPage"
|
||||||
import { PasswordRecoveryPage } from "pages/auth/PasswordRecoveryPage"
|
import { PasswordRecoveryPage } from "pages/auth/PasswordRecoveryPage"
|
||||||
import { RegistrationPage } from "pages/auth/RegistrationPage"
|
import { RegistrationPage } from "pages/auth/RegistrationPage"
|
||||||
|
import { WelcomePage } from "pages/WelcomePage"
|
||||||
import React, { useEffect } from "react"
|
import React, { useEffect } from "react"
|
||||||
import ReactGA from "react-ga4"
|
import ReactGA from "react-ga4"
|
||||||
import { HashRouter, Navigate, Route, Routes, useLocation, useNavigate } from "react-router-dom"
|
import { HashRouter, Navigate, Route, Routes, useLocation, useNavigate } from "react-router-dom"
|
||||||
import Tinycon from "tinycon"
|
import Tinycon from "tinycon"
|
||||||
import useLocalStorage from "use-local-storage"
|
import useLocalStorage from "use-local-storage"
|
||||||
import { WelcomePage } from "./pages/WelcomePage"
|
|
||||||
|
|
||||||
function Providers(props: { children: React.ReactNode }) {
|
function Providers(props: { children: React.ReactNode }) {
|
||||||
const preferredColorScheme = useColorScheme()
|
const preferredColorScheme = useColorScheme()
|
||||||
@@ -51,9 +51,8 @@ function Providers(props: { children: React.ReactNode }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ModalsProvider>
|
<ModalsProvider>
|
||||||
<NotificationsProvider position="bottom-right" zIndex={9999}>
|
<Notifications position="bottom-right" zIndex={9999} />
|
||||||
<ErrorBoundary>{props.children}</ErrorBoundary>
|
<ErrorBoundary>{props.children}</ErrorBoundary>
|
||||||
</NotificationsProvider>
|
|
||||||
</ModalsProvider>
|
</ModalsProvider>
|
||||||
</MantineProvider>
|
</MantineProvider>
|
||||||
</ColorSchemeProvider>
|
</ColorSchemeProvider>
|
||||||
@@ -123,7 +122,7 @@ function GoogleAnalyticsHandler() {
|
|||||||
}, [googleAnalyticsCode])
|
}, [googleAnalyticsCode])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ReactGA.send({ hitType: "pageview", page: location.pathname })
|
if (ReactGA.isInitialized) ReactGA.send({ hitType: "pageview", page: location.pathname })
|
||||||
}, [location])
|
}, [location])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
/* eslint-disable import/first */
|
/* eslint-disable import/first */
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
|
||||||
import { DeepMockProxy, mockDeep, mockReset } from "vitest-mock-extended"
|
|
||||||
|
|
||||||
vi.doMock("app/client", () => ({ client: mockDeep() }))
|
|
||||||
|
|
||||||
import { configureStore } from "@reduxjs/toolkit"
|
import { configureStore } from "@reduxjs/toolkit"
|
||||||
import { client } from "app/client"
|
import { client } from "app/client"
|
||||||
import { reducers } from "app/store"
|
import { reducers } from "app/store"
|
||||||
import { Entries, Entry } from "app/types"
|
import { Entries, Entry } from "app/types"
|
||||||
import { AxiosResponse } from "axios"
|
import { AxiosResponse } from "axios"
|
||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||||
|
import { mockReset } from "vitest-mock-extended"
|
||||||
import { loadEntries, loadMoreEntries, markAllEntries, markEntry } from "./entries"
|
import { loadEntries, loadMoreEntries, markAllEntries, markEntry } from "./entries"
|
||||||
|
|
||||||
describe("entries", () => {
|
const mockClient = await vi.hoisted(async () => {
|
||||||
const mockClient = client as DeepMockProxy<typeof client>
|
const mockModule = await import("vitest-mock-extended")
|
||||||
|
return mockModule.mockDeep<typeof client>()
|
||||||
|
})
|
||||||
|
vi.mock("app/client", () => ({ client: mockClient }))
|
||||||
|
|
||||||
|
describe("entries", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockReset(mockClient)
|
mockReset(mockClient)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -230,8 +230,8 @@ export interface Settings {
|
|||||||
readingOrder: ReadingOrder
|
readingOrder: ReadingOrder
|
||||||
showRead: boolean
|
showRead: boolean
|
||||||
scrollMarks: boolean
|
scrollMarks: boolean
|
||||||
theme?: string
|
|
||||||
customCss?: string
|
customCss?: string
|
||||||
|
customJs?: string
|
||||||
scrollSpeed: number
|
scrollSpeed: number
|
||||||
sharingSettings: SharingSettings
|
sharingSettings: SharingSettings
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,3 +64,5 @@ export const openLinkInBackgroundTab = (url: string) => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const truncate = (str: string, n: number) => (str.length > n ? `${str.slice(0, n - 1)}\u2026` : str)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 43 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 44 KiB |
@@ -1,14 +1,15 @@
|
|||||||
import { ActionIcon, Button, ButtonVariant, useMantineTheme } from "@mantine/core"
|
import { ActionIcon, Button, useMantineTheme } from "@mantine/core"
|
||||||
import { ActionIconVariant } from "@mantine/core/lib/ActionIcon/ActionIcon.styles"
|
import { ActionIconProps } from "@mantine/core/lib/ActionIcon/ActionIcon"
|
||||||
|
import { ButtonProps } from "@mantine/core/lib/Button/Button"
|
||||||
import { useMediaQuery } from "@mantine/hooks"
|
import { useMediaQuery } from "@mantine/hooks"
|
||||||
import { forwardRef, MouseEventHandler, ReactNode } from "react"
|
import { forwardRef, MouseEventHandler, ReactNode } from "react"
|
||||||
|
|
||||||
interface ActionButtonProps {
|
interface ActionButtonProps {
|
||||||
className?: string
|
className?: string
|
||||||
icon?: ReactNode
|
icon?: ReactNode
|
||||||
label?: string
|
label?: ReactNode
|
||||||
onClick?: MouseEventHandler
|
onClick?: MouseEventHandler
|
||||||
variant?: ActionIconVariant & ButtonVariant
|
variant?: ActionIconProps["variant"] & ButtonProps["variant"]
|
||||||
showLabelOnMobile?: boolean
|
showLabelOnMobile?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ interface ActionButtonProps {
|
|||||||
export const ActionButton = forwardRef<HTMLButtonElement, ActionButtonProps>((props: ActionButtonProps, ref) => {
|
export const ActionButton = forwardRef<HTMLButtonElement, ActionButtonProps>((props: ActionButtonProps, ref) => {
|
||||||
const theme = useMantineTheme()
|
const theme = useMantineTheme()
|
||||||
const variant = props.variant ?? "subtle"
|
const variant = props.variant ?? "subtle"
|
||||||
const mobile = !useMediaQuery(`(min-width: ${theme.breakpoints.lg}px)`)
|
const mobile = !useMediaQuery(`(min-width: ${theme.breakpoints.lg})`)
|
||||||
const iconOnly = !props.showLabelOnMobile && (mobile || !props.label)
|
const iconOnly = !props.showLabelOnMobile && (mobile || !props.label)
|
||||||
return iconOnly ? (
|
return iconOnly ? (
|
||||||
<ActionIcon ref={ref} color={theme.primaryColor} variant={variant} className={props.className} onClick={props.onClick}>
|
<ActionIcon ref={ref} color={theme.primaryColor} variant={variant} className={props.className} onClick={props.onClick}>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { t } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Alert as MantineAlert, Box } from "@mantine/core"
|
import { Box, Alert as MantineAlert } from "@mantine/core"
|
||||||
import { Fragment } from "react"
|
import { Fragment } from "react"
|
||||||
import { TbAlertCircle, TbAlertTriangle, TbCircleCheck } from "react-icons/tb"
|
import { TbAlertCircle, TbAlertTriangle, TbCircleCheck } from "react-icons/tb"
|
||||||
|
|
||||||
@@ -10,24 +10,24 @@ export interface ErrorsAlertProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Alert(props: ErrorsAlertProps) {
|
export function Alert(props: ErrorsAlertProps) {
|
||||||
let title: string
|
let title: React.ReactNode
|
||||||
let color: string
|
let color: string
|
||||||
let icon: React.ReactNode
|
let icon: React.ReactNode
|
||||||
|
|
||||||
const level = props.level ?? "error"
|
const level = props.level ?? "error"
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case "error":
|
case "error":
|
||||||
title = t`Error`
|
title = <Trans>Error</Trans>
|
||||||
color = "red"
|
color = "red"
|
||||||
icon = <TbAlertCircle />
|
icon = <TbAlertCircle />
|
||||||
break
|
break
|
||||||
case "warning":
|
case "warning":
|
||||||
title = t`Warning`
|
title = <Trans>Warning</Trans>
|
||||||
color = "orange"
|
color = "orange"
|
||||||
icon = <TbAlertTriangle />
|
icon = <TbAlertTriangle />
|
||||||
break
|
break
|
||||||
case "success":
|
case "success":
|
||||||
title = t`Success`
|
title = <Trans>Success</Trans>
|
||||||
color = "green"
|
color = "green"
|
||||||
icon = <TbCircleCheck />
|
icon = <TbCircleCheck />
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Box, Button, Checkbox, Group, PasswordInput, Stack, TextInput } from "@mantine/core"
|
import { Box, Button, Checkbox, Group, PasswordInput, Stack, TextInput } from "@mantine/core"
|
||||||
import { useForm } from "@mantine/form"
|
import { useForm } from "@mantine/form"
|
||||||
import { client, errorToStrings } from "app/client"
|
import { client, errorToStrings } from "app/client"
|
||||||
@@ -29,11 +29,11 @@ export function UserEdit(props: UserEditProps) {
|
|||||||
|
|
||||||
<form onSubmit={form.onSubmit(saveUser.execute)}>
|
<form onSubmit={form.onSubmit(saveUser.execute)}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<TextInput label={t`Name`} {...form.getInputProps("name")} required />
|
<TextInput label={<Trans>Name</Trans>} {...form.getInputProps("name")} required />
|
||||||
<PasswordInput label={t`Password`} {...form.getInputProps("password")} required={!props.user} />
|
<PasswordInput label={<Trans>Password</Trans>} {...form.getInputProps("password")} required={!props.user} />
|
||||||
<TextInput type="email" label={t`E-mail`} {...form.getInputProps("email")} />
|
<TextInput type="email" label={<Trans>E-mail</Trans>} {...form.getInputProps("email")} />
|
||||||
<Checkbox label={t`Admin`} {...form.getInputProps("admin", { type: "checkbox" })} />
|
<Checkbox label={<Trans>Admin</Trans>} {...form.getInputProps("admin", { type: "checkbox" })} />
|
||||||
<Checkbox label={t`Enabled`} {...form.getInputProps("enabled", { type: "checkbox" })} />
|
<Checkbox label={<Trans>Enabled</Trans>} {...form.getInputProps("enabled", { type: "checkbox" })} />
|
||||||
|
|
||||||
<Group>
|
<Group>
|
||||||
<Button variant="default" onClick={props.onCancel}>
|
<Button variant="default" onClick={props.onCancel}>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { openModal } from "@mantine/modals"
|
import { openModal } from "@mantine/modals"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import {
|
import {
|
||||||
@@ -17,11 +17,11 @@ import { openLinkInBackgroundTab } from "app/utils"
|
|||||||
import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp"
|
import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp"
|
||||||
import { Loader } from "components/Loader"
|
import { Loader } from "components/Loader"
|
||||||
import { useMousetrap } from "hooks/useMousetrap"
|
import { useMousetrap } from "hooks/useMousetrap"
|
||||||
import throttle from "lodash/throttle"
|
import { useViewMode } from "hooks/useViewMode"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import InfiniteScroll from "react-infinite-scroller"
|
import InfiniteScroll from "react-infinite-scroller"
|
||||||
|
import { throttle } from "throttle-debounce"
|
||||||
import { FeedEntry } from "./FeedEntry"
|
import { FeedEntry } from "./FeedEntry"
|
||||||
import { useViewMode } from "../../hooks/useViewMode"
|
|
||||||
|
|
||||||
export function FeedEntries() {
|
export function FeedEntries() {
|
||||||
const source = useAppSelector(state => state.entries.source)
|
const source = useAppSelector(state => state.entries.source)
|
||||||
@@ -82,7 +82,7 @@ export function FeedEntries() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const throttledListener = throttle(listener, 100)
|
const throttledListener = throttle(100, listener)
|
||||||
scrollArea?.addEventListener("scroll", throttledListener)
|
scrollArea?.addEventListener("scroll", throttledListener)
|
||||||
return () => scrollArea?.removeEventListener("scroll", throttledListener)
|
return () => scrollArea?.removeEventListener("scroll", throttledListener)
|
||||||
}, [dispatch, entries, viewMode, scrollMarks, scrollingToEntry])
|
}, [dispatch, entries, viewMode, scrollMarks, scrollingToEntry])
|
||||||
@@ -234,11 +234,18 @@ export function FeedEntries() {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
useMousetrap("g a", () => dispatch(redirectToRootCategory()))
|
useMousetrap("g a", () => dispatch(redirectToRootCategory()))
|
||||||
useMousetrap("?", () => openModal({ title: t`Keyboard shortcuts`, size: "xl", children: <KeyboardShortcutsHelp /> }))
|
useMousetrap("?", () =>
|
||||||
|
openModal({
|
||||||
|
title: <Trans>Keyboard shortcuts</Trans>,
|
||||||
|
size: "xl",
|
||||||
|
children: <KeyboardShortcutsHelp />,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
if (!entries) return <Loader />
|
if (!entries) return <Loader />
|
||||||
return (
|
return (
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
|
id="entries"
|
||||||
initialLoad={false}
|
initialLoad={false}
|
||||||
loadMore={() => dispatch(loadMoreEntries())}
|
loadMore={() => dispatch(loadMoreEntries())}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Anchor, Box, createStyles, Divider, Paper } from "@mantine/core"
|
import { Box, createStyles, Divider, Paper } from "@mantine/core"
|
||||||
import { MantineNumberSize } from "@mantine/styles"
|
import { MantineNumberSize } from "@mantine/styles"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import { markEntry } from "app/slices/entries"
|
import { markEntry } from "app/slices/entries"
|
||||||
import { useAppDispatch } from "app/store"
|
import { useAppDispatch } from "app/store"
|
||||||
import { Entry, ViewMode } from "app/types"
|
import { Entry, ViewMode } from "app/types"
|
||||||
|
import { useViewMode } from "hooks/useViewMode"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { useSwipeable } from "react-swipeable"
|
import { useSwipeable } from "react-swipeable"
|
||||||
import { useViewMode } from "../../hooks/useViewMode"
|
|
||||||
import { FeedEntryBody } from "./FeedEntryBody"
|
import { FeedEntryBody } from "./FeedEntryBody"
|
||||||
import { FeedEntryCompactHeader } from "./FeedEntryCompactHeader"
|
import { FeedEntryCompactHeader } from "./FeedEntryCompactHeader"
|
||||||
import { FeedEntryContextMenu, useFeedEntryContextMenu } from "./FeedEntryContextMenu"
|
import { FeedEntryContextMenu, useFeedEntryContextMenu } from "./FeedEntryContextMenu"
|
||||||
@@ -25,7 +25,7 @@ const useStyles = createStyles((theme, props: FeedEntryProps & { viewMode?: View
|
|||||||
if (theme.colorScheme === "dark") backgroundColor = props.entry.read ? "inherit" : theme.colors.dark[5]
|
if (theme.colorScheme === "dark") backgroundColor = props.entry.read ? "inherit" : theme.colors.dark[5]
|
||||||
else backgroundColor = props.entry.read && !props.expanded ? theme.colors.gray[0] : "inherit"
|
else backgroundColor = props.entry.read && !props.expanded ? theme.colors.gray[0] : "inherit"
|
||||||
|
|
||||||
let marginY = theme.spacing.xs
|
let marginY = 10
|
||||||
if (props.viewMode === "title") marginY = 2
|
if (props.viewMode === "title") marginY = 2
|
||||||
else if (props.viewMode === "cozy") marginY = 6
|
else if (props.viewMode === "cozy") marginY = 6
|
||||||
|
|
||||||
@@ -53,13 +53,18 @@ const useStyles = createStyles((theme, props: FeedEntryProps & { viewMode?: View
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
headerLink: {
|
||||||
|
color: "inherit",
|
||||||
|
textDecoration: "none",
|
||||||
|
},
|
||||||
body: {
|
body: {
|
||||||
maxWidth: Constants.layout.entryMaxWidth,
|
maxWidth: Constants.layout.entryMaxWidth,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.showSelectionIndicator) {
|
if (props.showSelectionIndicator) {
|
||||||
styles.paper.borderLeftColor = theme.colorScheme === "dark" ? theme.colors.orange[4] : theme.colors.orange[6]
|
const borderLeftColor = theme.colorScheme === "dark" ? theme.colors.orange[4] : theme.colors.orange[6]
|
||||||
|
styles.paper.borderLeftColor = `${borderLeftColor} !important`
|
||||||
}
|
}
|
||||||
|
|
||||||
return styles
|
return styles
|
||||||
@@ -91,8 +96,8 @@ export function FeedEntry(props: FeedEntryProps) {
|
|||||||
const compactHeader = !props.expanded && (viewMode === "title" || viewMode === "cozy")
|
const compactHeader = !props.expanded && (viewMode === "title" || viewMode === "cozy")
|
||||||
return (
|
return (
|
||||||
<Paper withBorder radius={borderRadius} className={classes.paper}>
|
<Paper withBorder radius={borderRadius} className={classes.paper}>
|
||||||
<Anchor
|
<a
|
||||||
variant="text"
|
className={classes.headerLink}
|
||||||
href={props.entry.url}
|
href={props.entry.url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
@@ -104,7 +109,7 @@ export function FeedEntry(props: FeedEntryProps) {
|
|||||||
{compactHeader && <FeedEntryCompactHeader entry={props.entry} />}
|
{compactHeader && <FeedEntryCompactHeader entry={props.entry} />}
|
||||||
{!compactHeader && <FeedEntryHeader entry={props.entry} expanded={props.expanded} />}
|
{!compactHeader && <FeedEntryHeader entry={props.entry} expanded={props.expanded} />}
|
||||||
</Box>
|
</Box>
|
||||||
</Anchor>
|
</a>
|
||||||
{props.expanded && (
|
{props.expanded && (
|
||||||
<Box px={paddingX} pb={paddingY}>
|
<Box px={paddingX} pb={paddingY}>
|
||||||
<Box className={classes.body} sx={{ direction: props.entry.rtl ? "rtl" : "ltr" }}>
|
<Box className={classes.body} sx={{ direction: props.entry.rtl ? "rtl" : "ltr" }}>
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { createStyles, Group } from "@mantine/core"
|
import { createStyles, Group } from "@mantine/core"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries"
|
import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries"
|
||||||
import { redirectToFeed } from "app/slices/redirect"
|
import { redirectToFeed } from "app/slices/redirect"
|
||||||
import { useAppDispatch, useAppSelector } from "app/store"
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
import { Entry } from "app/types"
|
import { Entry } from "app/types"
|
||||||
import { openLinkInBackgroundTab } from "app/utils"
|
import { openLinkInBackgroundTab, truncate } from "app/utils"
|
||||||
import { throttle, truncate } from "lodash"
|
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import { Item, Menu, Separator, useContextMenu } from "react-contexify"
|
import { Item, Menu, Separator, useContextMenu } from "react-contexify"
|
||||||
import { TbArrowBarToDown, TbExternalLink, TbEyeCheck, TbEyeOff, TbRss, TbStar, TbStarOff } from "react-icons/tb"
|
import { TbArrowBarToDown, TbExternalLink, TbEyeCheck, TbEyeOff, TbRss, TbStar, TbStarOff } from "react-icons/tb"
|
||||||
|
import { throttle } from "throttle-debounce"
|
||||||
|
|
||||||
interface FeedEntryContextMenuProps {
|
interface FeedEntryContextMenuProps {
|
||||||
entry: Entry
|
entry: Entry
|
||||||
@@ -29,6 +29,7 @@ const useStyles = createStyles(theme => ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const menuId = (entry: Entry) => entry.id
|
const menuId = (entry: Entry) => entry.id
|
||||||
|
|
||||||
export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
|
export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
|
||||||
const { classes, theme } = useStyles()
|
const { classes, theme } = useStyles()
|
||||||
const sourceType = useAppSelector(state => state.entries.source.type)
|
const sourceType = useAppSelector(state => state.entries.source.type)
|
||||||
@@ -64,13 +65,13 @@ export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
|
|||||||
<Item onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}>
|
<Item onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}>
|
||||||
<Group>
|
<Group>
|
||||||
{props.entry.starred ? <TbStarOff size={iconSize} /> : <TbStar size={iconSize} />}
|
{props.entry.starred ? <TbStarOff size={iconSize} /> : <TbStar size={iconSize} />}
|
||||||
{props.entry.starred ? t`Unstar` : t`Star`}
|
{props.entry.starred ? <Trans>Unstar</Trans> : <Trans>Star</Trans>}
|
||||||
</Group>
|
</Group>
|
||||||
</Item>
|
</Item>
|
||||||
<Item onClick={() => dispatch(markEntry({ entry: props.entry, read: !props.entry.read }))}>
|
<Item onClick={() => dispatch(markEntry({ entry: props.entry, read: !props.entry.read }))}>
|
||||||
<Group>
|
<Group>
|
||||||
{props.entry.read ? <TbEyeOff size={iconSize} /> : <TbEyeCheck size={iconSize} />}
|
{props.entry.read ? <TbEyeOff size={iconSize} /> : <TbEyeCheck size={iconSize} />}
|
||||||
{props.entry.read ? t`Keep unread` : t`Mark as read`}
|
{props.entry.read ? <Trans>Keep unread</Trans> : <Trans>Mark as read</Trans>}
|
||||||
</Group>
|
</Group>
|
||||||
</Item>
|
</Item>
|
||||||
<Item onClick={() => dispatch(markEntriesUpToEntry(props.entry))}>
|
<Item onClick={() => dispatch(markEntriesUpToEntry(props.entry))}>
|
||||||
@@ -91,7 +92,7 @@ export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
|
|||||||
>
|
>
|
||||||
<Group>
|
<Group>
|
||||||
<TbRss size={iconSize} />
|
<TbRss size={iconSize} />
|
||||||
<Trans>Go to {truncate(props.entry.feedName)}</Trans>
|
<Trans>Go to {truncate(props.entry.feedName, 30)}</Trans>
|
||||||
</Group>
|
</Group>
|
||||||
</Item>
|
</Item>
|
||||||
</>
|
</>
|
||||||
@@ -117,7 +118,7 @@ export function useFeedEntryContextMenu(entry: Entry) {
|
|||||||
const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId)
|
const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId)
|
||||||
|
|
||||||
const listener = () => contextMenu.hideAll()
|
const listener = () => contextMenu.hideAll()
|
||||||
const throttledListener = throttle(listener, 100)
|
const throttledListener = throttle(100, listener)
|
||||||
|
|
||||||
scrollArea?.addEventListener("scroll", throttledListener)
|
scrollArea?.addEventListener("scroll", throttledListener)
|
||||||
return () => scrollArea?.removeEventListener("scroll", throttledListener)
|
return () => scrollArea?.removeEventListener("scroll", throttledListener)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t } from "@lingui/macro"
|
import { t, Trans } from "@lingui/macro"
|
||||||
import { Group, Indicator, MultiSelect, Popover } from "@mantine/core"
|
import { Group, Indicator, MultiSelect, Popover } from "@mantine/core"
|
||||||
import { useMediaQuery } from "@mantine/hooks"
|
import { useMediaQuery } from "@mantine/hooks"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
@@ -7,9 +7,9 @@ import { useAppDispatch, useAppSelector } from "app/store"
|
|||||||
import { Entry } from "app/types"
|
import { Entry } from "app/types"
|
||||||
import { ActionButton } from "components/ActionButtton"
|
import { ActionButton } from "components/ActionButtton"
|
||||||
import { ButtonToolbar } from "components/ButtonToolbar"
|
import { ButtonToolbar } from "components/ButtonToolbar"
|
||||||
import { throttle } from "lodash"
|
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { TbArrowBarToDown, TbExternalLink, TbEyeCheck, TbEyeOff, TbShare, TbStar, TbStarOff, TbTag } from "react-icons/tb"
|
import { TbArrowBarToDown, TbExternalLink, TbEyeCheck, TbEyeOff, TbShare, TbStar, TbStarOff, TbTag } from "react-icons/tb"
|
||||||
|
import { throttle } from "throttle-debounce"
|
||||||
import { ShareButtons } from "./ShareButtons"
|
import { ShareButtons } from "./ShareButtons"
|
||||||
|
|
||||||
interface FeedEntryFooterProps {
|
interface FeedEntryFooterProps {
|
||||||
@@ -20,7 +20,7 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
|
|||||||
const [scrollPosition, setScrollPosition] = useState(0)
|
const [scrollPosition, setScrollPosition] = useState(0)
|
||||||
const sharingSettings = useAppSelector(state => state.user.settings?.sharingSettings)
|
const sharingSettings = useAppSelector(state => state.user.settings?.sharingSettings)
|
||||||
const tags = useAppSelector(state => state.user.tags)
|
const tags = useAppSelector(state => state.user.tags)
|
||||||
const mobile = !useMediaQuery(`(min-width: ${Constants.layout.mobileBreakpoint}px)`)
|
const mobile = !useMediaQuery(`(min-width: ${Constants.layout.mobileBreakpoint})`)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
const showSharingButtons = sharingSettings && Object.values(sharingSettings).some(v => v)
|
const showSharingButtons = sharingSettings && Object.values(sharingSettings).some(v => v)
|
||||||
@@ -38,7 +38,7 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
|
|||||||
const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId)
|
const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId)
|
||||||
|
|
||||||
const listener = () => setScrollPosition(scrollArea ? scrollArea.scrollTop : 0)
|
const listener = () => setScrollPosition(scrollArea ? scrollArea.scrollTop : 0)
|
||||||
const throttledListener = throttle(listener, 100)
|
const throttledListener = throttle(100, listener)
|
||||||
|
|
||||||
scrollArea?.addEventListener("scroll", throttledListener)
|
scrollArea?.addEventListener("scroll", throttledListener)
|
||||||
return () => scrollArea?.removeEventListener("scroll", throttledListener)
|
return () => scrollArea?.removeEventListener("scroll", throttledListener)
|
||||||
@@ -50,20 +50,20 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
|
|||||||
{props.entry.markable && (
|
{props.entry.markable && (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={props.entry.read ? <TbEyeOff size={18} /> : <TbEyeCheck size={18} />}
|
icon={props.entry.read ? <TbEyeOff size={18} /> : <TbEyeCheck size={18} />}
|
||||||
label={props.entry.read ? t`Keep unread` : t`Mark as read`}
|
label={props.entry.read ? <Trans>Keep unread</Trans> : <Trans>Mark as read</Trans>}
|
||||||
onClick={readStatusButtonClicked}
|
onClick={readStatusButtonClicked}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={props.entry.starred ? <TbStarOff size={18} /> : <TbStar size={18} />}
|
icon={props.entry.starred ? <TbStarOff size={18} /> : <TbStar size={18} />}
|
||||||
label={props.entry.starred ? t`Unstar` : t`Star`}
|
label={props.entry.starred ? <Trans>Unstar</Trans> : <Trans>Star</Trans>}
|
||||||
onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}
|
onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{showSharingButtons && (
|
{showSharingButtons && (
|
||||||
<Popover withArrow withinPortal shadow="md" positionDependencies={[scrollPosition]} closeOnClickOutside={!mobile}>
|
<Popover withArrow withinPortal shadow="md" positionDependencies={[scrollPosition]} closeOnClickOutside={!mobile}>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<ActionButton icon={<TbShare size={18} />} label={t`Share`} />
|
<ActionButton icon={<TbShare size={18} />} label={<Trans>Share</Trans>} />
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown>
|
<Popover.Dropdown>
|
||||||
<ShareButtons url={props.entry.url} description={props.entry.title} />
|
<ShareButtons url={props.entry.url} description={props.entry.title} />
|
||||||
@@ -74,8 +74,8 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
|
|||||||
{tags && (
|
{tags && (
|
||||||
<Popover withArrow withinPortal shadow="md" positionDependencies={[scrollPosition]} closeOnClickOutside={!mobile}>
|
<Popover withArrow withinPortal shadow="md" positionDependencies={[scrollPosition]} closeOnClickOutside={!mobile}>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<Indicator label={props.entry.tags.length} showZero={false} dot={false} inline size={16}>
|
<Indicator label={props.entry.tags.length} disabled={props.entry.tags.length === 0} inline size={16}>
|
||||||
<ActionButton icon={<TbTag size={18} />} label={t`Tags`} />
|
<ActionButton icon={<TbTag size={18} />} label={<Trans>Tags</Trans>} />
|
||||||
</Indicator>
|
</Indicator>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown>
|
<Popover.Dropdown>
|
||||||
@@ -94,13 +94,13 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<a href={props.entry.url} target="_blank" rel="noreferrer">
|
<a href={props.entry.url} target="_blank" rel="noreferrer">
|
||||||
<ActionButton icon={<TbExternalLink size={18} />} label={t`Open link`} />
|
<ActionButton icon={<TbExternalLink size={18} />} label={<Trans>Open link</Trans>} />
|
||||||
</a>
|
</a>
|
||||||
</ButtonToolbar>
|
</ButtonToolbar>
|
||||||
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={<TbArrowBarToDown size={18} />}
|
icon={<TbArrowBarToDown size={18} />}
|
||||||
label={t`Mark as read up to here`}
|
label={<Trans>Mark as read up to here</Trans>}
|
||||||
onClick={() => dispatch(markEntriesUpToEntry(props.entry))}
|
onClick={() => dispatch(markEntriesUpToEntry(props.entry))}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ export function AddCategory() {
|
|||||||
|
|
||||||
<form onSubmit={form.onSubmit(addCategory.execute)}>
|
<form onSubmit={form.onSubmit(addCategory.execute)}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<TextInput label={t`Category`} placeholder={t`Category`} {...form.getInputProps("name")} required />
|
<TextInput label={<Trans>Category</Trans>} placeholder={t`Category`} {...form.getInputProps("name")} required />
|
||||||
<CategorySelect label={t`Parent`} {...form.getInputProps("parentId")} clearable />
|
<CategorySelect label={<Trans>Parent</Trans>} {...form.getInputProps("parentId")} clearable />
|
||||||
<Group position="center">
|
<Group position="center">
|
||||||
<Button variant="default" onClick={() => dispatch(redirectToSelectedSource())}>
|
<Button variant="default" onClick={() => dispatch(redirectToSelectedSource())}>
|
||||||
<Trans>Cancel</Trans>
|
<Trans>Cancel</Trans>
|
||||||
|
|||||||
@@ -36,9 +36,14 @@ export function ImportOpml() {
|
|||||||
<form onSubmit={form.onSubmit(v => importOpml.execute(v.file))}>
|
<form onSubmit={form.onSubmit(v => importOpml.execute(v.file))}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<FileInput
|
<FileInput
|
||||||
label={t`OPML file`}
|
label={<Trans>OPML file</Trans>}
|
||||||
placeholder={t`OPML file`}
|
placeholder={t`OPML file`}
|
||||||
description={t`An opml file is an XML file containing feed URLs and categories. You can get an OPML file by exporting your data from other feed reading services.`}
|
description={
|
||||||
|
<Trans>
|
||||||
|
An opml file is an XML file containing feed URLs and categories. You can get an OPML file by exporting your
|
||||||
|
data from other feed reading services.
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
{...form.getInputProps("file")}
|
{...form.getInputProps("file")}
|
||||||
required
|
required
|
||||||
accept="application/xml"
|
accept="application/xml"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Box, Button, Group, Stack, Stepper, TextInput } from "@mantine/core"
|
import { Box, Button, Group, Stack, Stepper, TextInput } from "@mantine/core"
|
||||||
import { useForm } from "@mantine/form"
|
import { useForm } from "@mantine/form"
|
||||||
import { client, errorToStrings } from "app/client"
|
import { client, errorToStrings } from "app/client"
|
||||||
@@ -74,24 +74,33 @@ export function Subscribe() {
|
|||||||
<form onSubmit={nextStep}>
|
<form onSubmit={nextStep}>
|
||||||
<Stepper active={activeStep} onStepClick={setActiveStep}>
|
<Stepper active={activeStep} onStepClick={setActiveStep}>
|
||||||
<Stepper.Step
|
<Stepper.Step
|
||||||
label={t`Analyze feed`}
|
label={<Trans>Analyze feed</Trans>}
|
||||||
description={t`Check that the feed is working`}
|
description={<Trans>Check that the feed is working</Trans>}
|
||||||
allowStepSelect={activeStep === 1}
|
allowStepSelect={activeStep === 1}
|
||||||
>
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={t`Feed URL`}
|
label={<Trans>Feed URL</Trans>}
|
||||||
placeholder="http://www.mysite.com/rss"
|
placeholder="http://www.mysite.com/rss"
|
||||||
description={t`The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page.`}
|
description={
|
||||||
|
<Trans>
|
||||||
|
The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed
|
||||||
|
will try to find the feed in the page.
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
required
|
required
|
||||||
autoFocus
|
autoFocus
|
||||||
{...step0Form.getInputProps("url")}
|
{...step0Form.getInputProps("url")}
|
||||||
/>
|
/>
|
||||||
</Stepper.Step>
|
</Stepper.Step>
|
||||||
<Stepper.Step label={t`Subscribe`} description={t`Subscribe to the feed`} allowStepSelect={false}>
|
<Stepper.Step
|
||||||
|
label={<Trans>Subscribe</Trans>}
|
||||||
|
description={<Trans>Subscribe to the feed</Trans>}
|
||||||
|
allowStepSelect={false}
|
||||||
|
>
|
||||||
<Stack>
|
<Stack>
|
||||||
<TextInput label={t`Feed URL`} {...step1Form.getInputProps("url")} disabled />
|
<TextInput label={<Trans>Feed URL</Trans>} {...step1Form.getInputProps("url")} disabled />
|
||||||
<TextInput label={t`Feed name`} {...step1Form.getInputProps("title")} required autoFocus />
|
<TextInput label={<Trans>Feed name</Trans>} {...step1Form.getInputProps("title")} required autoFocus />
|
||||||
<CategorySelect label={t`Category`} {...step1Form.getInputProps("categoryId")} clearable />
|
<CategorySelect label={<Trans>Category</Trans>} {...step1Form.getInputProps("categoryId")} clearable />
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stepper.Step>
|
</Stepper.Step>
|
||||||
</Stepper>
|
</Stepper>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t } from "@lingui/macro"
|
import { t, Trans } from "@lingui/macro"
|
||||||
import { ActionIcon, Center, Divider, Indicator, Popover, TextInput } from "@mantine/core"
|
import { ActionIcon, Center, Divider, Indicator, Popover, TextInput } from "@mantine/core"
|
||||||
import { useForm } from "@mantine/form"
|
import { useForm } from "@mantine/form"
|
||||||
import { reloadEntries, search } from "app/slices/entries"
|
import { reloadEntries, search } from "app/slices/entries"
|
||||||
@@ -17,6 +17,7 @@ function HeaderDivider() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const iconSize = 18
|
const iconSize = 18
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const settings = useAppSelector(state => state.user.settings)
|
const settings = useAppSelector(state => state.user.settings)
|
||||||
const profile = useAppSelector(state => state.user.profile)
|
const profile = useAppSelector(state => state.user.profile)
|
||||||
@@ -40,26 +41,30 @@ export function Header() {
|
|||||||
return (
|
return (
|
||||||
<Center>
|
<Center>
|
||||||
<ButtonToolbar>
|
<ButtonToolbar>
|
||||||
<ActionButton icon={<TbRefresh size={iconSize} />} label={t`Refresh`} onClick={() => dispatch(reloadEntries())} />
|
<ActionButton
|
||||||
|
icon={<TbRefresh size={iconSize} />}
|
||||||
|
label={<Trans>Refresh</Trans>}
|
||||||
|
onClick={() => dispatch(reloadEntries())}
|
||||||
|
/>
|
||||||
<MarkAllAsReadButton iconSize={iconSize} />
|
<MarkAllAsReadButton iconSize={iconSize} />
|
||||||
|
|
||||||
<HeaderDivider />
|
<HeaderDivider />
|
||||||
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={settings.readingMode === "all" ? <TbEye size={iconSize} /> : <TbEyeOff size={iconSize} />}
|
icon={settings.readingMode === "all" ? <TbEye size={iconSize} /> : <TbEyeOff size={iconSize} />}
|
||||||
label={settings.readingMode === "all" ? t`All` : t`Unread`}
|
label={settings.readingMode === "all" ? <Trans>All</Trans> : <Trans>Unread</Trans>}
|
||||||
onClick={() => dispatch(changeReadingMode(settings.readingMode === "all" ? "unread" : "all"))}
|
onClick={() => dispatch(changeReadingMode(settings.readingMode === "all" ? "unread" : "all"))}
|
||||||
/>
|
/>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={settings.readingOrder === "asc" ? <TbArrowUp size={iconSize} /> : <TbArrowDown size={iconSize} />}
|
icon={settings.readingOrder === "asc" ? <TbArrowUp size={iconSize} /> : <TbArrowDown size={iconSize} />}
|
||||||
label={settings.readingOrder === "asc" ? t`Asc` : t`Desc`}
|
label={settings.readingOrder === "asc" ? <Trans>Asc</Trans> : <Trans>Desc</Trans>}
|
||||||
onClick={() => dispatch(changeReadingOrder(settings.readingOrder === "asc" ? "desc" : "asc"))}
|
onClick={() => dispatch(changeReadingOrder(settings.readingOrder === "asc" ? "desc" : "asc"))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Popover>
|
<Popover>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<Indicator disabled={!searchFromStore}>
|
<Indicator disabled={!searchFromStore}>
|
||||||
<ActionButton icon={<TbSearch size={iconSize} />} label={t`Search`} />
|
<ActionButton icon={<TbSearch size={iconSize} />} label={<Trans>Search</Trans>} />
|
||||||
</Indicator>
|
</Indicator>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown>
|
<Popover.Dropdown>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
|
|
||||||
import { Button, Code, Group, Modal, Slider, Stack, Text } from "@mantine/core"
|
import { Button, Code, Group, Modal, Slider, Stack, Text } from "@mantine/core"
|
||||||
import { markAllEntries } from "app/slices/entries"
|
import { markAllEntries } from "app/slices/entries"
|
||||||
@@ -17,7 +17,7 @@ export function MarkAllAsReadButton(props: { iconSize: number }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal opened={opened} onClose={() => setOpened(false)} title={t`Mark all entries as read`}>
|
<Modal opened={opened} onClose={() => setOpened(false)} title={<Trans>Mark all entries as read</Trans>}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
{threshold === 0 && (
|
{threshold === 0 && (
|
||||||
@@ -72,7 +72,7 @@ export function MarkAllAsReadButton(props: { iconSize: number }) {
|
|||||||
</Modal>
|
</Modal>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={<TbChecks size={props.iconSize} />}
|
icon={<TbChecks size={props.iconSize} />}
|
||||||
label={t`Mark all as read`}
|
label={<Trans>Mark all as read</Trans>}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setThreshold(0)
|
setThreshold(0)
|
||||||
setOpened(true)
|
setOpened(true)
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Box, Divider, Group, Menu, SegmentedControl, SegmentedControlItem, useMantineColorScheme } from "@mantine/core"
|
import { Box, Divider, Group, Menu, SegmentedControl, SegmentedControlItem, useMantineColorScheme } from "@mantine/core"
|
||||||
import { showNotification } from "@mantine/notifications"
|
import { showNotification } from "@mantine/notifications"
|
||||||
import { client } from "app/client"
|
import { client } from "app/client"
|
||||||
import { redirectToAbout, redirectToAdminUsers, redirectToMetrics, redirectToSettings } from "app/slices/redirect"
|
import { redirectToAbout, redirectToAdminUsers, redirectToMetrics, redirectToSettings } from "app/slices/redirect"
|
||||||
import { useAppDispatch, useAppSelector } from "app/store"
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
import { ViewMode } from "app/types"
|
import { ViewMode } from "app/types"
|
||||||
|
import { useViewMode } from "hooks/useViewMode"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import {
|
import {
|
||||||
TbChartLine,
|
TbChartLine,
|
||||||
@@ -20,7 +21,6 @@ import {
|
|||||||
TbUsers,
|
TbUsers,
|
||||||
TbWorldDownload,
|
TbWorldDownload,
|
||||||
} from "react-icons/tb"
|
} from "react-icons/tb"
|
||||||
import { useViewMode } from "../../hooks/useViewMode"
|
|
||||||
|
|
||||||
interface ProfileMenuProps {
|
interface ProfileMenuProps {
|
||||||
control: React.ReactElement
|
control: React.ReactElement
|
||||||
@@ -111,7 +111,7 @@ export function ProfileMenu(props: ProfileMenuProps) {
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
client.feed.refreshAll().then(() => {
|
client.feed.refreshAll().then(() => {
|
||||||
showNotification({
|
showNotification({
|
||||||
message: t`Your feeds have been queued for refresh.`,
|
message: <Trans>Your feeds have been queued for refresh.</Trans>,
|
||||||
color: "green",
|
color: "green",
|
||||||
autoClose: 1000,
|
autoClose: 1000,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import { Trans } from "@lingui/macro"
|
||||||
|
import { Box, Button, Group, Stack, Textarea } from "@mantine/core"
|
||||||
|
import { useForm } from "@mantine/form"
|
||||||
|
import { client, errorToStrings } from "app/client"
|
||||||
|
import { redirectToSelectedSource } from "app/slices/redirect"
|
||||||
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
|
import { Alert } from "components/Alert"
|
||||||
|
import { useEffect } from "react"
|
||||||
|
import { useAsyncCallback } from "react-async-hook"
|
||||||
|
import { TbDeviceFloppy } from "react-icons/tb"
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
customCss: string
|
||||||
|
customJs: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CustomCodeSettings() {
|
||||||
|
const settings = useAppSelector(state => state.user.settings)
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
|
const form = useForm<FormData>()
|
||||||
|
const { setValues } = form
|
||||||
|
|
||||||
|
const saveCustomCode = useAsyncCallback(
|
||||||
|
async (d: FormData) => {
|
||||||
|
if (!settings) return
|
||||||
|
await client.user.saveSettings({
|
||||||
|
...settings,
|
||||||
|
customCss: d.customCss,
|
||||||
|
customJs: d.customJs,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onSuccess: () => {
|
||||||
|
window.location.reload()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!settings) return
|
||||||
|
setValues({
|
||||||
|
customCss: settings.customCss,
|
||||||
|
customJs: settings.customJs,
|
||||||
|
})
|
||||||
|
}, [setValues, settings])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{saveCustomCode.error && (
|
||||||
|
<Box mb="md">
|
||||||
|
<Alert messages={errorToStrings(saveCustomCode.error)} />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<form onSubmit={form.onSubmit(saveCustomCode.execute)}>
|
||||||
|
<Stack>
|
||||||
|
<Textarea
|
||||||
|
autosize
|
||||||
|
minRows={4}
|
||||||
|
maxRows={15}
|
||||||
|
{...form.getInputProps("customCss")}
|
||||||
|
description={<Trans>Custom CSS rules that will be applied</Trans>}
|
||||||
|
styles={{
|
||||||
|
input: {
|
||||||
|
fontFamily: "monospace",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
autosize
|
||||||
|
minRows={4}
|
||||||
|
maxRows={15}
|
||||||
|
{...form.getInputProps("customJs")}
|
||||||
|
description={<Trans>Custom JS code that will be executed on page load</Trans>}
|
||||||
|
styles={{
|
||||||
|
input: {
|
||||||
|
fontFamily: "monospace",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Group>
|
||||||
|
<Button variant="default" onClick={() => dispatch(redirectToSelectedSource())}>
|
||||||
|
<Trans>Cancel</Trans>
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" leftIcon={<TbDeviceFloppy size={16} />} loading={saveCustomCode.loading}>
|
||||||
|
<Trans>Save</Trans>
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Divider, Select, SimpleGrid, Stack, Switch } from "@mantine/core"
|
import { Divider, Select, SimpleGrid, Stack, Switch } from "@mantine/core"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import { changeLanguage, changeScrollMarks, changeScrollSpeed, changeSharingSetting, changeShowRead } from "app/slices/user"
|
import { changeLanguage, changeScrollMarks, changeScrollSpeed, changeSharingSetting, changeShowRead } from "app/slices/user"
|
||||||
@@ -17,7 +17,7 @@ export function DisplaySettings() {
|
|||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<Select
|
<Select
|
||||||
description={t`Language`}
|
description={<Trans>Language</Trans>}
|
||||||
value={language}
|
value={language}
|
||||||
data={locales.map(l => ({
|
data={locales.map(l => ({
|
||||||
value: l.key,
|
value: l.key,
|
||||||
@@ -27,24 +27,24 @@ export function DisplaySettings() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
label={t`Scroll smoothly when navigating between entries`}
|
label={<Trans>Scroll smoothly when navigating between entries</Trans>}
|
||||||
checked={scrollSpeed ? scrollSpeed > 0 : false}
|
checked={scrollSpeed ? scrollSpeed > 0 : false}
|
||||||
onChange={e => dispatch(changeScrollSpeed(e.currentTarget.checked))}
|
onChange={e => dispatch(changeScrollSpeed(e.currentTarget.checked))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
label={t`Show feeds and categories with no unread entries`}
|
label={<Trans>Show feeds and categories with no unread entries</Trans>}
|
||||||
checked={showRead}
|
checked={showRead}
|
||||||
onChange={e => dispatch(changeShowRead(e.currentTarget.checked))}
|
onChange={e => dispatch(changeShowRead(e.currentTarget.checked))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
label={t`In expanded view, scrolling through entries mark them as read`}
|
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
|
||||||
checked={scrollMarks}
|
checked={scrollMarks}
|
||||||
onChange={e => dispatch(changeScrollMarks(e.currentTarget.checked))}
|
onChange={e => dispatch(changeScrollMarks(e.currentTarget.checked))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Divider label={t`Sharing sites`} labelPosition="center" />
|
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
|
||||||
|
|
||||||
<SimpleGrid cols={2}>
|
<SimpleGrid cols={2}>
|
||||||
{(Object.keys(Constants.sharing) as Array<keyof SharingSettings>).map(site => (
|
{(Object.keys(Constants.sharing) as Array<keyof SharingSettings>).map(site => (
|
||||||
|
|||||||
@@ -41,13 +41,13 @@ export function ProfileSettings() {
|
|||||||
|
|
||||||
const openDeleteProfileModal = () =>
|
const openDeleteProfileModal = () =>
|
||||||
openConfirmModal({
|
openConfirmModal({
|
||||||
title: t`Delete account`,
|
title: <Trans>Delete account</Trans>,
|
||||||
children: (
|
children: (
|
||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
<Trans>Are you sure you want to delete your account? There's no turning back!</Trans>
|
<Trans>Are you sure you want to delete your account? There's no turning back!</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
),
|
),
|
||||||
labels: { confirm: t`Confirm`, cancel: t`Cancel` },
|
labels: { confirm: <Trans>Confirm</Trans>, cancel: <Trans>Cancel</Trans> },
|
||||||
confirmProps: { color: "red" },
|
confirmProps: { color: "red" },
|
||||||
onConfirm: () => deleteProfile.execute(),
|
onConfirm: () => deleteProfile.execute(),
|
||||||
})
|
})
|
||||||
@@ -77,12 +77,16 @@ export function ProfileSettings() {
|
|||||||
|
|
||||||
<form onSubmit={form.onSubmit(saveProfile.execute)}>
|
<form onSubmit={form.onSubmit(saveProfile.execute)}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Input.Wrapper label={t`User name`}>
|
<Input.Wrapper label={<Trans>User name</Trans>}>
|
||||||
<Box>{profile?.name}</Box>
|
<Box>{profile?.name}</Box>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
<Input.Wrapper
|
<Input.Wrapper
|
||||||
label={t`OPML export`}
|
label={<Trans>OPML export</Trans>}
|
||||||
description={t`Export your subscriptions and categories as an OPML file that can be imported in other feed reading services`}
|
description={
|
||||||
|
<Trans>
|
||||||
|
Export your subscriptions and categories as an OPML file that can be imported in other feed reading services
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Box>
|
<Box>
|
||||||
<Anchor href="rest/feed/export" download="commafeed_opml.xml">
|
<Anchor href="rest/feed/export" download="commafeed_opml.xml">
|
||||||
@@ -91,20 +95,20 @@ export function ProfileSettings() {
|
|||||||
</Box>
|
</Box>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label={t`Current password`}
|
label={<Trans>Current password</Trans>}
|
||||||
description={t`Enter your current password to change profile settings`}
|
description={<Trans>Enter your current password to change profile settings</Trans>}
|
||||||
required
|
required
|
||||||
{...form.getInputProps("currentPassword")}
|
{...form.getInputProps("currentPassword")}
|
||||||
/>
|
/>
|
||||||
<TextInput type="email" label={t`E-mail`} {...form.getInputProps("email")} required />
|
<TextInput type="email" label={<Trans>E-mail</Trans>} {...form.getInputProps("email")} required />
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label={t`New password`}
|
label={<Trans>New password</Trans>}
|
||||||
description={t`Changing password will generate a new API key`}
|
description={<Trans>Changing password will generate a new API key</Trans>}
|
||||||
{...form.getInputProps("newPassword")}
|
{...form.getInputProps("newPassword")}
|
||||||
/>
|
/>
|
||||||
<PasswordInput label={t`Confirm password`} {...form.getInputProps("newPasswordConfirmation")} />
|
<PasswordInput label={<Trans>Confirm password</Trans>} {...form.getInputProps("newPasswordConfirmation")} />
|
||||||
<TextInput label={t`API key`} readOnly value={profile?.apiKey} />
|
<TextInput label={<Trans>API key</Trans>} readOnly value={profile?.apiKey} />
|
||||||
<Checkbox label={t`Generate new API key`} {...form.getInputProps("newApiKey", { type: "checkbox" })} />
|
<Checkbox label={<Trans>Generate new API key</Trans>} {...form.getInputProps("newApiKey", { type: "checkbox" })} />
|
||||||
|
|
||||||
<Group>
|
<Group>
|
||||||
<Button variant="default" onClick={() => dispatch(redirectToSelectedSource())}>
|
<Button variant="default" onClick={() => dispatch(redirectToSelectedSource())}>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Box, Stack } from "@mantine/core"
|
import { Box, Stack } from "@mantine/core"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import {
|
import {
|
||||||
@@ -27,6 +27,7 @@ const expandedIcon = <TbChevronDown size={16} />
|
|||||||
const collapsedIcon = <TbChevronRight size={16} />
|
const collapsedIcon = <TbChevronRight size={16} />
|
||||||
|
|
||||||
const errorThreshold = 9
|
const errorThreshold = 9
|
||||||
|
|
||||||
export function Tree() {
|
export function Tree() {
|
||||||
const root = useAppSelector(state => state.tree.rootCategory)
|
const root = useAppSelector(state => state.tree.rootCategory)
|
||||||
const source = useAppSelector(state => state.entries.source)
|
const source = useAppSelector(state => state.entries.source)
|
||||||
@@ -63,7 +64,7 @@ export function Tree() {
|
|||||||
const allCategoryNode = () => (
|
const allCategoryNode = () => (
|
||||||
<TreeNode
|
<TreeNode
|
||||||
id={Constants.categories.all.id}
|
id={Constants.categories.all.id}
|
||||||
name={t`All`}
|
name={<Trans>All</Trans>}
|
||||||
icon={allIcon}
|
icon={allIcon}
|
||||||
unread={categoryUnreadCount(root)}
|
unread={categoryUnreadCount(root)}
|
||||||
selected={source.type === "category" && source.id === Constants.categories.all.id}
|
selected={source.type === "category" && source.id === Constants.categories.all.id}
|
||||||
@@ -76,7 +77,7 @@ export function Tree() {
|
|||||||
const starredCategoryNode = () => (
|
const starredCategoryNode = () => (
|
||||||
<TreeNode
|
<TreeNode
|
||||||
id={Constants.categories.starred.id}
|
id={Constants.categories.starred.id}
|
||||||
name={t`Starred`}
|
name={<Trans>Starred</Trans>}
|
||||||
icon={starredIcon}
|
icon={starredIcon}
|
||||||
unread={0}
|
unread={0}
|
||||||
selected={source.type === "category" && source.id === Constants.categories.starred.id}
|
selected={source.type === "category" && source.id === Constants.categories.starred.id}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { UnreadCount } from "./UnreadCount"
|
|||||||
|
|
||||||
interface TreeNodeProps {
|
interface TreeNodeProps {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: ReactNode
|
||||||
icon: ReactNode | string
|
icon: ReactNode
|
||||||
unread: number
|
unread: number
|
||||||
selected: boolean
|
selected: boolean
|
||||||
expanded?: boolean
|
expanded?: boolean
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t } from "@lingui/macro"
|
import { t, Trans } from "@lingui/macro"
|
||||||
import { Box, Center, Kbd, TextInput } from "@mantine/core"
|
import { Box, Center, Kbd, TextInput } from "@mantine/core"
|
||||||
import { openSpotlight, SpotlightAction, SpotlightProvider } from "@mantine/spotlight"
|
import { openSpotlight, SpotlightAction, SpotlightProvider } from "@mantine/spotlight"
|
||||||
import { redirectToFeed } from "app/slices/redirect"
|
import { redirectToFeed } from "app/slices/redirect"
|
||||||
@@ -11,6 +11,7 @@ import { TbSearch } from "react-icons/tb"
|
|||||||
export interface TreeSearchProps {
|
export interface TreeSearchProps {
|
||||||
feeds: Subscription[]
|
feeds: Subscription[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TreeSearch(props: TreeSearchProps) {
|
export function TreeSearch(props: TreeSearchProps) {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ export function TreeSearch(props: TreeSearchProps) {
|
|||||||
searchIcon={searchIcon}
|
searchIcon={searchIcon}
|
||||||
searchPlaceholder={t`Search`}
|
searchPlaceholder={t`Search`}
|
||||||
shortcut="ctrl+k"
|
shortcut="ctrl+k"
|
||||||
nothingFoundMessage={t`Nothing found`}
|
nothingFoundMessage={<Trans>Nothing found</Trans>}
|
||||||
>
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
placeholder={t`Search`}
|
placeholder={t`Search`}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import { ViewMode } from "app/types"
|
||||||
import useLocalStorage from "use-local-storage"
|
import useLocalStorage from "use-local-storage"
|
||||||
import { ViewMode } from "../app/types"
|
|
||||||
|
|
||||||
export function useViewMode() {
|
export function useViewMode() {
|
||||||
const [viewMode, setViewMode] = useLocalStorage<ViewMode>("view-mode", "detailed")
|
const [viewMode, setViewMode] = useLocalStorage<ViewMode>("view-mode", "detailed")
|
||||||
|
|||||||
@@ -29,37 +29,7 @@ import "dayjs/locale/sk"
|
|||||||
import "dayjs/locale/sv"
|
import "dayjs/locale/sv"
|
||||||
import "dayjs/locale/tr"
|
import "dayjs/locale/tr"
|
||||||
import "dayjs/locale/zh"
|
import "dayjs/locale/zh"
|
||||||
import {
|
|
||||||
ar,
|
|
||||||
ca,
|
|
||||||
cs,
|
|
||||||
cy,
|
|
||||||
da,
|
|
||||||
de,
|
|
||||||
en,
|
|
||||||
es,
|
|
||||||
fa,
|
|
||||||
fi,
|
|
||||||
fr,
|
|
||||||
gl,
|
|
||||||
hu,
|
|
||||||
id,
|
|
||||||
it,
|
|
||||||
ja,
|
|
||||||
ko,
|
|
||||||
ms,
|
|
||||||
nb,
|
|
||||||
nl,
|
|
||||||
nn,
|
|
||||||
pl,
|
|
||||||
PluralCategory,
|
|
||||||
pt,
|
|
||||||
ru,
|
|
||||||
sk,
|
|
||||||
sv,
|
|
||||||
tr,
|
|
||||||
zh,
|
|
||||||
} from "make-plural"
|
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import { messages as arMessages } from "./locales/ar/messages"
|
import { messages as arMessages } from "./locales/ar/messages"
|
||||||
import { messages as caMessages } from "./locales/ca/messages"
|
import { messages as caMessages } from "./locales/ca/messages"
|
||||||
@@ -94,48 +64,42 @@ interface Locale {
|
|||||||
key: string
|
key: string
|
||||||
label: string
|
label: string
|
||||||
messages: Messages
|
messages: Messages
|
||||||
plurals?: (n: number | string, ord?: boolean) => PluralCategory
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add an object to the array to add a new locale
|
// add an object to the array to add a new locale
|
||||||
// don't forget to also add it to the 'locales' array in .linguirc
|
// don't forget to also add it to the 'locales' array in .linguirc
|
||||||
export const locales: Locale[] = [
|
export const locales: Locale[] = [
|
||||||
{ key: "ar", messages: arMessages, plurals: ar, label: "العربية" },
|
{ key: "ar", messages: arMessages, label: "العربية" },
|
||||||
{ key: "ca", messages: caMessages, plurals: ca, label: "Català" },
|
{ key: "ca", messages: caMessages, label: "Català" },
|
||||||
{ key: "cs", messages: csMessages, plurals: cs, label: "Čeština" },
|
{ key: "cs", messages: csMessages, label: "Čeština" },
|
||||||
{ key: "cy", messages: cyMessages, plurals: cy, label: "Cymraeg" },
|
{ key: "cy", messages: cyMessages, label: "Cymraeg" },
|
||||||
{ key: "da", messages: daMessages, plurals: da, label: "Danish" },
|
{ key: "da", messages: daMessages, label: "Danish" },
|
||||||
{ key: "de", messages: deMessages, plurals: de, label: "Deutsch" },
|
{ key: "de", messages: deMessages, label: "Deutsch" },
|
||||||
{ key: "en", messages: enMessages, plurals: en, label: "English" },
|
{ key: "en", messages: enMessages, label: "English" },
|
||||||
{ key: "es", messages: esMessages, plurals: es, label: "Español" },
|
{ key: "es", messages: esMessages, label: "Español" },
|
||||||
{ key: "fa", messages: faMessages, plurals: fa, label: "فارسی" },
|
{ key: "fa", messages: faMessages, label: "فارسی" },
|
||||||
{ key: "fi", messages: fiMessages, plurals: fi, label: "Suomi" },
|
{ key: "fi", messages: fiMessages, label: "Suomi" },
|
||||||
{ key: "fr", messages: frMessages, plurals: fr, label: "Français" },
|
{ key: "fr", messages: frMessages, label: "Français" },
|
||||||
{ key: "gl", messages: glMessages, plurals: gl, label: "Galician" },
|
{ key: "gl", messages: glMessages, label: "Galician" },
|
||||||
{ key: "hu", messages: huMessages, plurals: hu, label: "Magyar" },
|
{ key: "hu", messages: huMessages, label: "Magyar" },
|
||||||
{ key: "id", messages: idMessages, plurals: id, label: "Indonesian" },
|
{ key: "id", messages: idMessages, label: "Indonesian" },
|
||||||
{ key: "it", messages: itMessages, plurals: it, label: "Italiano" },
|
{ key: "it", messages: itMessages, label: "Italiano" },
|
||||||
{ key: "ja", messages: jaMessages, plurals: ja, label: "日本語" },
|
{ key: "ja", messages: jaMessages, label: "日本語" },
|
||||||
{ key: "ko", messages: koMessages, plurals: ko, label: "한국어" },
|
{ key: "ko", messages: koMessages, label: "한국어" },
|
||||||
{ key: "ms", messages: msMessages, plurals: ms, label: "Bahasa Malaysian" },
|
{ key: "ms", messages: msMessages, label: "Bahasa Malaysian" },
|
||||||
{ key: "nb", messages: nbMessages, plurals: nb, label: "Norsk (bokmål)" },
|
{ key: "nb", messages: nbMessages, label: "Norsk (bokmål)" },
|
||||||
{ key: "nl", messages: nlMessages, plurals: nl, label: "Nederlands" },
|
{ key: "nl", messages: nlMessages, label: "Nederlands" },
|
||||||
{ key: "nn", messages: nnMessages, plurals: nn, label: "Norsk (nynorsk)" },
|
{ key: "nn", messages: nnMessages, label: "Norsk (nynorsk)" },
|
||||||
{ key: "pl", messages: plMessages, plurals: pl, label: "Polski" },
|
{ key: "pl", messages: plMessages, label: "Polski" },
|
||||||
{ key: "pt", messages: ptMessages, plurals: pt, label: "Português" },
|
{ key: "pt", messages: ptMessages, label: "Português" },
|
||||||
{ key: "ru", messages: ruMessages, plurals: ru, label: "Русский" },
|
{ key: "ru", messages: ruMessages, label: "Русский" },
|
||||||
{ key: "sk", messages: skMessages, plurals: sk, label: "Slovenčina" },
|
{ key: "sk", messages: skMessages, label: "Slovenčina" },
|
||||||
{ key: "sv", messages: svMessages, plurals: sv, label: "Svenska" },
|
{ key: "sv", messages: svMessages, label: "Svenska" },
|
||||||
{ key: "tr", messages: trMessages, plurals: tr, label: "Türkçe" },
|
{ key: "tr", messages: trMessages, label: "Türkçe" },
|
||||||
{ key: "zh", messages: zhMessages, plurals: zh, label: "简体中文" },
|
{ key: "zh", messages: zhMessages, label: "简体中文" },
|
||||||
]
|
]
|
||||||
|
|
||||||
locales.forEach(l => {
|
locales.forEach(l => {
|
||||||
i18n.loadLocaleData({
|
|
||||||
[l.key]: {
|
|
||||||
plurals: l.plurals,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
i18n.load({
|
i18n.load({
|
||||||
[l.key]: l.messages,
|
[l.key]: l.messages,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "ملحقات المستعرض"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr "السيطرة"
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "كلمة المرور الحالية"
|
msgstr "كلمة المرور الحالية"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "تاريخ الإنشاء"
|
msgstr "تاريخ الإنشاء"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Extensions del navegador"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Contrasenya actual"
|
msgstr "Contrasenya actual"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Data de creació"
|
msgstr "Data de creació"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Rozšíření prohlížeče"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Aktuální heslo"
|
msgstr "Aktuální heslo"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Datum vytvoření"
|
msgstr "Datum vytvoření"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Estyniadau porwr"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Cyfrinair presennol"
|
msgstr "Cyfrinair presennol"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Dyddiad creu"
|
msgstr "Dyddiad creu"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Browserudvidelser"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Nuværende adgangskode"
|
msgstr "Nuværende adgangskode"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Dato oprettet"
|
msgstr "Dato oprettet"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Browsererweiterungen"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr "Strg"
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Aktuelles Passwort"
|
msgstr "Aktuelles Passwort"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Erstellungsdatum"
|
msgstr "Erstellungsdatum"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Browser extentions"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr "Ctrl"
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Current password"
|
msgstr "Current password"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr "Custom CSS rules that will be applied"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr "Custom JS code that will be executed on page load"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr "Custom code"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Date created"
|
msgstr "Date created"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr "Right click"
|
msgstr "Right click"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Extensiones del navegador"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Contraseña actual"
|
msgstr "Contraseña actual"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Fecha de creación"
|
msgstr "Fecha de creación"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "گسترش مرورگر"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "رمز عبور فعلی"
|
msgstr "رمز عبور فعلی"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "تاریخ ایجاد"
|
msgstr "تاریخ ایجاد"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Selaimen laajennukset"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Nykyinen salasana"
|
msgstr "Nykyinen salasana"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Luontipäivämäärä"
|
msgstr "Luontipäivämäärä"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Extensions pour navigateurs"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr "Ctrl"
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Mot de passe actuel"
|
msgstr "Mot de passe actuel"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Date de création"
|
msgstr "Date de création"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Extensións do navegador"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Contrasinal actual"
|
msgstr "Contrasinal actual"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Data de creación"
|
msgstr "Data de creación"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Böngészőbővítések"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Jelenlegi jelszó"
|
msgstr "Jelenlegi jelszó"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Létrehozás dátuma"
|
msgstr "Létrehozás dátuma"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Ekstensi peramban"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Kata sandi saat ini"
|
msgstr "Kata sandi saat ini"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Tanggal dibuat"
|
msgstr "Tanggal dibuat"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Estensioni del browser"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr "ctrl"
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Password attuale"
|
msgstr "Password attuale"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Data di creazione"
|
msgstr "Data di creazione"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "ブラウザ拡張機能"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr "コントロール"
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "現在のパスワード"
|
msgstr "現在のパスワード"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "作成日"
|
msgstr "作成日"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "브라우저 확장"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr "컨트롤"
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "현재 비밀번호"
|
msgstr "현재 비밀번호"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "생성 날짜"
|
msgstr "생성 날짜"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Peluasan penyemak imbas"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Kata laluan semasa"
|
msgstr "Kata laluan semasa"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Tarikh dibuat"
|
msgstr "Tarikh dibuat"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Nettleserutvidelser"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Gjeldende passord"
|
msgstr "Gjeldende passord"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Dato opprettet"
|
msgstr "Dato opprettet"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Browserextensies"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Huidig wachtwoord"
|
msgstr "Huidig wachtwoord"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Datum gemaakt"
|
msgstr "Datum gemaakt"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Nettleserutvidelser"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Gjeldende passord"
|
msgstr "Gjeldende passord"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Dato opprettet"
|
msgstr "Dato opprettet"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Rozszerzenia przeglądarki"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "aktualne hasło"
|
msgstr "aktualne hasło"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Data utworzenia"
|
msgstr "Data utworzenia"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Extensões do navegador"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Senha atual"
|
msgstr "Senha atual"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Data de criação"
|
msgstr "Data de criação"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Расширения браузера"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Текущий пароль"
|
msgstr "Текущий пароль"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Дата создания"
|
msgstr "Дата создания"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Rozšírenia prehliadača"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Aktuálne heslo"
|
msgstr "Aktuálne heslo"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Dátum vytvorenia"
|
msgstr "Dátum vytvorenia"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Webbläsartillägg"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Aktuellt lösenord"
|
msgstr "Aktuellt lösenord"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Datum skapat"
|
msgstr "Datum skapat"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "Tarayıcı uzantıları"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr ""
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "Geçerli şifre"
|
msgstr "Geçerli şifre"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Oluşturulma tarihi"
|
msgstr "Oluşturulma tarihi"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ msgstr "浏览器扩展"
|
|||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
@@ -194,6 +195,18 @@ msgstr "控制"
|
|||||||
msgid "Current password"
|
msgid "Current password"
|
||||||
msgstr "当前密码"
|
msgstr "当前密码"
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom CSS rules that will be applied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
msgid "Custom JS code that will be executed on page load"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Custom code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "创建日期"
|
msgstr "创建日期"
|
||||||
@@ -622,6 +635,7 @@ msgid "Right click"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const useStyles = createStyles(theme => ({
|
|||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
fontSize: 120,
|
fontSize: 120,
|
||||||
lineHeight: 1,
|
lineHeight: 1,
|
||||||
marginBottom: theme.spacing.xl * 1.5,
|
marginBottom: `calc(${theme.spacing.xl} * 1.5)`,
|
||||||
color: theme.colors[theme.primaryColor][3],
|
color: theme.colors[theme.primaryColor][3],
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ const useStyles = createStyles(theme => ({
|
|||||||
maxWidth: 540,
|
maxWidth: 540,
|
||||||
margin: "auto",
|
margin: "auto",
|
||||||
marginTop: theme.spacing.xl,
|
marginTop: theme.spacing.xl,
|
||||||
marginBottom: theme.spacing.xl * 1.5,
|
marginBottom: `calc(${theme.spacing.xl} * 1.5)`,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Center, Title } from "@mantine/core"
|
import { Center, Title } from "@mantine/core"
|
||||||
import { Logo } from "../components/Logo"
|
import { Logo } from "components/Logo"
|
||||||
|
|
||||||
export function PageTitle() {
|
export function PageTitle() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { t } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Anchor, Box, Center, Container, Divider, Group, Image, Title, useMantineColorScheme } from "@mantine/core"
|
import { Anchor, Box, Center, Container, Divider, Group, Image, Title, useMantineColorScheme } from "@mantine/core"
|
||||||
import { useMediaQuery } from "@mantine/hooks"
|
import { useMediaQuery } from "@mantine/hooks"
|
||||||
|
import { client } from "app/client"
|
||||||
|
import { Constants } from "app/constants"
|
||||||
|
import { redirectToLogin, redirectToRegistration, redirectToRootCategory } from "app/slices/redirect"
|
||||||
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
import welcome_page_dark from "assets/welcome_page_dark.png"
|
import welcome_page_dark from "assets/welcome_page_dark.png"
|
||||||
import welcome_page_light from "assets/welcome_page_light.png"
|
import welcome_page_light from "assets/welcome_page_light.png"
|
||||||
|
import { ActionButton } from "components/ActionButtton"
|
||||||
|
import { ButtonToolbar } from "components/ButtonToolbar"
|
||||||
import { useAsyncCallback } from "react-async-hook"
|
import { useAsyncCallback } from "react-async-hook"
|
||||||
import { SiGithub, TbKey, TbUserPlus } from "react-icons/all"
|
import { SiGithub, TbKey, TbUserPlus } from "react-icons/all"
|
||||||
import { SiTwitter } from "react-icons/si"
|
import { SiTwitter } from "react-icons/si"
|
||||||
import { TbClock, TbMoon, TbSun } from "react-icons/tb"
|
import { TbClock, TbMoon, TbSun } from "react-icons/tb"
|
||||||
import { client } from "../app/client"
|
|
||||||
import { Constants } from "../app/constants"
|
|
||||||
import { redirectToLogin, redirectToRegistration, redirectToRootCategory } from "../app/slices/redirect"
|
|
||||||
import { useAppDispatch, useAppSelector } from "../app/store"
|
|
||||||
import { ActionButton } from "../components/ActionButtton"
|
|
||||||
import { ButtonToolbar } from "../components/ButtonToolbar"
|
|
||||||
import { PageTitle } from "./PageTitle"
|
import { PageTitle } from "./PageTitle"
|
||||||
|
|
||||||
export function WelcomePage() {
|
export function WelcomePage() {
|
||||||
@@ -38,7 +38,7 @@ export function WelcomePage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Header() {
|
function Header() {
|
||||||
const mobile = !useMediaQuery(`(min-width: ${Constants.layout.mobileBreakpoint}px)`)
|
const mobile = !useMediaQuery(`(min-width: ${Constants.layout.mobileBreakpoint})`)
|
||||||
|
|
||||||
if (mobile) {
|
if (mobile) {
|
||||||
return (
|
return (
|
||||||
@@ -76,7 +76,7 @@ function Buttons() {
|
|||||||
<ButtonToolbar>
|
<ButtonToolbar>
|
||||||
{serverInfos?.demoAccountEnabled && (
|
{serverInfos?.demoAccountEnabled && (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={t`Try the demo!`}
|
label={<Trans>Try the demo!</Trans>}
|
||||||
icon={<TbClock size={iconSize} />}
|
icon={<TbClock size={iconSize} />}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => login.execute({ name: "demo", password: "demo" })}
|
onClick={() => login.execute({ name: "demo", password: "demo" })}
|
||||||
@@ -84,7 +84,7 @@ function Buttons() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={t`Log in`}
|
label={<Trans>Log in</Trans>}
|
||||||
icon={<TbKey size={iconSize} />}
|
icon={<TbKey size={iconSize} />}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => dispatch(redirectToLogin())}
|
onClick={() => dispatch(redirectToLogin())}
|
||||||
@@ -92,7 +92,7 @@ function Buttons() {
|
|||||||
/>
|
/>
|
||||||
{serverInfos?.allowRegistrations && (
|
{serverInfos?.allowRegistrations && (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={t`Sign up`}
|
label={<Trans>Sign up</Trans>}
|
||||||
icon={<TbUserPlus size={iconSize} />}
|
icon={<TbUserPlus size={iconSize} />}
|
||||||
variant="filled"
|
variant="filled"
|
||||||
onClick={() => dispatch(redirectToRegistration())}
|
onClick={() => dispatch(redirectToRegistration())}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { ActionIcon, Box, Code, Container, Group, Table, Text, Title, useMantineTheme } from "@mantine/core"
|
import { ActionIcon, Box, Code, Container, Group, Table, Text, Title, useMantineTheme } from "@mantine/core"
|
||||||
import { closeAllModals, openConfirmModal, openModal } from "@mantine/modals"
|
import { closeAllModals, openConfirmModal, openModal } from "@mantine/modals"
|
||||||
import { client, errorToStrings } from "app/client"
|
import { client, errorToStrings } from "app/client"
|
||||||
@@ -7,6 +7,7 @@ import { UserEdit } from "components/admin/UserEdit"
|
|||||||
import { Alert } from "components/Alert"
|
import { Alert } from "components/Alert"
|
||||||
import { Loader } from "components/Loader"
|
import { Loader } from "components/Loader"
|
||||||
import { RelativeDate } from "components/RelativeDate"
|
import { RelativeDate } from "components/RelativeDate"
|
||||||
|
import { ReactNode } from "react"
|
||||||
import { useAsync, useAsyncCallback } from "react-async-hook"
|
import { useAsync, useAsyncCallback } from "react-async-hook"
|
||||||
import { TbCheck, TbPencil, TbPlus, TbTrash, TbX } from "react-icons/tb"
|
import { TbCheck, TbPencil, TbPlus, TbTrash, TbX } from "react-icons/tb"
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ export function AdminUsersPage() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const openUserEditModal = (title: string, user?: UserModel) => {
|
const openUserEditModal = (title: ReactNode, user?: UserModel) => {
|
||||||
openModal({
|
openModal({
|
||||||
title,
|
title,
|
||||||
children: (
|
children: (
|
||||||
@@ -45,7 +46,7 @@ export function AdminUsersPage() {
|
|||||||
const openUserDeleteModal = (user: UserModel) => {
|
const openUserDeleteModal = (user: UserModel) => {
|
||||||
const userName = user.name
|
const userName = user.name
|
||||||
openConfirmModal({
|
openConfirmModal({
|
||||||
title: t`Delete user`,
|
title: <Trans>Delete user</Trans>,
|
||||||
children: (
|
children: (
|
||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
<Trans>
|
<Trans>
|
||||||
@@ -53,7 +54,7 @@ export function AdminUsersPage() {
|
|||||||
</Trans>
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
),
|
),
|
||||||
labels: { confirm: t`Confirm`, cancel: t`Cancel` },
|
labels: { confirm: <Trans>Confirm</Trans>, cancel: <Trans>Cancel</Trans> },
|
||||||
confirmProps: { color: "red" },
|
confirmProps: { color: "red" },
|
||||||
onConfirm: () => deleteUser.execute({ id: user.id }),
|
onConfirm: () => deleteUser.execute({ id: user.id }),
|
||||||
})
|
})
|
||||||
@@ -65,7 +66,7 @@ export function AdminUsersPage() {
|
|||||||
<Title order={3} mb="md">
|
<Title order={3} mb="md">
|
||||||
<Group>
|
<Group>
|
||||||
<Trans>Manage users</Trans>
|
<Trans>Manage users</Trans>
|
||||||
<ActionIcon color={theme.primaryColor} onClick={() => openUserEditModal(t`Add user`)}>
|
<ActionIcon color={theme.primaryColor} onClick={() => openUserEditModal(<Trans>Add user</Trans>)}>
|
||||||
<TbPlus size={20} />
|
<TbPlus size={20} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Group>
|
</Group>
|
||||||
@@ -126,7 +127,7 @@ export function AdminUsersPage() {
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<Group>
|
<Group>
|
||||||
<ActionIcon color={theme.primaryColor} onClick={() => openUserEditModal(t`Edit user`, u)}>
|
<ActionIcon color={theme.primaryColor} onClick={() => openUserEditModal(<Trans>Edit user</Trans>, u)}>
|
||||||
<TbPencil size={18} />
|
<TbPencil size={18} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const useStyles = createStyles(() => ({
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
function Section(props: { title: string; icon: React.ReactNode; children: React.ReactNode }) {
|
function Section(props: { title: React.ReactNode; icon: React.ReactNode; children: React.ReactNode }) {
|
||||||
const { classes } = useStyles()
|
const { classes } = useStyles()
|
||||||
return (
|
return (
|
||||||
<Box my="xl">
|
<Box my="xl">
|
||||||
@@ -38,7 +38,7 @@ function NextUnreadBookmarklet() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<CategorySelect value={categoryId} onChange={c => c && setCategoryId(c)} withAll description={t`Category`} />
|
<CategorySelect value={categoryId} onChange={c => c && setCategoryId(c)} withAll description={<Trans>Category</Trans>} />
|
||||||
<NativeSelect
|
<NativeSelect
|
||||||
data={[
|
data={[
|
||||||
{ value: "desc", label: t`Newest first` },
|
{ value: "desc", label: t`Newest first` },
|
||||||
@@ -46,7 +46,7 @@ function NextUnreadBookmarklet() {
|
|||||||
]}
|
]}
|
||||||
value={order}
|
value={order}
|
||||||
onChange={e => setOrder(e.target.value)}
|
onChange={e => setOrder(e.target.value)}
|
||||||
description={t`Order`}
|
description={<Trans>Order</Trans>}
|
||||||
/>
|
/>
|
||||||
<Trans>Drag link to bookmark bar</Trans>
|
<Trans>Drag link to bookmark bar</Trans>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
@@ -58,6 +58,7 @@ function NextUnreadBookmarklet() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bitcoinAddress = <Code>{Constants.bitcoinWalletAddress}</Code>
|
const bitcoinAddress = <Code>{Constants.bitcoinWalletAddress}</Code>
|
||||||
|
|
||||||
export function AboutPage() {
|
export function AboutPage() {
|
||||||
const version = useAppSelector(state => state.server.serverInfos?.version)
|
const version = useAppSelector(state => state.server.serverInfos?.version)
|
||||||
const revision = useAppSelector(state => state.server.serverInfos?.gitCommit)
|
const revision = useAppSelector(state => state.server.serverInfos?.gitCommit)
|
||||||
@@ -65,7 +66,7 @@ export function AboutPage() {
|
|||||||
return (
|
return (
|
||||||
<Container size="xl">
|
<Container size="xl">
|
||||||
<SimpleGrid cols={2} breakpoints={[{ maxWidth: Constants.layout.mobileBreakpoint, cols: 1 }]}>
|
<SimpleGrid cols={2} breakpoints={[{ maxWidth: Constants.layout.mobileBreakpoint, cols: 1 }]}>
|
||||||
<Section title={t`About`} icon={<TbHelp size={24} />}>
|
<Section title={<Trans>About</Trans>} icon={<TbHelp size={24} />}>
|
||||||
<Box>
|
<Box>
|
||||||
<Trans>
|
<Trans>
|
||||||
CommaFeed version {version} ({revision})
|
CommaFeed version {version} ({revision})
|
||||||
@@ -119,7 +120,7 @@ export function AboutPage() {
|
|||||||
<Trans>For those of you who prefer bitcoin, here is the address: {bitcoinAddress}</Trans>
|
<Trans>For those of you who prefer bitcoin, here is the address: {bitcoinAddress}</Trans>
|
||||||
</Box>
|
</Box>
|
||||||
</Section>
|
</Section>
|
||||||
<Section title={t`Goodies`} icon={<TbPuzzle size={24} />}>
|
<Section title={<Trans>Goodies</Trans>} icon={<TbPuzzle size={24} />}>
|
||||||
<List>
|
<List>
|
||||||
<List.Item>
|
<List.Item>
|
||||||
<Trans>Browser extentions</Trans>
|
<Trans>Browser extentions</Trans>
|
||||||
@@ -161,10 +162,10 @@ export function AboutPage() {
|
|||||||
</List.Item>
|
</List.Item>
|
||||||
</List>
|
</List>
|
||||||
</Section>
|
</Section>
|
||||||
<Section title={t`Keyboard shortcuts`} icon={<TbKeyboard size={24} />}>
|
<Section title={<Trans>Keyboard shortcuts</Trans>} icon={<TbKeyboard size={24} />}>
|
||||||
<KeyboardShortcutsHelp />
|
<KeyboardShortcutsHelp />
|
||||||
</Section>
|
</Section>
|
||||||
<Section title={t`REST API`} icon={<TbRocket size={24} />}>
|
<Section title={<Trans>REST API</Trans>} icon={<TbRocket size={24} />}>
|
||||||
<Anchor onClick={() => dispatch(redirectToApiDocumentation())}>
|
<Anchor onClick={() => dispatch(redirectToApiDocumentation())}>
|
||||||
<Trans>Go to the API documentation.</Trans>
|
<Trans>Go to the API documentation.</Trans>
|
||||||
</Anchor>
|
</Anchor>
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ export function AddPage() {
|
|||||||
<Container size="sm" px={0}>
|
<Container size="sm" px={0}>
|
||||||
<Tabs defaultValue="subscribe">
|
<Tabs defaultValue="subscribe">
|
||||||
<Tabs.List>
|
<Tabs.List>
|
||||||
<Tabs.Tab value="subscribe" icon={<TbRss />}>
|
<Tabs.Tab value="subscribe" icon={<TbRss size={16} />}>
|
||||||
<Trans>Subscribe</Trans>
|
<Trans>Subscribe</Trans>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
<Tabs.Tab value="category" icon={<TbFolderPlus />}>
|
<Tabs.Tab value="category" icon={<TbFolderPlus size={16} />}>
|
||||||
<Trans>Add category</Trans>
|
<Trans>Add category</Trans>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
<Tabs.Tab value="opml" icon={<TbFileImport />}>
|
<Tabs.Tab value="opml" icon={<TbFileImport size={16} />}>
|
||||||
<Trans>OPML</Trans>
|
<Trans>OPML</Trans>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Anchor, Box, Button, Code, Container, Divider, Group, Input, NumberInput, Stack, Text, TextInput, Title } from "@mantine/core"
|
import { Anchor, Box, Button, Code, Container, Divider, Group, Input, NumberInput, Stack, Text, TextInput, Title } from "@mantine/core"
|
||||||
import { useForm } from "@mantine/form"
|
import { useForm } from "@mantine/form"
|
||||||
import { openConfirmModal } from "@mantine/modals"
|
import { openConfirmModal } from "@mantine/modals"
|
||||||
@@ -48,7 +48,7 @@ export function CategoryDetailsPage() {
|
|||||||
const openDeleteCategoryModal = () => {
|
const openDeleteCategoryModal = () => {
|
||||||
const categoryName = category?.name
|
const categoryName = category?.name
|
||||||
return openConfirmModal({
|
return openConfirmModal({
|
||||||
title: t`Delete Category`,
|
title: <Trans>Delete Category</Trans>,
|
||||||
children: (
|
children: (
|
||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
<Trans>
|
<Trans>
|
||||||
@@ -56,7 +56,7 @@ export function CategoryDetailsPage() {
|
|||||||
</Trans>
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
),
|
),
|
||||||
labels: { confirm: t`Confirm`, cancel: t`Cancel` },
|
labels: { confirm: <Trans>Confirm</Trans>, cancel: <Trans>Cancel</Trans> },
|
||||||
confirmProps: { color: "red" },
|
confirmProps: { color: "red" },
|
||||||
onConfirm: () => deleteCategory.execute({ id: +id }),
|
onConfirm: () => deleteCategory.execute({ id: +id }),
|
||||||
})
|
})
|
||||||
@@ -91,7 +91,7 @@ export function CategoryDetailsPage() {
|
|||||||
<form onSubmit={form.onSubmit(modifyCategory.execute)}>
|
<form onSubmit={form.onSubmit(modifyCategory.execute)}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Title order={3}>{category.name}</Title>
|
<Title order={3}>{category.name}</Title>
|
||||||
<Input.Wrapper label={t`Generated feed url`}>
|
<Input.Wrapper label={<Trans>Generated feed url</Trans>}>
|
||||||
<Box>
|
<Box>
|
||||||
{apiKey && (
|
{apiKey && (
|
||||||
<Anchor
|
<Anchor
|
||||||
@@ -108,14 +108,16 @@ export function CategoryDetailsPage() {
|
|||||||
|
|
||||||
{editable && (
|
{editable && (
|
||||||
<>
|
<>
|
||||||
<TextInput label={t`Name`} {...form.getInputProps("name")} required />
|
<Divider />
|
||||||
|
|
||||||
|
<TextInput label={<Trans>Name</Trans>} {...form.getInputProps("name")} required />
|
||||||
<CategorySelect
|
<CategorySelect
|
||||||
label={t`Parent Category`}
|
label={<Trans>Parent Category</Trans>}
|
||||||
{...form.getInputProps("parentId")}
|
{...form.getInputProps("parentId")}
|
||||||
clearable
|
clearable
|
||||||
withoutCategoryIds={[id]}
|
withoutCategoryIds={[id]}
|
||||||
/>
|
/>
|
||||||
<NumberInput label={t`Position`} {...form.getInputProps("position")} required min={0} />
|
<NumberInput label={<Trans>Position</Trans>} {...form.getInputProps("position")} required min={0} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Anchor, Box, Button, Code, Container, Divider, Group, Input, NumberInput, Stack, Text, TextInput, Title } from "@mantine/core"
|
import { Anchor, Box, Button, Code, Container, Divider, Group, Input, NumberInput, Stack, Text, TextInput, Title } from "@mantine/core"
|
||||||
import { useForm } from "@mantine/form"
|
import { useForm } from "@mantine/form"
|
||||||
import { openConfirmModal } from "@mantine/modals"
|
import { openConfirmModal } from "@mantine/modals"
|
||||||
@@ -47,6 +47,7 @@ function FilteringExpressionDescription() {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FeedDetailsPage() {
|
export function FeedDetailsPage() {
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
if (!id) throw Error("id required")
|
if (!id) throw Error("id required")
|
||||||
@@ -75,7 +76,7 @@ export function FeedDetailsPage() {
|
|||||||
const openUnsubscribeModal = () => {
|
const openUnsubscribeModal = () => {
|
||||||
const feedName = feed?.name
|
const feedName = feed?.name
|
||||||
return openConfirmModal({
|
return openConfirmModal({
|
||||||
title: t`Unsubscribe`,
|
title: <Trans>Unsubscribe</Trans>,
|
||||||
children: (
|
children: (
|
||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
<Trans>
|
<Trans>
|
||||||
@@ -83,7 +84,7 @@ export function FeedDetailsPage() {
|
|||||||
</Trans>
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
),
|
),
|
||||||
labels: { confirm: t`Confirm`, cancel: t`Cancel` },
|
labels: { confirm: <Trans>Confirm</Trans>, cancel: <Trans>Cancel</Trans> },
|
||||||
confirmProps: { color: "red" },
|
confirmProps: { color: "red" },
|
||||||
onConfirm: () => unsubscribe.execute({ id: +id }),
|
onConfirm: () => unsubscribe.execute({ id: +id }),
|
||||||
})
|
})
|
||||||
@@ -112,34 +113,34 @@ export function FeedDetailsPage() {
|
|||||||
<form onSubmit={form.onSubmit(modifyFeed.execute)}>
|
<form onSubmit={form.onSubmit(modifyFeed.execute)}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Title order={3}>{feed.name}</Title>
|
<Title order={3}>{feed.name}</Title>
|
||||||
<Input.Wrapper label={t`Feed URL`}>
|
<Input.Wrapper label={<Trans>Feed URL</Trans>}>
|
||||||
<Box>
|
<Box>
|
||||||
<Anchor href={feed.feedUrl} target="_blank" rel="noreferrer">
|
<Anchor href={feed.feedUrl} target="_blank" rel="noreferrer">
|
||||||
{feed.feedUrl}
|
{feed.feedUrl}
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</Box>
|
</Box>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
<Input.Wrapper label={t`Website`}>
|
<Input.Wrapper label={<Trans>Website</Trans>}>
|
||||||
<Box>
|
<Box>
|
||||||
<Anchor href={feed.feedLink} target="_blank" rel="noreferrer">
|
<Anchor href={feed.feedLink} target="_blank" rel="noreferrer">
|
||||||
{feed.feedLink}
|
{feed.feedLink}
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</Box>
|
</Box>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
<Input.Wrapper label={t`Last refresh`}>
|
<Input.Wrapper label={<Trans>Last refresh</Trans>}>
|
||||||
<Box>
|
<Box>
|
||||||
<RelativeDate date={feed.lastRefresh} />
|
<RelativeDate date={feed.lastRefresh} />
|
||||||
</Box>
|
</Box>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
<Input.Wrapper label={t`Last refresh message`}>
|
<Input.Wrapper label={<Trans>Last refresh message</Trans>}>
|
||||||
<Box>{feed.message ?? t`N/A`}</Box>
|
<Box>{feed.message ?? <Trans>N/A</Trans>}</Box>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
<Input.Wrapper label={t`Next refresh`}>
|
<Input.Wrapper label={<Trans>Next refresh</Trans>}>
|
||||||
<Box>
|
<Box>
|
||||||
<RelativeDate date={feed.nextRefresh} />
|
<RelativeDate date={feed.nextRefresh} />
|
||||||
</Box>
|
</Box>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
<Input.Wrapper label={t`Generated feed url`}>
|
<Input.Wrapper label={<Trans>Generated feed url</Trans>}>
|
||||||
<Box>
|
<Box>
|
||||||
{apiKey && (
|
{apiKey && (
|
||||||
<Anchor href={`rest/feed/entriesAsFeed?id=${feed.id}&apiKey=${apiKey}`} target="_blank" rel="noreferrer">
|
<Anchor href={`rest/feed/entriesAsFeed?id=${feed.id}&apiKey=${apiKey}`} target="_blank" rel="noreferrer">
|
||||||
@@ -150,11 +151,13 @@ export function FeedDetailsPage() {
|
|||||||
</Box>
|
</Box>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
|
|
||||||
<TextInput label={t`Name`} {...form.getInputProps("name")} required />
|
<Divider />
|
||||||
<CategorySelect label={t`Category`} {...form.getInputProps("categoryId")} clearable />
|
|
||||||
<NumberInput label={t`Position`} {...form.getInputProps("position")} required min={0} />
|
<TextInput label={<Trans>Name</Trans>} {...form.getInputProps("name")} required />
|
||||||
|
<CategorySelect label={<Trans>Category</Trans>} {...form.getInputProps("categoryId")} clearable />
|
||||||
|
<NumberInput label={<Trans>Position</Trans>} {...form.getInputProps("position")} required min={0} />
|
||||||
<TextInput
|
<TextInput
|
||||||
label={t`Filtering expression`}
|
label={<Trans>Filtering expression</Trans>}
|
||||||
description={<FilteringExpressionDescription />}
|
description={<FilteringExpressionDescription />}
|
||||||
{...form.getInputProps("filter")}
|
{...form.getInputProps("filter")}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { ActionIcon, Anchor, Box, Center, Divider, Group, Title, useMantineTheme } from "@mantine/core"
|
import { ActionIcon, Box, Center, createStyles, Divider, Group, Title, useMantineTheme } from "@mantine/core"
|
||||||
import { useViewportSize } from "@mantine/hooks"
|
import { useViewportSize } from "@mantine/hooks"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import { EntrySourceType, loadEntries } from "app/slices/entries"
|
import { EntrySourceType, loadEntries } from "app/slices/entries"
|
||||||
@@ -27,7 +27,15 @@ interface FeedEntriesPageProps {
|
|||||||
sourceType: EntrySourceType
|
sourceType: EntrySourceType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles(() => ({
|
||||||
|
sourceWebsiteLink: {
|
||||||
|
color: "inherit",
|
||||||
|
textDecoration: "none",
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
export function FeedEntriesPage(props: FeedEntriesPageProps) {
|
export function FeedEntriesPage(props: FeedEntriesPageProps) {
|
||||||
|
const { classes } = useStyles()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const { id = Constants.categories.all.id } = useParams()
|
const { id = Constants.categories.all.id } = useParams()
|
||||||
const viewport = useViewportSize()
|
const viewport = useViewportSize()
|
||||||
@@ -63,9 +71,9 @@ export function FeedEntriesPage(props: FeedEntriesPageProps) {
|
|||||||
<Box mb={viewport.height - Constants.layout.headerHeight - 210}>
|
<Box mb={viewport.height - Constants.layout.headerHeight - 210}>
|
||||||
<Group spacing="xl">
|
<Group spacing="xl">
|
||||||
{sourceWebsiteUrl && (
|
{sourceWebsiteUrl && (
|
||||||
<Anchor href={sourceWebsiteUrl} target="_blank" rel="noreferrer" variant="text">
|
<a href={sourceWebsiteUrl} target="_blank" rel="noreferrer" className={classes.sourceWebsiteLink}>
|
||||||
<Title order={3}>{sourceLabel}</Title>
|
<Title order={3}>{sourceLabel}</Title>
|
||||||
</Anchor>
|
</a>
|
||||||
)}
|
)}
|
||||||
{!sourceWebsiteUrl && <Title order={3}>{sourceLabel}</Title>}
|
{!sourceWebsiteUrl && <Title order={3}>{sourceLabel}</Title>}
|
||||||
{sourceLabel && (
|
{sourceLabel && (
|
||||||
@@ -77,7 +85,7 @@ export function FeedEntriesPage(props: FeedEntriesPageProps) {
|
|||||||
|
|
||||||
<FeedEntries />
|
<FeedEntries />
|
||||||
|
|
||||||
{!hasMore && <Divider my="xl" label={t`No more entries`} labelPosition="center" />}
|
{!hasMore && <Divider my="xl" label={<Trans>No more entries</Trans>} labelPosition="center" />}
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
Anchor,
|
|
||||||
AppShell,
|
AppShell,
|
||||||
Box,
|
Box,
|
||||||
Burger,
|
Burger,
|
||||||
@@ -37,13 +36,13 @@ interface LayoutProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sidebarPadding = DEFAULT_THEME.spacing.xs
|
const sidebarPadding = DEFAULT_THEME.spacing.xs
|
||||||
const sidebarRightBorderWidth = 1
|
const sidebarRightBorderWidth = "1px"
|
||||||
|
|
||||||
const useStyles = createStyles(theme => ({
|
const useStyles = createStyles(theme => ({
|
||||||
sidebarContent: {
|
sidebarContent: {
|
||||||
maxWidth: Constants.layout.sidebarWidth - sidebarPadding * 2 - sidebarRightBorderWidth,
|
maxWidth: `calc(${Constants.layout.sidebarWidth}px - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`,
|
||||||
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
||||||
maxWidth: `calc(100vw - ${sidebarPadding * 2 + sidebarRightBorderWidth}px)`,
|
maxWidth: `calc(100vw - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mainContentWrapper: {
|
mainContentWrapper: {
|
||||||
@@ -68,14 +67,12 @@ const useStyles = createStyles(theme => ({
|
|||||||
function LogoAndTitle() {
|
function LogoAndTitle() {
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
return (
|
return (
|
||||||
<Anchor onClick={() => dispatch(redirectToRootCategory())} variant="text">
|
<Center inline onClick={() => dispatch(redirectToRootCategory())} style={{ cursor: "pointer" }}>
|
||||||
<Center inline>
|
<Logo size={24} />
|
||||||
<Logo size={24} />
|
<Title order={3} pl="md">
|
||||||
<Title order={3} pl="md">
|
CommaFeed
|
||||||
CommaFeed
|
</Title>
|
||||||
</Title>
|
</Center>
|
||||||
</Center>
|
|
||||||
</Anchor>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +119,7 @@ export default function Layout({ sidebar, header }: LayoutProps) {
|
|||||||
classNames={{ main: classes.mainContentWrapper }}
|
classNames={{ main: classes.mainContentWrapper }}
|
||||||
navbar={
|
navbar={
|
||||||
<Navbar
|
<Navbar
|
||||||
|
id="sidebar"
|
||||||
p={sidebarPadding}
|
p={sidebarPadding}
|
||||||
hiddenBreakpoint={Constants.layout.mobileBreakpoint}
|
hiddenBreakpoint={Constants.layout.mobileBreakpoint}
|
||||||
hidden={!mobileMenuOpen}
|
hidden={!mobileMenuOpen}
|
||||||
@@ -133,7 +131,7 @@ export default function Layout({ sidebar, header }: LayoutProps) {
|
|||||||
</Navbar>
|
</Navbar>
|
||||||
}
|
}
|
||||||
header={
|
header={
|
||||||
<Header height={Constants.layout.headerHeight} p="md">
|
<Header id="header" height={Constants.layout.headerHeight} p="md">
|
||||||
<OnMobile>
|
<OnMobile>
|
||||||
{mobileMenuOpen && (
|
{mobileMenuOpen && (
|
||||||
<Group position="apart">
|
<Group position="apart">
|
||||||
@@ -171,7 +169,7 @@ export default function Layout({ sidebar, header }: LayoutProps) {
|
|||||||
if (ref) ref.id = Constants.dom.mainScrollAreaId
|
if (ref) ref.id = Constants.dom.mainScrollAreaId
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box className={classes.mainContent}>
|
<Box id="content" className={classes.mainContent}>
|
||||||
<Suspense fallback={<Loader />}>
|
<Suspense fallback={<Loader />}>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
import { Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
import { Container, Tabs } from "@mantine/core"
|
import { Container, Tabs } from "@mantine/core"
|
||||||
|
import { CustomCodeSettings } from "components/settings/CustomCodeSettings"
|
||||||
import { DisplaySettings } from "components/settings/DisplaySettings"
|
import { DisplaySettings } from "components/settings/DisplaySettings"
|
||||||
import { ProfileSettings } from "components/settings/ProfileSettings"
|
import { ProfileSettings } from "components/settings/ProfileSettings"
|
||||||
import { TbPhoto, TbUser } from "react-icons/tb"
|
import { TbCode, TbPhoto, TbUser } from "react-icons/tb"
|
||||||
|
|
||||||
export function SettingsPage() {
|
export function SettingsPage() {
|
||||||
return (
|
return (
|
||||||
<Container size="sm" px={0}>
|
<Container size="sm" px={0}>
|
||||||
<Tabs defaultValue="display">
|
<Tabs defaultValue="display">
|
||||||
<Tabs.List>
|
<Tabs.List>
|
||||||
<Tabs.Tab value="display" icon={<TbPhoto />}>
|
<Tabs.Tab value="display" icon={<TbPhoto size={16} />}>
|
||||||
<Trans>Display</Trans>
|
<Trans>Display</Trans>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
<Tabs.Tab value="profile" icon={<TbUser />}>
|
<Tabs.Tab value="customCode" icon={<TbCode size={16} />}>
|
||||||
|
<Trans>Custom code</Trans>
|
||||||
|
</Tabs.Tab>
|
||||||
|
<Tabs.Tab value="profile" icon={<TbUser size={16} />}>
|
||||||
<Trans>Profile</Trans>
|
<Trans>Profile</Trans>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
@@ -21,6 +25,10 @@ export function SettingsPage() {
|
|||||||
<DisplaySettings />
|
<DisplaySettings />
|
||||||
</Tabs.Panel>
|
</Tabs.Panel>
|
||||||
|
|
||||||
|
<Tabs.Panel value="customCode" pt="xl">
|
||||||
|
<CustomCodeSettings />
|
||||||
|
</Tabs.Panel>
|
||||||
|
|
||||||
<Tabs.Panel value="profile" pt="xl">
|
<Tabs.Panel value="profile" pt="xl">
|
||||||
<ProfileSettings />
|
<ProfileSettings />
|
||||||
</Tabs.Panel>
|
</Tabs.Panel>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { t, Trans } from "@lingui/macro"
|
import { Trans } from "@lingui/macro"
|
||||||
|
|
||||||
import { Anchor, Box, Button, Container, Group, Input, Stack, Title } from "@mantine/core"
|
import { Anchor, Box, Button, Container, Group, Input, Stack, Title } from "@mantine/core"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
@@ -16,7 +16,7 @@ export function TagDetailsPage() {
|
|||||||
<Container>
|
<Container>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Title order={3}>{id}</Title>
|
<Title order={3}>{id}</Title>
|
||||||
<Input.Wrapper label={t`Generated feed url`}>
|
<Input.Wrapper label={<Trans>Generated feed url</Trans>}>
|
||||||
<Box>
|
<Box>
|
||||||
{apiKey && (
|
{apiKey && (
|
||||||
<Anchor
|
<Anchor
|
||||||
|
|||||||
@@ -42,15 +42,17 @@ export function LoginPage() {
|
|||||||
<form onSubmit={form.onSubmit(login.execute)}>
|
<form onSubmit={form.onSubmit(login.execute)}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={t`User Name or E-mail`}
|
label={<Trans>User Name or E-mail</Trans>}
|
||||||
placeholder={t`User Name or E-mail`}
|
placeholder={t`User Name or E-mail`}
|
||||||
{...form.getInputProps("name")}
|
{...form.getInputProps("name")}
|
||||||
description={serverInfos?.demoAccountEnabled ? t`Try out CommaFeed with the demo account: demo/demo` : ""}
|
description={
|
||||||
|
serverInfos?.demoAccountEnabled ? <Trans>Try out CommaFeed with the demo account: demo/demo</Trans> : ""
|
||||||
|
}
|
||||||
size="md"
|
size="md"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label={t`Password`}
|
label={<Trans>Password</Trans>}
|
||||||
placeholder={t`Password`}
|
placeholder={t`Password`}
|
||||||
{...form.getInputProps("password")}
|
{...form.getInputProps("password")}
|
||||||
size="md"
|
size="md"
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function PasswordRecoveryPage() {
|
|||||||
<Stack>
|
<Stack>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="email"
|
type="email"
|
||||||
label={t`E-mail`}
|
label={<Trans>E-mail</Trans>}
|
||||||
placeholder={t`E-mail`}
|
placeholder={t`E-mail`}
|
||||||
{...form.getInputProps("email")}
|
{...form.getInputProps("email")}
|
||||||
size="md"
|
size="md"
|
||||||
|
|||||||
@@ -53,14 +53,14 @@ export function RegistrationPage() {
|
|||||||
<TextInput label="User Name" placeholder="User Name" {...form.getInputProps("name")} size="md" required />
|
<TextInput label="User Name" placeholder="User Name" {...form.getInputProps("name")} size="md" required />
|
||||||
<TextInput
|
<TextInput
|
||||||
type="email"
|
type="email"
|
||||||
label={t`E-mail address`}
|
label={<Trans>E-mail address</Trans>}
|
||||||
placeholder={t`E-mail address`}
|
placeholder={t`E-mail address`}
|
||||||
{...form.getInputProps("email")}
|
{...form.getInputProps("email")}
|
||||||
size="md"
|
size="md"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label={t`Password`}
|
label={<Trans>Password</Trans>}
|
||||||
placeholder={t`Password`}
|
placeholder={t`Password`}
|
||||||
{...form.getInputProps("password")}
|
{...form.getInputProps("password")}
|
||||||
size="md"
|
size="md"
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ export default defineConfig({
|
|||||||
"/rest": "http://localhost:8083",
|
"/rest": "http://localhost:8083",
|
||||||
"/ws": "ws://localhost:8083",
|
"/ws": "ws://localhost:8083",
|
||||||
"/swagger": "http://localhost:8083",
|
"/swagger": "http://localhost:8083",
|
||||||
|
"/custom_css.css": "http://localhost:8083",
|
||||||
|
"/custom_js.js": "http://localhost:8083",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed</artifactId>
|
<artifactId>commafeed</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>commafeed-server</artifactId>
|
<artifactId>commafeed-server</artifactId>
|
||||||
<name>CommaFeed Server</name>
|
<name>CommaFeed Server</name>
|
||||||
@@ -39,13 +39,6 @@
|
|||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<parameters>true</parameters>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
@@ -233,7 +226,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed-client</artifactId>
|
<artifactId>commafeed-client</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import com.commafeed.frontend.resource.ServerREST;
|
|||||||
import com.commafeed.frontend.resource.UserREST;
|
import com.commafeed.frontend.resource.UserREST;
|
||||||
import com.commafeed.frontend.servlet.AnalyticsServlet;
|
import com.commafeed.frontend.servlet.AnalyticsServlet;
|
||||||
import com.commafeed.frontend.servlet.CustomCssServlet;
|
import com.commafeed.frontend.servlet.CustomCssServlet;
|
||||||
|
import com.commafeed.frontend.servlet.CustomJsServlet;
|
||||||
import com.commafeed.frontend.servlet.LogoutServlet;
|
import com.commafeed.frontend.servlet.LogoutServlet;
|
||||||
import com.commafeed.frontend.servlet.NextUnreadServlet;
|
import com.commafeed.frontend.servlet.NextUnreadServlet;
|
||||||
import com.commafeed.frontend.session.SessionHelperFactoryProvider;
|
import com.commafeed.frontend.session.SessionHelperFactoryProvider;
|
||||||
@@ -173,6 +174,7 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
|||||||
environment.servlets().addServlet("next", injector.getInstance(NextUnreadServlet.class)).addMapping("/next");
|
environment.servlets().addServlet("next", injector.getInstance(NextUnreadServlet.class)).addMapping("/next");
|
||||||
environment.servlets().addServlet("logout", injector.getInstance(LogoutServlet.class)).addMapping("/logout");
|
environment.servlets().addServlet("logout", injector.getInstance(LogoutServlet.class)).addMapping("/logout");
|
||||||
environment.servlets().addServlet("customCss", injector.getInstance(CustomCssServlet.class)).addMapping("/custom_css.css");
|
environment.servlets().addServlet("customCss", injector.getInstance(CustomCssServlet.class)).addMapping("/custom_css.css");
|
||||||
|
environment.servlets().addServlet("customJs", injector.getInstance(CustomJsServlet.class)).addMapping("/custom_js.js");
|
||||||
environment.servlets().addServlet("analytics.js", injector.getInstance(AnalyticsServlet.class)).addMapping("/analytics.js");
|
environment.servlets().addServlet("analytics.js", injector.getInstance(AnalyticsServlet.class)).addMapping("/analytics.js");
|
||||||
|
|
||||||
// WebSocket endpoint
|
// WebSocket endpoint
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.commafeed.backend.cache;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import redis.clients.jedis.DefaultJedisClientConfig;
|
import redis.clients.jedis.DefaultJedisClientConfig;
|
||||||
import redis.clients.jedis.HostAndPort;
|
import redis.clients.jedis.HostAndPort;
|
||||||
import redis.clients.jedis.JedisClientConfig;
|
import redis.clients.jedis.JedisClientConfig;
|
||||||
@@ -11,7 +10,6 @@ import redis.clients.jedis.JedisPool;
|
|||||||
import redis.clients.jedis.JedisPoolConfig;
|
import redis.clients.jedis.JedisPoolConfig;
|
||||||
import redis.clients.jedis.Protocol;
|
import redis.clients.jedis.Protocol;
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Getter
|
@Getter
|
||||||
public class RedisPoolFactory {
|
public class RedisPoolFactory {
|
||||||
|
|
||||||
|
|||||||
@@ -46,24 +46,22 @@ public class UserSettings extends AbstractModel {
|
|||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private ReadingOrder readingOrder;
|
private ReadingOrder readingOrder;
|
||||||
|
|
||||||
@Enumerated(EnumType.STRING)
|
|
||||||
@Column(nullable = false)
|
|
||||||
private ViewMode viewMode;
|
|
||||||
|
|
||||||
@Column(name = "user_lang", length = 4)
|
@Column(name = "user_lang", length = 4)
|
||||||
private String language;
|
private String language;
|
||||||
|
|
||||||
private boolean showRead;
|
private boolean showRead;
|
||||||
private boolean scrollMarks;
|
private boolean scrollMarks;
|
||||||
|
|
||||||
@Column(length = 32)
|
|
||||||
private String theme;
|
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Column(length = Integer.MAX_VALUE)
|
@Column(length = Integer.MAX_VALUE)
|
||||||
@Type(type = "org.hibernate.type.TextType")
|
@Type(type = "org.hibernate.type.TextType")
|
||||||
private String customCss;
|
private String customCss;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
@Column(length = Integer.MAX_VALUE)
|
||||||
|
@Type(type = "org.hibernate.type.TextType")
|
||||||
|
private String customJs;
|
||||||
|
|
||||||
@Column(name = "scroll_speed")
|
@Column(name = "scroll_speed")
|
||||||
private int scrollSpeed;
|
private int scrollSpeed;
|
||||||
|
|
||||||
|
|||||||
@@ -20,21 +20,18 @@ public class Settings implements Serializable {
|
|||||||
@ApiModelProperty(value = "user reads entries in ascending or descending order", allowableValues = "asc,desc", required = true)
|
@ApiModelProperty(value = "user reads entries in ascending or descending order", allowableValues = "asc,desc", required = true)
|
||||||
private String readingOrder;
|
private String readingOrder;
|
||||||
|
|
||||||
@ApiModelProperty(value = "user viewing mode, either title-only or expande view", allowableValues = "title,expanded", required = true)
|
|
||||||
private String viewMode;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "user wants category and feeds with no unread entries shown", required = true)
|
@ApiModelProperty(value = "user wants category and feeds with no unread entries shown", required = true)
|
||||||
private boolean showRead;
|
private boolean showRead;
|
||||||
|
|
||||||
@ApiModelProperty(value = "In expanded view, scroll through entries mark them as read", required = true)
|
@ApiModelProperty(value = "In expanded view, scroll through entries mark them as read", required = true)
|
||||||
private boolean scrollMarks;
|
private boolean scrollMarks;
|
||||||
|
|
||||||
@ApiModelProperty(value = "user's selected theme")
|
|
||||||
private String theme;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "user's custom css for the website")
|
@ApiModelProperty(value = "user's custom css for the website")
|
||||||
private String customCss;
|
private String customCss;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "user's custom js for the website")
|
||||||
|
private String customJs;
|
||||||
|
|
||||||
@ApiModelProperty(value = "user's preferred scroll speed when navigating between entries", required = true)
|
@ApiModelProperty(value = "user's preferred scroll speed when navigating between entries", required = true)
|
||||||
private int scrollSpeed;
|
private int scrollSpeed;
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import com.commafeed.backend.model.UserRole.Role;
|
|||||||
import com.commafeed.backend.model.UserSettings;
|
import com.commafeed.backend.model.UserSettings;
|
||||||
import com.commafeed.backend.model.UserSettings.ReadingMode;
|
import com.commafeed.backend.model.UserSettings.ReadingMode;
|
||||||
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
||||||
import com.commafeed.backend.model.UserSettings.ViewMode;
|
|
||||||
import com.commafeed.backend.service.MailService;
|
import com.commafeed.backend.service.MailService;
|
||||||
import com.commafeed.backend.service.PasswordEncryptionService;
|
import com.commafeed.backend.service.PasswordEncryptionService;
|
||||||
import com.commafeed.backend.service.UserService;
|
import com.commafeed.backend.service.UserService;
|
||||||
@@ -88,7 +87,6 @@ public class UserREST {
|
|||||||
if (settings != null) {
|
if (settings != null) {
|
||||||
s.setReadingMode(settings.getReadingMode().name());
|
s.setReadingMode(settings.getReadingMode().name());
|
||||||
s.setReadingOrder(settings.getReadingOrder().name());
|
s.setReadingOrder(settings.getReadingOrder().name());
|
||||||
s.setViewMode(settings.getViewMode().name());
|
|
||||||
s.setShowRead(settings.isShowRead());
|
s.setShowRead(settings.isShowRead());
|
||||||
|
|
||||||
s.getSharingSettings().setEmail(settings.isEmail());
|
s.getSharingSettings().setEmail(settings.isEmail());
|
||||||
@@ -101,16 +99,14 @@ public class UserREST {
|
|||||||
s.getSharingSettings().setBuffer(settings.isBuffer());
|
s.getSharingSettings().setBuffer(settings.isBuffer());
|
||||||
|
|
||||||
s.setScrollMarks(settings.isScrollMarks());
|
s.setScrollMarks(settings.isScrollMarks());
|
||||||
s.setTheme(settings.getTheme());
|
|
||||||
s.setCustomCss(settings.getCustomCss());
|
s.setCustomCss(settings.getCustomCss());
|
||||||
|
s.setCustomJs(settings.getCustomJs());
|
||||||
s.setLanguage(settings.getLanguage());
|
s.setLanguage(settings.getLanguage());
|
||||||
s.setScrollSpeed(settings.getScrollSpeed());
|
s.setScrollSpeed(settings.getScrollSpeed());
|
||||||
} else {
|
} else {
|
||||||
s.setReadingMode(ReadingMode.unread.name());
|
s.setReadingMode(ReadingMode.unread.name());
|
||||||
s.setReadingOrder(ReadingOrder.desc.name());
|
s.setReadingOrder(ReadingOrder.desc.name());
|
||||||
s.setViewMode(ViewMode.title.name());
|
|
||||||
s.setShowRead(true);
|
s.setShowRead(true);
|
||||||
s.setTheme("default");
|
|
||||||
|
|
||||||
s.getSharingSettings().setEmail(true);
|
s.getSharingSettings().setEmail(true);
|
||||||
s.getSharingSettings().setGmail(true);
|
s.getSharingSettings().setGmail(true);
|
||||||
@@ -144,10 +140,9 @@ public class UserREST {
|
|||||||
s.setReadingMode(ReadingMode.valueOf(settings.getReadingMode()));
|
s.setReadingMode(ReadingMode.valueOf(settings.getReadingMode()));
|
||||||
s.setReadingOrder(ReadingOrder.valueOf(settings.getReadingOrder()));
|
s.setReadingOrder(ReadingOrder.valueOf(settings.getReadingOrder()));
|
||||||
s.setShowRead(settings.isShowRead());
|
s.setShowRead(settings.isShowRead());
|
||||||
s.setViewMode(ViewMode.valueOf(settings.getViewMode()));
|
|
||||||
s.setScrollMarks(settings.isScrollMarks());
|
s.setScrollMarks(settings.isScrollMarks());
|
||||||
s.setTheme(settings.getTheme());
|
|
||||||
s.setCustomCss(settings.getCustomCss());
|
s.setCustomCss(settings.getCustomCss());
|
||||||
|
s.setCustomJs(settings.getCustomJs());
|
||||||
s.setLanguage(settings.getLanguage());
|
s.setLanguage(settings.getLanguage());
|
||||||
s.setScrollSpeed(settings.getScrollSpeed());
|
s.setScrollSpeed(settings.getScrollSpeed());
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.commafeed.frontend.servlet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
|
||||||
|
import com.commafeed.backend.dao.UnitOfWork;
|
||||||
|
import com.commafeed.backend.dao.UserSettingsDAO;
|
||||||
|
import com.commafeed.backend.model.User;
|
||||||
|
import com.commafeed.backend.model.UserSettings;
|
||||||
|
import com.commafeed.frontend.session.SessionHelper;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
abstract class AbstractCustomCodeServlet extends HttpServlet {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final SessionFactory sessionFactory;
|
||||||
|
private final UserSettingsDAO userSettingsDAO;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void doGet(final HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||||
|
resp.setContentType(getMimeType());
|
||||||
|
|
||||||
|
final Optional<User> user = new SessionHelper(req).getLoggedInUser();
|
||||||
|
if (!user.isPresent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserSettings settings = UnitOfWork.call(sessionFactory, () -> userSettingsDAO.findByUser(user.get()));
|
||||||
|
if (settings == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String customCode = getCustomCode(settings);
|
||||||
|
if (customCode == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.getWriter().write(customCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getMimeType();
|
||||||
|
|
||||||
|
protected abstract String getCustomCode(UserSettings settings);
|
||||||
|
}
|
||||||
@@ -1,47 +1,29 @@
|
|||||||
package com.commafeed.frontend.servlet;
|
package com.commafeed.frontend.servlet;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
|
|
||||||
import com.commafeed.backend.dao.UnitOfWork;
|
|
||||||
import com.commafeed.backend.dao.UserSettingsDAO;
|
import com.commafeed.backend.dao.UserSettingsDAO;
|
||||||
import com.commafeed.backend.model.User;
|
|
||||||
import com.commafeed.backend.model.UserSettings;
|
import com.commafeed.backend.model.UserSettings;
|
||||||
import com.commafeed.frontend.session.SessionHelper;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
public class CustomCssServlet extends AbstractCustomCodeServlet {
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
private static final long serialVersionUID = 1L;
|
||||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
|
||||||
@Singleton
|
|
||||||
public class CustomCssServlet extends HttpServlet {
|
|
||||||
|
|
||||||
private final SessionFactory sessionFactory;
|
@Inject
|
||||||
private final UserSettingsDAO userSettingsDAO;
|
public CustomCssServlet(SessionFactory sessionFactory, UserSettingsDAO userSettingsDAO) {
|
||||||
|
super(sessionFactory, userSettingsDAO);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
protected String getMimeType() {
|
||||||
resp.setContentType("text/css");
|
return "text/css";
|
||||||
|
|
||||||
final Optional<User> user = new SessionHelper(req).getLoggedInUser();
|
|
||||||
if (!user.isPresent()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserSettings settings = UnitOfWork.call(sessionFactory, () -> userSettingsDAO.findByUser(user.get()));
|
|
||||||
if (settings == null || settings.getCustomCss() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.getWriter().write(settings.getCustomCss());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCustomCode(UserSettings settings) {
|
||||||
|
return settings.getCustomCss();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.commafeed.frontend.servlet;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
|
||||||
|
import com.commafeed.backend.dao.UserSettingsDAO;
|
||||||
|
import com.commafeed.backend.model.UserSettings;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class CustomJsServlet extends AbstractCustomCodeServlet {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public CustomJsServlet(SessionFactory sessionFactory, UserSettingsDAO userSettingsDAO) {
|
||||||
|
super(sessionFactory, userSettingsDAO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMimeType() {
|
||||||
|
return "application/javascript";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCustomCode(UserSettings settings) {
|
||||||
|
return settings.getCustomJs();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||||
|
|
||||||
|
|
||||||
|
<changeSet id="delete-removed-settings" author="athou">
|
||||||
|
<dropColumn tableName="USERSETTINGS" columnName="theme" />
|
||||||
|
<dropColumn tableName="USERSETTINGS" columnName="viewMode" />
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
<changeSet id="add-customjs-column" author="athou">
|
||||||
|
<addColumn tableName="USERSETTINGS">
|
||||||
|
<column name="customJs" type="CLOB" />
|
||||||
|
</addColumn>
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
</databaseChangeLog>
|
||||||
@@ -1,21 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||||
|
|
||||||
<property name="blob_type" value="bytea" dbms="postgresql"/>
|
<property name="blob_type" value="bytea" dbms="postgresql"/>
|
||||||
<property name="blob_type" value="blob" dbms="h2" />
|
<property name="blob_type" value="blob" dbms="h2"/>
|
||||||
<property name="blob_type" value="blob" dbms="mysql,mariadb" />
|
<property name="blob_type" value="blob" dbms="mysql,mariadb"/>
|
||||||
<property name="blob_type" value="blob" dbms="mssql" />
|
<property name="blob_type" value="blob" dbms="mssql"/>
|
||||||
|
|
||||||
|
<include file="changelogs/db.changelog-1.0.xml"/>
|
||||||
|
<include file="changelogs/db.changelog-1.1.xml"/>
|
||||||
|
<include file="changelogs/db.changelog-1.2.xml"/>
|
||||||
|
<include file="changelogs/db.changelog-1.3.xml"/>
|
||||||
|
<include file="changelogs/db.changelog-1.4.xml"/>
|
||||||
|
<include file="changelogs/db.changelog-1.5.xml"/>
|
||||||
|
<include file="changelogs/db.changelog-2.1.xml"/>
|
||||||
|
<include file="changelogs/db.changelog-2.2.xml"/>
|
||||||
|
<include file="changelogs/db.changelog-2.6.xml"/>
|
||||||
|
<include file="changelogs/db.changelog-3.2.xml"/>
|
||||||
|
|
||||||
<include file="changelogs/db.changelog-1.0.xml" />
|
|
||||||
<include file="changelogs/db.changelog-1.1.xml" />
|
|
||||||
<include file="changelogs/db.changelog-1.2.xml" />
|
|
||||||
<include file="changelogs/db.changelog-1.3.xml" />
|
|
||||||
<include file="changelogs/db.changelog-1.4.xml" />
|
|
||||||
<include file="changelogs/db.changelog-1.5.xml" />
|
|
||||||
<include file="changelogs/db.changelog-2.1.xml" />
|
|
||||||
<include file="changelogs/db.changelog-2.2.xml" />
|
|
||||||
<include file="changelogs/db.changelog-2.6.xml" />
|
|
||||||
|
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
21
pom.xml
21
pom.xml
@@ -1,11 +1,11 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed</artifactId>
|
<artifactId>commafeed</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.3.2</version>
|
||||||
<name>CommaFeed</name>
|
<name>CommaFeed</name>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
@@ -15,26 +15,15 @@
|
|||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>only-eclipse</id>
|
|
||||||
<activation>
|
|
||||||
<property>
|
|
||||||
<name>m2e.version</name>
|
|
||||||
</property>
|
|
||||||
</activation>
|
|
||||||
<build>
|
|
||||||
<directory>target-ide</directory>
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.10.1</version>
|
<version>3.10.1</version>
|
||||||
|
<configuration>
|
||||||
|
<parameters>true</parameters>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|||||||
Reference in New Issue
Block a user